1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <fcntl.h>
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <vector>
22 
23 #include "plugin_manager.h"
24 #include "plugin_watcher.h"
25 
26 #include "logging.h"
27 
28 using namespace testing::ext;
29 
30 namespace {
31 constexpr int DEAFULT_FILE_MODE = 0777;
32 
33 #if defined(__i386__) || defined(__x86_64__)
34 const std::string DEFAULT_TEST_PATH = "./";
35 #else
36 const std::string DEFAULT_TEST_PATH_1 = "/data/local/tmp/watchertest/1/";
37 const std::string DEFAULT_TEST_PATH_2 = "/data/local/tmp/watchertest/2/";
38 const std::string DEFAULT_TEST_PATH_3 = "/data/local/tmp/watchertest/3/";
39 const std::string NO_EXIST_TEST_PATH = "/data/local/tmp/noexist/";
40 #endif
41 
42 class PluginWatchTest : public ::testing::Test {
43 protected:
44     static constexpr int TEMP_DELAY = 10 * 1000;
SetUpTestCase()45     static void SetUpTestCase() {}
TearDownTestCase()46     static void TearDownTestCase() {}
47 
48     void SetUp() override
49     {
50         std::string cmd = "mkdir -p " + DEFAULT_TEST_PATH_1;
51         system(cmd.c_str());
52         cmd = "mkdir -p " + DEFAULT_TEST_PATH_2;
53         system(cmd.c_str());
54         cmd = "mkdir -p " + DEFAULT_TEST_PATH_3;
55         system(cmd.c_str());
56         sort(expectFileList.begin(), expectFileList.end());
57     }
58 
59     void TearDown() override
60     {
61         cmpFileList.clear();
62     }
63 
OnPluginAddedStub(const std::string& path)64     void OnPluginAddedStub(const std::string& path)
65     {
66         cmpFileList.push_back(path);
67         sort(cmpFileList.begin(), cmpFileList.end());
68     }
69 
OnPluginRemovedStub(const std::string& path)70     void OnPluginRemovedStub(const std::string& path)
71     {
72         for (auto iter = cmpFileList.cbegin(); iter != cmpFileList.cend(); iter++) {
73             if (*iter == path) {
74                 cmpFileList.erase(iter);
75                 break;
76             }
77         }
78     }
79 
CreateFile(std::string dirPath) const80     void CreateFile(std::string dirPath) const
81     {
82         for (auto it : createFileList) {
83             int fd = creat((dirPath + it).c_str(), DEAFULT_FILE_MODE);
84             if (fd > 0) {
85                 close(fd);
86             }
87         }
88     }
89 
AddFile(std::string dirPath) const90     void AddFile(std::string dirPath) const
91     {
92         for (auto it : addFileList) {
93             int fd = creat((dirPath + it).c_str(), DEAFULT_FILE_MODE);
94             if (fd < 0) {
95                 return;
96             }
97             write(fd, "testcase", 1);
98             close(fd);
99         }
100     }
101 
DeleteFile(std::string dirPath) const102     void DeleteFile(std::string dirPath) const
103     {
104         for (auto it : createFileList) {
105             if (remove((dirPath + it).c_str()) != 0) {
106                 return;
107             }
108         }
109         for (auto it : addFileList) {
110             if (remove((dirPath + it).c_str()) != 0) {
111                 return;
112             }
113         }
114     }
115 
CheckFileList(std::string dirPath) const116     bool CheckFileList(std::string dirPath) const
117     {
118         if (cmpFileList.size() != expectFileList.size()) {
119             return false;
120         }
121 
122         for (size_t i = 0; i < cmpFileList.size(); i++) {
123             if (cmpFileList.at(i) != (dirPath + expectFileList.at(i))) {
124                 return false;
125             }
126         }
127 
128         return true;
129     }
130 
131 private:
132     std::vector<std::string> cmpFileList;
133 
134     const std::vector<std::string> createFileList = {
135         "lib_6.so", "lib_5.so", "lib_8.so", "lib_4.so", "test1.txt"
136     };
137 
138     const std::vector<std::string> addFileList = {
139         "libadd_6.so", "libadd_5.so", "libadd_8.so", "libadd_4.so", "test2.txt"
140     };
141 
142     std::vector<std::string> expectFileList = {
143         "libadd_6.so", "libadd_5.so", "libadd_8.so", "libadd_4.so",
144         "lib_6.so",    "lib_5.so",    "lib_8.so",    "lib_4.so"
145     };
146 };
147 
148 class MockPluginWatcher : public PluginWatcher {
149 public:
MockPluginWatcher(const PluginManagerPtr& pluginManager)150     explicit MockPluginWatcher(const PluginManagerPtr& pluginManager) : PluginWatcher(pluginManager) {}
151     ~MockPluginWatcher() = default;
152     MOCK_METHOD1(OnPluginAdded, void(const std::string&));
153     MOCK_METHOD1(OnPluginRemoved, void(const std::string&));
154 };
155 
156 /**
157  * @tc.name: plugin
158  * @tc.desc: Monitor single plugin dir.
159  * @tc.type: FUNC
160  */
HWTEST_F(PluginWatchTest, SingleWatchDirTest, TestSize.Level1)161 HWTEST_F(PluginWatchTest, SingleWatchDirTest, TestSize.Level1)
162 {
163     auto pluginManage = std::make_shared<PluginManager>();
164     MockPluginWatcher watcher(pluginManage);
165 
166     EXPECT_CALL(watcher, OnPluginAdded(testing::_)).WillRepeatedly(
167         testing::Invoke(this, &PluginWatchTest::OnPluginAddedStub));
168     EXPECT_CALL(watcher, OnPluginRemoved(testing::_)).WillRepeatedly(
169         testing::Invoke(this, &PluginWatchTest::OnPluginRemovedStub));
170     CreateFile(DEFAULT_TEST_PATH_1);
171 
172     EXPECT_TRUE(watcher.ScanPlugins(DEFAULT_TEST_PATH_1));
173     EXPECT_TRUE(watcher.WatchPlugins(DEFAULT_TEST_PATH_1));
174     usleep(TEMP_DELAY);
175     AddFile(DEFAULT_TEST_PATH_1);
176     usleep(TEMP_DELAY);
177     EXPECT_EQ(CheckFileList(DEFAULT_TEST_PATH_1), true);
178     DeleteFile(DEFAULT_TEST_PATH_1);
179     usleep(TEMP_DELAY);
180     EXPECT_EQ(cmpFileList.size(), 0);
181 }
182 
183 /**
184  * @tc.name: plugin
185  * @tc.desc: Monitor multi plugin dir.
186  * @tc.type: FUNC
187  */
HWTEST_F(PluginWatchTest, MultiWatchDirTest, TestSize.Level1)188 HWTEST_F(PluginWatchTest, MultiWatchDirTest, TestSize.Level1)
189 {
190     auto pluginManage = std::make_shared<PluginManager>();
191     MockPluginWatcher watcher(pluginManage);
192 
193     EXPECT_CALL(watcher, OnPluginAdded(testing::_)).WillRepeatedly(
194         testing::Invoke(this, &PluginWatchTest::OnPluginAddedStub));
195     EXPECT_CALL(watcher, OnPluginRemoved(testing::_)).WillRepeatedly(
196         testing::Invoke(this, &PluginWatchTest::OnPluginRemovedStub));
197     CreateFile(DEFAULT_TEST_PATH_1);
198     EXPECT_TRUE(watcher.ScanPlugins(DEFAULT_TEST_PATH_1));
199     EXPECT_TRUE(watcher.WatchPlugins(DEFAULT_TEST_PATH_1));
200     usleep(TEMP_DELAY);
201     AddFile(DEFAULT_TEST_PATH_1);
202     usleep(TEMP_DELAY);
203     EXPECT_EQ(CheckFileList(DEFAULT_TEST_PATH_1), true);
204     DeleteFile(DEFAULT_TEST_PATH_1);
205     usleep(TEMP_DELAY);
206     EXPECT_EQ(cmpFileList.size(), 0);
207 
208     CreateFile(DEFAULT_TEST_PATH_2);
209     EXPECT_TRUE(watcher.ScanPlugins(DEFAULT_TEST_PATH_2));
210     EXPECT_TRUE(watcher.WatchPlugins(DEFAULT_TEST_PATH_2));
211     usleep(TEMP_DELAY);
212     AddFile(DEFAULT_TEST_PATH_2);
213     usleep(TEMP_DELAY);
214     EXPECT_EQ(CheckFileList(DEFAULT_TEST_PATH_2), true);
215     DeleteFile(DEFAULT_TEST_PATH_2);
216     usleep(TEMP_DELAY);
217     EXPECT_EQ(cmpFileList.size(), 0);
218 
219     CreateFile(DEFAULT_TEST_PATH_3);
220     EXPECT_TRUE(watcher.ScanPlugins(DEFAULT_TEST_PATH_3));
221     EXPECT_TRUE(watcher.WatchPlugins(DEFAULT_TEST_PATH_3));
222     usleep(TEMP_DELAY);
223     AddFile(DEFAULT_TEST_PATH_3);
224     usleep(TEMP_DELAY);
225     EXPECT_EQ(CheckFileList(DEFAULT_TEST_PATH_3), true);
226     DeleteFile(DEFAULT_TEST_PATH_3);
227     usleep(TEMP_DELAY);
228     EXPECT_EQ(cmpFileList.size(), 0);
229 }
230 
231 /**
232  * @tc.name: plugin
233  * @tc.desc: Exception test.
234  * @tc.type: FUNC
235  */
HWTEST_F(PluginWatchTest, ExceptionTest, TestSize.Level1)236 HWTEST_F(PluginWatchTest, ExceptionTest, TestSize.Level1)
237 {
238     auto pluginManage = std::make_shared<PluginManager>();
239     MockPluginWatcher watcher(pluginManage);
240     EXPECT_FALSE(watcher.ScanPlugins(NO_EXIST_TEST_PATH));
241     EXPECT_FALSE(watcher.WatchPlugins(NO_EXIST_TEST_PATH));
242 }
243 } // namespace
244