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
31 using namespace testing::ext;
32
33 static const char *TEST_READ_FILE = "/data/local/tmp/splice_read_file.txt";
34 static const char *TEST_WRITE_FILE = "/data/local/tmp/splice_write_file.txt";
35 static const char *TEST_DATA = "Hello World!";
36 static const int TEST_DATA_LEN = strlen(TEST_DATA);
37 static const int MAX_LEN = 128;
38
39 class HatsSpliceTest : public testing::Test {
40 public:
41 static void SetUpTestCase();
42 static void TearDownTestCase();
43 void SetUp();
44 void TearDown();
45 private:
46 };
SetUp()47 void 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 }
TearDown()53 void HatsSpliceTest::TearDown()
54 {
55 (void)remove(TEST_READ_FILE);
56 (void)remove(TEST_WRITE_FILE);
57 }
SetUpTestCase()58 void HatsSpliceTest::SetUpTestCase()
59 {
60 }
TearDownTestCase()61 void 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 */
HWTEST_F(HatsSpliceTest, SpliceMoveFileDataToPipeSuccess_0001, Function | MediumTest | Level1)73 HWTEST_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 */
HWTEST_F(HatsSpliceTest, SpliceMoveFileDataToPipeSuccess_0002, Function | MediumTest | Level1)105 HWTEST_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 */
HWTEST_F(HatsSpliceTest, SpliceInvalidFdFailed_0003, Function | MediumTest | Level2)143 HWTEST_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 */
HWTEST_F(HatsSpliceTest, SpliceNoPipeFdFailed_0004, Function | MediumTest | Level2)178 HWTEST_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 */
HWTEST_F(HatsSpliceTest, SplicePipeOffsetNotNullFailed_0005, Function | MediumTest | Level2)203 HWTEST_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 */
HWTEST_F(HatsSpliceTest, SpliceFdOpenAsAppendFailed_0006, Function | MediumTest | Level2)232 HWTEST_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 */
HWTEST_F(HatsSpliceTest, SpliceUseTheSamePipeFdFailed_0007, Function | MediumTest | Level2)264 HWTEST_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 }