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 <cstring>
17 #include <dlfcn.h>
18 #include <fcntl.h>
19 #include <gtest/gtest.h>
20 #include <cinttypes>
21 #include <cstdio>
22 #include <ctime>
23 #include <unistd.h>
24 
25 #include "hiperf_module.h"
26 #include "hiperf_plugin_config.pb.h"
27 #include "plugin_module_api.h"
28 
29 using namespace testing::ext;
30 
31 namespace {
32 const std::string DEFAULT_LIB("libhiperfplugin.z.so");
33 const std::string DEFAULT_OUT_PATH("/data/local/tmp/perf.data");
34 const int DEFAULT_WAIT = 2;
35 
36 class HiperfPluginUnittest : public ::testing::Test {
37 public:
SetUpTestCase()38     static void SetUpTestCase() {};
TearDownTestCase()39     static void TearDownTestCase() {};
40 
SetUp()41     void SetUp() {}
TearDown()42     void TearDown() {}
43 };
44 
WriteFunc(WriterStruct* writer, const void* data, size_t size)45 long WriteFunc(WriterStruct* writer, const void* data, size_t size)
46 {
47     if (writer == nullptr || data == nullptr || size <= 0) {
48         return -1;
49     }
50 
51     return 0;
52 }
53 
FlushFunc(WriterStruct* writer)54 bool FlushFunc(WriterStruct* writer)
55 {
56     if (writer == nullptr) {
57         return false;
58     }
59     return true;
60 }
61 
62 /**
63  * @tc.name: hiperf plugin
64  * @tc.desc: Test framework
65  * @tc.type: FUNC
66  */
HWTEST_F(HiperfPluginUnittest, TestFramework, TestSize.Level1)67 HWTEST_F(HiperfPluginUnittest, TestFramework, TestSize.Level1)
68 {
69     void* handle = dlopen(DEFAULT_LIB.c_str(), RTLD_LAZY);
70     EXPECT_NE(handle, nullptr);
71     PluginModuleStruct* plugin = reinterpret_cast<PluginModuleStruct*>(dlsym(handle, "g_pluginModule"));
72     EXPECT_NE(plugin, nullptr);
73     EXPECT_STREQ(plugin->name, "hiperf-plugin");
74 
75     // set config
76     HiperfPluginConfig config;
77     config.set_outfile_name(DEFAULT_OUT_PATH);
78     config.set_record_args("-a -c 0 -d 2");
79     int size = config.ByteSizeLong();
80     ASSERT_GT(size, 0);
81     std::vector<uint8_t> configData(size);
82     ASSERT_GT(config.SerializeToArray(configData.data(), configData.size()), 0);
83 
84     // test framework process
85     WriterStruct writer = {WriteFunc, FlushFunc};
86     std::vector<uint8_t> dataBuffer(plugin->resultBufferSizeHint);
87     EXPECT_EQ(plugin->callbacks->onRegisterWriterStruct(&writer), 0);
88     EXPECT_EQ(plugin->callbacks->onPluginSessionStart(configData.data(), configData.size()), 0);
89     EXPECT_EQ(plugin->callbacks->onPluginSessionStop(), 0);
90 
91     dlclose(handle);
92 }
93 
HWTEST_F(HiperfPluginUnittest, TestNoRecordTarget, TestSize.Level1)94 HWTEST_F(HiperfPluginUnittest, TestNoRecordTarget, TestSize.Level1)
95 {
96     HiperfPluginConfig config;
97     config.set_outfile_name(DEFAULT_OUT_PATH);
98     std::vector<uint8_t> buffer(config.ByteSizeLong());
99     ASSERT_TRUE(config.SerializeToArray(buffer.data(), buffer.size())) << "proto serialize FAILED!";
100 
101     ASSERT_NE(HiperfPluginSessionStart(buffer.data(), buffer.size()), 0) << "hiperf should return failed";
102 }
103 
HWTEST_F(HiperfPluginUnittest, TestRepeatOutput, TestSize.Level1)104 HWTEST_F(HiperfPluginUnittest, TestRepeatOutput, TestSize.Level1)
105 {
106     HiperfPluginConfig config;
107     config.set_log_level(HiperfPluginConfig_LogLevel_MUCH);
108     config.set_outfile_name(DEFAULT_OUT_PATH); // 1: set output file
109     // 2: set output file by "-o"
110     config.set_record_args("-a -c 0 -d 2 -o /data/local/tmp/perf.data2");
111     std::vector<uint8_t> buffer(config.ByteSizeLong());
112     ASSERT_TRUE(config.SerializeToArray(buffer.data(), buffer.size())) << "proto serialize FAILED!";
113 
114     ASSERT_NE(HiperfPluginSessionStart(buffer.data(), buffer.size()), 0) << "hiperf should return failed";
115 }
116 
HWTEST_F(HiperfPluginUnittest, TestRepeatStart, TestSize.Level1)117 HWTEST_F(HiperfPluginUnittest, TestRepeatStart, TestSize.Level1)
118 {
119     HiperfPluginConfig config;
120     config.set_log_level(HiperfPluginConfig_LogLevel_VERBOSE);
121     config.set_outfile_name(DEFAULT_OUT_PATH);
122     config.set_record_args("-a -c 0 -d 2");
123     std::vector<uint8_t> buffer(config.ByteSizeLong());
124     ASSERT_TRUE(config.SerializeToArray(buffer.data(), buffer.size())) << "proto serialize FAILED!";
125 
126     ASSERT_EQ(HiperfPluginSessionStart(buffer.data(), buffer.size()), 0) << "hiperf should return ok";
127     // repeate to start
128     ASSERT_NE(HiperfPluginSessionStart(buffer.data(), buffer.size()), 0) << "hiperf should return failed";
129     ASSERT_EQ(HiperfPluginSessionStop(), 0) << "hiperf should return ok";
130 }
131 
HWTEST_F(HiperfPluginUnittest, TestStopBeforeHiperfExit, TestSize.Level1)132 HWTEST_F(HiperfPluginUnittest, TestStopBeforeHiperfExit, TestSize.Level1)
133 {
134     HiperfPluginConfig config;
135     config.set_log_level(HiperfPluginConfig_LogLevel_DEBUG);
136     config.set_outfile_name(DEFAULT_OUT_PATH);
137     config.set_record_args("-a -c 0 -d 20"); // hiperf will exit after 20s
138     std::vector<uint8_t> buffer(config.ByteSizeLong());
139     ASSERT_TRUE(config.SerializeToArray(buffer.data(), buffer.size())) << "proto serialize FAILED!";
140 
141     ASSERT_EQ(HiperfPluginSessionStart(buffer.data(), buffer.size()), 0) << "hiperf should return ok";
142 
143     sleep(DEFAULT_WAIT);
144     ASSERT_EQ(HiperfPluginSessionStop(), 0) << "hiperf should return ok";
145 }
146 
HWTEST_F(HiperfPluginUnittest, TestStopAfterHiperfExit, TestSize.Level1)147 HWTEST_F(HiperfPluginUnittest, TestStopAfterHiperfExit, TestSize.Level1)
148 {
149     HiperfPluginConfig config;
150     config.set_outfile_name(DEFAULT_OUT_PATH);
151     config.set_record_args("-a -c 0 -d 1"); // hiperf will exit after 1s
152     std::vector<uint8_t> buffer(config.ByteSizeLong());
153     ASSERT_TRUE(config.SerializeToArray(buffer.data(), buffer.size())) << "proto serialize FAILED!";
154 
155     ASSERT_EQ(HiperfPluginSessionStart(buffer.data(), buffer.size()), 0) << "hiperf should return ok";
156     sleep(DEFAULT_WAIT);
157     ASSERT_EQ(HiperfPluginSessionStop(), 0) << "hiperf should return ok";
158 }
159 
CheckRecordFile(const std::string& fileName)160 void CheckRecordFile(const std::string& fileName)
161 {
162     ASSERT_EQ(access(fileName.c_str(), F_OK), 0) << "perf.data should be exist";
163 
164     std::unique_ptr<FILE, int (*)(FILE*)> fp(fopen(fileName.c_str(), "rb"), fclose);
165     ASSERT_NE(fp, nullptr);
166 
167     constexpr long perfDataHeaderLen = 13 * 8;
168     fseek(fp.get(), 0, SEEK_END);
169     ASSERT_GE(ftell(fp.get()), perfDataHeaderLen) << "perf.data should have data";
170     fseek(fp.get(), 0, SEEK_SET);
171 
172     char buff[perfDataHeaderLen] = {0};
173     long rLen = fread(buff, 1, perfDataHeaderLen, fp.get());
174     ASSERT_EQ(rLen, perfDataHeaderLen);
175     ASSERT_EQ(strncmp(buff, "PERFILE2", strlen("PERFILE2")), 0) << "perf.data magic error";
176 }
177 
HWTEST_F(HiperfPluginUnittest, TestCheckOutputFile, TestSize.Level1)178 HWTEST_F(HiperfPluginUnittest, TestCheckOutputFile, TestSize.Level1)
179 {
180     HiperfPluginConfig config;
181     config.set_outfile_name(DEFAULT_OUT_PATH);
182     config.set_record_args("-a -c 0 -d 2");
183     std::vector<uint8_t> buffer(config.ByteSizeLong());
184     ASSERT_TRUE(config.SerializeToArray(buffer.data(), buffer.size())) << "proto serialize FAILED!";
185 
186     ASSERT_EQ(HiperfPluginSessionStart(buffer.data(), buffer.size()), 0) << "hiperf should return ok";
187     sleep(DEFAULT_WAIT);
188     ASSERT_EQ(HiperfPluginSessionStop(), 0) << "hiperf should return ok";
189 
190     CheckRecordFile(DEFAULT_OUT_PATH);
191 }
192 } // namespace
193