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 <gtest/gtest.h>
17 #include <dlfcn.h>
18 #include "diskio_data_plugin.h"
19 #include "plugin_module_api.h"
20 
21 using namespace testing::ext;
22 
23 namespace {
24 const std::string DEFAULT_TEST_PATH = "/data/local/tmp/resources";
25 const std::string SO_PATH = "libdiskiodataplugin.z.so";
26 const std::string DEFAULT_BIN_PATH("/data/local/tmp/diskiodataplugintest");
27 constexpr uint32_t BUF_SIZE = 4 * 1024 * 1024;
28 constexpr int WRITE_KB = 1000;
29 
30 std::string g_path;
31 std::string g_testPath;
32 
33 struct TestVmstat {
34     int64_t pgpgin;
35     int64_t pgpgout;
36 };
37 
38 TestVmstat g_vmStat = {2072559, 27543064};
39 
40 class DiskioDataPluginTest : public ::testing::Test {
41 public:
SetUpTestCase()42     static void SetUpTestCase() {}
43 
TearDownTestCase()44     static void TearDownTestCase()
45     {
46         if (access(g_testPath.c_str(), F_OK) == 0) {
47             std::string str = "rm -rf " + g_testPath;
48             system(str.c_str());
49         }
50     }
51 };
52 
Getexepath()53 string Getexepath()
54 {
55     char buf[PATH_MAX] = "";
56     std::string path = "/proc/self/exe";
57     size_t rslt = readlink(path.c_str(), buf, sizeof(buf));
58     if (rslt < 0 || (rslt >= sizeof(buf))) {
59         return "";
60     }
61     buf[rslt] = '\0';
62     for (int i = rslt; i >= 0; i--) {
63         if (buf[i] == '/') {
64             buf[i + 1] = '\0';
65             break;
66         }
67     }
68     return buf;
69 }
70 
GetFullPath(std::string path)71 std::string GetFullPath(std::string path)
72 {
73     if (path.size() > 0 && path[0] != '/') {
74         return Getexepath() + path;
75     }
76     return path;
77 }
78 
PluginDiskioInfoStub(DiskioDataPlugin& diskioPlugin, DiskioData& diskioData, bool unusualBuff)79 bool PluginDiskioInfoStub(DiskioDataPlugin& diskioPlugin, DiskioData& diskioData, bool unusualBuff)
80 {
81     DiskioConfig protoConfig;
82     std::vector<uint8_t> configData(protoConfig.ByteSizeLong());
83     int ret = protoConfig.SerializeToArray(configData.data(), configData.size());
84     if (ret < 0) {
85         return false;
86     }
87 
88     // start
89     ret = diskioPlugin.Start(configData.data(), configData.size());
90     if (ret < 0) {
91         return false;
92     }
93 
94     // report
95     std::vector<uint8_t> bufferData(BUF_SIZE);
96     if (unusualBuff) { // buffer异常,调整缓冲区长度为1,测试异常情况
97         bufferData.resize(1, 0);
98     }
99 
100     ret = diskioPlugin.Report(bufferData.data(), bufferData.size());
101     if (ret > 0) {
102         diskioData.ParseFromArray(bufferData.data(), ret);
103         return true;
104     }
105     return false;
106 }
107 
108 /**
109  * @tc.name: diskio plugin
110  * @tc.desc: Test whether the path exists.
111  * @tc.type: FUNC
112  */
HWTEST_F(DiskioDataPluginTest, TestPath, TestSize.Level1)113 HWTEST_F(DiskioDataPluginTest, TestPath, TestSize.Level1)
114 {
115     g_path = GetFullPath(DEFAULT_TEST_PATH);
116     g_testPath = g_path;
117     EXPECT_NE("", g_path);
118     g_path += "/proc/vmstat";
119 }
120 
121 /**
122  * @tc.name: diskio plugin
123  * @tc.desc: diskio information test for specific path.
124  * @tc.type: FUNC
125  */
HWTEST_F(DiskioDataPluginTest, TestPlugin, TestSize.Level1)126 HWTEST_F(DiskioDataPluginTest, TestPlugin, TestSize.Level1)
127 {
128     DiskioDataPlugin diskioPlugin;
129     DiskioData diskioData;
130     diskioPlugin.SetPath(g_path);
131 
132     EXPECT_TRUE(PluginDiskioInfoStub(diskioPlugin, diskioData, false));
133     EXPECT_EQ(diskioData.prev_rd_sectors_kb(), 0);
134     EXPECT_EQ(diskioData.prev_wr_sectors_kb(), 0);
135     EXPECT_EQ(diskioData.rd_sectors_kb(), g_vmStat.pgpgin);
136     EXPECT_EQ(diskioData.wr_sectors_kb(), g_vmStat.pgpgout);
137 
138     EXPECT_EQ(diskioPlugin.Stop(), 0);
139 
140     // 缓冲区异常
141     EXPECT_FALSE(PluginDiskioInfoStub(diskioPlugin, diskioData, true));
142     EXPECT_EQ(diskioPlugin.Stop(), 0);
143 }
144 
145 /**
146  * @tc.name: diskio plugin
147  * @tc.desc: diskio information test for unusual path.
148  * @tc.type: FUNC
149  */
HWTEST_F(DiskioDataPluginTest, TestPluginBoundary, TestSize.Level1)150 HWTEST_F(DiskioDataPluginTest, TestPluginBoundary, TestSize.Level1)
151 {
152     DiskioDataPlugin diskioPlugin;
153     DiskioData diskioData;
154     diskioPlugin.SetPath("123");
155     EXPECT_FALSE(PluginDiskioInfoStub(diskioPlugin, diskioData, false));
156     diskioPlugin.Stop();
157 }
158 
159 /**
160  * @tc.name: diskio plugin
161  * @tc.desc: diskio plugin registration test.
162  * @tc.type: FUNC
163  */
HWTEST_F(DiskioDataPluginTest, TestPluginRegister, TestSize.Level1)164 HWTEST_F(DiskioDataPluginTest, TestPluginRegister, TestSize.Level1)
165 {
166     void* handle = dlopen(SO_PATH.c_str(), RTLD_LAZY);
167     ASSERT_NE(handle, nullptr);
168     PluginModuleStruct* diskioPlugin = (PluginModuleStruct*)dlsym(handle, "g_pluginModule");
169     ASSERT_NE(diskioPlugin, nullptr);
170     EXPECT_STREQ(diskioPlugin->name, "diskio-plugin");
171     EXPECT_EQ(diskioPlugin->resultBufferSizeHint, BUF_SIZE);
172 
173     // Serialize config
174     DiskioConfig protoConfig;
175     int configLength = protoConfig.ByteSizeLong();
176     ASSERT_EQ(configLength, 0);
177     std::vector<uint8_t> configBuffer(configLength);
178     EXPECT_TRUE(protoConfig.SerializeToArray(configBuffer.data(), configLength));
179 
180     // run plugin
181     std::vector<uint8_t> dataBuffer(diskioPlugin->resultBufferSizeHint);
182     EXPECT_EQ(diskioPlugin->callbacks->onPluginSessionStart(configBuffer.data(), configLength), RET_SUCC);
183     ASSERT_GT(diskioPlugin->callbacks->onPluginReportResult(dataBuffer.data(), diskioPlugin->resultBufferSizeHint), 0);
184     EXPECT_EQ(diskioPlugin->callbacks->onPluginSessionStop(), RET_SUCC);
185 
186     // 反序列化失败导致的start失败
187     configLength++;
188     std::vector<uint8_t> configBuffer2(configLength);
189     EXPECT_TRUE(protoConfig.SerializeToArray(configBuffer2.data(), configLength));
190     EXPECT_EQ(diskioPlugin->callbacks->onPluginSessionStart(configBuffer2.data(), configLength+1), RET_FAIL);
191 }
192 
ExecuteBin(const std::string& bin, const std::vector<std::string>& args)193 bool ExecuteBin(const std::string& bin, const std::vector<std::string>& args)
194 {
195     std::vector<char*> argv;
196     for (size_t i = 0; i < args.size(); i++) {
197         argv.push_back(const_cast<char*>(args[i].c_str()));
198     }
199     argv.push_back(nullptr); // last item in argv must be NULL
200 
201     int retval = execvp(bin.c_str(), argv.data());
202     CHECK_TRUE(retval != -1, false, "execv %s failed, %d!", bin.c_str(), errno);
203     _exit(EXIT_FAILURE);
204     abort(); // never should be here.
205     return true;
206 }
207 
208 /**
209  * @tc.name: diskio plugin
210  * @tc.desc: test ParseDiskioInfo for system file
211  * @tc.type: FUNC
212  */
HWTEST_F(DiskioDataPluginTest, TestSystemFile, TestSize.Level1)213 HWTEST_F(DiskioDataPluginTest, TestSystemFile, TestSize.Level1)
214 {
215     DiskioDataPlugin plugin1, plugin2;
216     DiskioData diskioData1, diskioData2;
217 
218     std::string cmd = "chmod 777 " + DEFAULT_BIN_PATH;
219     system(cmd.c_str());
220 
221     EXPECT_TRUE(PluginDiskioInfoStub(plugin1, diskioData1, false));
222     pid_t pid = fork();
223     if (pid == 0) {
224         // set 1, write data to disk
225         std::vector<std::string> argv = {"childpidtest", "1"};
226         ASSERT_TRUE(ExecuteBin(DEFAULT_BIN_PATH, argv));
227     }
228     sleep(1); // 睡眠1s,确保已写入磁盘1000kb的数据
229     EXPECT_TRUE(PluginDiskioInfoStub(plugin2, diskioData2, false));
230     EXPECT_LE(diskioData1.wr_sectors_kb() + WRITE_KB, diskioData2.wr_sectors_kb());
231 
232     while (waitpid(-1, nullptr, WNOHANG) == 0) {
233         kill(pid, SIGKILL);
234     }
235 
236     plugin1.Stop();
237     plugin2.Stop();
238 }
239 
240 /**
241  * @tc.name: diskio plugin
242  * @tc.desc: test io_stats.cpp
243  * @tc.type: FUNC
244  */
HWTEST_F(DiskioDataPluginTest, TestIOStats, TestSize.Level1)245 HWTEST_F(DiskioDataPluginTest, TestIOStats, TestSize.Level1)
246 {
247     IoStats ioStats;
248     StatsData statsData;
249     EXPECT_TRUE(ioStats.GetIoData());
250     EXPECT_TRUE(ioStats.PutPluginStatsData(statsData));
251 
252     IoStats ioStatsIoReport(DiskioConfig::IO_REPORT);
253     EXPECT_TRUE(ioStatsIoReport.GetIoData());
254     EXPECT_TRUE(ioStatsIoReport.PutPluginStatsData(statsData));
255 
256     IoStats ioStatsIoReportEx(DiskioConfig::IO_REPORT_EX);
257     EXPECT_TRUE(ioStatsIoReportEx.GetIoData());
258     EXPECT_TRUE(ioStatsIoReportEx.PutPluginStatsData(statsData));
259 }
260 } // namespace
261