1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
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#include <gtest/gtest.h>
16
17#include <thread>
18#include <chrono>
19#include <unistd.h>
20#include <fstream>
21
22#include <buffer_utils.h>
23#include "surface_buffer_impl.h"
24#include "sandbox_utils.h"
25
26
27using namespace testing;
28using namespace testing::ext;
29
30namespace OHOS::Rosen {
31class BufferUtilsTest : public testing::Test {
32public:
33    static void SetUpTestCase();
34    static void TearDownTestCase();
35
36    static inline BufferRequestConfig requestConfig = {
37        .width = 0x100,
38        .height = 0x100,
39        .strideAlignment = 0x8,
40        .format = GRAPHIC_PIXEL_FMT_RGBA_8888,
41        .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
42        .timeout = 0,
43    };
44
45    static inline sptr<SurfaceBuffer> buffer = nullptr;
46    static inline std::string flagPath = "/data/bq_dump";
47    static inline std::string name_ = "test";
48};
49
50namespace fs = std::filesystem;
51
52void BufferUtilsTest::SetUpTestCase()
53{
54    buffer = nullptr;
55
56    // open dump flag
57    std::ofstream outfile(flagPath);
58    outfile << "touch" << std::endl;
59    outfile.close();
60}
61
62void BufferUtilsTest::TearDownTestCase()
63{
64    buffer = nullptr;
65
66    // delete dump flag
67    if (fs::exists(flagPath)) {
68        fs::remove(flagPath);
69    }
70}
71
72/*
73* Function: WriteToFile
74* Type: Function
75* Rank: Important(2)
76* EnvConditions: N/A
77* CaseDescription: 1. call DumpToFileAsync
78*                  2. check ret
79 */
80HWTEST_F(BufferUtilsTest, DumpToFileAsyncTest001, Function | MediumTest | Level2)
81{
82    const pid_t pid = GetRealPid();
83
84    // Alloc buffer
85    buffer = new SurfaceBufferImpl();
86    buffer->Alloc(requestConfig);
87
88    // Call DumpToFileAsync
89    GSError ret = DumpToFileAsync(pid, name_, buffer);
90    ASSERT_EQ(ret, OHOS::GSERROR_OK);
91
92    // Expect Buffer Dump to be completed within 20ms.
93    std::chrono::milliseconds dura(20);
94    std::this_thread::sleep_for(dura);
95
96    const std::string directory = "/data";
97    const std::string prefix = "bq_" + std::to_string(pid) + "_" + name_;
98    size_t dumpFileSize = 0;
99    // Traverse the directory and find the dump file.
100    for (const auto& entry : fs::recursive_directory_iterator(directory)) {
101        if (entry.is_regular_file() && entry.path().filename().string().find(prefix) == 0) {
102            // Open the file to create a stream
103            std::ifstream dumpFile(entry.path(), std::ios::binary);
104            std::vector<uint8_t> file_data((std::istreambuf_iterator<char>(dumpFile)),
105                std::istreambuf_iterator<char>());
106            // Get fileSize from the file stream
107            dumpFileSize = file_data.size();
108            dumpFile.close();
109            fs::remove(entry.path());
110            break;
111        }
112    }
113
114    ASSERT_EQ(dumpFileSize, buffer->GetSize());
115}
116
117/*
118* Function: WriteToFile
119* Type: Function
120* Rank: Important(2)
121* EnvConditions: N/A
122* CaseDescription: 1. call DumpToFileAsync
123*                  2. check ret
124 */
125HWTEST_F(BufferUtilsTest, DumpToFileAsyncTest002, Function | MediumTest | Level2)
126{
127    const pid_t pid = GetRealPid();
128
129    // Alloc buffer
130    buffer = new SurfaceBufferImpl();
131    buffer->Alloc(requestConfig);
132
133    // Call DumpToFileAsync
134    GSError ret = DumpToFileAsync(pid, name_, buffer);
135    ASSERT_EQ(ret, OHOS::GSERROR_OK);
136
137    // Expect Buffer Dump to be completed within 20ms.
138    std::chrono::milliseconds dura(20);
139    std::this_thread::sleep_for(dura);
140
141    const std::string directory = "/data/storage/el1/base";
142    if (access(directory.c_str(), F_OK) == 0) {
143        const std::string prefix = "bq_" + std::to_string(pid) + "_" + name_;
144        size_t dumpFileSize = 0;
145        // Traverse the directory and find the dump file.
146        for (const auto& entry : fs::recursive_directory_iterator(directory)) {
147            if (entry.is_regular_file() && entry.path().filename().string().find(prefix) == 0) {
148                // Open the file to create a stream
149                std::ifstream dumpFile(entry.path(), std::ios::binary);
150                std::vector<uint8_t> file_data((std::istreambuf_iterator<char>(dumpFile)),
151                    std::istreambuf_iterator<char>());
152                // Get fileSize from the file stream
153                dumpFileSize = file_data.size();
154                dumpFile.close();
155                fs::remove(entry.path());
156                break;
157            }
158        }
159
160        ASSERT_EQ(dumpFileSize, buffer->GetSize());
161    }
162}
163
164/*
165* Function: WriteToFile
166* Type: Function
167* Rank: Important(2)
168* EnvConditions: N/A
169* CaseDescription: 1. call DumpToFileAsync
170*                  2. check ret
171 */
172HWTEST_F(BufferUtilsTest, DumpToFileAsyncTest003, Function | MediumTest | Level2)
173{
174    buffer = nullptr;
175    GSError ret = DumpToFileAsync(0, name_, buffer);
176    ASSERT_NE(ret, OHOS::GSERROR_OK);
177}
178
179/*
180* Function: SizeLimitTest
181* Type: Function
182* Rank: Important(2)
183* EnvConditions: N/A
184* CaseDescription: 1. make size bigger than SURFACE_PARCEL_SIZE_LIMIT and check the ret
185 */
186HWTEST_F(BufferUtilsTest, SizeLimitTest001, Function | MediumTest | Level2)
187{
188    MessageParcel parcel;
189    uint32_t size = SURFACE_PARCEL_SIZE_LIMIT + 1;
190
191    BufferFlushConfigWithDamages flushConfig = {
192        .damages = std::vector<Rect>(size),
193    };
194    EXPECT_EQ(WriteFlushConfig(parcel, flushConfig), GSERROR_INVALID_ARGUMENTS);
195    EXPECT_TRUE(parcel.WriteUint32(size));
196    EXPECT_EQ(ReadFlushConfig(parcel, flushConfig), GSERROR_BINDER);
197
198    auto infos = std::vector<BufferVerifyAllocInfo>(size);
199    EXPECT_EQ(WriteVerifyAllocInfo(parcel, infos), GSERROR_INVALID_ARGUMENTS);
200    EXPECT_TRUE(parcel.WriteUint32(size));
201    ReadVerifyAllocInfo(parcel, infos);
202
203    auto metaData = std::vector<GraphicHDRMetaData>(size);
204    EXPECT_EQ(WriteHDRMetaData(parcel, metaData), GSERROR_INVALID_ARGUMENTS);
205    EXPECT_TRUE(parcel.WriteUint32(size));
206    EXPECT_EQ(ReadHDRMetaData(parcel, metaData), GSERROR_BINDER);
207
208    auto metaDataSet = std::vector<uint8_t>(size);
209    EXPECT_EQ(WriteHDRMetaDataSet(parcel, metaDataSet), GSERROR_INVALID_ARGUMENTS);
210    EXPECT_TRUE(parcel.WriteUint32(size));
211    EXPECT_EQ(ReadHDRMetaDataSet(parcel, metaDataSet), GSERROR_BINDER);
212
213    GraphicExtDataHandle *handle = static_cast<GraphicExtDataHandle *>(
214        malloc(sizeof(GraphicExtDataHandle) + sizeof(int32_t)));
215    handle->fd = -1;
216    handle->reserveInts = size;
217    handle->reserve[0] = 0;
218    sptr<SurfaceTunnelHandle> tunnelHandle = new SurfaceTunnelHandle();
219    EXPECT_EQ(WriteExtDataHandle(parcel, handle), GSERROR_INVALID_ARGUMENTS);
220    EXPECT_TRUE(parcel.WriteUint32(size));
221    EXPECT_EQ(ReadExtDataHandle(parcel, tunnelHandle), GSERROR_BINDER);
222}
223}