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 ©_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 ©_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 ©_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