1#include <fcntl.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <errno.h>
5
6#include <sys/stat.h>
7#include <sys/types.h>
8
9#include "9p.h"
10#include "vfs.h"
11#include "9pfs.h"
12#include "xtimer.h"
13
14#include "lwip.h"
15#include "lwip/netif.h"
16
17#include "net/af.h"
18#include "net/ipv6/addr.h"
19#include "net/sock/tcp.h"
20
21#include "embUnit.h"
22#include "../../util.h"
23
24/**
25 * 9P file system superblock.
26 */
27static _9pfs fs;
28
29/**
30 * Mount point where the 9pfs is mounted.
31 */
32static vfs_mount_t mountp;
33
34static void
35set_up(void)
36{
37 int ret;
38
39 mountp.mount_point = "/mnt";
40 mountp.fs = &_9p_file_system;
41 mountp.private_data = &fs;
42
43 _9pinit(&fs.ctx, recvfn, sendfn);
44 if ((ret = vfs_mount(&mountp)))
45 fprintf(stderr, "vfs_mount failed: %d\n", ret);
46}
47
48static void
49tear_down(void)
50{
51 int ret;
52
53 if ((ret = vfs_umount(&mountp)))
54 fprintf(stderr, "vfs_umount failed: %d\n", ret);
55}
56
57static void
58test_9pfs__create_and_remove_directory(void)
59{
60 struct stat st;
61
62 TEST_ASSERT_EQUAL_INT(0, vfs_mkdir("/mnt/foo/wtf", S_IRUSR|S_IWUSR));
63 TEST_ASSERT_EQUAL_INT(0, vfs_rmdir("/mnt/foo/wtf"));
64
65 TEST_ASSERT(vfs_stat("/mnt/foo/wtf", &st) != 0);
66 TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
67}
68
69static void
70test_9pfs__read(void)
71{
72 int fd;
73 ssize_t n;
74 char dest[BUFSIZ];
75
76 fd = vfs_open("/mnt/foo/bar/hello", OREAD, S_IRUSR|S_IWUSR);
77 TEST_ASSERT(fd >= 0);
78
79 n = vfs_read(fd, dest, BUFSIZ - 1);
80 TEST_ASSERT_EQUAL_INT(13, n);
81
82 dest[n] = '\0';
83 TEST_ASSERT_EQUAL_STRING("Hello World!\n", (char*)dest);
84
85 TEST_ASSERT_EQUAL_INT(0, vfs_close(fd));
86}
87
88static void
89test_9pfs__lseek_and_read(void)
90{
91 int fd;
92 ssize_t n;
93 char dest[BUFSIZ];
94
95 fd = vfs_open("/mnt/foo/bar/hello", OREAD, S_IRUSR|S_IWUSR);
96 TEST_ASSERT(fd >= 0);
97
98 TEST_ASSERT_EQUAL_INT(6, vfs_lseek(fd, 6, SEEK_SET));
99
100 n = vfs_read(fd, dest, BUFSIZ - 1);
101 TEST_ASSERT_EQUAL_INT(7, n);
102
103 dest[n] = '\0';
104 TEST_ASSERT_EQUAL_STRING("World!\n", (char*)dest);
105
106 TEST_ASSERT_EQUAL_INT(0, vfs_close(fd));
107}
108
109static void
110test_9pfs__create_and_delete(void)
111{
112 int fd;
113 struct stat buf;
114
115 fd = vfs_open("/mnt/foo/falafel", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
116 TEST_ASSERT(fd >= 0);
117
118 TEST_ASSERT_EQUAL_INT(0, vfs_close(fd));
119 TEST_ASSERT_EQUAL_INT(0, vfs_unlink("/mnt/foo/falafel"));
120
121 TEST_ASSERT(vfs_stat("/mnt/foo/falafel", &buf) < 0);
122}
123
124static void
125test_9pfs__write_lseek_and_read(void)
126{
127 int fd;
128 ssize_t n;
129 char *str = "foobar";
130 char dest[7];
131
132 fd = vfs_open("/mnt/writeme", O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
133 TEST_ASSERT(fd >= 0);
134
135 TEST_ASSERT_EQUAL_INT(2, cntfids(fs.ctx.fids));
136
137 n = vfs_write(fd, str, 6);
138 TEST_ASSERT_EQUAL_INT(6, n);
139
140 TEST_ASSERT_EQUAL_INT(0, vfs_lseek(fd, 0, SEEK_SET));
141
142 n = vfs_read(fd, dest, 6);
143 TEST_ASSERT_EQUAL_INT(6, n);
144
145 dest[6] = '\0';
146 TEST_ASSERT_EQUAL_STRING(str, (char*)dest);
147
148 TEST_ASSERT_EQUAL_INT(0, vfs_close(fd));
149 TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
150}
151
152static void
153test_9pfs__opendir_and_closedir(void)
154{
155 vfs_DIR dirp;
156
157 TEST_ASSERT_EQUAL_INT(0, vfs_opendir(&dirp, "/mnt/foo"));
158 TEST_ASSERT_EQUAL_INT(2, cntfids(fs.ctx.fids));
159 TEST_ASSERT_EQUAL_INT(0, vfs_closedir(&dirp));
160
161 TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
162}
163
164static void
165test_9pfs__opendir_file(void)
166{
167 vfs_DIR dirp;
168
169 TEST_ASSERT_EQUAL_INT(-ENOTDIR,
170 vfs_opendir(&dirp, "/mnt/foo/bar/hello"));
171 TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
172}
173
174static void
175test_9pfs__readdir_single_entry(void)
176{
177 vfs_DIR dirp;
178 vfs_dirent_t entry;
179
180 TEST_ASSERT_EQUAL_INT(0, vfs_opendir(&dirp, "/mnt/foo"));
181 TEST_ASSERT_EQUAL_INT(1, vfs_readdir(&dirp, &entry));
182 TEST_ASSERT_EQUAL_STRING("bar", (char*)entry.d_name);
183 TEST_ASSERT_EQUAL_INT(0, vfs_readdir(&dirp, &entry));
184
185 TEST_ASSERT_EQUAL_INT(0, vfs_closedir(&dirp));
186 TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
187}
188
189static void
190test_9pfs__readdir_multiple_entries(void)
191{
192 int i;
193 vfs_DIR dirp;
194 vfs_dirent_t entry;
195 char dirname[VFS_NAME_MAX + 1];
196
197 TEST_ASSERT_EQUAL_INT(0, vfs_opendir(&dirp, "/mnt/dirs"));
198 for (i = 1; i <= 5; i++) {
199 TEST_ASSERT_EQUAL_INT(1, vfs_readdir(&dirp, &entry));
200 snprintf(dirname, sizeof(dirname), "%d", i);
201 TEST_ASSERT_EQUAL_STRING((char*)dirname, (char*)entry.d_name);
202 }
203 TEST_ASSERT_EQUAL_INT(0, vfs_readdir(&dirp, &entry));
204
205 TEST_ASSERT_EQUAL_INT(0, vfs_closedir(&dirp));
206 TEST_ASSERT_EQUAL_INT(1, cntfids(fs.ctx.fids));
207}
208
209Test*
210tests_9pfs_tests(void)
211{
212 EMB_UNIT_TESTFIXTURES(fixtures) {
213 new_TestFixture(test_9pfs__read),
214 new_TestFixture(test_9pfs__lseek_and_read),
215 new_TestFixture(test_9pfs__create_and_delete),
216 new_TestFixture(test_9pfs__write_lseek_and_read),
217 new_TestFixture(test_9pfs__create_and_remove_directory),
218 new_TestFixture(test_9pfs__opendir_and_closedir),
219 new_TestFixture(test_9pfs__opendir_file),
220 new_TestFixture(test_9pfs__readdir_single_entry),
221 new_TestFixture(test_9pfs__readdir_multiple_entries),
222 };
223
224 EMB_UNIT_TESTCALLER(_9pfs_tests, set_up, tear_down, fixtures);
225 return (Test*)&_9pfs_tests;
226}
227
228int
229main(void)
230{
231 char *addr, *port;
232 sock_tcp_ep_t remote = SOCK_IPV6_EP_ANY;
233
234 GETENV(addr, "NINERIOT_ADDR");
235 GETENV(port, "NINERIOT_PPORT");
236
237 remote.port = atoi(port);
238 if (!ipv6_addr_from_str((ipv6_addr_t *)&remote.addr, addr)) {
239 fprintf(stderr, "Address '%s' is malformed\n", addr);
240 return EXIT_FAILURE;
241 }
242
243 puts("Waiting for address autoconfiguration...");
244 xtimer_sleep(3);
245
246 if (sock_tcp_connect(&psock, &remote, 0, SOCK_FLAGS_REUSE_EP) < 0) {
247 fprintf(stderr, "Couldn't connect to server\n");
248 return EXIT_FAILURE;
249 }
250
251 fs.uname = "glenda";
252 fs.aname = NULL;
253
254 TESTS_START();
255 TESTS_RUN(tests_9pfs_tests());
256 TESTS_END();
257
258 sock_tcp_disconnect(&psock);
259 return EXIT_SUCCESS;
260}