# HG changeset patch # User Olaf Wintermann # Date 1577797662 -3600 # Node ID dd6c155c082aa86e694d12cb3acda4b2624f3387 # Parent 2ba512b284b9f12ec247fa3e0bb1d2f1558e4b37 add simple vfs implementation for testing diff -r 2ba512b284b9 -r dd6c155c082a src/server/test/main.c --- a/src/server/test/main.c Tue Dec 31 11:57:02 2019 +0100 +++ b/src/server/test/main.c Tue Dec 31 14:07:42 2019 +0100 @@ -41,6 +41,7 @@ #include +#include "vfs.h" #include "webdav.h" void test() { @@ -61,6 +62,12 @@ UcxTestSuite* suite = ucx_test_suite_new(); + // vfs tests + ucx_test_register(suite, test_vfs_open); + ucx_test_register(suite, test_vfs_mkdir); + ucx_test_register(suite, test_vfs_opendir); + ucx_test_register(suite, test_readdir); + // webdav tests ucx_test_register(suite, test_propfind_parse); ucx_test_register(suite, test_proppatch_parse); diff -r 2ba512b284b9 -r dd6c155c082a src/server/test/objs.mk --- a/src/server/test/objs.mk Tue Dec 31 11:57:02 2019 +0100 +++ b/src/server/test/objs.mk Tue Dec 31 14:07:42 2019 +0100 @@ -33,6 +33,7 @@ TESTOBJ = main.o TESTOBJ += testutils.o TESTOBJ += webdav.o +TESTOBJ += vfs.o TESTOBJS = $(TESTOBJ:%=$(TEST_OBJPRE)%) TESTSOURCE = $(TESTOBJ:%.o=test/%.c) diff -r 2ba512b284b9 -r dd6c155c082a src/server/test/vfs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/test/vfs.c Tue Dec 31 14:07:42 2019 +0100 @@ -0,0 +1,350 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2019 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include + +#include "../daemon/session.h" + +#include "testutils.h" + +#include "vfs.h" + +typedef struct TestVFS { + UcxMap *files; +} TestVFS; + +typedef struct TestVFSFile { + VFSFile file; + sstr_t path; + int isdir; +} TestVFSFile; + +typedef struct TestVFSDir { + VFSDir dir; + TestVFSFile *file; + UcxMapIterator i; + sstr_t name; +} TestVFSDir; + +/* dir io */ + +static char* test_resource_name(char *url) { + sstr_t urlstr = sstr(url); + if(urlstr.ptr[urlstr.length-1] == '/') { + urlstr.length--; + } + sstr_t resname = sstrrchr(urlstr, '/'); + if(resname.length > 1) { + return resname.ptr+1; + } else { + return url; + } +} + +int testvfs_readdir(VFS_DIR dir, VFS_ENTRY *entry, int getstat) { + TestVFS *vfs = dir->ctx->vfs->instance; + TestVFSDir *vfsdir = (TestVFSDir*)dir; + + sstr_t prefix = sstrcat(2, vfsdir->file->path, S("/")); + + TestVFSFile *file = NULL; + UCX_MAP_FOREACH(key, file, vfsdir->i) { + if(sstrprefix(file->path, prefix)) { + break; + } else { + file = NULL; + } + } + free(prefix.ptr); + + if(file) { + vfsdir->name = sstrdup_a( + session_get_allocator(dir->ctx->sn), + sstr(test_resource_name(file->path.ptr))); + entry->name = vfsdir->name.ptr; + return 1; + } else { + return 0; + } +} + +void testvfs_dir_close(VFS_DIR dir) { + TestVFSDir *testdir = (TestVFSDir*)dir; + pool_free(testdir->dir.ctx->sn->pool, dir); + +} + +VFS_DIRIO test_dir_io = { + testvfs_readdir, + testvfs_dir_close +}; + + +/* vfs funcs */ + +SYS_FILE testvfs_open(VFSContext *ctx, char *path, int oflags) { + TestVFS *vfs = ctx->vfs->instance; + TestVFSFile *file = NULL; + + sstr_t s_path = sstr(path); + if(sstrsuffix(s_path, S("/"))) { + s_path.length--; + } + + file = ucx_map_sstr_get(vfs->files, s_path); + if(!file) { + if((oflags & O_CREAT) == O_CREAT) { + file = pool_malloc(ctx->sn->pool, sizeof(TestVFSFile)); + ZERO(file, sizeof(TestVFSFile)); + file->path = sstrdup_a(session_get_allocator(ctx->sn), s_path); + + ucx_map_sstr_put(vfs->files, s_path, file); + } + } + + return (SYS_FILE)file; +} + +int testvfs_stat(VFSContext *ctx, char *path, struct stat *buf) { + TestVFS *vfs = ctx->vfs->instance; + TestVFSFile *file = NULL; + + sstr_t s_path = sstr(path); + if(sstrsuffix(s_path, S("/"))) { + s_path.length--; + } + + file = ucx_map_sstr_get(vfs->files, s_path); + if(!file) { + return 1; + } + return 0; +} + +int testvfs_fstat(VFSContext *ctx, SYS_FILE fd, struct stat *buf) { + return 0; +} + +VFS_DIR testvfs_opendir(VFSContext *ctx, char *path) { + TestVFS *vfs = ctx->vfs->instance; + TestVFSFile *file = NULL; + + sstr_t s_path = sstr(path); + if(sstrsuffix(s_path, S("/"))) { + s_path.length--; + } + + file = ucx_map_sstr_get(vfs->files, s_path); + if(!file) { + return NULL; + } + + if(!file->isdir) { + return NULL; + } + + TestVFSDir *dir = pool_malloc(ctx->sn->pool, sizeof(TestVFSDir)); + ZERO(dir, sizeof(TestVFSDir)); + dir->file = file; + dir->i = ucx_map_iterator(vfs->files); + + dir->dir.ctx = ctx; + dir->dir.io = &test_dir_io; + + return (VFS_DIR)dir; +} + +VFS_DIR testvfs_fdopendir(VFSContext *ctx, SYS_FILE fd) { + TestVFS *vfs = ctx->vfs->instance; + TestVFSFile *file = (TestVFSFile*)fd; + if(!file->isdir) { + return NULL; + } + + TestVFSDir *dir = pool_malloc(ctx->sn->pool, sizeof(TestVFSDir)); + ZERO(dir, sizeof(TestVFSDir)); + dir->file = file; + dir->i = ucx_map_iterator(vfs->files); + + dir->dir.ctx = ctx; + dir->dir.io = &test_dir_io; + + return (VFS_DIR)dir; +} + +int testvfs_mkdir(VFSContext *ctx, char *path) { + SYS_FILE fd = testvfs_open(ctx, path, O_CREAT); + if(!fd) { + return 1; + } + + TestVFSFile *file = (TestVFSFile*)fd; + file->isdir = 1; + + return 0; +} + +int testvfs_unlink(VFSContext *ctx, char *path) { + return 0; +} + +static VFS testVFSClass = { + testvfs_open, + testvfs_stat, + testvfs_fstat, + testvfs_opendir, + testvfs_fdopendir, + testvfs_mkdir, + testvfs_unlink, + 0, + NULL +}; + + +VFS* testvfs_create(Session *sn) { + TestVFS *vfs = pool_malloc(sn->pool, sizeof(TestVFS)); + vfs->files = ucx_map_new_a(session_get_allocator(sn), 64); + + testVFSClass.instance = vfs; + return &testVFSClass; +} + + +/* ------------------------------------------------------------------------- */ +// +// VFS Tests +// +/* ------------------------------------------------------------------------- */ + +UCX_TEST(test_vfs_open) { + Session *sn = testutil_session(); + Request *rq = testutil_request(sn->pool, "PUT", "/"); + rq->vfs = testvfs_create(sn); + + VFSContext *vfs = vfs_request_context(sn, rq); + + UCX_TEST_BEGIN; + + UCX_TEST_ASSERT(vfs, "vfs is NULL"); + + SYS_FILE f1 = vfs_open(vfs, "/file1", O_CREAT); + UCX_TEST_ASSERT(f1, "f1 not opened"); + + SYS_FILE f2 = vfs_open(vfs, "/file1", 0); + UCX_TEST_ASSERT(f2, "f2 not opened"); + + UCX_TEST_END; + + testutil_destroy_session(sn); +} + +UCX_TEST(test_vfs_mkdir) { + Session *sn = testutil_session(); + Request *rq = testutil_request(sn->pool, "PUT", "/"); + rq->vfs = testvfs_create(sn); + + VFSContext *vfs = vfs_request_context(sn, rq); + + UCX_TEST_BEGIN; + + int err = vfs_mkdir(vfs, "/dir"); + UCX_TEST_ASSERT(err == 0, "error not 0"); + + SYS_FILE fd = vfs_open(vfs, "/dir", 0); + UCX_TEST_ASSERT(fd, "no fd"); + + UCX_TEST_END; + + testutil_destroy_session(sn); +} + +UCX_TEST(test_vfs_opendir) { + Session *sn = testutil_session(); + Request *rq = testutil_request(sn->pool, "PUT", "/"); + rq->vfs = testvfs_create(sn); + + VFSContext *vfs = vfs_request_context(sn, rq); + + UCX_TEST_BEGIN; + + int err = vfs_mkdir(vfs, "/dir"); + UCX_TEST_ASSERT(err == 0, "error not 0"); + + VFSDir *dir = vfs_opendir(vfs, "/dir"); + UCX_TEST_ASSERT(dir, "no dir"); + + UCX_TEST_END; + + testutil_destroy_session(sn); +} + +UCX_TEST(test_readdir) { + Session *sn = testutil_session(); + Request *rq = testutil_request(sn->pool, "PUT", "/"); + rq->vfs = testvfs_create(sn); + + VFSContext *vfs = vfs_request_context(sn, rq); + + UCX_TEST_BEGIN; + + int err = vfs_mkdir(vfs, "/dir"); + UCX_TEST_ASSERT(err == 0, "error not 0"); + + // add some test file to /dir + UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file1", O_CREAT), "creation of file1 failed"); + UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file2", O_CREAT), "creation of file2 failed"); + UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file3", O_CREAT), "creation of file3 failed"); + UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file4", O_CREAT), "creation of file4 failed"); + + VFSDir *dir = vfs_opendir(vfs, "/dir"); + UCX_TEST_ASSERT(dir, "dir not opened"); + + UcxMap *files = ucx_map_new(8); + + VFSEntry entry; + while(vfs_readdir(dir, &entry)) { + ucx_map_cstr_put(files, entry.name, dir); + } + + UCX_TEST_ASSERT(files->count == 4, "wrong files count"); + UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file1"), "file1 missing"); + UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file2"), "file2 missing"); + UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file3"), "file3 missing"); + UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file4"), "file4 missing"); + + ucx_map_free(files); + + UCX_TEST_END; + + testutil_destroy_session(sn); +} diff -r 2ba512b284b9 -r dd6c155c082a src/server/test/vfs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/test/vfs.h Tue Dec 31 14:07:42 2019 +0100 @@ -0,0 +1,53 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2019 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TEST_VFS_H +#define TEST_VFS_H + +#include "../public/nsapi.h" +#include "../public/vfs.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +VFS* testvfs_create(Session *sn); + +UCX_TEST(test_vfs_open); +UCX_TEST(test_vfs_mkdir); +UCX_TEST(test_vfs_opendir); +UCX_TEST(test_readdir); + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_VFS_H */ + diff -r 2ba512b284b9 -r dd6c155c082a src/server/test/webdav.c --- a/src/server/test/webdav.c Tue Dec 31 11:57:02 2019 +0100 +++ b/src/server/test/webdav.c Tue Dec 31 14:07:42 2019 +0100 @@ -42,7 +42,7 @@ /* ----------------------------- Test Backends --------------------------*/ static int backend2_init_called = 0; -static int backend2_propfind_do_called = 0; +static int backend2_propfind_do_count = 0; static int backend2_propfind_finish_called = 0; // backend2 @@ -62,7 +62,7 @@ WebdavResource *resource, struct stat *s) { - backend2_propfind_do_called = 1; + backend2_propfind_do_count++; return 0; } @@ -82,7 +82,7 @@ // backend1 static int backend1_init_called = 0; -static int backend1_propfind_do_called = 0; +static int backend1_propfind_do_count = 0; static int backend1_propfind_finish_called = 0; @@ -112,7 +112,7 @@ WebdavResource *resource, struct stat *s) { - backend1_propfind_do_called = 1; + backend1_propfind_do_count++; return 0; } @@ -131,10 +131,10 @@ static void reset_backends(void) { backend1_init_called = 0; - backend1_propfind_do_called = 0; + backend1_propfind_do_count = 0; backend1_propfind_finish_called = 0; backend2_init_called = 0; - backend2_propfind_do_called = 0; + backend2_propfind_do_count = 0; backend2_propfind_finish_called = 0; } @@ -785,9 +785,28 @@ int err = webdav_op_propfind_begin(op, "/", NULL, NULL); UCX_TEST_ASSERT(err == 0, "err not 0"); - UCX_TEST_ASSERT(backend1_propfind_do_called == 1, "backend1 propfind_do not called"); - UCX_TEST_ASSERT(backend2_propfind_do_called == 1, "backend2 propfind_do not called"); + UCX_TEST_ASSERT(backend1_propfind_do_count == 1, "backend1 propfind_do not called"); + UCX_TEST_ASSERT(backend2_propfind_do_count == 1, "backend2 propfind_do not called"); UCX_TEST_END; } + +UCX_TEST(test_webdav_op_propfind_children) { + reset_backends(); + + Session *sn; + Request *rq; + + UCX_TEST_BEGIN; + WebdavOperation *op = test_propfind_op(&sn, &rq, TEST_PROPFIND1); + UCX_TEST_ASSERT(op, "WebdavOperation not created"); + + int err = webdav_op_propfind_begin(op, "/", NULL, NULL); + UCX_TEST_ASSERT(err == 0, "propfind_begin error"); + + + + + UCX_TEST_END; +}