blob: 76ec89398b643fca4d311fd023fb6517f2d0c1e4 [file] [log] [blame]
/*
* db-test.c : test the wc_db subsystem
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
#include <apr_pools.h>
#include <apr_general.h>
#include "svn_types.h"
/* Make sure SVN_DEPRECATED is defined as empty before including svn_io.h.
We don't want to trigger deprecation warnings. */
#ifdef SVN_DEPRECATED
#undef SVN_DEPRECATED
#endif
#define SVN_DEPRECATED
#include "svn_io.h"
#include "svn_dirent_uri.h"
#include "svn_pools.h"
#include "private/svn_sqlite.h"
#include "../../libsvn_wc/wc_db.h"
#include "private/svn_wc_private.h"
#include "../svn_test.h"
#include "utils.h"
#define ROOT_ONE "http://example.com/one"
#define ROOT_TWO "http://example.com/two"
#define ROOT_THREE "http://example.com/three"
#define UUID_ONE "uuid1"
#define UUID_TWO "uuid2"
#define UUID_THREE "uuid3"
#define TIME_1 1235142208
#define TIME_2 1235142268
#define TIME_3 1235142328
#define TIME_1s APR_STRINGIFY(TIME_1) "000000"
#define TIME_2s APR_STRINGIFY(TIME_2) "000000"
#define TIME_3s APR_STRINGIFY(TIME_3) "000000"
#define TIME_1a apr_time_from_sec(TIME_1)
#define TIME_2a apr_time_from_sec(TIME_2)
#define TIME_3a apr_time_from_sec(TIME_3)
#define AUTHOR_1 "johndoe"
#define AUTHOR_2 "janedoe"
/* Some arbitrary checksum values */
#define MD5_1 "2d18c5e57e84c5b8a5e9a6e13fa394dc"
#define SHA1_1 "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"
#define F_TC_DATA "(conflict F file update edited deleted (version 22 " ROOT_ONE " 1 2 branch1/ft/F none) (version 22 " ROOT_ONE " 1 3 branch1/ft/F file))"
#define G_TC_DATA "(conflict G file update edited deleted (version 22 " ROOT_ONE " 1 2 branch1/ft/F none) (version 22 " ROOT_ONE " 1 3 branch1/ft/F file))"
static const char * const TESTING_DATA = (
/* Load our test data.
Note: do not use named-column insertions. This allows us to test
the column count in the schema matches our expectation here. */
"insert into repository values (1, '" ROOT_ONE "', '" UUID_ONE "'); "
"insert into repository values (2, '" ROOT_TWO "', '" UUID_TWO "'); "
"insert into wcroot values (1, null); "
"insert into pristine values ('$sha1$" SHA1_1 "', NULL, 15, 1, '$md5 $" MD5_1 "'); "
);
#define NOT_MOVED FALSE, NULL
#define NO_COPY_FROM 0, NULL, SVN_INVALID_REVNUM
static const svn_test__nodes_data_t nodes_init_data[] = {
/* load the base nodes into the nodes table */
{ 0, "", "normal", 1, "", 1, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "A", "normal", 1, "A", 1, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1,
FALSE, NULL, 10, 10 },
{ 0, "B", "excluded", 1, "B", SVN_INVALID_REVNUM, NOT_MOVED,
svn_node_symlink},
{ 0, "C", "server-excluded", 1, "C", 0, NOT_MOVED,
svn_node_unknown},
{ 0, "D", "not-present", 1, "D", 0, NOT_MOVED,
svn_node_unknown},
{ 0, "E", "incomplete", 1, "E", 1, NOT_MOVED,
svn_node_unknown},
{ 0, "F", "normal", 1, "F", 1, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2},
{ 0, "G", "normal", 2, "G-alt", 1, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
{ 0, "H", "normal", 1, "H", 1, NOT_MOVED,
svn_node_symlink, "()", NULL, NULL, "H-target", 1, TIME_1a, AUTHOR_1 },
{ 0, "I", "normal", 1, "I", 1, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "J", "normal", 1, "J", 1, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "J/J-e", "normal", 1, "J/J-e", 1, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "J/J-e/J-e-a", "normal", 1, "J/J-e/J-e-a", 1, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "J/J-e/J-e-b", "normal", 1, "J/J-e/J-e-b", 1, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "J/J-e/J-e-b/Jeba", "normal", 1, "J/J-e/J-e-b/Jeba", 1, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "J/J-f", "normal", 1, "J/J-f", 1, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "J/J-f/J-f-a", "normal", 1, "J/J-f/J-f-a", 1, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "J", "normal", 1, "J", 1, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "K", "normal", 1, "K", 1, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "K/K-a", "normal", 2, "K/K-a", 1, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2,
FALSE, NULL, 15, 14},
{ 0, "K/K-b", "normal", 2, "K/K-b", 1, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2,
FALSE, NULL, 15, 14},
/* Load data into the working layers of NODES */
{ 1, "I", "normal", 2, "some/dir", 2, NOT_MOVED,
svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
/* J was originally a local addition, but its descendants are replaced,
so let's turn J in a copy */
{ 1, "J", "normal", 2, "q", 2, NOT_MOVED,
svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 1, "J/J-a", "normal", 2, "q/J-a", 2, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
{ 1, "J/J-b", "normal", 2, "q/J-b", 2, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 3, "J/J-b/J-b-a", "normal", 2, "another/dir", 2, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 1, "J/J-b/J-b-b", "normal", 2, "q/J-b/J-b-b", 2, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
{ 1, "J/J-c", "normal", 2, "q/J-c", 2, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 1, "J/J-c/J-c-a", "normal", 2, "q/J-c/J-c-a", 2, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 2, "J/J-c", "base-deleted", NO_COPY_FROM, NOT_MOVED,
svn_node_dir},
{ 2, "J/J-c/J-c-a", "base-deleted", NO_COPY_FROM, NOT_MOVED,
svn_node_dir},
{ 2, "J/J-d", "normal", 2, "moved/file", 2, TRUE, NULL,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
{ 0, "moved", "normal", 2, "moved", 2, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
{ 0, "moved/file", "normal", 2, "moved/file", 2, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
{ 2, "moved/file", "base-deleted", NO_COPY_FROM, FALSE, "J/J-d",
svn_node_file},
{ 1, "J/J-e", "normal", 2, "q/J-e", 2, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 1, "J/J-e/J-e-a", "normal", 2, "q/J-e/J-e-a", 2, NOT_MOVED,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
{ 1, "J/J-e/J-e-b", "normal", 2, "q/J-e/J-e-b", 2, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 2, "J/J-e", "base-deleted", NO_COPY_FROM, FALSE, "other/place",
svn_node_dir},
{ 2, "J/J-e/J-e-a", "base-deleted", NO_COPY_FROM, NOT_MOVED,
svn_node_file},
{ 2, "J/J-e/J-e-b", "base-deleted", NO_COPY_FROM, NOT_MOVED,
svn_node_dir},
{ 1, "J/J-e/J-e-b/Jeba", "base-deleted", NO_COPY_FROM, NOT_MOVED,
svn_node_file},
{ 1, "J/J-f", "normal", 2, "q/J-f", 2, NOT_MOVED,
svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 1, "J/J-f/J-f-a", "base-deleted", NO_COPY_FROM, NOT_MOVED,
svn_node_dir},
{ 1, "K", "base-deleted", NO_COPY_FROM, NOT_MOVED,
svn_node_dir},
{ 1, "K/K-a", "base-deleted", NO_COPY_FROM, NOT_MOVED,
svn_node_file},
{ 1, "K/K-b", "base-deleted", NO_COPY_FROM, FALSE, "moved/away",
svn_node_file},
{ 1, "L", "normal", 2, "from", 2, NOT_MOVED,
svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 1, "L/L-a", "normal", 2, "from/L-a", 2, NOT_MOVED,
svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 1, "L/L-a/L-a-a", "normal", 2, "from/L-a/L-a-a", 2, NOT_MOVED,
svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 2, "L/L-a", "base-deleted", NO_COPY_FROM, NOT_MOVED,
svn_node_dir},
{ 2, "L/L-a/L-a-a", "base-deleted", NO_COPY_FROM, NOT_MOVED,
svn_node_dir},
{ 0, "other", "normal", 2, "other", 2, NOT_MOVED,
svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 2, "other/place", "normal", 2, "q/J-e", 2, TRUE, NULL,
svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 2, "other/place/J-e-a", "normal", 2, "q/J-e/J-e-a", 2, TRUE, NULL,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
{ 2, "other/place/J-e-b", "normal", 2, "q/J-e/J-e-b", 2, TRUE, NULL,
svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
{ 2, "other/place/J-e-b/Jeba", "normal", 2, "q/J-e/J-e-b/Jeba", 2, TRUE, NULL,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1 },
/*** NEW ****/
{ 2, "moved/away", "normal", 2, "K/K-b", 1, TRUE, NULL,
svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2,
FALSE, NULL, 15, 14},
{ 0 }
};
static const svn_test__actual_data_t actual_init_data[] = {
{ "A", NULL, "changelist", NULL },
{ "F", NULL, NULL, F_TC_DATA },
{ "G", NULL, NULL, F_TC_DATA },
{ 0 }
};
static svn_error_t *
create_open(svn_wc__db_t **db,
const char **local_abspath,
const char *subdir,
apr_pool_t *pool)
{
SVN_ERR(svn_dirent_get_absolute(local_abspath,
svn_dirent_join(
svn_test_data_path("db-test", pool),
subdir, pool),
pool));
SVN_ERR(svn_io_remove_dir2(*local_abspath, TRUE, NULL, NULL, pool));
SVN_ERR(svn_wc__db_open(db, NULL, FALSE, TRUE, pool, pool));
SVN_ERR(svn_test__create_fake_wc(*local_abspath, TESTING_DATA,
nodes_init_data, actual_init_data, pool));
svn_test_add_dir_cleanup(*local_abspath);
return SVN_NO_ERROR;
}
/* Convert VALUE to a const svn_string_t *, and create a mapping from
NAME to the converted data type in PROPS. */
static void
set_prop(apr_hash_t *props, const char *name, const char *value,
apr_pool_t *result_pool)
{
const svn_string_t *propval = svn_string_create(value, result_pool);
apr_hash_set(props, name, APR_HASH_KEY_STRING, propval);
}
static svn_error_t *
validate_abspath(const char *wcroot_abspath,
const char *expected_relpath,
const char *actual_abspath,
apr_pool_t *scratch_pool)
{
SVN_TEST_STRING_ASSERT(actual_abspath,
svn_dirent_join(wcroot_abspath,
expected_relpath,
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
test_getting_info(apr_pool_t *pool)
{
const char *local_abspath;
svn_node_kind_t kind;
svn_wc__db_status_t status;
svn_revnum_t revision;
const char *repos_relpath;
const char *repos_root_url;
const char *repos_uuid;
svn_revnum_t changed_rev;
apr_time_t changed_date;
const char *changed_author;
svn_depth_t depth;
const svn_checksum_t *checksum;
const char *target;
svn_boolean_t had_props;
apr_hash_t *props;
svn_boolean_t update_root;
svn_wc__db_lock_t *lock;
svn_wc__db_t *db;
svn_error_t *err;
SVN_ERR(create_open(&db, &local_abspath, "test_getting_info", pool));
/* Test: basic fetching of data. */
SVN_ERR(svn_wc__db_base_get_info(
&status, &kind, &revision,
&repos_relpath, &repos_root_url, &repos_uuid,
&changed_rev, &changed_date, &changed_author,&depth, &checksum,
&target, &lock, &had_props, &props,
&update_root,
db, local_abspath,
pool, pool));
SVN_TEST_ASSERT(kind == svn_node_dir);
SVN_TEST_ASSERT(status == svn_wc__db_status_normal);
SVN_TEST_ASSERT(revision == 1);
SVN_TEST_STRING_ASSERT(repos_relpath, "");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
SVN_TEST_ASSERT(changed_rev == 1);
SVN_TEST_ASSERT(changed_date == TIME_1a);
SVN_TEST_STRING_ASSERT(changed_author, AUTHOR_1);
SVN_TEST_ASSERT(depth == svn_depth_infinity);
SVN_TEST_ASSERT(checksum == NULL);
SVN_TEST_ASSERT(target == NULL);
SVN_TEST_ASSERT(lock == NULL);
SVN_TEST_ASSERT(!had_props);
SVN_TEST_ASSERT(apr_hash_count(props) == 0);
/* SVN_TEST_ASSERT(update_root == ???); */
/* Test: file-specific values. */
SVN_ERR(svn_wc__db_base_get_info(
NULL, &kind, NULL,
&repos_relpath, &repos_root_url, &repos_uuid,
NULL, NULL, NULL, NULL,
&checksum, NULL, NULL,
NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "A", pool),
pool, pool));
SVN_TEST_ASSERT(kind == svn_node_file);
SVN_TEST_STRING_ASSERT(SHA1_1, svn_checksum_to_cstring(checksum, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "A");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
/* Test: symlink kind, excluded presence, default values for columns. */
SVN_ERR(svn_wc__db_base_get_info(
&status, &kind, &revision,
&repos_relpath, &repos_root_url, &repos_uuid,
&changed_rev, &changed_date, &changed_author,
&depth, &checksum, &target, &lock,
NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "B", pool),
pool, pool));
SVN_TEST_ASSERT(kind == svn_node_symlink);
SVN_TEST_ASSERT(status == svn_wc__db_status_excluded);
SVN_TEST_ASSERT(!SVN_IS_VALID_REVNUM(revision));
SVN_TEST_STRING_ASSERT(repos_relpath, "B");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
SVN_TEST_ASSERT(!SVN_IS_VALID_REVNUM(changed_rev));
SVN_TEST_ASSERT(changed_date == 0);
SVN_TEST_ASSERT(changed_author == NULL);
SVN_TEST_ASSERT(depth == svn_depth_unknown);
SVN_TEST_ASSERT(checksum == NULL);
SVN_TEST_ASSERT(target == NULL);
SVN_TEST_ASSERT(lock == NULL);
/* Test: unknown kind, server-excluded presence. */
SVN_ERR(svn_wc__db_base_get_info(
&status, &kind, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "C", pool),
pool, pool));
SVN_TEST_ASSERT(kind == svn_node_unknown);
SVN_TEST_ASSERT(status == svn_wc__db_status_server_excluded);
/* Test: not-present presence. */
SVN_ERR(svn_wc__db_base_get_info(
&status, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "D", pool),
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_not_present);
/* Test: incomplete presence. */
SVN_ERR(svn_wc__db_base_get_info(
&status, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "E", pool),
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_incomplete);
/* Test: SHA1 checksum. */
SVN_ERR(svn_wc__db_base_get_info(
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, &checksum, NULL,
NULL, NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "F", pool),
pool, pool));
SVN_TEST_STRING_ASSERT(SHA1_1,
svn_checksum_to_cstring(checksum, pool));
/* Test: alternate repository (switched file). */
SVN_ERR(svn_wc__db_base_get_info(
NULL, NULL, NULL,
&repos_relpath, &repos_root_url, &repos_uuid,
&changed_rev, &changed_date, &changed_author,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "G", pool),
pool, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "G-alt");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_TWO);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_TWO);
SVN_TEST_ASSERT(changed_rev == 2);
SVN_TEST_ASSERT(changed_date == TIME_2a);
SVN_TEST_STRING_ASSERT(changed_author, AUTHOR_2);
/* Test: symlink target. */
SVN_ERR(svn_wc__db_base_get_info(
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, &checksum, &target,
NULL, NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "H", pool),
pool, pool));
SVN_TEST_ASSERT(checksum == NULL);
SVN_TEST_STRING_ASSERT(target, "H-target");
/* Test: missing node. */
err = svn_wc__db_base_get_info(
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "missing-file", pool),
pool, pool);
SVN_TEST_ASSERT_ERROR(err, SVN_ERR_WC_PATH_NOT_FOUND);
return SVN_NO_ERROR;
}
static svn_error_t *
validate_node(svn_wc__db_t *db,
const char *local_abspath,
const char *relpath,
svn_node_kind_t expected_kind,
svn_wc__db_status_t expected_status,
apr_pool_t *scratch_pool)
{
const char *path = svn_dirent_join(local_abspath, relpath, scratch_pool);
svn_node_kind_t kind;
svn_wc__db_status_t status;
apr_hash_t *props;
const svn_string_t *value;
SVN_ERR(svn_wc__db_base_get_info(
&status, &kind, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
db, path,
scratch_pool, scratch_pool));
SVN_TEST_ASSERT(kind == expected_kind);
SVN_TEST_ASSERT(status == expected_status);
switch (status)
{
case svn_wc__db_status_server_excluded:
case svn_wc__db_status_excluded:
case svn_wc__db_status_incomplete:
case svn_wc__db_status_not_present:
/* Our tests aren't setting properties on these node types, so
short-circuit examination of name/value pairs, to avoid having
to handle the error from svn_wc__db_base_get_props(). */
return SVN_NO_ERROR;
default:
break; /* Fall through */
}
SVN_ERR(svn_wc__db_base_get_props(&props, db, path,
scratch_pool, scratch_pool));
SVN_TEST_ASSERT(props != NULL);
value = apr_hash_get(props, "p1", APR_HASH_KEY_STRING);
SVN_TEST_STRING_ASSERT(value->data, "v1");
value = apr_hash_get(props, "for-file", APR_HASH_KEY_STRING);
SVN_TEST_STRING_ASSERT(value->data, relpath);
SVN_ERR(svn_wc__db_read_props(&props, db, path,
scratch_pool, scratch_pool));
SVN_TEST_ASSERT(props != NULL);
value = apr_hash_get(props, "p1", APR_HASH_KEY_STRING);
SVN_TEST_STRING_ASSERT(value->data, "v1");
SVN_ERR(svn_wc__db_read_pristine_props(&props, db, path,
scratch_pool, scratch_pool));
SVN_TEST_ASSERT(props != NULL);
value = apr_hash_get(props, "p1", APR_HASH_KEY_STRING);
SVN_TEST_STRING_ASSERT(value->data, "v1");
/* Now add a property value and read it back (all on actual) */
{
apr_hash_t *actual_props = apr_hash_copy(scratch_pool, props);
apr_hash_set(actual_props, "p999", APR_HASH_KEY_STRING, value);
SVN_ERR(svn_wc__db_op_set_props(db, path, actual_props, FALSE,
NULL, NULL, scratch_pool));
SVN_ERR(svn_wc__db_read_props(&props, db, path,
scratch_pool, scratch_pool));
SVN_TEST_ASSERT(props != NULL);
value = apr_hash_get(props, "p999", APR_HASH_KEY_STRING);
SVN_TEST_STRING_ASSERT(value->data, "v1");
}
return SVN_NO_ERROR;
}
static svn_error_t *
test_inserting_nodes(apr_pool_t *pool)
{
const char *local_abspath;
svn_checksum_t *checksum;
svn_wc__db_t *db;
apr_hash_t *props;
const apr_array_header_t *children;
SVN_ERR(create_open(&db, &local_abspath, "test_insert_nodes", pool));
props = apr_hash_make(pool);
set_prop(props, "p1", "v1", pool);
children = svn_cstring_split("N-a N-b N-c", " ", FALSE, pool);
SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, SHA1_1, pool));
/* Create a new directory and several child nodes. */
set_prop(props, "for-file", "N", pool);
SVN_ERR(svn_wc__db_base_add_directory(
db, svn_dirent_join(local_abspath, "N", pool),
local_abspath,
"N", ROOT_ONE, UUID_ONE, 3,
props,
1, TIME_1a, AUTHOR_1,
children, svn_depth_infinity,
NULL, FALSE, NULL, NULL, NULL, NULL,
pool));
/* Replace an incomplete node with a file node. */
set_prop(props, "for-file", "N/N-a", pool);
SVN_ERR(svn_wc__db_base_add_file(
db, svn_dirent_join(local_abspath, "N/N-a", pool),
local_abspath,
"N/N-a", ROOT_ONE, UUID_ONE, 3,
props,
1, TIME_1a, AUTHOR_1,
checksum,
NULL, FALSE, FALSE, NULL, NULL, FALSE, FALSE,
NULL, NULL,
pool));
/* Create a new symlink node. */
set_prop(props, "for-file", "O", pool);
SVN_ERR(svn_wc__db_base_add_symlink(
db, svn_dirent_join(local_abspath, "O", pool),
local_abspath,
"O", ROOT_ONE, UUID_ONE, 3,
props,
1, TIME_1a, AUTHOR_1,
"O-target",
NULL, FALSE, FALSE, NULL, NULL, FALSE, FALSE,
NULL, NULL,
pool));
/* Replace an incomplete node with an server-excluded file node. */
SVN_ERR(svn_wc__db_base_add_excluded_node(
db, svn_dirent_join(local_abspath, "N/N-b", pool),
"N/N-b", ROOT_ONE, UUID_ONE, 3,
svn_node_file, svn_wc__db_status_server_excluded,
NULL, NULL,
pool));
/* Create a new excluded directory node. */
SVN_ERR(svn_wc__db_base_add_excluded_node(
db, svn_dirent_join(local_abspath, "P", pool),
"P", ROOT_ONE, UUID_ONE, 3,
svn_node_dir, svn_wc__db_status_excluded,
NULL, NULL,
pool));
/* Create a new not-present symlink node. */
SVN_ERR(svn_wc__db_base_add_not_present_node(
db, svn_dirent_join(local_abspath, "Q", pool),
"Q", ROOT_ONE, UUID_ONE, 3,
svn_node_symlink,
NULL, NULL,
pool));
/* Create a new server-excluded unknown-kind node. */
SVN_ERR(svn_wc__db_base_add_excluded_node(
db, svn_dirent_join(local_abspath, "R", pool),
"R", ROOT_ONE, UUID_ONE, 3,
svn_node_unknown, svn_wc__db_status_server_excluded,
NULL, NULL,
pool));
/* Are all the nodes where we expect them to be? */
SVN_ERR(validate_node(db, local_abspath, "N",
svn_node_dir, svn_wc__db_status_normal,
pool));
SVN_ERR(validate_node(db, local_abspath, "N/N-a",
svn_node_file, svn_wc__db_status_normal,
pool));
SVN_ERR(validate_node(db, local_abspath, "N/N-b",
svn_node_file,
svn_wc__db_status_server_excluded,
pool));
SVN_ERR(validate_node(db, local_abspath, "N/N-c",
svn_node_unknown, svn_wc__db_status_incomplete,
pool));
SVN_ERR(validate_node(db, local_abspath, "O",
svn_node_symlink, svn_wc__db_status_normal,
pool));
SVN_ERR(validate_node(db, local_abspath, "P",
svn_node_dir, svn_wc__db_status_excluded,
pool));
SVN_ERR(validate_node(db, local_abspath, "Q",
svn_node_symlink, svn_wc__db_status_not_present,
pool));
SVN_ERR(validate_node(db, local_abspath, "R",
svn_node_unknown,
svn_wc__db_status_server_excluded,
pool));
/* ### do we need to test any attributes of the node? */
/* ### yes: test the repos inheritance stuff (at least) */
return SVN_NO_ERROR;
}
static svn_error_t *
test_children(apr_pool_t *pool)
{
const char *local_abspath;
svn_wc__db_t *db;
const apr_array_header_t *children;
int i;
SVN_ERR(create_open(&db, &local_abspath, "test_children", pool));
SVN_ERR(svn_wc__db_base_get_children(&children,
db, local_abspath,
pool, pool));
SVN_TEST_ASSERT(children->nelts == 13);
for (i = children->nelts; i--; )
{
const char *name = APR_ARRAY_IDX(children, i, const char *);
if (strcmp(name, "moved") == 0
|| strcmp(name, "other") == 0)
{
continue;
}
SVN_TEST_ASSERT(strlen(name) == 1);
/* ### check the actual values */
}
SVN_ERR(svn_wc__db_read_children(&children,
db, local_abspath,
pool, pool));
SVN_TEST_ASSERT(children->nelts == 14);
for (i = children->nelts; i--; )
{
const char *name = APR_ARRAY_IDX(children, i, const char *);
if (strcmp(name, "moved") == 0
|| strcmp(name, "other") == 0)
{
continue;
}
SVN_TEST_ASSERT(strlen(name) == 1);
/* ### check the actual values */
}
/* ### insert some more children. replace some nodes. check values. */
return SVN_NO_ERROR;
}
static svn_error_t *
test_working_info(apr_pool_t *pool)
{
const char *local_abspath;
svn_node_kind_t kind;
svn_wc__db_status_t status;
svn_revnum_t revision;
const char *repos_relpath;
const char *repos_root_url;
const char *repos_uuid;
svn_revnum_t changed_rev;
apr_time_t changed_date;
const char *changed_author;
apr_time_t recorded_time;
svn_depth_t depth;
const svn_checksum_t *checksum;
svn_filesize_t recorded_size;
const char *target;
const char *changelist;
const char *original_repos_relpath;
const char *original_root_url;
const char *original_uuid;
svn_revnum_t original_revnum;
svn_boolean_t op_root;
svn_boolean_t had_props;
svn_boolean_t props_mod;
svn_boolean_t have_base;
svn_boolean_t have_more_work;
svn_boolean_t have_work;
svn_boolean_t conflicted;
svn_wc__db_lock_t *lock;
svn_wc__db_t *db;
SVN_ERR(create_open(&db, &local_abspath, "test_working_info", pool));
/* Test: basic fetching of data. */
SVN_ERR(svn_wc__db_read_info(
&status, &kind, &revision,
&repos_relpath, &repos_root_url, &repos_uuid,
&changed_rev, &changed_date, &changed_author,
&depth, &checksum, &target, &original_repos_relpath,
&original_root_url, &original_uuid, &original_revnum,
&lock, &recorded_size, &recorded_time, &changelist,
&conflicted, &op_root, &had_props, &props_mod,
&have_base, &have_more_work, &have_work,
db, svn_dirent_join(local_abspath, "I", pool),
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_added);
SVN_TEST_ASSERT(kind == svn_node_dir);
SVN_TEST_ASSERT(revision == SVN_INVALID_REVNUM);
SVN_TEST_ASSERT(repos_relpath == NULL);
SVN_TEST_ASSERT(repos_root_url == NULL);
SVN_TEST_ASSERT(repos_uuid == NULL);
SVN_TEST_ASSERT(changed_rev == 2);
SVN_TEST_ASSERT(changed_date == TIME_2a);
SVN_TEST_STRING_ASSERT(changed_author, AUTHOR_2);
SVN_TEST_ASSERT(depth == svn_depth_immediates);
SVN_TEST_ASSERT(checksum == NULL);
SVN_TEST_ASSERT(recorded_size == SVN_INVALID_FILESIZE);
SVN_TEST_ASSERT(target == NULL);
SVN_TEST_STRING_ASSERT(changelist, NULL);
SVN_TEST_STRING_ASSERT(original_repos_relpath, "some/dir");
SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
SVN_TEST_ASSERT(original_revnum == 2);
SVN_TEST_ASSERT(!had_props);
SVN_TEST_ASSERT(!props_mod);
SVN_TEST_ASSERT(have_base);
/* SVN_TEST_ASSERT(have_more_work...); */
SVN_TEST_ASSERT(have_work);
SVN_TEST_ASSERT(!conflicted);
SVN_TEST_ASSERT(lock == NULL);
/* SVN_TEST_ASSERT(last_mod_time...); */
/* SVN_TEST_ASSERT(op_root...); */
/* ### we need a hojillion more tests in here. I just want to get this
### round checked in, so I'm skipping more tests at this point. */
SVN_ERR(svn_wc__db_read_info(
&status, &kind, &revision,
&repos_relpath, &repos_root_url, &repos_uuid,
&changed_rev, &changed_date, &changed_author,
&depth, &checksum, &target, &original_repos_relpath,
&original_root_url, &original_uuid, &original_revnum,
&lock, &recorded_size, &recorded_time, &changelist,
&conflicted, &op_root, &had_props, &props_mod,
&have_base, &have_more_work, &have_work,
db, svn_dirent_join(local_abspath, "A", pool),
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_normal);
SVN_TEST_ASSERT(kind == svn_node_file);
SVN_TEST_STRING_ASSERT(changelist, "changelist");
SVN_TEST_ASSERT(revision == 1);
SVN_TEST_STRING_ASSERT(repos_relpath, "A");
SVN_TEST_STRING_ASSERT(repos_root_url, "http://example.com/one");
SVN_TEST_STRING_ASSERT(repos_uuid, "uuid1");
SVN_TEST_ASSERT(changed_rev == 1);
SVN_TEST_ASSERT(changed_date == TIME_1a);
SVN_TEST_STRING_ASSERT(changed_author, AUTHOR_1);
SVN_TEST_ASSERT(depth == svn_depth_unknown);
SVN_TEST_ASSERT(checksum != NULL);
SVN_TEST_ASSERT(recorded_size == 10);
SVN_TEST_ASSERT(target == NULL);
return SVN_NO_ERROR;
}
static svn_error_t *
test_pdh(apr_pool_t *pool)
{
const char *local_abspath;
svn_wc__db_t *db;
SVN_ERR(create_open(&db, &local_abspath, "test_pdh", pool));
/* NOTE: this test doesn't do anything apparent -- it simply exercises
some internal functionality of wc_db. This is a handy driver for
debugging wc_db to ensure it manages per-directory handles properly. */
SVN_ERR(svn_wc__db_base_add_excluded_node(
db, svn_dirent_join(local_abspath, "sub", pool),
"sub", ROOT_ONE, UUID_ONE, 1,
svn_node_file, svn_wc__db_status_server_excluded,
NULL, NULL,
pool));
SVN_ERR(svn_wc__db_base_add_directory(
db, svn_dirent_join(local_abspath, "sub2", pool),
local_abspath, "sub2", ROOT_ONE, UUID_ONE, 1,
apr_hash_make(pool), 1, 1, "me", NULL,
svn_depth_infinity, NULL, FALSE, NULL, NULL,
NULL, NULL, pool));
SVN_ERR(svn_wc__db_base_add_excluded_node(
db, svn_dirent_join(local_abspath, "sub2/A", pool),
"sub2/A", ROOT_ONE, UUID_ONE, 1,
svn_node_file, svn_wc__db_status_server_excluded,
NULL, NULL,
pool));
return SVN_NO_ERROR;
}
static svn_error_t *
test_scan_addition(apr_pool_t *pool)
{
const char *local_abspath;
svn_wc__db_t *db;
svn_wc__db_status_t status;
const char *op_root_abspath;
const char *repos_relpath;
const char *repos_root_url;
const char *repos_uuid;
const char *original_repos_relpath;
const char *original_root_url;
const char *original_uuid;
svn_revnum_t original_revision;
const char *moved_from_abspath;
const char *move_op_root_abspath;
const char *move_op_root_src;
const char *delete_op_root_abspath;
SVN_ERR(create_open(&db, &local_abspath, "test_scan_addition", pool));
/* Simple addition of a directory. */
SVN_ERR(svn_wc__db_scan_addition(
&status, &op_root_abspath,
&repos_relpath, &repos_root_url, &repos_uuid,
&original_repos_relpath, &original_root_url, &original_uuid,
&original_revision,
db, svn_dirent_join(local_abspath, "J", pool),
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
SVN_ERR(validate_abspath(local_abspath, "J", op_root_abspath, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "J");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
SVN_TEST_STRING_ASSERT(original_repos_relpath, "q");
SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
SVN_TEST_ASSERT(original_revision == 2);
/* Simple copy (affects how scan-up is started). */
SVN_ERR(svn_wc__db_scan_addition(
&status, &op_root_abspath,
&repos_relpath, &repos_root_url, &repos_uuid,
&original_repos_relpath, &original_root_url, &original_uuid,
&original_revision,
db, svn_dirent_join(local_abspath, "J/J-a", pool),
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
SVN_ERR(validate_abspath(local_abspath, "J", op_root_abspath, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-a");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
SVN_TEST_STRING_ASSERT(original_repos_relpath, "q");
SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
SVN_TEST_ASSERT(original_revision == 2);
/* Node was moved here. */
SVN_ERR(svn_wc__db_scan_addition(
&status, &op_root_abspath,
&repos_relpath, &repos_root_url, &repos_uuid,
&original_repos_relpath, &original_root_url, &original_uuid,
&original_revision,
db, svn_dirent_join(local_abspath, "J/J-d", pool),
pool, pool));
SVN_ERR(svn_wc__db_scan_moved(
&moved_from_abspath,
&move_op_root_abspath,
&move_op_root_src,
&delete_op_root_abspath,
db, svn_dirent_join(local_abspath, "J/J-d", pool),
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_moved_here);
SVN_ERR(validate_abspath(local_abspath, "J/J-d",
op_root_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "moved/file",
moved_from_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "J/J-d",
move_op_root_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "moved/file",
move_op_root_src, pool));
SVN_ERR(validate_abspath(local_abspath, "moved/file",
delete_op_root_abspath, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-d");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
SVN_TEST_STRING_ASSERT(original_repos_relpath, "moved/file");
SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
SVN_TEST_ASSERT(original_revision == 2);
/* Check root of a copy. */
SVN_ERR(svn_wc__db_scan_addition(
&status, &op_root_abspath,
&repos_relpath, &repos_root_url, &repos_uuid,
&original_repos_relpath, &original_root_url, &original_uuid,
&original_revision,
db, svn_dirent_join(local_abspath, "J/J-b", pool),
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
SVN_ERR(validate_abspath(local_abspath, "J",
op_root_abspath, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-b");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
SVN_TEST_STRING_ASSERT(original_repos_relpath, "q");
SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
SVN_TEST_ASSERT(original_revision == 2);
/* Ignore parent copy. Use copy closest to target. */
SVN_ERR(svn_wc__db_scan_addition(
&status, &op_root_abspath,
&repos_relpath, &repos_root_url, &repos_uuid,
&original_repos_relpath, &original_root_url, &original_uuid,
&original_revision,
db, svn_dirent_join(local_abspath, "J/J-b/J-b-a", pool),
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
SVN_ERR(validate_abspath(local_abspath, "J/J-b/J-b-a",
op_root_abspath, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-b/J-b-a");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
SVN_TEST_STRING_ASSERT(original_repos_relpath, "another/dir");
SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
SVN_TEST_ASSERT(original_revision == 2);
/* Inherit parent copy. */
SVN_ERR(svn_wc__db_scan_addition(
&status, &op_root_abspath,
&repos_relpath, &repos_root_url, &repos_uuid,
&original_repos_relpath, &original_root_url, &original_uuid,
&original_revision,
db, svn_dirent_join(local_abspath, "J/J-b/J-b-b", pool),
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
SVN_ERR(validate_abspath(local_abspath, "J",
op_root_abspath, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-b/J-b-b");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
SVN_TEST_STRING_ASSERT(original_repos_relpath, "q");
SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
SVN_TEST_ASSERT(original_revision == 2);
return SVN_NO_ERROR;
}
static svn_error_t *
test_scan_deletion(apr_pool_t *pool)
{
const char *local_abspath;
svn_wc__db_t *db;
const char *base_del_abspath;
const char *work_del_abspath;
const char *moved_to_abspath;
const char *copy_op_root_abspath;
SVN_ERR(create_open(&db, &local_abspath, "test_scan_deletion", pool));
/* Node was moved elsewhere. */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
&copy_op_root_abspath,
db, svn_dirent_join(local_abspath, "J/J-e", pool),
pool, pool));
SVN_ERR(validate_abspath(local_abspath, "J",
base_del_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "other/place",
moved_to_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "J/J-e",
work_del_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "other/place",
copy_op_root_abspath, pool));
/* Node was moved elsewhere (child of operation root). */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
&copy_op_root_abspath,
db, svn_dirent_join(local_abspath, "J/J-e/J-e-a", pool),
pool, pool));
SVN_ERR(validate_abspath(local_abspath, "J",
base_del_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "other/place/J-e-a",
moved_to_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "J/J-e",
work_del_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "other/place",
copy_op_root_abspath, pool));
/* Root of delete. Parent is a WORKING node. */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
NULL,
db, svn_dirent_join(local_abspath, "J/J-c", pool),
pool, pool));
/* Implicit delete of "J" (via replacement). */
SVN_ERR(validate_abspath(local_abspath, "J",
base_del_abspath, pool));
SVN_TEST_ASSERT(moved_to_abspath == NULL);
SVN_ERR(validate_abspath(local_abspath, "J/J-c",
work_del_abspath, pool));
/* Child of a deleted root. */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
NULL,
db, svn_dirent_join(local_abspath, "J/J-c/J-c-a", pool),
pool, pool));
/* Implicit delete of "J" (via replacement). */
SVN_ERR(validate_abspath(local_abspath, "J",
base_del_abspath, pool));
SVN_TEST_ASSERT(moved_to_abspath == NULL);
SVN_ERR(validate_abspath(local_abspath, "J/J-c",
work_del_abspath, pool));
/* Base-deleted tree extending past deleted WORKING subtree. */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
NULL,
db, svn_dirent_join(local_abspath, "J/J-e/J-e-b/Jeba", pool),
pool, pool));
/* ### I don't understand this. "J/J-e/J-e-b/Jeba" is a deleted
base node that is not overlayed by the replacement rooted at "J".
Why does base_del_abspath refer to "J-e"? */
SVN_ERR(validate_abspath(local_abspath, "J",
base_del_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "other/place/J-e-b/Jeba",
moved_to_abspath, pool));
SVN_TEST_STRING_ASSERT(work_del_abspath, NULL);
/* Base-deleted tree extending past added WORKING tree. */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
NULL,
db, svn_dirent_join(local_abspath, "J/J-f/J-f-a", pool),
pool, pool));
/* Implicit delete of "J" (via replacement). */
SVN_ERR(validate_abspath(local_abspath, "J",
base_del_abspath, pool));
SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL);
SVN_TEST_STRING_ASSERT(work_del_abspath, NULL);
/* Root of delete. Parent is a BASE node. */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
NULL,
db, svn_dirent_join(local_abspath, "K", pool),
pool, pool));
SVN_ERR(validate_abspath(local_abspath, "K",
base_del_abspath, pool));
SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL);
SVN_TEST_STRING_ASSERT(work_del_abspath, NULL);
/* Base-deleted tree. Start below root. */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
NULL,
db, svn_dirent_join(local_abspath, "K/K-a", pool),
pool, pool));
SVN_ERR(validate_abspath(local_abspath, "K",
base_del_abspath, pool));
SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL);
SVN_TEST_STRING_ASSERT(work_del_abspath, NULL);
/* Base-deleted tree via move. */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
&copy_op_root_abspath,
db, svn_dirent_join(local_abspath, "K/K-b", pool),
pool, pool));
SVN_ERR(validate_abspath(local_abspath, "K",
base_del_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "moved/away",
moved_to_abspath, pool));
SVN_ERR(validate_abspath(local_abspath, "moved/away",
copy_op_root_abspath, pool));
SVN_TEST_STRING_ASSERT(work_del_abspath, NULL);
/* Subtree deletion of added tree. Start at child. */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
NULL,
db, svn_dirent_join(local_abspath, "L/L-a/L-a-a", pool),
pool, pool));
SVN_TEST_STRING_ASSERT(base_del_abspath, NULL);
SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL);
SVN_ERR(validate_abspath(local_abspath, "L/L-a",
work_del_abspath, pool));
/* Subtree deletion of added tree. Start at root. */
SVN_ERR(svn_wc__db_scan_deletion(
&base_del_abspath,
&moved_to_abspath,
&work_del_abspath,
NULL,
db, svn_dirent_join(local_abspath, "L/L-a", pool),
pool, pool));
SVN_TEST_STRING_ASSERT(base_del_abspath, NULL);
SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL);
SVN_ERR(validate_abspath(local_abspath, "L/L-a",
work_del_abspath, pool));
return SVN_NO_ERROR;
}
static svn_error_t *
test_global_relocate(apr_pool_t *pool)
{
const char *local_abspath;
svn_wc__db_t *db;
const char *repos_relpath;
const char *repos_root_url;
const char *repos_uuid;
SVN_ERR(create_open(&db, &local_abspath, "test_global_relocate", pool));
/* Initial sanity check. */
SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL,
&repos_relpath, &repos_root_url, &repos_uuid,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
db, local_abspath,
pool, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
/* Test relocating to a repos not existent in the db */
SVN_ERR(svn_wc__db_global_relocate(db, local_abspath, ROOT_THREE, pool));
SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL,
&repos_relpath, &repos_root_url, &repos_uuid,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
db, local_abspath,
pool, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_THREE);
/* The UUID should still be the same. */
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
/* While we're at it, let's see if the children have been relocated, too. */
SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL,
&repos_relpath, &repos_root_url, &repos_uuid,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "F",
pool),
pool, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "F");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_THREE);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
/* Alternate repository is not relocated. */
SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL,
&repos_relpath, &repos_root_url, &repos_uuid,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
db, svn_dirent_join(local_abspath, "G",
pool),
pool, pool));
SVN_TEST_STRING_ASSERT(repos_relpath, "G-alt");
SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_TWO);
SVN_TEST_STRING_ASSERT(repos_uuid, UUID_TWO);
return SVN_NO_ERROR;
}
static int
detect_work_item(const svn_skel_t *work_item)
{
/* Test work items are a list with one integer atom as operation */
if (!work_item->children)
return -1;
work_item = work_item->children;
if (!work_item->is_atom || work_item->len != 1)
return -1;
return work_item->data[0] - '0';
}
static svn_error_t *
test_work_queue(apr_pool_t *pool)
{
svn_wc__db_t *db;
const char *local_abspath;
svn_skel_t *work_item;
int run_count[3] = { 4, 7, 2 }; /* run the work 13 times, total. */
int fetches = 0;
apr_int64_t last_id = 0;
SVN_ERR(create_open(&db, &local_abspath, "test_work_queue", pool));
/* Create three work items. */
work_item = svn_skel__make_empty_list(pool);
svn_skel__prepend_int(0, work_item, pool);
SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, pool));
work_item = svn_skel__make_empty_list(pool);
svn_skel__prepend_int(1, work_item, pool);
SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, pool));
work_item = svn_skel__make_empty_list(pool);
svn_skel__prepend_int(2, work_item, pool);
SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, pool));
while (TRUE)
{
apr_uint64_t id;
int which;
/* Fetch the next work item, or break when the work queue is empty. */
SVN_ERR(svn_wc__db_wq_fetch_next(&id, &work_item, db, local_abspath,
last_id, pool, pool));
if (work_item == NULL)
break;
/* Got one. We should never fetch work more than 13 times. */
++fetches;
SVN_TEST_ASSERT(fetches <= 13);
/* Parse the work item to see which of the three we found. */
which = detect_work_item(work_item);
SVN_TEST_ASSERT(which >= 0 && which <= 2);
/* We should not see an item after we've run it enough times.
Note: strictly speaking, "in the wild" a work item could remain
after a call to wq_completed (ie. crash while that function was
processing), but we don't really have a way to test that here. */
SVN_TEST_ASSERT(run_count[which] > 0);
/* If we have run this particular item enough times, then go ahead
and remove it from the work queue. */
if (--run_count[which] == 0)
last_id = id;
else
last_id = 0;
}
/* Should have run precisely 13 work items. */
SVN_TEST_ASSERT(fetches == 13);
return SVN_NO_ERROR;
}
static svn_error_t *
test_externals_store(apr_pool_t *pool)
{
svn_wc__db_t *db;
const char *local_abspath;
svn_checksum_t *orig_checksum;
const char *file_external_path;
const char *dir_external_path;
const char *subdir;
apr_hash_t *props = apr_hash_make(pool);
svn_string_t *value = svn_string_create("value-data", pool);
apr_hash_set(props, "key", APR_HASH_KEY_STRING, value);
SVN_ERR(create_open(&db, &local_abspath, "test_externals_store", pool));
/* Directory I exists in the standard test db */
subdir = svn_dirent_join(local_abspath, "I", pool);
SVN_ERR(svn_checksum_parse_hex(&orig_checksum, svn_checksum_sha1, SHA1_1,
pool));
file_external_path = svn_dirent_join(subdir, "file-external", pool);
dir_external_path = svn_dirent_join(subdir, "dir-external", pool);
SVN_ERR(svn_wc__db_external_add_file(db,
file_external_path,
local_abspath /* wri_abspath */,
"some/location",
"svn://some-repos/svn",
"not-a-uuid",
12,
props,
NULL,
10,
987654,
"somebody",
orig_checksum,
NULL,
subdir,
"some/new-location",
90,
12,
FALSE, NULL,
FALSE,
NULL,
NULL,
pool));
SVN_ERR(svn_wc__db_external_add_dir(db,
dir_external_path,
local_abspath /* wri_abspath */,
"svn://other-repos/nsv",
"no-uuid-either",
subdir,
"some/other-location",
70,
32,
NULL,
pool));
{
svn_wc__db_status_t status;
svn_node_kind_t kind;
const char *repos_root_url;
const char *repos_uuid;
const char *defining_abspath;
const char *recorded_repos_relpath;
svn_revnum_t recorded_peg_revision;
svn_revnum_t recorded_revision;
SVN_ERR(svn_wc__db_external_read(&status, &kind, &defining_abspath,
&repos_root_url, &repos_uuid,
&recorded_repos_relpath,
&recorded_peg_revision,
&recorded_revision,
db, file_external_path, local_abspath,
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_normal);
SVN_TEST_ASSERT(kind == svn_node_file);
SVN_TEST_STRING_ASSERT(repos_root_url, "svn://some-repos/svn");
SVN_TEST_STRING_ASSERT(repos_uuid, "not-a-uuid");
SVN_TEST_STRING_ASSERT(defining_abspath, subdir);
SVN_TEST_STRING_ASSERT(recorded_repos_relpath, "some/new-location");
SVN_TEST_ASSERT(recorded_peg_revision == 90);
SVN_TEST_ASSERT(recorded_revision == 12);
{
apr_hash_t *new_props;
svn_string_t *v;
SVN_ERR(svn_wc__db_base_get_props(&new_props, db,
file_external_path,
pool, pool));
SVN_TEST_ASSERT(new_props != NULL);
v = apr_hash_get(new_props, "key", APR_HASH_KEY_STRING);
SVN_TEST_ASSERT(v != NULL);
SVN_TEST_STRING_ASSERT(v->data, "value-data");
}
SVN_ERR(svn_wc__db_external_read(&status, &kind, &defining_abspath,
&repos_root_url, &repos_uuid,
&recorded_repos_relpath,
&recorded_peg_revision,
&recorded_revision,
db, dir_external_path, local_abspath,
pool, pool));
SVN_TEST_ASSERT(status == svn_wc__db_status_normal);
SVN_TEST_ASSERT(kind == svn_node_dir);
SVN_TEST_STRING_ASSERT(repos_root_url, "svn://other-repos/nsv");
SVN_TEST_STRING_ASSERT(repos_uuid, "no-uuid-either");
SVN_TEST_STRING_ASSERT(defining_abspath, subdir);
SVN_TEST_STRING_ASSERT(recorded_repos_relpath, "some/other-location");
SVN_TEST_ASSERT(recorded_peg_revision == 70);
SVN_TEST_ASSERT(recorded_revision == 32);
}
return SVN_NO_ERROR;
}
static int max_threads = 2;
static struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
SVN_TEST_PASS2(test_getting_info,
"get information from wc.db"),
SVN_TEST_PASS2(test_inserting_nodes,
"insert different nodes into wc.db"),
SVN_TEST_PASS2(test_children,
"getting the list of BASE or WORKING children"),
SVN_TEST_PASS2(test_working_info,
"reading information about the WORKING tree"),
SVN_TEST_PASS2(test_pdh,
"creation of per-directory handles"),
SVN_TEST_PASS2(test_scan_addition,
"scanning added working nodes"),
SVN_TEST_PASS2(test_scan_deletion,
"deletion introspection functions"),
SVN_TEST_PASS2(test_global_relocate,
"relocating a node"),
SVN_TEST_PASS2(test_work_queue,
"work queue processing"),
SVN_TEST_PASS2(test_externals_store,
"externals store"),
SVN_TEST_NULL
};
SVN_TEST_MAIN