add simple vfs implementation for testing webdav

Tue, 31 Dec 2019 14:07:42 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Tue, 31 Dec 2019 14:07:42 +0100
branch
webdav
changeset 219
dd6c155c082a
parent 218
2ba512b284b9
child 220
2915b6c11aec

add simple vfs implementation for testing

src/server/test/main.c file | annotate | diff | comparison | revisions
src/server/test/objs.mk file | annotate | diff | comparison | revisions
src/server/test/vfs.c file | annotate | diff | comparison | revisions
src/server/test/vfs.h file | annotate | diff | comparison | revisions
src/server/test/webdav.c file | annotate | diff | comparison | revisions
--- 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 <ucx/test.h>
 
+#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);
--- 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)
--- /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 <stdio.h>
+#include <stdlib.h>
+
+#include <ucx/string.h>
+#include <ucx/list.h>
+#include <ucx/map.h>
+
+#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);
+}
--- /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 <ucx/test.h>
+
+#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 */
+
--- 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;
+}

mercurial