changeset 20240:5142d4fbf69b

lib-fs: Improved unit tests.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Wed, 01 Jun 2016 17:12:51 +0300
parents 6b546cab619f
children 1309caf0ca75
files src/lib-fs/Makefile.am src/lib-fs/fs-test-async.c src/lib-fs/fs-test.c src/lib-fs/fs-test.h src/lib-fs/test-fs-metawrap.c
diffstat 5 files changed, 191 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-fs/Makefile.am	Wed Jun 01 17:12:10 2016 +0300
+++ b/src/lib-fs/Makefile.am	Wed Jun 01 17:12:51 2016 +0300
@@ -14,6 +14,7 @@
 	fs-randomfail.c \
 	fs-posix.c \
 	fs-test.c \
+	fs-test-async.c \
 	fs-sis.c \
 	fs-sis-common.c \
 	fs-sis-queue.c \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-fs/fs-test-async.c	Wed Jun 01 17:12:51 2016 +0300
@@ -0,0 +1,97 @@
+/* Copyright (c) 2016 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str.h"
+#include "ostream.h"
+#include "fs-test.h"
+#include "test-common.h"
+
+static void test_fs_async_write(const char *test_name, struct fs *fs)
+{
+	struct fs_file *file;
+	struct test_fs_file *test_file;
+	struct ostream *output;
+	unsigned int i;
+
+	test_begin(t_strdup_printf("%s: async write", test_name));
+	for (i = 0; i < 3; i++) {
+		file = fs_file_init(fs, "foo", FS_OPEN_MODE_REPLACE |
+				    FS_OPEN_FLAG_ASYNC);
+		output = fs_write_stream(file);
+
+		o_stream_nsend_str(output, "12345");
+		if (i < 2) {
+			test_assert(fs_write_stream_finish(file, &output) == 0);
+			test_assert(output == NULL);
+			test_assert(fs_write_stream_finish_async(file) == 0);
+		}
+
+		test_file = test_fs_file_get(fs, "foo");
+		test_file->wait_async = FALSE;
+
+		switch (i) {
+		case 0:
+			test_assert(fs_write_stream_finish_async(file) > 0);
+			test_assert(test_file->contents->used > 0);
+			break;
+		case 1:
+			test_file->io_failure = TRUE;
+			test_assert(fs_write_stream_finish_async(file) < 0);
+			test_assert(test_file->contents->used == 0);
+			break;
+		case 2:
+			fs_write_stream_abort(file, &output);
+			test_assert(test_file->contents->used == 0);
+			break;
+		}
+		fs_file_deinit(&file);
+	}
+	test_end();
+}
+
+static void test_fs_async_copy(const char *test_name, struct fs *fs)
+{
+	struct fs_file *src, *dest;
+	struct test_fs_file *test_file;
+
+	test_begin(t_strdup_printf("%s: async copy", test_name));
+
+	src = fs_file_init(fs, "foo", FS_OPEN_MODE_REPLACE);
+	test_assert(fs_write(src, "source", 6) == 0);
+
+	dest = fs_file_init(fs, "bar", FS_OPEN_MODE_REPLACE |
+			    FS_OPEN_FLAG_ASYNC);
+
+	test_assert(fs_copy(src, dest) == -1 && errno == EAGAIN);
+
+	test_file = test_fs_file_get(fs, "bar");
+	test_file->wait_async = FALSE;
+
+	test_assert(fs_copy_finish_async(dest) == 0);
+	test_assert(test_file->contents->used > 0);
+	fs_file_deinit(&dest);
+
+	fs_file_deinit(&src);
+	test_end();
+}
+
+void test_fs_async(const char *test_name, enum fs_properties properties,
+		   const char *driver, const char *args)
+{
+	struct fs_settings fs_set;
+	struct fs *fs;
+	struct test_fs *test_fs;
+	const char *error;
+
+	memset(&fs_set, 0, sizeof(fs_set));
+	if (fs_init(driver, args, &fs_set, &fs, &error) < 0)
+		i_fatal("fs_init() failed: %s", error);
+
+	test_fs = test_fs_get(fs);
+	test_fs->properties = properties;
+
+	test_fs_async_write(test_name, fs);
+	test_fs_async_copy(test_name, fs);
+
+	fs_deinit(&fs);
+}
--- a/src/lib-fs/fs-test.c	Wed Jun 01 17:12:10 2016 +0300
+++ b/src/lib-fs/fs-test.c	Wed Jun 01 17:12:51 2016 +0300
@@ -40,17 +40,19 @@
 
 static struct fs_file *
 fs_test_file_init(struct fs *_fs, const char *path,
-		  enum fs_open_mode mode, enum fs_open_flags flags ATTR_UNUSED)
+		  enum fs_open_mode mode, enum fs_open_flags flags)
 {
 	struct test_fs_file *file;
 
 	file = i_new(struct test_fs_file, 1);
 	file->file.fs = _fs;
 	file->file.path = i_strdup(path);
+	file->file.flags = flags;
 	file->mode = mode;
 	file->contents = buffer_create_dynamic(default_pool, 1024);
 	file->exists = TRUE;
 	file->seekable = TRUE;
+	file->wait_async = (flags & FS_OPEN_FLAG_ASYNC) != 0;
 	return &file->file;
 }
 
@@ -102,6 +104,16 @@
 fs_test_get_metadata(struct fs_file *_file,
 		     const ARRAY_TYPE(fs_metadata) **metadata_r)
 {
+	struct test_fs_file *file = (struct test_fs_file *)_file;
+
+	if (file->wait_async) {
+		fs_set_error_async(_file->fs);
+		return -1;
+	}
+	if (file->io_failure) {
+		errno = EIO;
+		return -1;
+	}
 	fs_metadata_init(_file);
 	*metadata_r = &_file->metadata;
 	return 0;
@@ -132,6 +144,8 @@
 
 	if (!file->exists)
 		return i_stream_create_error(ENOENT);
+	if (file->io_failure)
+		return i_stream_create_error(EIO);
 	input = test_istream_create_data(file->contents->data,
 					 file->contents->used);
 	i_stream_add_destroy_callback(input, fs_test_stream_destroyed, file);
@@ -155,6 +169,14 @@
 {
 	struct test_fs_file *file = (struct test_fs_file *)_file;
 
+	if (_file->output != NULL)
+		o_stream_destroy(&_file->output);
+	if (file->wait_async) {
+		fs_set_error_async(_file->fs);
+		return 0;
+	}
+	if (file->io_failure)
+		success = FALSE;
 	if (!success)
 		buffer_set_used_size(file->contents, 0);
 	return success ? 1 : -1;
@@ -186,6 +208,14 @@
 {
 	struct test_fs_file *file = (struct test_fs_file *)_file;
 
+	if (file->wait_async) {
+		fs_set_error_async(_file->fs);
+		return -1;
+	}
+	if (file->io_failure) {
+		errno = EIO;
+		return -1;
+	}
 	return file->exists ? 1 : 0;
 }
 
@@ -193,6 +223,14 @@
 {
 	struct test_fs_file *file = (struct test_fs_file *)_file;
 
+	if (file->wait_async) {
+		fs_set_error_async(_file->fs);
+		return -1;
+	}
+	if (file->io_failure) {
+		errno = EIO;
+		return -1;
+	}
 	if (!file->exists) {
 		errno = ENOENT;
 		return -1;
@@ -204,9 +242,22 @@
 
 static int fs_test_copy(struct fs_file *_src, struct fs_file *_dest)
 {
-	struct test_fs_file *src = (struct test_fs_file *)_src;
+	struct test_fs_file *src;
 	struct test_fs_file *dest = (struct test_fs_file *)_dest;
 
+	if (_src != NULL)
+		dest->copy_src = test_fs_file_get(_src->fs, fs_file_path(_src));
+	src = dest->copy_src;
+	if (dest->wait_async) {
+		fs_set_error_async(_dest->fs);
+		return -1;
+	}
+	dest->copy_src = NULL;
+
+	if (dest->io_failure) {
+		errno = EIO;
+		return -1;
+	}
 	if (!src->exists) {
 		errno = ENOENT;
 		return -1;
@@ -220,6 +271,12 @@
 static int fs_test_rename(struct fs_file *_src, struct fs_file *_dest)
 {
 	struct test_fs_file *src = (struct test_fs_file *)_src;
+	struct test_fs_file *dest = (struct test_fs_file *)_dest;
+
+	if (src->wait_async || dest->wait_async) {
+		fs_set_error_async(_dest->fs);
+		return -1;
+	}
 
 	if (fs_test_copy(_src, _dest) < 0)
 		return -1;
@@ -231,6 +288,11 @@
 {
 	struct test_fs_file *file = (struct test_fs_file *)_file;
 
+	if (file->wait_async) {
+		fs_set_error_async(_file->fs);
+		return -1;
+	}
+
 	if (!file->exists) {
 		errno = ENOENT;
 		return -1;
@@ -302,21 +364,26 @@
 	return ret;
 }
 
-struct test_fs_file *test_fs_file_get(struct fs *fs, unsigned int n)
+struct test_fs *test_fs_get(struct fs *fs)
 {
-	struct fs_file *file;
-
 	while (strcmp(fs->name, "test") != 0) {
 		i_assert(fs->parent != NULL);
 		fs = fs->parent;
 	}
+	return (struct test_fs *)fs;
+}
 
-	file = fs->files;
-	for (; n > 0; n--) {
+struct test_fs_file *test_fs_file_get(struct fs *fs, const char *path)
+{
+	struct fs_file *file;
+
+	fs = &test_fs_get(fs)->fs;
+
+	for (file = fs->files;; file = file->next) {
 		i_assert(file != NULL);
-		file = file->next;
+		if (strcmp(fs_file_path(file), path) == 0)
+			break;
 	}
-	i_assert(file != NULL);
 	return (struct test_fs_file *)file;
 }
 
--- a/src/lib-fs/fs-test.h	Wed Jun 01 17:12:10 2016 +0300
+++ b/src/lib-fs/fs-test.h	Wed Jun 01 17:12:51 2016 +0300
@@ -18,12 +18,15 @@
 
 	buffer_t *contents;
 	struct istream *input;
+	struct test_fs_file *copy_src;
 
 	bool prefetched;
 	bool locked;
 	bool exists;
 	bool seekable;
 	bool closed;
+	bool io_failure;
+	bool wait_async;
 };
 
 struct test_fs_iter {
@@ -33,6 +36,10 @@
 	bool failed;
 };
 
-struct test_fs_file *test_fs_file_get(struct fs *fs, unsigned int n);
+struct test_fs *test_fs_get(struct fs *fs);
+struct test_fs_file *test_fs_file_get(struct fs *fs, const char *path);
+
+void test_fs_async(const char *test_name, enum fs_properties properties,
+		   const char *driver, const char *args);
 
 #endif
--- a/src/lib-fs/test-fs-metawrap.c	Wed Jun 01 17:12:10 2016 +0300
+++ b/src/lib-fs/test-fs-metawrap.c	Wed Jun 01 17:12:51 2016 +0300
@@ -26,7 +26,7 @@
 	for (i = 0; i < 2; i++) {
 		file = fs_file_init(fs, "foo", FS_OPEN_MODE_READONLY);
 
-		test_file = test_fs_file_get(fs, 0);
+		test_file = test_fs_file_get(fs, "foo");
 		str_append(test_file->contents, "key:value\n\n12345678901234567890");
 
 		if (i == 0) {
@@ -46,10 +46,18 @@
 	test_end();
 }
 
+static void test_fs_metawrap_async(void)
+{
+	test_fs_async("metawrap", FS_PROPERTY_METADATA, "metawrap", "test");
+	test_fs_async("metawrap passthrough", 0, "metawrap", "test");
+	test_fs_async("double-metawrap", FS_PROPERTY_METADATA, "metawrap", "metawrap:test");
+}
+
 int main(void)
 {
 	static void (*test_functions[])(void) = {
 		test_fs_metawrap_stat,
+		test_fs_metawrap_async,
 		NULL
 	};
 	return test_run(test_functions);