|
1 /* |
|
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
3 * |
|
4 * Copyright 2019 Olaf Wintermann. All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * 1. Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * |
|
12 * 2. Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
26 * POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #include <stdio.h> |
|
30 #include <stdlib.h> |
|
31 |
|
32 #include <ucx/string.h> |
|
33 #include <ucx/list.h> |
|
34 #include <ucx/map.h> |
|
35 |
|
36 #include "../daemon/session.h" |
|
37 |
|
38 #include "testutils.h" |
|
39 |
|
40 #include "vfs.h" |
|
41 |
|
42 typedef struct TestVFS { |
|
43 UcxMap *files; |
|
44 } TestVFS; |
|
45 |
|
46 typedef struct TestVFSFile { |
|
47 VFSFile file; |
|
48 sstr_t path; |
|
49 int isdir; |
|
50 } TestVFSFile; |
|
51 |
|
52 typedef struct TestVFSDir { |
|
53 VFSDir dir; |
|
54 TestVFSFile *file; |
|
55 UcxMapIterator i; |
|
56 sstr_t name; |
|
57 } TestVFSDir; |
|
58 |
|
59 /* dir io */ |
|
60 |
|
61 static char* test_resource_name(char *url) { |
|
62 sstr_t urlstr = sstr(url); |
|
63 if(urlstr.ptr[urlstr.length-1] == '/') { |
|
64 urlstr.length--; |
|
65 } |
|
66 sstr_t resname = sstrrchr(urlstr, '/'); |
|
67 if(resname.length > 1) { |
|
68 return resname.ptr+1; |
|
69 } else { |
|
70 return url; |
|
71 } |
|
72 } |
|
73 |
|
74 int testvfs_readdir(VFS_DIR dir, VFS_ENTRY *entry, int getstat) { |
|
75 TestVFS *vfs = dir->ctx->vfs->instance; |
|
76 TestVFSDir *vfsdir = (TestVFSDir*)dir; |
|
77 |
|
78 sstr_t prefix = sstrcat(2, vfsdir->file->path, S("/")); |
|
79 |
|
80 TestVFSFile *file = NULL; |
|
81 UCX_MAP_FOREACH(key, file, vfsdir->i) { |
|
82 if(sstrprefix(file->path, prefix)) { |
|
83 break; |
|
84 } else { |
|
85 file = NULL; |
|
86 } |
|
87 } |
|
88 free(prefix.ptr); |
|
89 |
|
90 if(file) { |
|
91 vfsdir->name = sstrdup_a( |
|
92 session_get_allocator(dir->ctx->sn), |
|
93 sstr(test_resource_name(file->path.ptr))); |
|
94 entry->name = vfsdir->name.ptr; |
|
95 return 1; |
|
96 } else { |
|
97 return 0; |
|
98 } |
|
99 } |
|
100 |
|
101 void testvfs_dir_close(VFS_DIR dir) { |
|
102 TestVFSDir *testdir = (TestVFSDir*)dir; |
|
103 pool_free(testdir->dir.ctx->sn->pool, dir); |
|
104 |
|
105 } |
|
106 |
|
107 VFS_DIRIO test_dir_io = { |
|
108 testvfs_readdir, |
|
109 testvfs_dir_close |
|
110 }; |
|
111 |
|
112 |
|
113 /* vfs funcs */ |
|
114 |
|
115 SYS_FILE testvfs_open(VFSContext *ctx, char *path, int oflags) { |
|
116 TestVFS *vfs = ctx->vfs->instance; |
|
117 TestVFSFile *file = NULL; |
|
118 |
|
119 sstr_t s_path = sstr(path); |
|
120 if(sstrsuffix(s_path, S("/"))) { |
|
121 s_path.length--; |
|
122 } |
|
123 |
|
124 file = ucx_map_sstr_get(vfs->files, s_path); |
|
125 if(!file) { |
|
126 if((oflags & O_CREAT) == O_CREAT) { |
|
127 file = pool_malloc(ctx->sn->pool, sizeof(TestVFSFile)); |
|
128 ZERO(file, sizeof(TestVFSFile)); |
|
129 file->path = sstrdup_a(session_get_allocator(ctx->sn), s_path); |
|
130 |
|
131 ucx_map_sstr_put(vfs->files, s_path, file); |
|
132 } |
|
133 } |
|
134 |
|
135 return (SYS_FILE)file; |
|
136 } |
|
137 |
|
138 int testvfs_stat(VFSContext *ctx, char *path, struct stat *buf) { |
|
139 TestVFS *vfs = ctx->vfs->instance; |
|
140 TestVFSFile *file = NULL; |
|
141 |
|
142 sstr_t s_path = sstr(path); |
|
143 if(sstrsuffix(s_path, S("/"))) { |
|
144 s_path.length--; |
|
145 } |
|
146 |
|
147 file = ucx_map_sstr_get(vfs->files, s_path); |
|
148 if(!file) { |
|
149 return 1; |
|
150 } |
|
151 return 0; |
|
152 } |
|
153 |
|
154 int testvfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { |
|
155 return 0; |
|
156 } |
|
157 |
|
158 VFS_DIR testvfs_opendir(VFSContext *ctx, char *path) { |
|
159 TestVFS *vfs = ctx->vfs->instance; |
|
160 TestVFSFile *file = NULL; |
|
161 |
|
162 sstr_t s_path = sstr(path); |
|
163 if(sstrsuffix(s_path, S("/"))) { |
|
164 s_path.length--; |
|
165 } |
|
166 |
|
167 file = ucx_map_sstr_get(vfs->files, s_path); |
|
168 if(!file) { |
|
169 return NULL; |
|
170 } |
|
171 |
|
172 if(!file->isdir) { |
|
173 return NULL; |
|
174 } |
|
175 |
|
176 TestVFSDir *dir = pool_malloc(ctx->sn->pool, sizeof(TestVFSDir)); |
|
177 ZERO(dir, sizeof(TestVFSDir)); |
|
178 dir->file = file; |
|
179 dir->i = ucx_map_iterator(vfs->files); |
|
180 |
|
181 dir->dir.ctx = ctx; |
|
182 dir->dir.io = &test_dir_io; |
|
183 |
|
184 return (VFS_DIR)dir; |
|
185 } |
|
186 |
|
187 VFS_DIR testvfs_fdopendir(VFSContext *ctx, SYS_FILE fd) { |
|
188 TestVFS *vfs = ctx->vfs->instance; |
|
189 TestVFSFile *file = (TestVFSFile*)fd; |
|
190 if(!file->isdir) { |
|
191 return NULL; |
|
192 } |
|
193 |
|
194 TestVFSDir *dir = pool_malloc(ctx->sn->pool, sizeof(TestVFSDir)); |
|
195 ZERO(dir, sizeof(TestVFSDir)); |
|
196 dir->file = file; |
|
197 dir->i = ucx_map_iterator(vfs->files); |
|
198 |
|
199 dir->dir.ctx = ctx; |
|
200 dir->dir.io = &test_dir_io; |
|
201 |
|
202 return (VFS_DIR)dir; |
|
203 } |
|
204 |
|
205 int testvfs_mkdir(VFSContext *ctx, char *path) { |
|
206 SYS_FILE fd = testvfs_open(ctx, path, O_CREAT); |
|
207 if(!fd) { |
|
208 return 1; |
|
209 } |
|
210 |
|
211 TestVFSFile *file = (TestVFSFile*)fd; |
|
212 file->isdir = 1; |
|
213 |
|
214 return 0; |
|
215 } |
|
216 |
|
217 int testvfs_unlink(VFSContext *ctx, char *path) { |
|
218 return 0; |
|
219 } |
|
220 |
|
221 static VFS testVFSClass = { |
|
222 testvfs_open, |
|
223 testvfs_stat, |
|
224 testvfs_fstat, |
|
225 testvfs_opendir, |
|
226 testvfs_fdopendir, |
|
227 testvfs_mkdir, |
|
228 testvfs_unlink, |
|
229 0, |
|
230 NULL |
|
231 }; |
|
232 |
|
233 |
|
234 VFS* testvfs_create(Session *sn) { |
|
235 TestVFS *vfs = pool_malloc(sn->pool, sizeof(TestVFS)); |
|
236 vfs->files = ucx_map_new_a(session_get_allocator(sn), 64); |
|
237 |
|
238 testVFSClass.instance = vfs; |
|
239 return &testVFSClass; |
|
240 } |
|
241 |
|
242 |
|
243 /* ------------------------------------------------------------------------- */ |
|
244 // |
|
245 // VFS Tests |
|
246 // |
|
247 /* ------------------------------------------------------------------------- */ |
|
248 |
|
249 UCX_TEST(test_vfs_open) { |
|
250 Session *sn = testutil_session(); |
|
251 Request *rq = testutil_request(sn->pool, "PUT", "/"); |
|
252 rq->vfs = testvfs_create(sn); |
|
253 |
|
254 VFSContext *vfs = vfs_request_context(sn, rq); |
|
255 |
|
256 UCX_TEST_BEGIN; |
|
257 |
|
258 UCX_TEST_ASSERT(vfs, "vfs is NULL"); |
|
259 |
|
260 SYS_FILE f1 = vfs_open(vfs, "/file1", O_CREAT); |
|
261 UCX_TEST_ASSERT(f1, "f1 not opened"); |
|
262 |
|
263 SYS_FILE f2 = vfs_open(vfs, "/file1", 0); |
|
264 UCX_TEST_ASSERT(f2, "f2 not opened"); |
|
265 |
|
266 UCX_TEST_END; |
|
267 |
|
268 testutil_destroy_session(sn); |
|
269 } |
|
270 |
|
271 UCX_TEST(test_vfs_mkdir) { |
|
272 Session *sn = testutil_session(); |
|
273 Request *rq = testutil_request(sn->pool, "PUT", "/"); |
|
274 rq->vfs = testvfs_create(sn); |
|
275 |
|
276 VFSContext *vfs = vfs_request_context(sn, rq); |
|
277 |
|
278 UCX_TEST_BEGIN; |
|
279 |
|
280 int err = vfs_mkdir(vfs, "/dir"); |
|
281 UCX_TEST_ASSERT(err == 0, "error not 0"); |
|
282 |
|
283 SYS_FILE fd = vfs_open(vfs, "/dir", 0); |
|
284 UCX_TEST_ASSERT(fd, "no fd"); |
|
285 |
|
286 UCX_TEST_END; |
|
287 |
|
288 testutil_destroy_session(sn); |
|
289 } |
|
290 |
|
291 UCX_TEST(test_vfs_opendir) { |
|
292 Session *sn = testutil_session(); |
|
293 Request *rq = testutil_request(sn->pool, "PUT", "/"); |
|
294 rq->vfs = testvfs_create(sn); |
|
295 |
|
296 VFSContext *vfs = vfs_request_context(sn, rq); |
|
297 |
|
298 UCX_TEST_BEGIN; |
|
299 |
|
300 int err = vfs_mkdir(vfs, "/dir"); |
|
301 UCX_TEST_ASSERT(err == 0, "error not 0"); |
|
302 |
|
303 VFSDir *dir = vfs_opendir(vfs, "/dir"); |
|
304 UCX_TEST_ASSERT(dir, "no dir"); |
|
305 |
|
306 UCX_TEST_END; |
|
307 |
|
308 testutil_destroy_session(sn); |
|
309 } |
|
310 |
|
311 UCX_TEST(test_readdir) { |
|
312 Session *sn = testutil_session(); |
|
313 Request *rq = testutil_request(sn->pool, "PUT", "/"); |
|
314 rq->vfs = testvfs_create(sn); |
|
315 |
|
316 VFSContext *vfs = vfs_request_context(sn, rq); |
|
317 |
|
318 UCX_TEST_BEGIN; |
|
319 |
|
320 int err = vfs_mkdir(vfs, "/dir"); |
|
321 UCX_TEST_ASSERT(err == 0, "error not 0"); |
|
322 |
|
323 // add some test file to /dir |
|
324 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file1", O_CREAT), "creation of file1 failed"); |
|
325 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file2", O_CREAT), "creation of file2 failed"); |
|
326 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file3", O_CREAT), "creation of file3 failed"); |
|
327 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file4", O_CREAT), "creation of file4 failed"); |
|
328 |
|
329 VFSDir *dir = vfs_opendir(vfs, "/dir"); |
|
330 UCX_TEST_ASSERT(dir, "dir not opened"); |
|
331 |
|
332 UcxMap *files = ucx_map_new(8); |
|
333 |
|
334 VFSEntry entry; |
|
335 while(vfs_readdir(dir, &entry)) { |
|
336 ucx_map_cstr_put(files, entry.name, dir); |
|
337 } |
|
338 |
|
339 UCX_TEST_ASSERT(files->count == 4, "wrong files count"); |
|
340 UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file1"), "file1 missing"); |
|
341 UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file2"), "file2 missing"); |
|
342 UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file3"), "file3 missing"); |
|
343 UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file4"), "file4 missing"); |
|
344 |
|
345 ucx_map_free(files); |
|
346 |
|
347 UCX_TEST_END; |
|
348 |
|
349 testutil_destroy_session(sn); |
|
350 } |