summaryrefslogtreecommitdiff
path: root/subversion/tests/libsvn_subr/io-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/tests/libsvn_subr/io-test.c')
-rw-r--r--subversion/tests/libsvn_subr/io-test.c370
1 files changed, 351 insertions, 19 deletions
diff --git a/subversion/tests/libsvn_subr/io-test.c b/subversion/tests/libsvn_subr/io-test.c
index 82e8630..e9de6fb 100644
--- a/subversion/tests/libsvn_subr/io-test.c
+++ b/subversion/tests/libsvn_subr/io-test.c
@@ -26,10 +26,14 @@
#include <stdio.h>
#include <apr.h>
+#include <apr_version.h>
#include "svn_pools.h"
#include "svn_string.h"
+#include "svn_io.h"
#include "private/svn_skel.h"
+#include "private/svn_dep_compat.h"
+#include "private/svn_io_private.h"
#include "../svn_test.h"
#include "../svn_test_fs.h"
@@ -37,7 +41,7 @@
/* Helpers to create the test data directory. */
-#define TEST_DIR "io-test-temp"
+#define TEST_DIR_PREFIX "io-test-temp"
/* The definition for the test data files. */
struct test_file_definition_t
@@ -64,7 +68,7 @@ struct test_file_definition_t
char* created_path;
};
-struct test_file_definition_t test_file_definitions[] =
+static struct test_file_definition_t test_file_definitions_template[] =
{
{"empty", "", 0},
{"single_a", "a", 1},
@@ -119,6 +123,7 @@ struct test_file_definition_t test_file_definitions[] =
static svn_error_t *
create_test_file(struct test_file_definition_t* definition,
+ const char *testname,
apr_pool_t *pool,
apr_pool_t *scratch_pool)
{
@@ -127,6 +132,7 @@ create_test_file(struct test_file_definition_t* definition,
apr_off_t midpos = definition->size / 2;
svn_error_t *err = NULL;
int i;
+ const char *test_dir = apr_pstrcat(pool, TEST_DIR_PREFIX, testname, NULL);
if (definition->size < 5)
SVN_ERR_ASSERT(strlen(definition->data) >= (apr_size_t)definition->size);
@@ -134,9 +140,9 @@ create_test_file(struct test_file_definition_t* definition,
SVN_ERR_ASSERT(strlen(definition->data) >= 5);
- definition->created_path = svn_dirent_join(TEST_DIR,
- definition->name,
- pool);
+ definition->created_path = svn_dirent_join(test_dir,
+ definition->name,
+ pool);
SVN_ERR(svn_io_file_open(&file_h,
definition->created_path,
@@ -174,37 +180,47 @@ create_test_file(struct test_file_definition_t* definition,
/* Function to prepare the whole set of on-disk files to be compared. */
static svn_error_t *
-create_comparison_candidates(apr_pool_t *scratch_pool)
+create_comparison_candidates(struct test_file_definition_t **definitions,
+ const char *testname,
+ apr_pool_t *pool)
{
svn_node_kind_t kind;
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_pool_t *iterpool = svn_pool_create(pool);
struct test_file_definition_t *candidate;
svn_error_t *err = SVN_NO_ERROR;
+ apr_size_t count = 0;
+ const char *test_dir = apr_pstrcat(pool, TEST_DIR_PREFIX,
+ testname, NULL);
/* If there's already a directory named io-test-temp, delete it.
Doing things this way means that repositories stick around after
a failure for postmortem analysis, but also that tests can be
re-run without cleaning out the repositories created by prior
runs. */
- SVN_ERR(svn_io_check_path(TEST_DIR, &kind, scratch_pool));
+ SVN_ERR(svn_io_check_path(test_dir, &kind, pool));
if (kind == svn_node_dir)
- SVN_ERR(svn_io_remove_dir2(TEST_DIR, TRUE, NULL, NULL, scratch_pool));
+ SVN_ERR(svn_io_remove_dir2(test_dir, TRUE, NULL, NULL, pool));
else if (kind != svn_node_none)
return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
"There is already a file named '%s'",
- TEST_DIR);
+ test_dir);
- SVN_ERR(svn_io_dir_make(TEST_DIR, APR_OS_DEFAULT, scratch_pool));
+ SVN_ERR(svn_io_dir_make(test_dir, APR_OS_DEFAULT, pool));
- svn_test_add_dir_cleanup(TEST_DIR);
+ svn_test_add_dir_cleanup(test_dir);
- for (candidate = test_file_definitions;
+ for (candidate = test_file_definitions_template;
candidate->name != NULL;
candidate += 1)
+ count++;
+
+ *definitions = apr_pmemdup(pool, test_file_definitions_template,
+ (count + 1) * sizeof(**definitions));
+ for (candidate = *definitions; candidate->name != NULL; candidate += 1)
{
svn_pool_clear(iterpool);
- err = create_test_file(candidate, scratch_pool, iterpool);
+ err = create_test_file(candidate, testname, pool, iterpool);
if (err)
break;
}
@@ -227,8 +243,11 @@ test_two_file_size_comparison(apr_pool_t *scratch_pool)
svn_error_t *err = SVN_NO_ERROR;
svn_error_t *cmp_err;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ struct test_file_definition_t *test_file_definitions;
- SVN_ERR(create_comparison_candidates(scratch_pool));
+ SVN_ERR(create_comparison_candidates(&test_file_definitions,
+ "test_two_file_size_comparison",
+ scratch_pool));
for (outer = test_file_definitions; outer->name != NULL; outer += 1)
{
@@ -278,8 +297,11 @@ test_two_file_content_comparison(apr_pool_t *scratch_pool)
svn_error_t *err = SVN_NO_ERROR;
svn_error_t *cmp_err;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ struct test_file_definition_t *test_file_definitions;
- SVN_ERR(create_comparison_candidates(scratch_pool));
+ SVN_ERR(create_comparison_candidates(&test_file_definitions,
+ "test_two_file_content_comparison",
+ scratch_pool));
for (outer = test_file_definitions; outer->name != NULL; outer += 1)
{
@@ -331,8 +353,11 @@ test_three_file_size_comparison(apr_pool_t *scratch_pool)
svn_error_t *err = SVN_NO_ERROR;
svn_error_t *cmp_err;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ struct test_file_definition_t *test_file_definitions;
- SVN_ERR(create_comparison_candidates(scratch_pool));
+ SVN_ERR(create_comparison_candidates(&test_file_definitions,
+ "test_three_file_size_comparison",
+ scratch_pool));
for (outer = test_file_definitions; outer->name != NULL; outer += 1)
{
@@ -411,8 +436,11 @@ test_three_file_content_comparison(apr_pool_t *scratch_pool)
svn_error_t *err = SVN_NO_ERROR;
svn_error_t *cmp_err;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ struct test_file_definition_t *test_file_definitions;
- SVN_ERR(create_comparison_candidates(scratch_pool));
+ SVN_ERR(create_comparison_candidates(&test_file_definitions,
+ "test_three_file_content_comparison",
+ scratch_pool));
for (outer = test_file_definitions; outer->name != NULL; outer += 1)
{
@@ -507,10 +535,304 @@ read_length_line_shouldnt_loop(apr_pool_t *pool)
return SVN_NO_ERROR;
}
+/* Move the read pointer in FILE to absolute position OFFSET and align
+ * the read buffer to multiples of BLOCK_SIZE. BUFFERED is set only if
+ * FILE actually uses a read buffer. Use POOL for allocations.
+ */
+static svn_error_t *
+aligned_seek(apr_file_t *file,
+ apr_size_t block_size,
+ apr_size_t offset,
+ svn_boolean_t buffered,
+ apr_pool_t *pool)
+{
+ apr_off_t block_start;
+ apr_off_t current;
+
+ SVN_ERR(svn_io_file_aligned_seek(file, (apr_off_t)block_size,
+ &block_start, (apr_off_t)offset, pool));
+
+ /* block start shall be aligned to multiples of block_size.
+ If it isn't, it must be aligned to APR's default block size(pre-1.3 APR)
+ */
+ if (buffered)
+ {
+ SVN_TEST_ASSERT(block_start % block_size == 0);
+ SVN_TEST_ASSERT(offset - block_start < block_size);
+ }
+
+ /* we must be at the desired offset */
+ current = 0;
+ SVN_ERR(svn_io_file_seek(file, APR_CUR, &current, pool));
+ SVN_TEST_ASSERT(current == (apr_off_t)offset);
+
+ return SVN_NO_ERROR;
+}
+
+/* Move the read pointer in FILE to absolute position OFFSET, align the
+ * read buffer to multiples of BLOCK_SIZE and read one byte from that
+ * position. Verify that it matches the CONTENTS for that offset.
+ * BUFFERED is set only if FILE actually uses a read buffer.
+ * Use POOL for allocations.
+ */
+static svn_error_t *
+aligned_read_at(apr_file_t *file,
+ svn_stringbuf_t *contents,
+ apr_size_t block_size,
+ apr_size_t offset,
+ svn_boolean_t buffered,
+ apr_pool_t *pool)
+{
+ char c;
+ SVN_ERR(aligned_seek(file, block_size, offset, buffered, pool));
+
+ /* the data we read must match whatever we wrote there */
+ SVN_ERR(svn_io_file_getc(&c, file, pool));
+ SVN_TEST_ASSERT(c == contents->data[offset]);
+
+ return SVN_NO_ERROR;
+}
+
+/* Verify that aligned seek with the given BLOCK_SIZE works for FILE.
+ * CONTENTS is the data expected from FILE. BUFFERED is set only if FILE
+ * actually uses a read buffer. Use POOL for allocations.
+ */
+static svn_error_t *
+aligned_read(apr_file_t *file,
+ svn_stringbuf_t *contents,
+ apr_size_t block_size,
+ svn_boolean_t buffered,
+ apr_pool_t *pool)
+{
+ apr_size_t i;
+ apr_size_t offset = 0;
+ const apr_size_t prime = 78427;
+
+ /* "random" access to different offsets */
+ for (i = 0, offset = prime; i < 10; ++i, offset += prime)
+ SVN_ERR(aligned_read_at(file, contents, block_size,
+ offset % contents->len, buffered, pool));
+
+ /* we can seek to EOF */
+ SVN_ERR(aligned_seek(file, contents->len, block_size, buffered, pool));
+
+ /* reversed order access to all bytes */
+ for (i = contents->len; i > 0; --i)
+ SVN_ERR(aligned_read_at(file, contents, block_size, i - 1, buffered,
+ pool));
+
+ /* forward order access to all bytes */
+ for (i = 0; i < contents->len; ++i)
+ SVN_ERR(aligned_read_at(file, contents, block_size, i, buffered, pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+aligned_seek_test(apr_pool_t *pool)
+{
+ apr_size_t i;
+ const char *tmp_dir;
+ const char *tmp_file;
+ apr_file_t *f;
+ svn_stringbuf_t *contents;
+ const apr_size_t file_size = 100000;
+
+ /* create a temp folder & schedule it for automatic cleanup */
+
+ SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "aligned_seek_tmp", pool));
+ SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool));
+ SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool));
+ svn_test_add_dir_cleanup(tmp_dir);
+
+ /* create a temp file with know contents */
+
+ contents = svn_stringbuf_create_ensure(file_size, pool);
+ for (i = 0; i < file_size; ++i)
+ svn_stringbuf_appendbyte(contents, (char)rand());
+
+ SVN_ERR(svn_io_write_unique(&tmp_file, tmp_dir, contents->data,
+ contents->len,
+ svn_io_file_del_on_pool_cleanup, pool));
+
+ /* now, access read data with varying alignment sizes */
+ SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT, pool));
+ SVN_ERR(aligned_read(f, contents, 0x1000, TRUE, pool)); /* APR default */
+ SVN_ERR(aligned_read(f, contents, 0x8000, TRUE, pool)); /* "unusual" 32K */
+ SVN_ERR(aligned_read(f, contents, 0x10000, TRUE, pool)); /* FSX default */
+ SVN_ERR(aligned_read(f, contents, 0x100000, TRUE, pool)); /* larger than file */
+ SVN_ERR(aligned_read(f, contents, 10001, TRUE, pool)); /* odd, larger than
+ APR default */
+ SVN_ERR(aligned_read(f, contents, 1003, TRUE, pool)); /* odd, smaller than
+ APR default */
+ SVN_ERR(svn_io_file_close(f, pool));
+
+ /* now, try read data with buffering disabled.
+ That are a special case because APR reports a buffer size of 0. */
+ SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ, APR_OS_DEFAULT, pool));
+ SVN_ERR(aligned_read(f, contents, 0x1000, FALSE, pool));
+ SVN_ERR(aligned_read(f, contents, 0x8000, FALSE, pool));
+ SVN_ERR(aligned_read(f, contents, 0x10000, FALSE, pool));
+ SVN_ERR(aligned_read(f, contents, 0x100000, FALSE, pool));
+ SVN_ERR(aligned_read(f, contents, 10001, FALSE, pool));
+ SVN_ERR(aligned_read(f, contents, 1003, FALSE, pool));
+ SVN_ERR(svn_io_file_close(f, pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ignore_enoent(apr_pool_t *pool)
+{
+ const char *tmp_dir, *path;
+ const svn_io_dirent2_t *dirent_p;
+ apr_file_t *file;
+
+ /* Create an empty directory. */
+ SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "ignore_enoent", pool));
+ SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool));
+ SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool));
+ svn_test_add_dir_cleanup(tmp_dir);
+
+ /* Path does not exist. */
+ path = svn_dirent_join(tmp_dir, "not-present", pool);
+ SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, pool));
+ SVN_ERR(svn_io_remove_file2(path, TRUE, pool));
+ SVN_ERR(svn_io_set_file_read_only(path, TRUE, pool));
+ SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool));
+ SVN_ERR(svn_io_set_file_executable(path, TRUE, TRUE, pool));
+ SVN_ERR(svn_io_set_file_executable(path, FALSE, TRUE, pool));
+ SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, TRUE, TRUE, pool, pool));
+ SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, FALSE, TRUE, pool, pool));
+
+ /* Neither path nor parent exists. */
+ path = svn_dirent_join(path, "not-present", pool);
+ SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, pool));
+ SVN_ERR(svn_io_remove_file2(path, TRUE, pool));
+ SVN_ERR(svn_io_set_file_read_only(path, TRUE, pool));
+ SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool));
+ SVN_ERR(svn_io_set_file_executable(path, TRUE, TRUE, pool));
+ SVN_ERR(svn_io_set_file_executable(path, FALSE, TRUE, pool));
+ SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, TRUE, TRUE, pool, pool));
+ SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, FALSE, TRUE, pool, pool));
+
+ /* File does exist. */
+ path = svn_dirent_join(tmp_dir, "present", pool);
+ SVN_ERR(svn_io_file_open(&file, path,
+ APR_WRITE | APR_CREATE | APR_TRUNCATE,
+ APR_OS_DEFAULT,
+ pool));
+ SVN_ERR(svn_io_file_close(file, pool));
+
+ /* Path does not exist as child of file. */
+ path = svn_dirent_join(path, "not-present", pool);
+ SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, pool));
+ SVN_ERR(svn_io_remove_file2(path, TRUE, pool));
+ SVN_ERR(svn_io_set_file_read_only(path, TRUE, pool));
+ SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool));
+ SVN_ERR(svn_io_set_file_executable(path, TRUE, TRUE, pool));
+ SVN_ERR(svn_io_set_file_executable(path, FALSE, TRUE, pool));
+ SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, TRUE, TRUE, pool, pool));
+ SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, FALSE, TRUE, pool, pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_install_stream_to_longpath(apr_pool_t *pool)
+{
+ const char *tmp_dir;
+ const char *final_abspath;
+ const char *deep_dir;
+ svn_stream_t *stream;
+ svn_stringbuf_t *actual_content;
+ int i;
+
+ /* Create an empty directory. */
+ SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "test_install_stream_to_longpath",
+ pool));
+ SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool));
+ SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool));
+ svn_test_add_dir_cleanup(tmp_dir);
+
+ deep_dir = tmp_dir;
+
+ /* Generate very long path (> 260 symbols) */
+ for (i = 0; i < 26; i++)
+ {
+ deep_dir = svn_dirent_join(deep_dir, "1234567890", pool);
+ SVN_ERR(svn_io_make_dir_recursively(deep_dir, pool));
+ }
+
+ final_abspath = svn_dirent_join(deep_dir, "stream1", pool);
+ SVN_ERR(svn_stream__create_for_install(&stream, deep_dir, pool, pool));
+ SVN_ERR(svn_stream_puts(stream, "stream1 content"));
+ SVN_ERR(svn_stream_close(stream));
+ SVN_ERR(svn_stream__install_stream(stream,
+ final_abspath,
+ TRUE,
+ pool));
+
+ SVN_ERR(svn_stringbuf_from_file2(&actual_content,
+ final_abspath,
+ pool));
+
+ SVN_TEST_STRING_ASSERT(actual_content->data, "stream1 content");
+
+ return SVN_NO_ERROR;
+}
+static svn_error_t *
+test_apr_trunc_workaround(apr_pool_t *pool)
+{
+ const char *tmp_dir;
+ const char *tmp_file;
+ apr_file_t *f;
+ apr_size_t len;
+ apr_off_t offset;
+ char dummy;
+
+ /* create a temp folder & schedule it for automatic cleanup */
+ SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "test_apr_trunc_workaround",
+ pool));
+ SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool));
+ SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool));
+ svn_test_add_dir_cleanup(tmp_dir);
+
+ /* create an r/w file */
+ tmp_file = svn_dirent_join(tmp_dir, "file", pool);
+ SVN_ERR(svn_io_file_open(&f, tmp_file,
+ APR_READ | APR_WRITE | APR_BUFFERED | APR_CREATE |
+ APR_TRUNCATE,
+ APR_OS_DEFAULT, pool));
+
+ /* write some content and put it internally into read mode */
+ len = 10;
+ SVN_ERR(svn_io_file_write(f, "0123456789", &len, pool));
+
+ offset = 0;
+ SVN_ERR(svn_io_file_seek(f, APR_SET, &offset, pool));
+ SVN_ERR(svn_io_file_getc(&dummy, f, pool));
+
+ /* clear the file and write some new content */
+ SVN_ERR(svn_io_file_trunc(f, 0, pool));
+ len = 3;
+ SVN_ERR(svn_io_file_write(f, "abc", &len, pool));
+
+ /* we should now be positioned at the end of the new content */
+ offset = 0;
+ SVN_ERR(svn_io_file_seek(f, APR_CUR, &offset, pool));
+ SVN_TEST_ASSERT(offset == (int)len);
+
+ return SVN_NO_ERROR;
+}
+
/* The test table. */
-struct svn_test_descriptor_t test_funcs[] =
+static int max_threads = 3;
+
+static struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
SVN_TEST_PASS2(test_two_file_size_comparison,
@@ -523,5 +845,15 @@ struct svn_test_descriptor_t test_funcs[] =
"three file content comparison"),
SVN_TEST_PASS2(read_length_line_shouldnt_loop,
"svn_io_read_length_line() shouldn't loop"),
+ SVN_TEST_PASS2(aligned_seek_test,
+ "test aligned seek"),
+ SVN_TEST_PASS2(ignore_enoent,
+ "test ignore-enoent"),
+ SVN_TEST_PASS2(test_install_stream_to_longpath,
+ "test svn_stream__install_stream to long path"),
+ SVN_TEST_PASS2(test_apr_trunc_workaround,
+ "test workaround for APR in svn_io_file_trunc"),
SVN_TEST_NULL
};
+
+SVN_TEST_MAIN