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 <sys/mman.h>
18#include <sys/syscall.h>
19#include "buffer_writer.h"
20#include "plugin_service_types.pb.h"
21
22using namespace testing::ext;
23
24namespace {
25constexpr uint32_t SMB1_SIZE = 10 * 4096;
26constexpr uint32_t SMB2_SIZE = 10 * 4096;
27const std::string SMB1_NAME = "testsmb1";
28const std::string SMB2_NAME = "testsmb2";
29const std::string PLUGIN_NAME = "testplugin";
30const std::string PLUGIN_VERSION = "1.01";
31void *g_smbAddr1 = nullptr;
32void *g_smbAddr2 = nullptr;
33int g_smbFd1 = 0;
34int g_smbFd2 = 0;
35
36int InitShareMemory1()
37{
38    int fd = syscall(SYS_memfd_create, SMB1_NAME.c_str(), 0);
39    CHECK_TRUE(fd >= 0, -1, "CreateBlock FAIL SYS_memfd_create");
40
41    int check = ftruncate(fd, SMB1_SIZE);
42    if (check < 0) {
43        close(fd);
44        const int bufSize = 256;
45        char buf[bufSize] = { 0 };
46        strerror_r(errno, buf, bufSize);
47        PROFILER_LOG_ERROR(LOG_CORE, "CreateBlock ftruncate ERR : %s", buf);
48        return -1;
49    }
50
51    g_smbAddr1 = mmap(nullptr, SMB1_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
52    if (g_smbAddr1 == static_cast<void*>(MAP_FAILED)) {
53        close(fd);
54        const int bufSize = 256;
55        char buf[bufSize] = { 0 };
56        strerror_r(errno, buf, bufSize);
57        PROFILER_LOG_ERROR(LOG_CORE, "CreateBlock g_smbAddr1 mmap ERR : %s", buf);
58        return -1;
59    }
60
61    ShareMemoryBlock::BlockHeader* header_ = reinterpret_cast<ShareMemoryBlock::BlockHeader*>(g_smbAddr1);
62
63    // initialize header infos
64    header_->info.readOffset_ = 0;
65    header_->info.writeOffset_ = 0;
66    header_->info.memorySize_ = SMB1_SIZE - sizeof(ShareMemoryBlock::BlockHeader);
67    header_->info.bytesCount_ = 0;
68    header_->info.chunkCount_ = 0;
69
70    return fd;
71}
72
73int InitShareMemory2()
74{
75    int fd = syscall(SYS_memfd_create, SMB2_NAME.c_str(), 0);
76    CHECK_TRUE(fd >= 0, -1, "CreateBlock FAIL SYS_memfd_create");
77
78    int check = ftruncate(fd, SMB2_SIZE);
79    if (check < 0) {
80        close(fd);
81        const int bufSize = 256;
82        char buf[bufSize] = { 0 };
83        strerror_r(errno, buf, bufSize);
84        PROFILER_LOG_ERROR(LOG_CORE, "CreateBlock ftruncate ERR : %s", buf);
85        return -1;
86    }
87
88    g_smbAddr2 = mmap(nullptr, SMB2_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
89    if (g_smbAddr2 == static_cast<void*>(MAP_FAILED)) {
90        close(fd);
91        const int bufSize = 256;
92        char buf[bufSize] = { 0 };
93        strerror_r(errno, buf, bufSize);
94        PROFILER_LOG_ERROR(LOG_CORE, "CreateBlock g_smbAddr2 mmap ERR : %s", buf);
95        return -1;
96    }
97
98    ShareMemoryBlock::BlockHeader* header_ = reinterpret_cast<ShareMemoryBlock::BlockHeader*>(g_smbAddr2);
99
100    // initialize header infos
101    header_->info.readOffset_ = 0;
102    header_->info.writeOffset_ = 0;
103    header_->info.memorySize_ = SMB2_SIZE - sizeof(ShareMemoryBlock::BlockHeader);
104    header_->info.bytesCount_ = 0;
105    header_->info.chunkCount_ = 0;
106
107    return fd;
108}
109
110class BufferWriteTest : public ::testing::Test {
111protected:
112    static void SetUpTestCase()
113    {
114        g_smbFd1 = InitShareMemory1();
115        g_smbFd2 = InitShareMemory2();
116    }
117    static void TearDownTestCase() {}
118};
119
120bool CheckBuffer(uint8_t *buffer, size_t size)
121{
122    ShareMemoryBlock::BlockHeader* header_ = reinterpret_cast<ShareMemoryBlock::BlockHeader*>(g_smbAddr1);
123    uint8_t *cmpaddr = (uint8_t *)g_smbAddr1 + sizeof(ShareMemoryBlock::BlockHeader) + header_->info.readOffset_.load();
124    uint32_t cmpsize = *(uint32_t*)cmpaddr;
125    cmpaddr = cmpaddr + sizeof(uint32_t);
126    ProfilerPluginData pluginData;
127    pluginData.ParseFromArray(cmpaddr, cmpsize);
128    const char* data = pluginData.data().c_str();
129
130    header_->info.readOffset_ = header_->info.writeOffset_.load();
131    if (memcmp(buffer, data, size) == 0) {
132        return true;
133    }
134    return false;
135}
136
137
138bool CheckMessage(uint8_t *buffer, size_t size)
139{
140    ShareMemoryBlock::BlockHeader* header_ = reinterpret_cast<ShareMemoryBlock::BlockHeader*>(g_smbAddr2);
141    uint8_t *cmpaddr = (uint8_t *)g_smbAddr2 + sizeof(ShareMemoryBlock::BlockHeader) + header_->info.readOffset_.load();
142    cmpaddr = cmpaddr + sizeof(uint32_t);
143    header_->info.readOffset_ = header_->info.writeOffset_.load();
144
145    if (memcmp(buffer, cmpaddr, size) == 0) {
146        return true;
147    }
148    return false;
149}
150
151/**
152 * @tc.name: plugin
153 * @tc.desc: Write data to shared memory through writer.
154 * @tc.type: FUNC
155 */
156HWTEST_F(BufferWriteTest, WriteTest, TestSize.Level1)
157{
158    auto write = std::make_shared<BufferWriter>(PLUGIN_NAME, PLUGIN_VERSION, SMB1_SIZE, g_smbFd1, -1, 0);
159    uint8_t buffer1[] = {0x55, 0xAA, 0x55, 0xAA};
160    uint8_t buffer2[] = {0x11, 0x22, 0x33, 0x44};
161    uint8_t buffer3[] = {0xAA, 0xBB, 0xCC, 0xDD};
162    EXPECT_TRUE(write->Write(buffer1, sizeof(buffer1)));
163    EXPECT_TRUE(CheckBuffer(buffer1, sizeof(buffer1)));
164
165    EXPECT_TRUE(write->Write(buffer2, sizeof(buffer2)));
166    EXPECT_TRUE(CheckBuffer(buffer2, sizeof(buffer2)));
167
168    EXPECT_TRUE(write->Write(buffer3, sizeof(buffer3)));
169    EXPECT_TRUE(CheckBuffer(buffer3, sizeof(buffer3)));
170    EXPECT_FALSE(write->Write(nullptr, 0));
171}
172
173/**
174 * @tc.name: plugin
175 * @tc.desc: Write data to shared memory through writer.
176 * @tc.type: FUNC
177 */
178HWTEST_F(BufferWriteTest, WriteMessageTest, TestSize.Level1)
179{
180    uint8_t data[1024];
181    auto write = std::make_shared<BufferWriter>(PLUGIN_NAME, PLUGIN_VERSION, SMB2_SIZE, g_smbFd2, -1, 0);
182
183    ProfilerPluginConfig configData;
184    configData.set_name("111");
185    configData.set_plugin_sha256("222");
186    configData.set_sample_interval(1000);
187    size_t size = configData.ByteSizeLong();
188    configData.SerializeToArray(data, size);
189
190    EXPECT_TRUE(write->WriteMessage(configData, "111"));
191    EXPECT_TRUE(CheckMessage(data, size));
192
193    ProfilerPluginState stateData;
194    stateData.set_name("st");
195    stateData.set_state(ProfilerPluginState::IN_SESSION);
196    size = stateData.ByteSizeLong();
197    stateData.SerializeToArray(data, size);
198
199    EXPECT_TRUE(write->WriteMessage(stateData, "111"));
200    EXPECT_TRUE(CheckMessage(data, size));
201
202
203    ProfilerPluginData pluginData;
204    pluginData.set_name("test");
205    pluginData.set_status(1);
206    struct timespec ts;
207    clock_gettime(CLOCK_REALTIME, &ts);
208    pluginData.set_clock_id(ProfilerPluginData::CLOCKID_REALTIME);
209    pluginData.set_tv_sec(ts.tv_sec);
210    pluginData.set_tv_nsec(ts.tv_nsec);
211    size = pluginData.ByteSizeLong();
212    pluginData.SerializeToArray(data, size);
213
214    EXPECT_TRUE(write->WriteMessage(pluginData, "111"));
215    EXPECT_TRUE(CheckMessage(data, size));
216}
217} // namespace