1/*
2 * Copyright (C) 2024 HiHope Open Source Organization.
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 <cerrno>
17#include <cstdio>
18#include <cstdlib>
19#include <string>
20#include <vector>
21#include <fcntl.h>
22#include <unistd.h>
23#include <arpa/inet.h>
24#include <gtest/gtest.h>
25#include <netinet/in.h>
26#include <sys/stat.h>
27#include <sys/socket.h>
28#include <sys/types.h>
29#include "securec.h"
30
31using namespace testing::ext;
32
33static const char *TEST_READ_FILE = "/data/local/tmp/splice_read_file.txt";
34static const char *TEST_WRITE_FILE = "/data/local/tmp/splice_write_file.txt";
35static const char *TEST_DATA = "Hello World!";
36static const int TEST_DATA_LEN = strlen(TEST_DATA);
37static const int MAX_LEN = 128;
38
39class HatsSpliceTest : public testing::Test {
40public:
41static void SetUpTestCase();
42static void TearDownTestCase();
43void SetUp();
44void TearDown();
45private:
46};
47void HatsSpliceTest::SetUp()
48{
49    int fd = open(TEST_READ_FILE, O_WRONLY | O_CREAT, 0644);
50    write(fd, TEST_DATA, TEST_DATA_LEN);
51    close(fd);
52}
53void HatsSpliceTest::TearDown()
54{
55    (void)remove(TEST_READ_FILE);
56    (void)remove(TEST_WRITE_FILE);
57}
58void HatsSpliceTest::SetUpTestCase()
59{
60}
61void HatsSpliceTest::TearDownTestCase()
62{
63}
64
65/*
66 * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0100
67 * @tc.name   : SpliceMoveFileDataToPipeSuccess_0001
68 * @tc.desc   : Splice move data from file to pipe success.
69 * @tc.size   : MediumTest
70 * @tc.type   : Function
71 * @tc.level  : Level 1
72 */
73HWTEST_F(HatsSpliceTest, SpliceMoveFileDataToPipeSuccess_0001, Function | MediumTest | Level1)
74{
75    int ret;
76    char buffer[MAX_LEN] = { 0 };
77    int pipeFd[2];
78    int fdIn = open(TEST_READ_FILE, O_RDONLY);
79    EXPECT_TRUE(fdIn > 0);
80
81    // move common fd data to pipe success.
82    ret = pipe(pipeFd);
83    EXPECT_EQ(ret, 0);
84
85    ssize_t size = splice(fdIn, nullptr, pipeFd[1], nullptr, TEST_DATA_LEN, SPLICE_F_MOVE | SPLICE_F_MORE);
86    EXPECT_EQ(size, TEST_DATA_LEN);
87
88    size = read(pipeFd[0], buffer, MAX_LEN);
89    EXPECT_EQ(size, TEST_DATA_LEN);
90    EXPECT_STREQ(buffer, TEST_DATA);
91
92    close(fdIn);
93    close(pipeFd[0]);
94    close(pipeFd[1]);
95}
96
97/*
98 * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0200
99 * @tc.name   : SpliceMovePipeDataToFileSuccess_0002
100 * @tc.desc   : Splice move pipe data to file success.
101 * @tc.size   : MediumTest
102 * @tc.type   : Function
103 * @tc.level  : Level 1
104 */
105HWTEST_F(HatsSpliceTest, SpliceMoveFileDataToPipeSuccess_0002, Function | MediumTest | Level1)
106{
107    int ret;
108    off64_t offset = 0;
109    char buffer[MAX_LEN] = { 0 };
110    int pipeFd[2];
111    int fdOut = open(TEST_WRITE_FILE, O_RDWR | O_CREAT, 0644);
112    EXPECT_TRUE(fdOut > 0);
113
114    // move common fd data to pipe success.
115    ret = pipe(pipeFd);
116    EXPECT_EQ(ret, 0);
117    ssize_t size = write(pipeFd[1], TEST_DATA, TEST_DATA_LEN);
118    EXPECT_EQ(size, TEST_DATA_LEN);
119
120    ret = splice(pipeFd[0], nullptr, fdOut, &offset, TEST_DATA_LEN, SPLICE_F_MOVE | SPLICE_F_MORE);
121    EXPECT_EQ(ret, TEST_DATA_LEN);
122
123    off_t pos = lseek(fdOut, 0, SEEK_SET);
124    EXPECT_EQ(pos, 0);
125
126    size = read(fdOut, buffer, MAX_LEN);
127    EXPECT_EQ(size, TEST_DATA_LEN);
128    EXPECT_STREQ(buffer, TEST_DATA);
129
130    close(fdOut);
131    close(pipeFd[0]);
132    close(pipeFd[1]);
133}
134
135/*
136 * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0300
137 * @tc.name   : SpliceInvalidFdFailed_0003
138 * @tc.desc   : Splice was provided invalid file fd return failed, errno EBADF.
139 * @tc.size   : MediumTest
140 * @tc.type   : Function
141 * @tc.level  : Level 2
142 */
143HWTEST_F(HatsSpliceTest, SpliceInvalidFdFailed_0003, Function | MediumTest | Level2)
144{
145    int ret;
146    off64_t offset = 0;
147    int pipeFd[2];
148
149    ret = pipe(pipeFd);
150    EXPECT_EQ(ret, 0);
151    ssize_t size = write(pipeFd[1], TEST_DATA, TEST_DATA_LEN);
152    EXPECT_EQ(size, TEST_DATA_LEN);
153
154    // fdOut is invalid fd, failed
155    errno = 0;
156    ret = splice(pipeFd[0], nullptr, -1, &offset, TEST_DATA_LEN, SPLICE_F_NONBLOCK);
157    EXPECT_EQ(ret, -1);
158    EXPECT_EQ(errno, EBADF);
159
160    // fdIn is invalid fd, failed
161    errno = 0;
162    ret = splice(-1, &offset, pipeFd[1], nullptr, TEST_DATA_LEN, SPLICE_F_NONBLOCK);
163    EXPECT_EQ(ret, -1);
164    EXPECT_EQ(errno, EBADF);
165
166    close(pipeFd[0]);
167    close(pipeFd[1]);
168}
169
170/*
171 * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0400
172 * @tc.name   : SpliceNoPipeFdFailed_0004
173 * @tc.desc   : Splice neither fds refer to a pipe return failed, errno EINVAL.
174 * @tc.size   : MediumTest
175 * @tc.type   : Function
176 * @tc.level  : Level 2
177 */
178HWTEST_F(HatsSpliceTest, SpliceNoPipeFdFailed_0004, Function | MediumTest | Level2)
179{
180    int ret;
181    off64_t offset = 0;
182    int fdIn = open(TEST_READ_FILE, O_RDONLY);
183    EXPECT_TRUE(fdIn > 0);
184    int fdOut = open(TEST_WRITE_FILE, O_RDWR | O_TRUNC | O_CREAT, 0644);
185    EXPECT_TRUE(fdOut > 0);
186    errno = 0;
187    ret = splice(fdIn, &offset, fdOut, &offset, TEST_DATA_LEN, SPLICE_F_NONBLOCK);
188    EXPECT_EQ(ret, -1);
189    EXPECT_EQ(errno, EINVAL);
190
191    close(fdIn);
192    close(fdOut);
193}
194
195/*
196 * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0500
197 * @tc.name   : SplicePipeOffsetNotNullFailed_0005
198 * @tc.desc   : Splice pipeFd offset is not nullptr return failed, errno ESPIPE.
199 * @tc.size   : MediumTest
200 * @tc.type   : Function
201 * @tc.level  : Level 2
202 */
203HWTEST_F(HatsSpliceTest, SplicePipeOffsetNotNullFailed_0005, Function | MediumTest | Level2)
204{
205    int ret;
206    off64_t offset = 0;
207    int pipeFd[2];
208    int fdIn = open(TEST_READ_FILE, O_RDONLY);
209    EXPECT_TRUE(fdIn > 0);
210
211    ret = pipe(pipeFd);
212    EXPECT_EQ(ret, 0);
213
214    errno = 0;
215    ret = splice(fdIn, nullptr, pipeFd[1], &offset, TEST_DATA_LEN, SPLICE_F_MOVE | SPLICE_F_MORE);
216    EXPECT_EQ(ret, -1);
217    EXPECT_EQ(errno, ESPIPE);
218
219    close(fdIn);
220    close(pipeFd[0]);
221    close(pipeFd[1]);
222}
223
224/*
225 * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0600
226 * @tc.name   : SpliceFdOpenAsAppendFailed_0006
227 * @tc.desc   : Splice file fd was opened in append mode failed, errno EINVAL.
228 * @tc.size   : MediumTest
229 * @tc.type   : Function
230 * @tc.level  : Level 2
231 */
232HWTEST_F(HatsSpliceTest, SpliceFdOpenAsAppendFailed_0006, Function | MediumTest | Level2)
233{
234    int ret;
235    int pipeFd[2];
236    off64_t offset = 0;
237
238    int fd = open(TEST_WRITE_FILE, O_RDWR | O_APPEND | O_CREAT, 0644);
239    EXPECT_TRUE(fd > 0);
240
241    ret = pipe(pipeFd);
242    EXPECT_EQ(ret, 0);
243    ssize_t size = write(pipeFd[1], TEST_DATA, TEST_DATA_LEN);
244    EXPECT_EQ(size, TEST_DATA_LEN);
245
246    errno = 0;
247    ret = splice(pipeFd[0], nullptr, fd, &offset, TEST_DATA_LEN, SPLICE_F_NONBLOCK);
248    EXPECT_EQ(ret, -1);
249    EXPECT_EQ(errno, EINVAL);
250
251    close(fd);
252    close(pipeFd[0]);
253    close(pipeFd[1]);
254}
255
256/*
257 * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0700
258 * @tc.name   : SpliceUseTheSamePipeFdFailed_0007
259 * @tc.desc   : Splice fdIn and fdOut from the same pipe failed, errno EINVAL.
260 * @tc.size   : MediumTest
261 * @tc.type   : Function
262 * @tc.level  : Level 2
263 */
264HWTEST_F(HatsSpliceTest, SpliceUseTheSamePipeFdFailed_0007, Function | MediumTest | Level2)
265{
266    int ret;
267    int pipeFd[2];
268
269    ret = pipe(pipeFd);
270    EXPECT_EQ(ret, 0);
271    ssize_t size = write(pipeFd[1], TEST_DATA, TEST_DATA_LEN);
272    EXPECT_EQ(size, TEST_DATA_LEN);
273
274    errno = 0;
275    ret = splice(pipeFd[0], nullptr, pipeFd[1], nullptr, TEST_DATA_LEN, SPLICE_F_NONBLOCK);
276    EXPECT_EQ(ret, -1);
277    EXPECT_EQ(errno, EINVAL);
278
279    close(pipeFd[0]);
280    close(pipeFd[1]);
281}