1 /*
2  * db-test.c :  test the wc_db subsystem
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23 
24 #include <apr_pools.h>
25 #include <apr_general.h>
26 
27 #include "svn_types.h"
28 
29 /* Make sure SVN_DEPRECATED is defined as empty before including svn_io.h.
30    We don't want to trigger deprecation warnings.  */
31 #ifdef SVN_DEPRECATED
32 #undef SVN_DEPRECATED
33 #endif
34 #define SVN_DEPRECATED
35 #include "svn_io.h"
36 
37 #include "svn_dirent_uri.h"
38 #include "svn_pools.h"
39 
40 #include "private/svn_sqlite.h"
41 
42 #include "../../libsvn_wc/wc_db.h"
43 
44 #include "private/svn_wc_private.h"
45 
46 #include "../svn_test.h"
47 #include "utils.h"
48 
49 
50 #define ROOT_ONE "http://example.com/one"
51 #define ROOT_TWO "http://example.com/two"
52 #define ROOT_THREE "http://example.com/three"
53 
54 #define UUID_ONE "uuid1"
55 #define UUID_TWO "uuid2"
56 #define UUID_THREE "uuid3"
57 
58 #define TIME_1 1235142208
59 #define TIME_2 1235142268
60 #define TIME_3 1235142328
61 
62 #define TIME_1s APR_STRINGIFY(TIME_1) "000000"
63 #define TIME_2s APR_STRINGIFY(TIME_2) "000000"
64 #define TIME_3s APR_STRINGIFY(TIME_3) "000000"
65 
66 #define TIME_1a apr_time_from_sec(TIME_1)
67 #define TIME_2a apr_time_from_sec(TIME_2)
68 #define TIME_3a apr_time_from_sec(TIME_3)
69 
70 #define AUTHOR_1 "johndoe"
71 #define AUTHOR_2 "janedoe"
72 
73 /* Some arbitrary checksum values */
74 #define MD5_1 "2d18c5e57e84c5b8a5e9a6e13fa394dc"
75 #define SHA1_1 "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"
76 
77 #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))"
78 #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))"
79 
80 static const char * const TESTING_DATA = (
81    /* Load our test data.
82 
83       Note: do not use named-column insertions. This allows us to test
84       the column count in the schema matches our expectation here. */
85 
86    "insert into repository values (1, '" ROOT_ONE "', '" UUID_ONE "'); "
87    "insert into repository values (2, '" ROOT_TWO "', '" UUID_TWO "'); "
88    "insert into wcroot values (1, null); "
89 
90    "insert into pristine values ('$sha1$" SHA1_1 "', NULL, 15, 1, '$md5 $" MD5_1 "'); "
91 );
92 
93 #define NOT_MOVED FALSE, NULL
94 #define NO_COPY_FROM 0, NULL, SVN_INVALID_REVNUM
95 
96 static const svn_test__nodes_data_t nodes_init_data[] = {
97    /* load the base nodes into the nodes table */
98   { 0, "",            "normal",           1, "", 1,             NOT_MOVED,
99     svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
100 
101   { 0, "A",           "normal",           1, "A", 1,            NOT_MOVED,
102     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1,
103     FALSE, NULL, 10, 10 },
104 
105   { 0, "B",           "excluded",         1, "B", SVN_INVALID_REVNUM, NOT_MOVED,
106     svn_node_symlink},
107 
108   { 0, "C",           "server-excluded",  1, "C", 0,            NOT_MOVED,
109     svn_node_unknown},
110 
111   { 0, "D",           "not-present",      1, "D", 0,            NOT_MOVED,
112     svn_node_unknown},
113 
114   { 0, "E",           "incomplete",       1, "E", 1,            NOT_MOVED,
115     svn_node_unknown},
116 
117   { 0, "F",           "normal",           1, "F", 1,            NOT_MOVED,
118     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2},
119 
120   { 0, "G",           "normal",           2, "G-alt", 1,        NOT_MOVED,
121     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
122 
123   { 0, "H",           "normal",           1, "H", 1,            NOT_MOVED,
124     svn_node_symlink, "()", NULL, NULL, "H-target", 1, TIME_1a, AUTHOR_1 },
125 
126   { 0, "I",           "normal",           1, "I", 1,            NOT_MOVED,
127     svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
128 
129   { 0, "J",           "normal",           1, "J", 1,            NOT_MOVED,
130     svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
131 
132   { 0, "J/J-e",       "normal",           1, "J/J-e", 1,        NOT_MOVED,
133     svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
134 
135   { 0, "J/J-e/J-e-a", "normal",           1, "J/J-e/J-e-a", 1,  NOT_MOVED,
136     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1 },
137 
138   { 0, "J/J-e/J-e-b", "normal",           1, "J/J-e/J-e-b", 1,  NOT_MOVED,
139     svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
140 
141   { 0, "J/J-e/J-e-b/Jeba", "normal",      1, "J/J-e/J-e-b/Jeba", 1,  NOT_MOVED,
142     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1 },
143 
144   { 0, "J/J-f",       "normal",           1, "J/J-f", 1,        NOT_MOVED,
145     svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
146 
147   { 0, "J/J-f/J-f-a", "normal",           1, "J/J-f/J-f-a", 1,  NOT_MOVED,
148     svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
149 
150   { 0, "J",           "normal",           1, "J", 1,            NOT_MOVED,
151     svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
152 
153   { 0, "K",           "normal",           1, "K", 1,            NOT_MOVED,
154     svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
155 
156   { 0, "K/K-a",       "normal",           2, "K/K-a", 1,        NOT_MOVED,
157     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2,
158     FALSE, NULL, 15, 14},
159 
160   { 0, "K/K-b",       "normal",           2, "K/K-b", 1,        NOT_MOVED,
161     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2,
162     FALSE, NULL, 15, 14},
163 
164    /* Load data into the working layers of NODES */
165 
166   { 1, "I",           "normal",           2, "some/dir", 2,     NOT_MOVED,
167     svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
168 
169    /* J was originally a local addition, but its descendants are replaced,
170       so let's turn J in a copy */
171   { 1, "J",           "normal",           2, "q", 2,            NOT_MOVED,
172     svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
173 
174   { 1, "J/J-a",       "normal",           2, "q/J-a", 2,        NOT_MOVED,
175     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
176 
177   { 1, "J/J-b",       "normal",           2, "q/J-b", 2,        NOT_MOVED,
178     svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
179 
180   { 3, "J/J-b/J-b-a", "normal",           2, "another/dir", 2,  NOT_MOVED,
181     svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
182 
183   { 1, "J/J-b/J-b-b", "normal",           2, "q/J-b/J-b-b", 2,  NOT_MOVED,
184     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
185 
186   { 1, "J/J-c",       "normal",           2, "q/J-c", 2,        NOT_MOVED,
187     svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
188 
189   { 1, "J/J-c/J-c-a", "normal",           2, "q/J-c/J-c-a", 2,  NOT_MOVED,
190     svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
191 
192   { 2, "J/J-c",       "base-deleted",     NO_COPY_FROM,         NOT_MOVED,
193     svn_node_dir},
194 
195   { 2, "J/J-c/J-c-a", "base-deleted",     NO_COPY_FROM,         NOT_MOVED,
196     svn_node_dir},
197 
198   { 2, "J/J-d",       "normal",           2, "moved/file", 2,   TRUE, NULL,
199     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
200 
201   { 0, "moved",       "normal",           2, "moved", 2,        NOT_MOVED,
202     svn_node_dir, "()", "infinity", NULL, NULL, 1, TIME_1a, AUTHOR_1 },
203 
204   { 0, "moved/file",  "normal",           2, "moved/file", 2,   NOT_MOVED,
205     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
206 
207   { 2, "moved/file",  "base-deleted",     NO_COPY_FROM,         FALSE, "J/J-d",
208     svn_node_file},
209 
210   { 1, "J/J-e",       "normal",           2, "q/J-e", 2,        NOT_MOVED,
211     svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
212 
213   { 1, "J/J-e/J-e-a", "normal",           2, "q/J-e/J-e-a", 2,  NOT_MOVED,
214     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
215 
216   { 1, "J/J-e/J-e-b", "normal",           2, "q/J-e/J-e-b", 2,  NOT_MOVED,
217     svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
218 
219   { 2, "J/J-e",       "base-deleted",     NO_COPY_FROM,         FALSE, "other/place",
220     svn_node_dir},
221 
222   { 2, "J/J-e/J-e-a", "base-deleted",     NO_COPY_FROM,         NOT_MOVED,
223     svn_node_file},
224 
225   { 2, "J/J-e/J-e-b", "base-deleted",     NO_COPY_FROM,         NOT_MOVED,
226     svn_node_dir},
227 
228   { 1, "J/J-e/J-e-b/Jeba", "base-deleted", NO_COPY_FROM,        NOT_MOVED,
229     svn_node_file},
230 
231   { 1, "J/J-f",       "normal",           2, "q/J-f", 2,        NOT_MOVED,
232     svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
233 
234   { 1, "J/J-f/J-f-a", "base-deleted",     NO_COPY_FROM,         NOT_MOVED,
235     svn_node_dir},
236 
237   { 1, "K",           "base-deleted",     NO_COPY_FROM,         NOT_MOVED,
238     svn_node_dir},
239 
240   { 1, "K/K-a",       "base-deleted",     NO_COPY_FROM,         NOT_MOVED,
241     svn_node_file},
242 
243   { 1, "K/K-b",       "base-deleted",     NO_COPY_FROM,         FALSE, "moved/away",
244     svn_node_file},
245 
246   { 1, "L",           "normal",           2, "from", 2,         NOT_MOVED,
247     svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
248 
249   { 1, "L/L-a",       "normal",           2, "from/L-a", 2,     NOT_MOVED,
250     svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
251 
252   { 1, "L/L-a/L-a-a", "normal",           2, "from/L-a/L-a-a", 2, NOT_MOVED,
253     svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
254 
255   { 2, "L/L-a",       "base-deleted",     NO_COPY_FROM,         NOT_MOVED,
256     svn_node_dir},
257 
258   { 2, "L/L-a/L-a-a", "base-deleted",     NO_COPY_FROM,         NOT_MOVED,
259     svn_node_dir},
260 
261   { 0, "other",       "normal",           2, "other", 2,        NOT_MOVED,
262     svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
263 
264   { 2, "other/place", "normal",           2, "q/J-e", 2,        TRUE, NULL,
265     svn_node_dir, "()", "immediates", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
266 
267   { 2, "other/place/J-e-a", "normal",     2, "q/J-e/J-e-a", 2,  TRUE, NULL,
268     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2 },
269 
270   { 2, "other/place/J-e-b", "normal",     2, "q/J-e/J-e-b", 2,  TRUE, NULL,
271     svn_node_dir, "()", "infinity", NULL, NULL, 2, TIME_2a, AUTHOR_2 },
272 
273   { 2, "other/place/J-e-b/Jeba", "normal", 2, "q/J-e/J-e-b/Jeba", 2,  TRUE, NULL,
274     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 1, TIME_1a, AUTHOR_1 },
275 
276   /*** NEW ****/
277   { 2, "moved/away",  "normal",           2, "K/K-b", 1,        TRUE, NULL,
278     svn_node_file, "()", NULL, "$sha1$" SHA1_1, NULL, 2, TIME_2a, AUTHOR_2,
279     FALSE, NULL, 15, 14},
280   { 0 }
281 };
282 
283 static const svn_test__actual_data_t actual_init_data[] = {
284   { "A", NULL, "changelist", NULL },
285   { "F", NULL, NULL, F_TC_DATA },
286   { "G", NULL, NULL, F_TC_DATA },
287 
288   { 0 }
289 };
290 
291 static svn_error_t *
create_open(svn_wc__db_t ** db,const char ** local_abspath,const char * subdir,apr_pool_t * pool)292 create_open(svn_wc__db_t **db,
293             const char **local_abspath,
294             const char *subdir,
295             apr_pool_t *pool)
296 {
297   SVN_ERR(svn_dirent_get_absolute(local_abspath,
298                                   svn_dirent_join(
299                                         svn_test_data_path("db-test", pool),
300                                         subdir, pool),
301                                   pool));
302 
303   SVN_ERR(svn_io_remove_dir2(*local_abspath, TRUE, NULL, NULL, pool));
304 
305   SVN_ERR(svn_wc__db_open(db, NULL, FALSE, TRUE, pool, pool));
306   SVN_ERR(svn_test__create_fake_wc(*local_abspath, TESTING_DATA,
307                                    nodes_init_data, actual_init_data, pool));
308 
309   svn_test_add_dir_cleanup(*local_abspath);
310 
311   return SVN_NO_ERROR;
312 }
313 
314 
315 /* Convert VALUE to a const svn_string_t *, and create a mapping from
316    NAME to the converted data type in PROPS. */
317 static void
set_prop(apr_hash_t * props,const char * name,const char * value,apr_pool_t * result_pool)318 set_prop(apr_hash_t *props, const char *name, const char *value,
319          apr_pool_t *result_pool)
320 {
321   const svn_string_t *propval = svn_string_create(value, result_pool);
322 
323   apr_hash_set(props, name, APR_HASH_KEY_STRING, propval);
324 }
325 
326 
327 static svn_error_t *
validate_abspath(const char * wcroot_abspath,const char * expected_relpath,const char * actual_abspath,apr_pool_t * scratch_pool)328 validate_abspath(const char *wcroot_abspath,
329                  const char *expected_relpath,
330                  const char *actual_abspath,
331                  apr_pool_t *scratch_pool)
332 {
333   SVN_TEST_STRING_ASSERT(actual_abspath,
334                          svn_dirent_join(wcroot_abspath,
335                                 expected_relpath,
336                                 scratch_pool));
337   return SVN_NO_ERROR;
338 }
339 
340 
341 static svn_error_t *
test_getting_info(apr_pool_t * pool)342 test_getting_info(apr_pool_t *pool)
343 {
344   const char *local_abspath;
345   svn_node_kind_t kind;
346   svn_wc__db_status_t status;
347   svn_revnum_t revision;
348   const char *repos_relpath;
349   const char *repos_root_url;
350   const char *repos_uuid;
351   svn_revnum_t changed_rev;
352   apr_time_t changed_date;
353   const char *changed_author;
354   svn_depth_t depth;
355   const svn_checksum_t *checksum;
356   const char *target;
357   svn_boolean_t had_props;
358   apr_hash_t *props;
359   svn_boolean_t update_root;
360   svn_wc__db_lock_t *lock;
361   svn_wc__db_t *db;
362   svn_error_t *err;
363 
364   SVN_ERR(create_open(&db, &local_abspath, "test_getting_info", pool));
365 
366   /* Test: basic fetching of data. */
367   SVN_ERR(svn_wc__db_base_get_info(
368             &status, &kind, &revision,
369             &repos_relpath, &repos_root_url, &repos_uuid,
370             &changed_rev, &changed_date, &changed_author,&depth, &checksum,
371             &target, &lock, &had_props, &props,
372             &update_root,
373             db, local_abspath,
374             pool, pool));
375   SVN_TEST_ASSERT(kind == svn_node_dir);
376   SVN_TEST_ASSERT(status == svn_wc__db_status_normal);
377   SVN_TEST_ASSERT(revision == 1);
378   SVN_TEST_STRING_ASSERT(repos_relpath, "");
379   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
380   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
381   SVN_TEST_ASSERT(changed_rev == 1);
382   SVN_TEST_ASSERT(changed_date == TIME_1a);
383   SVN_TEST_STRING_ASSERT(changed_author, AUTHOR_1);
384   SVN_TEST_ASSERT(depth == svn_depth_infinity);
385   SVN_TEST_ASSERT(checksum == NULL);
386   SVN_TEST_ASSERT(target == NULL);
387   SVN_TEST_ASSERT(lock == NULL);
388   SVN_TEST_ASSERT(!had_props);
389   SVN_TEST_ASSERT(apr_hash_count(props) == 0);
390   /* SVN_TEST_ASSERT(update_root == ???); */
391 
392   /* Test: file-specific values. */
393   SVN_ERR(svn_wc__db_base_get_info(
394             NULL, &kind, NULL,
395             &repos_relpath, &repos_root_url, &repos_uuid,
396             NULL, NULL, NULL, NULL,
397             &checksum, NULL, NULL,
398             NULL, NULL, NULL,
399             db, svn_dirent_join(local_abspath, "A", pool),
400             pool, pool));
401   SVN_TEST_ASSERT(kind == svn_node_file);
402   SVN_TEST_STRING_ASSERT(SHA1_1, svn_checksum_to_cstring(checksum, pool));
403   SVN_TEST_STRING_ASSERT(repos_relpath, "A");
404   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
405   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
406 
407   /* Test: symlink kind, excluded presence, default values for columns. */
408   SVN_ERR(svn_wc__db_base_get_info(
409             &status, &kind, &revision,
410             &repos_relpath, &repos_root_url, &repos_uuid,
411             &changed_rev, &changed_date, &changed_author,
412             &depth, &checksum, &target, &lock,
413             NULL, NULL, NULL,
414             db, svn_dirent_join(local_abspath, "B", pool),
415             pool, pool));
416   SVN_TEST_ASSERT(kind == svn_node_symlink);
417   SVN_TEST_ASSERT(status == svn_wc__db_status_excluded);
418   SVN_TEST_ASSERT(!SVN_IS_VALID_REVNUM(revision));
419   SVN_TEST_STRING_ASSERT(repos_relpath, "B");
420   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
421   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
422   SVN_TEST_ASSERT(!SVN_IS_VALID_REVNUM(changed_rev));
423   SVN_TEST_ASSERT(changed_date == 0);
424   SVN_TEST_ASSERT(changed_author == NULL);
425   SVN_TEST_ASSERT(depth == svn_depth_unknown);
426   SVN_TEST_ASSERT(checksum == NULL);
427   SVN_TEST_ASSERT(target == NULL);
428   SVN_TEST_ASSERT(lock == NULL);
429 
430   /* Test: unknown kind, server-excluded presence. */
431   SVN_ERR(svn_wc__db_base_get_info(
432             &status, &kind, NULL,
433             NULL, NULL, NULL,
434             NULL, NULL, NULL,
435             NULL, NULL, NULL,
436             NULL, NULL, NULL, NULL,
437             db, svn_dirent_join(local_abspath, "C", pool),
438             pool, pool));
439   SVN_TEST_ASSERT(kind == svn_node_unknown);
440   SVN_TEST_ASSERT(status == svn_wc__db_status_server_excluded);
441 
442   /* Test: not-present presence. */
443   SVN_ERR(svn_wc__db_base_get_info(
444             &status, NULL, NULL,
445             NULL, NULL, NULL,
446             NULL, NULL, NULL,
447             NULL, NULL, NULL,
448             NULL, NULL, NULL, NULL,
449             db, svn_dirent_join(local_abspath, "D", pool),
450             pool, pool));
451   SVN_TEST_ASSERT(status == svn_wc__db_status_not_present);
452 
453   /* Test: incomplete presence. */
454   SVN_ERR(svn_wc__db_base_get_info(
455             &status, NULL, NULL,
456             NULL, NULL, NULL,
457             NULL, NULL, NULL,
458             NULL, NULL, NULL,
459             NULL, NULL, NULL, NULL,
460             db, svn_dirent_join(local_abspath, "E", pool),
461             pool, pool));
462   SVN_TEST_ASSERT(status == svn_wc__db_status_incomplete);
463 
464   /* Test: SHA1 checksum. */
465   SVN_ERR(svn_wc__db_base_get_info(
466             NULL, NULL, NULL,
467             NULL, NULL, NULL,
468             NULL, NULL, NULL,
469             NULL, &checksum, NULL,
470             NULL, NULL, NULL, NULL,
471             db, svn_dirent_join(local_abspath, "F", pool),
472             pool, pool));
473   SVN_TEST_STRING_ASSERT(SHA1_1,
474                          svn_checksum_to_cstring(checksum, pool));
475 
476   /* Test: alternate repository (switched file). */
477   SVN_ERR(svn_wc__db_base_get_info(
478             NULL, NULL, NULL,
479             &repos_relpath, &repos_root_url, &repos_uuid,
480             &changed_rev, &changed_date, &changed_author,
481             NULL, NULL, NULL,
482             NULL, NULL, NULL, NULL,
483             db, svn_dirent_join(local_abspath, "G", pool),
484             pool, pool));
485   SVN_TEST_STRING_ASSERT(repos_relpath, "G-alt");
486   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_TWO);
487   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_TWO);
488   SVN_TEST_ASSERT(changed_rev == 2);
489   SVN_TEST_ASSERT(changed_date == TIME_2a);
490   SVN_TEST_STRING_ASSERT(changed_author, AUTHOR_2);
491 
492   /* Test: symlink target. */
493   SVN_ERR(svn_wc__db_base_get_info(
494             NULL, NULL, NULL,
495             NULL, NULL, NULL,
496             NULL, NULL, NULL,
497             NULL, &checksum, &target,
498             NULL, NULL, NULL, NULL,
499             db, svn_dirent_join(local_abspath, "H", pool),
500             pool, pool));
501   SVN_TEST_ASSERT(checksum == NULL);
502   SVN_TEST_STRING_ASSERT(target, "H-target");
503 
504   /* Test: missing node. */
505   err = svn_wc__db_base_get_info(
506             NULL, NULL, NULL,
507             NULL, NULL, NULL,
508             NULL, NULL, NULL,
509             NULL, NULL, NULL,
510             NULL, NULL, NULL, NULL,
511             db, svn_dirent_join(local_abspath, "missing-file", pool),
512             pool, pool);
513   SVN_TEST_ASSERT_ERROR(err, SVN_ERR_WC_PATH_NOT_FOUND);
514 
515   return SVN_NO_ERROR;
516 }
517 
518 
519 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)520 validate_node(svn_wc__db_t *db,
521               const char *local_abspath,
522               const char *relpath,
523               svn_node_kind_t expected_kind,
524               svn_wc__db_status_t expected_status,
525               apr_pool_t *scratch_pool)
526 {
527   const char *path = svn_dirent_join(local_abspath, relpath, scratch_pool);
528   svn_node_kind_t kind;
529   svn_wc__db_status_t status;
530   apr_hash_t *props;
531   const svn_string_t *value;
532 
533   SVN_ERR(svn_wc__db_base_get_info(
534             &status, &kind, NULL,
535             NULL, NULL, NULL,
536             NULL, NULL, NULL,
537             NULL, NULL, NULL,
538             NULL, NULL, NULL, NULL,
539             db, path,
540             scratch_pool, scratch_pool));
541   SVN_TEST_ASSERT(kind == expected_kind);
542   SVN_TEST_ASSERT(status == expected_status);
543 
544   switch (status)
545     {
546     case svn_wc__db_status_server_excluded:
547     case svn_wc__db_status_excluded:
548     case svn_wc__db_status_incomplete:
549     case svn_wc__db_status_not_present:
550       /* Our tests aren't setting properties on these node types, so
551          short-circuit examination of name/value pairs, to avoid having
552          to handle the error from svn_wc__db_base_get_props(). */
553       return SVN_NO_ERROR;
554     default:
555       break; /* Fall through */
556     }
557 
558   SVN_ERR(svn_wc__db_base_get_props(&props, db, path,
559                                     scratch_pool, scratch_pool));
560 
561   SVN_TEST_ASSERT(props != NULL);
562 
563   value = apr_hash_get(props, "p1", APR_HASH_KEY_STRING);
564   SVN_TEST_STRING_ASSERT(value->data, "v1");
565 
566   value = apr_hash_get(props, "for-file", APR_HASH_KEY_STRING);
567   SVN_TEST_STRING_ASSERT(value->data, relpath);
568 
569   SVN_ERR(svn_wc__db_read_props(&props, db, path,
570                                 scratch_pool, scratch_pool));
571   SVN_TEST_ASSERT(props != NULL);
572   value = apr_hash_get(props, "p1", APR_HASH_KEY_STRING);
573   SVN_TEST_STRING_ASSERT(value->data, "v1");
574 
575   SVN_ERR(svn_wc__db_read_pristine_props(&props, db, path,
576                                          scratch_pool, scratch_pool));
577   SVN_TEST_ASSERT(props != NULL);
578   value = apr_hash_get(props, "p1", APR_HASH_KEY_STRING);
579   SVN_TEST_STRING_ASSERT(value->data, "v1");
580 
581   /* Now add a property value and read it back (all on actual) */
582   {
583     apr_hash_t *actual_props = apr_hash_copy(scratch_pool, props);
584     apr_hash_set(actual_props, "p999", APR_HASH_KEY_STRING, value);
585     SVN_ERR(svn_wc__db_op_set_props(db, path, actual_props, FALSE,
586                                     NULL, NULL, scratch_pool));
587     SVN_ERR(svn_wc__db_read_props(&props, db, path,
588                                   scratch_pool, scratch_pool));
589     SVN_TEST_ASSERT(props != NULL);
590     value = apr_hash_get(props, "p999", APR_HASH_KEY_STRING);
591     SVN_TEST_STRING_ASSERT(value->data, "v1");
592   }
593 
594   return SVN_NO_ERROR;
595 }
596 
597 
598 static svn_error_t *
test_inserting_nodes(apr_pool_t * pool)599 test_inserting_nodes(apr_pool_t *pool)
600 {
601   const char *local_abspath;
602   svn_checksum_t *checksum;
603   svn_wc__db_t *db;
604   apr_hash_t *props;
605   const apr_array_header_t *children;
606 
607   SVN_ERR(create_open(&db, &local_abspath, "test_insert_nodes", pool));
608 
609   props = apr_hash_make(pool);
610   set_prop(props, "p1", "v1", pool);
611 
612   children = svn_cstring_split("N-a N-b N-c", " ", FALSE, pool);
613 
614   SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, SHA1_1, pool));
615 
616   /* Create a new directory and several child nodes. */
617   set_prop(props, "for-file", "N", pool);
618   SVN_ERR(svn_wc__db_base_add_directory(
619             db, svn_dirent_join(local_abspath, "N", pool),
620             local_abspath,
621             "N", ROOT_ONE, UUID_ONE, 3,
622             props,
623             1, TIME_1a, AUTHOR_1,
624             children, svn_depth_infinity,
625             NULL, FALSE, NULL, NULL, NULL, NULL,
626             pool));
627 
628   /* Replace an incomplete node with a file node. */
629   set_prop(props, "for-file", "N/N-a", pool);
630   SVN_ERR(svn_wc__db_base_add_file(
631             db, svn_dirent_join(local_abspath, "N/N-a", pool),
632             local_abspath,
633             "N/N-a", ROOT_ONE, UUID_ONE, 3,
634             props,
635             1, TIME_1a, AUTHOR_1,
636             checksum,
637             NULL, FALSE, FALSE, NULL, NULL, FALSE, FALSE,
638             NULL, NULL,
639             pool));
640 
641   /* Create a new symlink node. */
642   set_prop(props, "for-file", "O", pool);
643   SVN_ERR(svn_wc__db_base_add_symlink(
644             db, svn_dirent_join(local_abspath, "O", pool),
645             local_abspath,
646             "O", ROOT_ONE, UUID_ONE, 3,
647             props,
648             1, TIME_1a, AUTHOR_1,
649             "O-target",
650             NULL, FALSE, FALSE, NULL, NULL, FALSE, FALSE,
651             NULL, NULL,
652             pool));
653 
654   /* Replace an incomplete node with an server-excluded file node. */
655   SVN_ERR(svn_wc__db_base_add_excluded_node(
656             db, svn_dirent_join(local_abspath, "N/N-b", pool),
657             "N/N-b", ROOT_ONE, UUID_ONE, 3,
658             svn_node_file, svn_wc__db_status_server_excluded,
659             NULL, NULL,
660             pool));
661 
662   /* Create a new excluded directory node. */
663   SVN_ERR(svn_wc__db_base_add_excluded_node(
664             db, svn_dirent_join(local_abspath, "P", pool),
665             "P", ROOT_ONE, UUID_ONE, 3,
666             svn_node_dir, svn_wc__db_status_excluded,
667             NULL, NULL,
668             pool));
669 
670   /* Create a new not-present symlink node. */
671   SVN_ERR(svn_wc__db_base_add_not_present_node(
672             db, svn_dirent_join(local_abspath, "Q", pool),
673             "Q", ROOT_ONE, UUID_ONE, 3,
674             svn_node_symlink,
675             NULL, NULL,
676             pool));
677 
678   /* Create a new server-excluded unknown-kind node. */
679   SVN_ERR(svn_wc__db_base_add_excluded_node(
680             db, svn_dirent_join(local_abspath, "R", pool),
681             "R", ROOT_ONE, UUID_ONE, 3,
682             svn_node_unknown, svn_wc__db_status_server_excluded,
683             NULL, NULL,
684             pool));
685 
686 
687   /* Are all the nodes where we expect them to be? */
688   SVN_ERR(validate_node(db, local_abspath, "N",
689                         svn_node_dir, svn_wc__db_status_normal,
690                         pool));
691   SVN_ERR(validate_node(db, local_abspath, "N/N-a",
692                         svn_node_file, svn_wc__db_status_normal,
693                         pool));
694   SVN_ERR(validate_node(db, local_abspath, "N/N-b",
695                         svn_node_file,
696                         svn_wc__db_status_server_excluded,
697                         pool));
698   SVN_ERR(validate_node(db, local_abspath, "N/N-c",
699                         svn_node_unknown, svn_wc__db_status_incomplete,
700                         pool));
701   SVN_ERR(validate_node(db, local_abspath, "O",
702                         svn_node_symlink, svn_wc__db_status_normal,
703                         pool));
704   SVN_ERR(validate_node(db, local_abspath, "P",
705                         svn_node_dir, svn_wc__db_status_excluded,
706                         pool));
707   SVN_ERR(validate_node(db, local_abspath, "Q",
708                         svn_node_symlink, svn_wc__db_status_not_present,
709                         pool));
710   SVN_ERR(validate_node(db, local_abspath, "R",
711                         svn_node_unknown,
712                         svn_wc__db_status_server_excluded,
713                         pool));
714 
715   /* ### do we need to test any attributes of the node? */
716 
717   /* ### yes: test the repos inheritance stuff (at least) */
718 
719   return SVN_NO_ERROR;
720 }
721 
722 
723 static svn_error_t *
test_children(apr_pool_t * pool)724 test_children(apr_pool_t *pool)
725 {
726   const char *local_abspath;
727   svn_wc__db_t *db;
728   const apr_array_header_t *children;
729   int i;
730 
731   SVN_ERR(create_open(&db, &local_abspath, "test_children", pool));
732 
733   SVN_ERR(svn_wc__db_base_get_children(&children,
734                                        db, local_abspath,
735                                        pool, pool));
736   SVN_TEST_ASSERT(children->nelts == 13);
737   for (i = children->nelts; i--; )
738     {
739       const char *name = APR_ARRAY_IDX(children, i, const char *);
740 
741       if (strcmp(name, "moved") == 0
742           || strcmp(name, "other") == 0)
743         {
744           continue;
745         }
746 
747       SVN_TEST_ASSERT(strlen(name) == 1);
748       /* ### check the actual values */
749     }
750 
751   SVN_ERR(svn_wc__db_read_children(&children,
752                                    db, local_abspath,
753                                    pool, pool));
754   SVN_TEST_ASSERT(children->nelts == 14);
755   for (i = children->nelts; i--; )
756     {
757       const char *name = APR_ARRAY_IDX(children, i, const char *);
758 
759       if (strcmp(name, "moved") == 0
760           || strcmp(name, "other") == 0)
761         {
762           continue;
763         }
764 
765       SVN_TEST_ASSERT(strlen(name) == 1);
766       /* ### check the actual values */
767     }
768 
769   /* ### insert some more children. replace some nodes. check values. */
770 
771   return SVN_NO_ERROR;
772 }
773 
774 
775 static svn_error_t *
test_working_info(apr_pool_t * pool)776 test_working_info(apr_pool_t *pool)
777 {
778   const char *local_abspath;
779   svn_node_kind_t kind;
780   svn_wc__db_status_t status;
781   svn_revnum_t revision;
782   const char *repos_relpath;
783   const char *repos_root_url;
784   const char *repos_uuid;
785   svn_revnum_t changed_rev;
786   apr_time_t changed_date;
787   const char *changed_author;
788   apr_time_t recorded_time;
789   svn_depth_t depth;
790   const svn_checksum_t *checksum;
791   svn_filesize_t recorded_size;
792   const char *target;
793   const char *changelist;
794   const char *original_repos_relpath;
795   const char *original_root_url;
796   const char *original_uuid;
797   svn_revnum_t original_revnum;
798   svn_boolean_t op_root;
799   svn_boolean_t had_props;
800   svn_boolean_t props_mod;
801   svn_boolean_t have_base;
802   svn_boolean_t have_more_work;
803   svn_boolean_t have_work;
804   svn_boolean_t conflicted;
805   svn_wc__db_lock_t *lock;
806   svn_wc__db_t *db;
807 
808   SVN_ERR(create_open(&db, &local_abspath, "test_working_info", pool));
809 
810   /* Test: basic fetching of data. */
811   SVN_ERR(svn_wc__db_read_info(
812             &status, &kind, &revision,
813             &repos_relpath, &repos_root_url, &repos_uuid,
814             &changed_rev, &changed_date, &changed_author,
815             &depth, &checksum, &target, &original_repos_relpath,
816             &original_root_url, &original_uuid, &original_revnum,
817             &lock, &recorded_size, &recorded_time, &changelist,
818             &conflicted, &op_root, &had_props, &props_mod,
819             &have_base, &have_more_work, &have_work,
820             db, svn_dirent_join(local_abspath, "I", pool),
821             pool, pool));
822   SVN_TEST_ASSERT(status == svn_wc__db_status_added);
823   SVN_TEST_ASSERT(kind == svn_node_dir);
824   SVN_TEST_ASSERT(revision == SVN_INVALID_REVNUM);
825   SVN_TEST_ASSERT(repos_relpath == NULL);
826   SVN_TEST_ASSERT(repos_root_url == NULL);
827   SVN_TEST_ASSERT(repos_uuid == NULL);
828   SVN_TEST_ASSERT(changed_rev == 2);
829   SVN_TEST_ASSERT(changed_date == TIME_2a);
830   SVN_TEST_STRING_ASSERT(changed_author, AUTHOR_2);
831   SVN_TEST_ASSERT(depth == svn_depth_immediates);
832   SVN_TEST_ASSERT(checksum == NULL);
833   SVN_TEST_ASSERT(recorded_size == SVN_INVALID_FILESIZE);
834   SVN_TEST_ASSERT(target == NULL);
835   SVN_TEST_STRING_ASSERT(changelist, NULL);
836   SVN_TEST_STRING_ASSERT(original_repos_relpath, "some/dir");
837   SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
838   SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
839   SVN_TEST_ASSERT(original_revnum == 2);
840   SVN_TEST_ASSERT(!had_props);
841   SVN_TEST_ASSERT(!props_mod);
842   SVN_TEST_ASSERT(have_base);
843   /* SVN_TEST_ASSERT(have_more_work...); */
844   SVN_TEST_ASSERT(have_work);
845   SVN_TEST_ASSERT(!conflicted);
846   SVN_TEST_ASSERT(lock == NULL);
847   /* SVN_TEST_ASSERT(last_mod_time...); */
848   /* SVN_TEST_ASSERT(op_root...); */
849 
850 
851   /* ### we need a hojillion more tests in here. I just want to get this
852      ### round checked in, so I'm skipping more tests at this point.  */
853   SVN_ERR(svn_wc__db_read_info(
854             &status, &kind, &revision,
855             &repos_relpath, &repos_root_url, &repos_uuid,
856             &changed_rev, &changed_date, &changed_author,
857             &depth, &checksum, &target, &original_repos_relpath,
858             &original_root_url, &original_uuid, &original_revnum,
859             &lock, &recorded_size, &recorded_time, &changelist,
860             &conflicted, &op_root, &had_props, &props_mod,
861             &have_base, &have_more_work, &have_work,
862             db, svn_dirent_join(local_abspath, "A", pool),
863             pool, pool));
864   SVN_TEST_ASSERT(status == svn_wc__db_status_normal);
865   SVN_TEST_ASSERT(kind == svn_node_file);
866   SVN_TEST_STRING_ASSERT(changelist, "changelist");
867   SVN_TEST_ASSERT(revision == 1);
868   SVN_TEST_STRING_ASSERT(repos_relpath, "A");
869   SVN_TEST_STRING_ASSERT(repos_root_url, "http://example.com/one");
870   SVN_TEST_STRING_ASSERT(repos_uuid, "uuid1");
871   SVN_TEST_ASSERT(changed_rev == 1);
872   SVN_TEST_ASSERT(changed_date == TIME_1a);
873   SVN_TEST_STRING_ASSERT(changed_author, AUTHOR_1);
874   SVN_TEST_ASSERT(depth == svn_depth_unknown);
875   SVN_TEST_ASSERT(checksum != NULL);
876   SVN_TEST_ASSERT(recorded_size == 10);
877   SVN_TEST_ASSERT(target == NULL);
878   return SVN_NO_ERROR;
879 }
880 
881 
882 static svn_error_t *
test_pdh(apr_pool_t * pool)883 test_pdh(apr_pool_t *pool)
884 {
885   const char *local_abspath;
886   svn_wc__db_t *db;
887 
888   SVN_ERR(create_open(&db, &local_abspath, "test_pdh", pool));
889 
890   /* NOTE: this test doesn't do anything apparent -- it simply exercises
891      some internal functionality of wc_db.  This is a handy driver for
892      debugging wc_db to ensure it manages per-directory handles properly.  */
893 
894   SVN_ERR(svn_wc__db_base_add_excluded_node(
895             db, svn_dirent_join(local_abspath, "sub", pool),
896             "sub", ROOT_ONE, UUID_ONE, 1,
897             svn_node_file, svn_wc__db_status_server_excluded,
898             NULL, NULL,
899             pool));
900 
901   SVN_ERR(svn_wc__db_base_add_directory(
902             db, svn_dirent_join(local_abspath, "sub2", pool),
903             local_abspath, "sub2", ROOT_ONE, UUID_ONE, 1,
904             apr_hash_make(pool), 1, 1, "me", NULL,
905             svn_depth_infinity, NULL, FALSE, NULL, NULL,
906             NULL, NULL, pool));
907 
908   SVN_ERR(svn_wc__db_base_add_excluded_node(
909             db, svn_dirent_join(local_abspath, "sub2/A", pool),
910             "sub2/A", ROOT_ONE, UUID_ONE, 1,
911             svn_node_file, svn_wc__db_status_server_excluded,
912             NULL, NULL,
913             pool));
914 
915   return SVN_NO_ERROR;
916 }
917 
918 
919 static svn_error_t *
test_scan_addition(apr_pool_t * pool)920 test_scan_addition(apr_pool_t *pool)
921 {
922   const char *local_abspath;
923   svn_wc__db_t *db;
924   svn_wc__db_status_t status;
925   const char *op_root_abspath;
926   const char *repos_relpath;
927   const char *repos_root_url;
928   const char *repos_uuid;
929   const char *original_repos_relpath;
930   const char *original_root_url;
931   const char *original_uuid;
932   svn_revnum_t original_revision;
933   const char *moved_from_abspath;
934   const char *move_op_root_abspath;
935   const char *move_op_root_src;
936   const char *delete_op_root_abspath;
937 
938   SVN_ERR(create_open(&db, &local_abspath, "test_scan_addition", pool));
939 
940   /* Simple addition of a directory. */
941   SVN_ERR(svn_wc__db_scan_addition(
942             &status, &op_root_abspath,
943             &repos_relpath, &repos_root_url, &repos_uuid,
944             &original_repos_relpath, &original_root_url, &original_uuid,
945             &original_revision,
946             db, svn_dirent_join(local_abspath, "J", pool),
947             pool, pool));
948   SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
949   SVN_ERR(validate_abspath(local_abspath, "J", op_root_abspath, pool));
950   SVN_TEST_STRING_ASSERT(repos_relpath, "J");
951   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
952   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
953   SVN_TEST_STRING_ASSERT(original_repos_relpath, "q");
954   SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
955   SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
956   SVN_TEST_ASSERT(original_revision == 2);
957 
958   /* Simple copy (affects how scan-up is started). */
959   SVN_ERR(svn_wc__db_scan_addition(
960             &status, &op_root_abspath,
961             &repos_relpath, &repos_root_url, &repos_uuid,
962             &original_repos_relpath, &original_root_url, &original_uuid,
963             &original_revision,
964             db, svn_dirent_join(local_abspath, "J/J-a", pool),
965             pool, pool));
966   SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
967   SVN_ERR(validate_abspath(local_abspath, "J", op_root_abspath, pool));
968   SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-a");
969   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
970   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
971   SVN_TEST_STRING_ASSERT(original_repos_relpath, "q");
972   SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
973   SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
974   SVN_TEST_ASSERT(original_revision == 2);
975 
976   /* Node was moved here. */
977   SVN_ERR(svn_wc__db_scan_addition(
978             &status, &op_root_abspath,
979             &repos_relpath, &repos_root_url, &repos_uuid,
980             &original_repos_relpath, &original_root_url, &original_uuid,
981             &original_revision,
982             db, svn_dirent_join(local_abspath, "J/J-d", pool),
983             pool, pool));
984   SVN_ERR(svn_wc__db_scan_moved(
985             &moved_from_abspath,
986             &move_op_root_abspath,
987             &move_op_root_src,
988             &delete_op_root_abspath,
989             db, svn_dirent_join(local_abspath, "J/J-d", pool),
990             pool, pool));
991   SVN_TEST_ASSERT(status == svn_wc__db_status_moved_here);
992   SVN_ERR(validate_abspath(local_abspath, "J/J-d",
993                                    op_root_abspath, pool));
994   SVN_ERR(validate_abspath(local_abspath, "moved/file",
995                                    moved_from_abspath, pool));
996   SVN_ERR(validate_abspath(local_abspath, "J/J-d",
997                                    move_op_root_abspath, pool));
998   SVN_ERR(validate_abspath(local_abspath, "moved/file",
999                                    move_op_root_src, pool));
1000   SVN_ERR(validate_abspath(local_abspath, "moved/file",
1001                                    delete_op_root_abspath, pool));
1002   SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-d");
1003   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
1004   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
1005   SVN_TEST_STRING_ASSERT(original_repos_relpath, "moved/file");
1006   SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
1007   SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
1008   SVN_TEST_ASSERT(original_revision == 2);
1009 
1010   /* Check root of a copy. */
1011   SVN_ERR(svn_wc__db_scan_addition(
1012             &status, &op_root_abspath,
1013             &repos_relpath, &repos_root_url, &repos_uuid,
1014             &original_repos_relpath, &original_root_url, &original_uuid,
1015             &original_revision,
1016             db, svn_dirent_join(local_abspath, "J/J-b", pool),
1017             pool, pool));
1018   SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
1019   SVN_ERR(validate_abspath(local_abspath, "J",
1020                                    op_root_abspath, pool));
1021   SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-b");
1022   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
1023   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
1024   SVN_TEST_STRING_ASSERT(original_repos_relpath, "q");
1025   SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
1026   SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
1027   SVN_TEST_ASSERT(original_revision == 2);
1028 
1029   /* Ignore parent copy. Use copy closest to target.  */
1030   SVN_ERR(svn_wc__db_scan_addition(
1031             &status, &op_root_abspath,
1032             &repos_relpath, &repos_root_url, &repos_uuid,
1033             &original_repos_relpath, &original_root_url, &original_uuid,
1034             &original_revision,
1035             db, svn_dirent_join(local_abspath, "J/J-b/J-b-a", pool),
1036             pool, pool));
1037   SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
1038   SVN_ERR(validate_abspath(local_abspath, "J/J-b/J-b-a",
1039                                    op_root_abspath, pool));
1040   SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-b/J-b-a");
1041   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
1042   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
1043   SVN_TEST_STRING_ASSERT(original_repos_relpath, "another/dir");
1044   SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
1045   SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
1046   SVN_TEST_ASSERT(original_revision == 2);
1047 
1048   /* Inherit parent copy. */
1049   SVN_ERR(svn_wc__db_scan_addition(
1050             &status, &op_root_abspath,
1051             &repos_relpath, &repos_root_url, &repos_uuid,
1052             &original_repos_relpath, &original_root_url, &original_uuid,
1053             &original_revision,
1054             db, svn_dirent_join(local_abspath, "J/J-b/J-b-b", pool),
1055             pool, pool));
1056   SVN_TEST_ASSERT(status == svn_wc__db_status_copied);
1057   SVN_ERR(validate_abspath(local_abspath, "J",
1058                                    op_root_abspath, pool));
1059   SVN_TEST_STRING_ASSERT(repos_relpath, "J/J-b/J-b-b");
1060   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
1061   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
1062   SVN_TEST_STRING_ASSERT(original_repos_relpath, "q");
1063   SVN_TEST_STRING_ASSERT(original_root_url, ROOT_TWO);
1064   SVN_TEST_STRING_ASSERT(original_uuid, UUID_TWO);
1065   SVN_TEST_ASSERT(original_revision == 2);
1066 
1067   return SVN_NO_ERROR;
1068 }
1069 
1070 
1071 static svn_error_t *
test_scan_deletion(apr_pool_t * pool)1072 test_scan_deletion(apr_pool_t *pool)
1073 {
1074   const char *local_abspath;
1075   svn_wc__db_t *db;
1076   const char *base_del_abspath;
1077   const char *work_del_abspath;
1078   const char *moved_to_abspath;
1079   const char *copy_op_root_abspath;
1080 
1081   SVN_ERR(create_open(&db, &local_abspath, "test_scan_deletion", pool));
1082 
1083   /* Node was moved elsewhere. */
1084   SVN_ERR(svn_wc__db_scan_deletion(
1085             &base_del_abspath,
1086             &moved_to_abspath,
1087             &work_del_abspath,
1088             &copy_op_root_abspath,
1089             db, svn_dirent_join(local_abspath, "J/J-e", pool),
1090             pool, pool));
1091   SVN_ERR(validate_abspath(local_abspath, "J",
1092                                    base_del_abspath, pool));
1093   SVN_ERR(validate_abspath(local_abspath, "other/place",
1094                                    moved_to_abspath, pool));
1095   SVN_ERR(validate_abspath(local_abspath, "J/J-e",
1096                                    work_del_abspath, pool));
1097   SVN_ERR(validate_abspath(local_abspath, "other/place",
1098                                    copy_op_root_abspath, pool));
1099 
1100   /* Node was moved elsewhere (child of operation root). */
1101   SVN_ERR(svn_wc__db_scan_deletion(
1102             &base_del_abspath,
1103             &moved_to_abspath,
1104             &work_del_abspath,
1105             &copy_op_root_abspath,
1106             db, svn_dirent_join(local_abspath, "J/J-e/J-e-a", pool),
1107             pool, pool));
1108   SVN_ERR(validate_abspath(local_abspath, "J",
1109                                    base_del_abspath, pool));
1110   SVN_ERR(validate_abspath(local_abspath, "other/place/J-e-a",
1111                                    moved_to_abspath, pool));
1112   SVN_ERR(validate_abspath(local_abspath, "J/J-e",
1113                                    work_del_abspath, pool));
1114   SVN_ERR(validate_abspath(local_abspath, "other/place",
1115                                    copy_op_root_abspath, pool));
1116 
1117   /* Root of delete. Parent is a WORKING node. */
1118   SVN_ERR(svn_wc__db_scan_deletion(
1119             &base_del_abspath,
1120             &moved_to_abspath,
1121             &work_del_abspath,
1122             NULL,
1123             db, svn_dirent_join(local_abspath, "J/J-c", pool),
1124             pool, pool));
1125   /* Implicit delete of "J" (via replacement).  */
1126   SVN_ERR(validate_abspath(local_abspath, "J",
1127                                    base_del_abspath, pool));
1128   SVN_TEST_ASSERT(moved_to_abspath == NULL);
1129   SVN_ERR(validate_abspath(local_abspath, "J/J-c",
1130                                    work_del_abspath, pool));
1131 
1132   /* Child of a deleted root. */
1133   SVN_ERR(svn_wc__db_scan_deletion(
1134             &base_del_abspath,
1135             &moved_to_abspath,
1136             &work_del_abspath,
1137             NULL,
1138             db, svn_dirent_join(local_abspath, "J/J-c/J-c-a", pool),
1139             pool, pool));
1140   /* Implicit delete of "J" (via replacement).  */
1141   SVN_ERR(validate_abspath(local_abspath, "J",
1142                                    base_del_abspath, pool));
1143   SVN_TEST_ASSERT(moved_to_abspath == NULL);
1144   SVN_ERR(validate_abspath(local_abspath, "J/J-c",
1145                                    work_del_abspath, pool));
1146 
1147   /* Base-deleted tree extending past deleted WORKING subtree.  */
1148   SVN_ERR(svn_wc__db_scan_deletion(
1149             &base_del_abspath,
1150             &moved_to_abspath,
1151             &work_del_abspath,
1152             NULL,
1153             db, svn_dirent_join(local_abspath, "J/J-e/J-e-b/Jeba", pool),
1154             pool, pool));
1155   /* ### I don't understand this.  "J/J-e/J-e-b/Jeba" is a deleted
1156      base node that is not overlayed by the replacement rooted at "J".
1157      Why does base_del_abspath refer to "J-e"?  */
1158   SVN_ERR(validate_abspath(local_abspath, "J",
1159                                    base_del_abspath, pool));
1160   SVN_ERR(validate_abspath(local_abspath, "other/place/J-e-b/Jeba",
1161                                    moved_to_abspath, pool));
1162   SVN_TEST_STRING_ASSERT(work_del_abspath, NULL);
1163 
1164   /* Base-deleted tree extending past added WORKING tree.  */
1165   SVN_ERR(svn_wc__db_scan_deletion(
1166             &base_del_abspath,
1167             &moved_to_abspath,
1168             &work_del_abspath,
1169             NULL,
1170             db, svn_dirent_join(local_abspath, "J/J-f/J-f-a", pool),
1171             pool, pool));
1172   /* Implicit delete of "J" (via replacement).  */
1173   SVN_ERR(validate_abspath(local_abspath, "J",
1174                                    base_del_abspath, pool));
1175   SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL);
1176   SVN_TEST_STRING_ASSERT(work_del_abspath, NULL);
1177 
1178   /* Root of delete. Parent is a BASE node. */
1179   SVN_ERR(svn_wc__db_scan_deletion(
1180             &base_del_abspath,
1181             &moved_to_abspath,
1182             &work_del_abspath,
1183             NULL,
1184             db, svn_dirent_join(local_abspath, "K", pool),
1185             pool, pool));
1186   SVN_ERR(validate_abspath(local_abspath, "K",
1187                                    base_del_abspath, pool));
1188   SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL);
1189   SVN_TEST_STRING_ASSERT(work_del_abspath, NULL);
1190 
1191   /* Base-deleted tree. Start below root.  */
1192   SVN_ERR(svn_wc__db_scan_deletion(
1193             &base_del_abspath,
1194             &moved_to_abspath,
1195             &work_del_abspath,
1196             NULL,
1197             db, svn_dirent_join(local_abspath, "K/K-a", pool),
1198             pool, pool));
1199   SVN_ERR(validate_abspath(local_abspath, "K",
1200                                    base_del_abspath, pool));
1201   SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL);
1202   SVN_TEST_STRING_ASSERT(work_del_abspath, NULL);
1203 
1204   /* Base-deleted tree via move.  */
1205   SVN_ERR(svn_wc__db_scan_deletion(
1206             &base_del_abspath,
1207             &moved_to_abspath,
1208             &work_del_abspath,
1209             &copy_op_root_abspath,
1210             db, svn_dirent_join(local_abspath, "K/K-b", pool),
1211             pool, pool));
1212   SVN_ERR(validate_abspath(local_abspath, "K",
1213                                    base_del_abspath, pool));
1214   SVN_ERR(validate_abspath(local_abspath, "moved/away",
1215                                    moved_to_abspath, pool));
1216   SVN_ERR(validate_abspath(local_abspath, "moved/away",
1217                                    copy_op_root_abspath, pool));
1218   SVN_TEST_STRING_ASSERT(work_del_abspath, NULL);
1219 
1220   /* Subtree deletion of added tree. Start at child.  */
1221   SVN_ERR(svn_wc__db_scan_deletion(
1222             &base_del_abspath,
1223             &moved_to_abspath,
1224             &work_del_abspath,
1225             NULL,
1226             db, svn_dirent_join(local_abspath, "L/L-a/L-a-a", pool),
1227             pool, pool));
1228   SVN_TEST_STRING_ASSERT(base_del_abspath, NULL);
1229   SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL);
1230   SVN_ERR(validate_abspath(local_abspath, "L/L-a",
1231                                    work_del_abspath, pool));
1232 
1233   /* Subtree deletion of added tree. Start at root.  */
1234   SVN_ERR(svn_wc__db_scan_deletion(
1235             &base_del_abspath,
1236             &moved_to_abspath,
1237             &work_del_abspath,
1238             NULL,
1239             db, svn_dirent_join(local_abspath, "L/L-a", pool),
1240             pool, pool));
1241   SVN_TEST_STRING_ASSERT(base_del_abspath, NULL);
1242   SVN_TEST_STRING_ASSERT(moved_to_abspath, NULL);
1243   SVN_ERR(validate_abspath(local_abspath, "L/L-a",
1244                                    work_del_abspath, pool));
1245 
1246   return SVN_NO_ERROR;
1247 }
1248 
1249 
1250 static svn_error_t *
test_global_relocate(apr_pool_t * pool)1251 test_global_relocate(apr_pool_t *pool)
1252 {
1253   const char *local_abspath;
1254   svn_wc__db_t *db;
1255   const char *repos_relpath;
1256   const char *repos_root_url;
1257   const char *repos_uuid;
1258 
1259   SVN_ERR(create_open(&db, &local_abspath, "test_global_relocate", pool));
1260 
1261   /* Initial sanity check. */
1262   SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL,
1263                                &repos_relpath, &repos_root_url, &repos_uuid,
1264                                NULL, NULL, NULL, NULL,
1265                                NULL, NULL, NULL, NULL,
1266                                NULL, NULL, NULL, NULL, NULL,
1267                                NULL, NULL, NULL, NULL, NULL,
1268                                NULL, NULL, NULL,
1269                                db, local_abspath,
1270                                pool, pool));
1271 
1272   SVN_TEST_STRING_ASSERT(repos_relpath, "");
1273   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_ONE);
1274   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
1275 
1276   /* Test relocating to a repos not existent in the db */
1277   SVN_ERR(svn_wc__db_global_relocate(db, local_abspath, ROOT_THREE, pool));
1278   SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL,
1279                                &repos_relpath, &repos_root_url, &repos_uuid,
1280                                NULL, NULL, NULL, NULL,
1281                                NULL, NULL, NULL, NULL,
1282                                NULL, NULL, NULL, NULL, NULL,
1283                                NULL, NULL, NULL, NULL, NULL,
1284                                NULL, NULL, NULL,
1285                                db, local_abspath,
1286                                pool, pool));
1287   SVN_TEST_STRING_ASSERT(repos_relpath, "");
1288   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_THREE);
1289   /* The UUID should still be the same. */
1290   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
1291 
1292   /* While we're at it, let's see if the children have been relocated, too. */
1293   SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL,
1294                                &repos_relpath, &repos_root_url, &repos_uuid,
1295                                NULL, NULL, NULL, NULL,
1296                                NULL, NULL, NULL, NULL,
1297                                NULL, NULL, NULL, NULL, NULL,
1298                                NULL, NULL, NULL, NULL, NULL,
1299                                NULL, NULL, NULL,
1300                                db, svn_dirent_join(local_abspath, "F",
1301                                                    pool),
1302                                pool, pool));
1303   SVN_TEST_STRING_ASSERT(repos_relpath, "F");
1304   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_THREE);
1305   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_ONE);
1306 
1307   /* Alternate repository is not relocated. */
1308   SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL,
1309                                &repos_relpath, &repos_root_url, &repos_uuid,
1310                                NULL, NULL, NULL, NULL,
1311                                NULL, NULL, NULL, NULL,
1312                                NULL, NULL, NULL, NULL, NULL,
1313                                NULL, NULL, NULL, NULL, NULL,
1314                                NULL, NULL, NULL,
1315                                db, svn_dirent_join(local_abspath, "G",
1316                                                    pool),
1317                                pool, pool));
1318   SVN_TEST_STRING_ASSERT(repos_relpath, "G-alt");
1319   SVN_TEST_STRING_ASSERT(repos_root_url, ROOT_TWO);
1320   SVN_TEST_STRING_ASSERT(repos_uuid, UUID_TWO);
1321 
1322   return SVN_NO_ERROR;
1323 }
1324 
1325 
1326 static int
detect_work_item(const svn_skel_t * work_item)1327 detect_work_item(const svn_skel_t *work_item)
1328 {
1329   /* Test work items are a list with one integer atom as operation */
1330   if (!work_item->children)
1331     return -1;
1332   work_item = work_item->children;
1333 
1334   if (!work_item->is_atom || work_item->len != 1)
1335     return -1;
1336   return work_item->data[0] - '0';
1337 }
1338 
1339 
1340 static svn_error_t *
test_work_queue(apr_pool_t * pool)1341 test_work_queue(apr_pool_t *pool)
1342 {
1343   svn_wc__db_t *db;
1344   const char *local_abspath;
1345   svn_skel_t *work_item;
1346   int run_count[3] = { 4, 7, 2 };  /* run the work 13 times, total.  */
1347   int fetches = 0;
1348   apr_int64_t last_id = 0;
1349 
1350   SVN_ERR(create_open(&db, &local_abspath, "test_work_queue", pool));
1351 
1352   /* Create three work items.  */
1353   work_item = svn_skel__make_empty_list(pool);
1354   svn_skel__prepend_int(0, work_item, pool);
1355   SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, pool));
1356 
1357   work_item = svn_skel__make_empty_list(pool);
1358   svn_skel__prepend_int(1, work_item, pool);
1359   SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, pool));
1360 
1361   work_item = svn_skel__make_empty_list(pool);
1362   svn_skel__prepend_int(2, work_item, pool);
1363   SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, pool));
1364 
1365   while (TRUE)
1366     {
1367       apr_uint64_t id;
1368       int which;
1369 
1370       /* Fetch the next work item, or break when the work queue is empty.  */
1371       SVN_ERR(svn_wc__db_wq_fetch_next(&id, &work_item, db, local_abspath,
1372                                        last_id, pool, pool));
1373       if (work_item == NULL)
1374         break;
1375 
1376       /* Got one. We should never fetch work more than 13 times.  */
1377       ++fetches;
1378       SVN_TEST_ASSERT(fetches <= 13);
1379 
1380       /* Parse the work item to see which of the three we found.  */
1381       which = detect_work_item(work_item);
1382       SVN_TEST_ASSERT(which >= 0 && which <= 2);
1383 
1384       /* We should not see an item after we've run it enough times.
1385 
1386          Note: strictly speaking, "in the wild" a work item could remain
1387          after a call to wq_completed (ie. crash while that function was
1388          processing), but we don't really have a way to test that here.  */
1389       SVN_TEST_ASSERT(run_count[which] > 0);
1390 
1391       /* If we have run this particular item enough times, then go ahead
1392          and remove it from the work queue.  */
1393       if (--run_count[which] == 0)
1394         last_id = id;
1395       else
1396         last_id = 0;
1397     }
1398 
1399   /* Should have run precisely 13 work items.  */
1400   SVN_TEST_ASSERT(fetches == 13);
1401 
1402   return SVN_NO_ERROR;
1403 }
1404 
1405 static svn_error_t *
test_externals_store(apr_pool_t * pool)1406 test_externals_store(apr_pool_t *pool)
1407 {
1408   svn_wc__db_t *db;
1409   const char *local_abspath;
1410   svn_checksum_t *orig_checksum;
1411   const char *file_external_path;
1412   const char *dir_external_path;
1413   const char *subdir;
1414   apr_hash_t *props = apr_hash_make(pool);
1415   svn_string_t *value = svn_string_create("value-data", pool);
1416 
1417   apr_hash_set(props, "key", APR_HASH_KEY_STRING, value);
1418 
1419   SVN_ERR(create_open(&db, &local_abspath, "test_externals_store", pool));
1420 
1421   /* Directory I exists in the standard test db */
1422   subdir = svn_dirent_join(local_abspath, "I", pool);
1423 
1424   SVN_ERR(svn_checksum_parse_hex(&orig_checksum, svn_checksum_sha1, SHA1_1,
1425                                  pool));
1426 
1427   file_external_path = svn_dirent_join(subdir, "file-external", pool);
1428   dir_external_path = svn_dirent_join(subdir, "dir-external", pool);
1429 
1430   SVN_ERR(svn_wc__db_external_add_file(db,
1431                                        file_external_path,
1432                                        local_abspath /* wri_abspath */,
1433                                        "some/location",
1434                                        "svn://some-repos/svn",
1435                                        "not-a-uuid",
1436                                        12,
1437                                        props,
1438                                        NULL,
1439                                        10,
1440                                        987654,
1441                                        "somebody",
1442                                        orig_checksum,
1443                                        NULL,
1444                                        subdir,
1445                                        "some/new-location",
1446                                        90,
1447                                        12,
1448                                        FALSE, NULL,
1449                                        FALSE,
1450                                        NULL,
1451                                        NULL,
1452                                        pool));
1453 
1454   SVN_ERR(svn_wc__db_external_add_dir(db,
1455                                       dir_external_path,
1456                                       local_abspath /* wri_abspath */,
1457                                       "svn://other-repos/nsv",
1458                                       "no-uuid-either",
1459                                       subdir,
1460                                       "some/other-location",
1461                                       70,
1462                                       32,
1463                                       NULL,
1464                                       pool));
1465 
1466   {
1467     svn_wc__db_status_t status;
1468     svn_node_kind_t kind;
1469     const char *repos_root_url;
1470     const char *repos_uuid;
1471     const char *defining_abspath;
1472     const char *recorded_repos_relpath;
1473     svn_revnum_t recorded_peg_revision;
1474     svn_revnum_t recorded_revision;
1475 
1476     SVN_ERR(svn_wc__db_external_read(&status, &kind, &defining_abspath,
1477                                      &repos_root_url, &repos_uuid,
1478                                      &recorded_repos_relpath,
1479                                      &recorded_peg_revision,
1480                                      &recorded_revision,
1481                                      db, file_external_path, local_abspath,
1482                                      pool, pool));
1483 
1484     SVN_TEST_ASSERT(status == svn_wc__db_status_normal);
1485     SVN_TEST_ASSERT(kind == svn_node_file);
1486     SVN_TEST_STRING_ASSERT(repos_root_url, "svn://some-repos/svn");
1487     SVN_TEST_STRING_ASSERT(repos_uuid, "not-a-uuid");
1488     SVN_TEST_STRING_ASSERT(defining_abspath, subdir);
1489     SVN_TEST_STRING_ASSERT(recorded_repos_relpath, "some/new-location");
1490     SVN_TEST_ASSERT(recorded_peg_revision == 90);
1491     SVN_TEST_ASSERT(recorded_revision == 12);
1492 
1493     {
1494       apr_hash_t *new_props;
1495       svn_string_t *v;
1496 
1497       SVN_ERR(svn_wc__db_base_get_props(&new_props, db,
1498                                         file_external_path,
1499                                         pool, pool));
1500 
1501       SVN_TEST_ASSERT(new_props != NULL);
1502       v = apr_hash_get(new_props, "key", APR_HASH_KEY_STRING);
1503       SVN_TEST_ASSERT(v != NULL);
1504       SVN_TEST_STRING_ASSERT(v->data, "value-data");
1505     }
1506 
1507     SVN_ERR(svn_wc__db_external_read(&status, &kind, &defining_abspath,
1508                                      &repos_root_url, &repos_uuid,
1509                                      &recorded_repos_relpath,
1510                                      &recorded_peg_revision,
1511                                      &recorded_revision,
1512                                      db, dir_external_path, local_abspath,
1513                                      pool, pool));
1514 
1515     SVN_TEST_ASSERT(status == svn_wc__db_status_normal);
1516     SVN_TEST_ASSERT(kind == svn_node_dir);
1517     SVN_TEST_STRING_ASSERT(repos_root_url, "svn://other-repos/nsv");
1518     SVN_TEST_STRING_ASSERT(repos_uuid, "no-uuid-either");
1519     SVN_TEST_STRING_ASSERT(defining_abspath, subdir);
1520     SVN_TEST_STRING_ASSERT(recorded_repos_relpath, "some/other-location");
1521     SVN_TEST_ASSERT(recorded_peg_revision == 70);
1522     SVN_TEST_ASSERT(recorded_revision == 32);
1523   }
1524 
1525   return SVN_NO_ERROR;
1526 }
1527 
1528 static int max_threads = 2;
1529 
1530 static struct svn_test_descriptor_t test_funcs[] =
1531   {
1532     SVN_TEST_NULL,
1533     SVN_TEST_PASS2(test_getting_info,
1534                    "get information from wc.db"),
1535     SVN_TEST_PASS2(test_inserting_nodes,
1536                    "insert different nodes into wc.db"),
1537     SVN_TEST_PASS2(test_children,
1538                    "getting the list of BASE or WORKING children"),
1539     SVN_TEST_PASS2(test_working_info,
1540                    "reading information about the WORKING tree"),
1541     SVN_TEST_PASS2(test_pdh,
1542                    "creation of per-directory handles"),
1543     SVN_TEST_PASS2(test_scan_addition,
1544                    "scanning added working nodes"),
1545     SVN_TEST_PASS2(test_scan_deletion,
1546                    "deletion introspection functions"),
1547     SVN_TEST_PASS2(test_global_relocate,
1548                    "relocating a node"),
1549     SVN_TEST_PASS2(test_work_queue,
1550                    "work queue processing"),
1551     SVN_TEST_PASS2(test_externals_store,
1552                    "externals store"),
1553     SVN_TEST_NULL
1554   };
1555 
1556 SVN_TEST_MAIN
1557