master
c 362 lines 10.7 KB
Raw
1 /*
2 * QEMU I/O channel file test
3 *
4 * Copyright (c) 2015 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "qemu/osdep.h"
22 #include "io/channel-file.h"
23 #include "io/channel-util.h"
24 #include "io-channel-helpers.h"
25 #include "qapi/error.h"
26 #include "qemu/module.h"
27
28 #define TEST_FILE "tests/test-io-channel-file.txt"
29 #define TEST_MASK 0600
30
31 /*
32 * On Windows the stat() function in the C library checks only
33 * the FAT-style READONLY attribute and does not look at the ACL at all.
34 */
35 #ifdef _WIN32
36 #define TEST_MASK_EXPECT 0700
37 #else
38 #define TEST_MASK_EXPECT 0777
39 #endif
40
41 static void test_io_channel_file_helper(int flags)
42 {
43 QIOChannel *src, *dst;
44 QIOChannelTest *test;
45 struct stat st;
46 mode_t mask;
47 int ret;
48
49 unlink(TEST_FILE);
50 src = QIO_CHANNEL(qio_channel_file_new_path(
51 TEST_FILE,
52 flags, TEST_MASK,
53 &error_abort));
54 dst = QIO_CHANNEL(qio_channel_file_new_path(
55 TEST_FILE,
56 O_RDONLY | O_BINARY, 0,
57 &error_abort));
58
59 test = qio_channel_test_new();
60 qio_channel_test_run_writer(test, src);
61 qio_channel_test_run_reader(test, dst);
62 qio_channel_test_validate(test);
63
64 /* Check that the requested mode took effect. */
65 mask = umask(0);
66 umask(mask);
67 ret = stat(TEST_FILE, &st);
68 g_assert_cmpint(ret, >, -1);
69 g_assert_cmpuint(TEST_MASK & ~mask, ==, st.st_mode & TEST_MASK_EXPECT);
70
71 unlink(TEST_FILE);
72 object_unref(OBJECT(src));
73 object_unref(OBJECT(dst));
74 }
75
76 static void test_io_channel_file(void)
77 {
78 test_io_channel_file_helper(O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
79 }
80
81 static void test_io_channel_file_rdwr(void)
82 {
83 test_io_channel_file_helper(O_RDWR | O_CREAT | O_TRUNC | O_BINARY);
84 }
85
86 static void test_io_channel_fd(void)
87 {
88 QIOChannel *ioc;
89 int fd = -1;
90
91 fd = open(TEST_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0600);
92 g_assert_cmpint(fd, >, -1);
93
94 ioc = qio_channel_new_fd(fd, &error_abort);
95
96 g_assert_cmpstr(object_get_typename(OBJECT(ioc)),
97 ==,
98 TYPE_QIO_CHANNEL_FILE);
99
100 unlink(TEST_FILE);
101 object_unref(OBJECT(ioc));
102 }
103
104
105 #ifdef CONFIG_PREADV
106 static void test_io_channel_pread_all(void)
107 {
108 QIOChannel *ioc;
109 char write_buf[] = "Hello World, pread_all";
110 char read_buf[sizeof(write_buf)] = {0};
111 int ret;
112
113 unlink(TEST_FILE);
114 ioc = QIO_CHANNEL(qio_channel_file_new_path(
115 TEST_FILE,
116 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
117 TEST_MASK,
118 &error_abort));
119
120 ret = qio_channel_pwrite_all(ioc, write_buf, sizeof(write_buf),
121 0, &error_abort);
122 g_assert_cmpint(ret, ==, 0);
123
124 /* Read back at offset 0 */
125 ret = qio_channel_pread_all(ioc, read_buf, sizeof(read_buf),
126 0, &error_abort);
127 g_assert_cmpint(ret, ==, 0);
128 g_assert_cmpmem(write_buf, sizeof(write_buf),
129 read_buf, sizeof(read_buf));
130
131 /* Read at a non-zero offset */
132 memset(read_buf, 0, sizeof(read_buf));
133 ret = qio_channel_pread_all(ioc, read_buf, sizeof(write_buf) - 7,
134 7, &error_abort);
135 g_assert_cmpint(ret, ==, 0);
136 g_assert_cmpmem(write_buf + 7, sizeof(write_buf) - 7,
137 read_buf, sizeof(write_buf) - 7);
138
139 unlink(TEST_FILE);
140 object_unref(OBJECT(ioc));
141 }
142
143 static void test_io_channel_preadv_all(void)
144 {
145 QIOChannel *ioc;
146 char write_buf[256];
147 char read_buf[256] = {0};
148 struct iovec write_iov[2];
149 struct iovec read_iov[2];
150 int ret;
151 size_t i;
152
153 for (i = 0; i < sizeof(write_buf); i++) {
154 write_buf[i] = i & 0xff;
155 }
156
157 unlink(TEST_FILE);
158 ioc = QIO_CHANNEL(qio_channel_file_new_path(
159 TEST_FILE,
160 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
161 TEST_MASK,
162 &error_abort));
163
164 /* Write using pwritev_all with 2 iovecs */
165 write_iov[0].iov_base = write_buf;
166 write_iov[0].iov_len = 128;
167 write_iov[1].iov_base = write_buf + 128;
168 write_iov[1].iov_len = 128;
169 ret = qio_channel_pwritev_all(ioc, write_iov, 2, 0, &error_abort);
170 g_assert_cmpint(ret, ==, 0);
171
172 /* Read back using preadv_all with 2 iovecs */
173 read_iov[0].iov_base = read_buf;
174 read_iov[0].iov_len = 128;
175 read_iov[1].iov_base = read_buf + 128;
176 read_iov[1].iov_len = 128;
177 ret = qio_channel_preadv_all(ioc, read_iov, 2, 0, &error_abort);
178 g_assert_cmpint(ret, ==, 0);
179
180 g_assert_cmpmem(write_buf, sizeof(write_buf),
181 read_buf, sizeof(read_buf));
182
183 /* Read at non-zero offset with preadv_all */
184 memset(read_buf, 0, sizeof(read_buf));
185 read_iov[0].iov_base = read_buf;
186 read_iov[0].iov_len = 64;
187 read_iov[1].iov_base = read_buf + 64;
188 read_iov[1].iov_len = 64;
189 ret = qio_channel_preadv_all(ioc, read_iov, 2, 128, &error_abort);
190 g_assert_cmpint(ret, ==, 0);
191
192 g_assert_cmpmem(write_buf + 128, 128,
193 read_buf, 128);
194
195 unlink(TEST_FILE);
196 object_unref(OBJECT(ioc));
197 }
198
199 static void test_io_channel_preadv_all_eof(void)
200 {
201 QIOChannel *ioc;
202 char write_buf[] = "Hello World, preadv_all_eof";
203 char read_buf[sizeof(write_buf)] = {0};
204 struct iovec iov;
205 int ret;
206 Error *err = NULL;
207
208 unlink(TEST_FILE);
209 ioc = QIO_CHANNEL(qio_channel_file_new_path(
210 TEST_FILE,
211 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
212 TEST_MASK,
213 &error_abort));
214
215 ret = qio_channel_pwrite_all(ioc, write_buf, sizeof(write_buf),
216 0, &error_abort);
217 g_assert_cmpint(ret, ==, 0);
218
219 /* Full read succeeds: should return 1 */
220 iov.iov_base = read_buf;
221 iov.iov_len = sizeof(read_buf);
222 ret = qio_channel_preadv_all_eof(ioc, &iov, 1, 0, &error_abort);
223 g_assert_cmpint(ret, ==, 1);
224 g_assert_cmpmem(write_buf, sizeof(write_buf),
225 read_buf, sizeof(read_buf));
226
227 /* Clean EOF: offset at file end, should return 0 */
228 iov.iov_base = read_buf;
229 iov.iov_len = 1;
230 ret = qio_channel_preadv_all_eof(ioc, &iov, 1,
231 sizeof(write_buf), &err);
232 g_assert_cmpint(ret, ==, 0);
233 g_assert_null(err);
234
235 /* Partial EOF: start before end, request extends past */
236 iov.iov_base = read_buf;
237 iov.iov_len = 8;
238 ret = qio_channel_preadv_all_eof(ioc, &iov, 1,
239 sizeof(write_buf) - 4, &err);
240 g_assert_cmpint(ret, ==, -1);
241 g_assert_nonnull(err);
242 error_free(err);
243 err = NULL;
244
245 /* Strict wrapper (preadv_all) treats clean EOF as error */
246 iov.iov_base = read_buf;
247 iov.iov_len = 1;
248 ret = qio_channel_preadv_all(ioc, &iov, 1,
249 sizeof(write_buf), &err);
250 g_assert_cmpint(ret, ==, -1);
251 g_assert_nonnull(err);
252 error_free(err);
253
254 unlink(TEST_FILE);
255 object_unref(OBJECT(ioc));
256 }
257
258 static void test_io_channel_pread_all_eof(void)
259 {
260 QIOChannel *ioc;
261 char write_buf[] = "Hello World, pread_all_eof";
262 char read_buf[sizeof(write_buf)] = {0};
263 int ret;
264 Error *err = NULL;
265
266 unlink(TEST_FILE);
267 ioc = QIO_CHANNEL(qio_channel_file_new_path(
268 TEST_FILE,
269 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
270 TEST_MASK,
271 &error_abort));
272
273 ret = qio_channel_pwrite_all(ioc, write_buf, sizeof(write_buf),
274 0, &error_abort);
275 g_assert_cmpint(ret, ==, 0);
276
277 /* Full read succeeds: should return 1 */
278 ret = qio_channel_pread_all_eof(ioc, read_buf, sizeof(read_buf),
279 0, &error_abort);
280 g_assert_cmpint(ret, ==, 1);
281 g_assert_cmpmem(write_buf, sizeof(write_buf),
282 read_buf, sizeof(read_buf));
283
284 /* Clean EOF: should return 0 */
285 ret = qio_channel_pread_all_eof(ioc, read_buf, 1,
286 sizeof(write_buf), &err);
287 g_assert_cmpint(ret, ==, 0);
288 g_assert_null(err);
289
290 /* Partial EOF: should return -1 */
291 ret = qio_channel_pread_all_eof(ioc, read_buf, 8,
292 sizeof(write_buf) - 4, &err);
293 g_assert_cmpint(ret, ==, -1);
294 g_assert_nonnull(err);
295 error_free(err);
296
297 unlink(TEST_FILE);
298 object_unref(OBJECT(ioc));
299 }
300 #endif /* CONFIG_PREADV */
301
302 #ifndef _WIN32
303 static void test_io_channel_pipe(bool async)
304 {
305 QIOChannel *src, *dst;
306 QIOChannelTest *test;
307 int fd[2];
308
309 if (!g_unix_open_pipe(fd, FD_CLOEXEC, NULL)) {
310 perror("pipe");
311 abort();
312 }
313
314 src = QIO_CHANNEL(qio_channel_file_new_fd(fd[1]));
315 dst = QIO_CHANNEL(qio_channel_file_new_fd(fd[0]));
316
317 test = qio_channel_test_new();
318 qio_channel_test_run_threads(test, async, src, dst);
319 qio_channel_test_validate(test);
320
321 object_unref(OBJECT(src));
322 object_unref(OBJECT(dst));
323 }
324
325
326 static void test_io_channel_pipe_async(void)
327 {
328 test_io_channel_pipe(true);
329 }
330
331 static void test_io_channel_pipe_sync(void)
332 {
333 test_io_channel_pipe(false);
334 }
335 #endif /* ! _WIN32 */
336
337
338 int main(int argc, char **argv)
339 {
340 module_call_init(MODULE_INIT_QOM);
341
342 g_test_init(&argc, &argv, NULL);
343
344 g_test_add_func("/io/channel/file", test_io_channel_file);
345 g_test_add_func("/io/channel/file/rdwr", test_io_channel_file_rdwr);
346 g_test_add_func("/io/channel/file/fd", test_io_channel_fd);
347 #ifdef CONFIG_PREADV
348 g_test_add_func("/io/channel/file/pread-all",
349 test_io_channel_pread_all);
350 g_test_add_func("/io/channel/file/preadv-all",
351 test_io_channel_preadv_all);
352 g_test_add_func("/io/channel/file/preadv-all-eof",
353 test_io_channel_preadv_all_eof);
354 g_test_add_func("/io/channel/file/pread-all-eof",
355 test_io_channel_pread_all_eof);
356 #endif
357 #ifndef _WIN32
358 g_test_add_func("/io/channel/pipe/sync", test_io_channel_pipe_sync);
359 g_test_add_func("/io/channel/pipe/async", test_io_channel_pipe_async);
360 #endif
361 return g_test_run();
362 }