1 /*
2 * Regression tests for mtcc code in the libsvn_client library.
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 "svn_pools.h"
25 #include "svn_props.h"
26 #include "svn_client.h"
27 #include "private/svn_client_mtcc.h"
28
29 #include "../svn_test.h"
30 #include "../svn_test_fs.h"
31
32 /* Baton for verify_commit_callback*/
33 struct verify_commit_baton
34 {
35 const svn_commit_info_t *commit_info;
36 apr_pool_t *result_pool;
37 };
38
39 /* Commit result collector for verify_mtcc_commit */
40 static svn_error_t *
verify_commit_callback(const svn_commit_info_t * commit_info,void * baton,apr_pool_t * pool)41 verify_commit_callback(const svn_commit_info_t *commit_info,
42 void *baton,
43 apr_pool_t *pool)
44 {
45 struct verify_commit_baton *vcb = baton;
46
47 vcb->commit_info = svn_commit_info_dup(commit_info, vcb->result_pool);
48 return SVN_NO_ERROR;
49 }
50
51 /* Create a stream from a c string */
52 static svn_stream_t *
cstr_stream(const char * data,apr_pool_t * result_pool)53 cstr_stream(const char *data, apr_pool_t *result_pool)
54 {
55 return svn_stream_from_string(svn_string_create(data, result_pool),
56 result_pool);
57 }
58
59 static svn_error_t *
verify_mtcc_commit(svn_client__mtcc_t * mtcc,svn_revnum_t expected_rev,apr_pool_t * pool)60 verify_mtcc_commit(svn_client__mtcc_t *mtcc,
61 svn_revnum_t expected_rev,
62 apr_pool_t *pool)
63 {
64 struct verify_commit_baton vcb;
65 vcb.commit_info = NULL;
66 vcb.result_pool = pool;
67
68 SVN_ERR(svn_client__mtcc_commit(NULL, verify_commit_callback, &vcb, mtcc, pool));
69
70 SVN_TEST_ASSERT(vcb.commit_info != NULL);
71 SVN_TEST_ASSERT(vcb.commit_info->revision == expected_rev);
72
73 return SVN_NO_ERROR;
74 }
75
76
77 /* Constructs a greek tree as revision 1 in the repository at repos_url */
78 static svn_error_t *
make_greek_tree(const char * repos_url,apr_pool_t * scratch_pool)79 make_greek_tree(const char *repos_url,
80 apr_pool_t *scratch_pool)
81 {
82 svn_client__mtcc_t *mtcc;
83 svn_client_ctx_t *ctx;
84 apr_pool_t *subpool;
85 int i;
86
87 subpool = svn_pool_create(scratch_pool);
88
89 SVN_ERR(svn_client_create_context2(&ctx, NULL, subpool));
90 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, subpool));
91
92 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 0, ctx, subpool, subpool));
93
94 for (i = 0; svn_test__greek_tree_nodes[i].path; i++)
95 {
96 if (svn_test__greek_tree_nodes[i].contents)
97 {
98 SVN_ERR(svn_client__mtcc_add_add_file(
99 svn_test__greek_tree_nodes[i].path,
100 cstr_stream(
101 svn_test__greek_tree_nodes[i].contents,
102 subpool),
103 NULL /* src_checksum */,
104 mtcc, subpool));
105 }
106 else
107 {
108 SVN_ERR(svn_client__mtcc_add_mkdir(
109 svn_test__greek_tree_nodes[i].path,
110 mtcc, subpool));
111 }
112 }
113
114 SVN_ERR(verify_mtcc_commit(mtcc, 1, subpool));
115
116 svn_pool_clear(subpool);
117 return SVN_NO_ERROR;
118 }
119
120 static svn_error_t *
test_mkdir(const svn_test_opts_t * opts,apr_pool_t * pool)121 test_mkdir(const svn_test_opts_t *opts,
122 apr_pool_t *pool)
123 {
124 svn_client__mtcc_t *mtcc;
125 svn_client_ctx_t *ctx;
126 const char *repos_url;
127
128 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-mkdir",
129 opts, pool, pool));
130
131 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
132 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
133
134 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 0, ctx, pool, pool));
135
136 SVN_ERR(svn_client__mtcc_add_mkdir("branches", mtcc, pool));
137 SVN_ERR(svn_client__mtcc_add_mkdir("trunk", mtcc, pool));
138 SVN_ERR(svn_client__mtcc_add_mkdir("branches/1.x", mtcc, pool));
139 SVN_ERR(svn_client__mtcc_add_mkdir("tags", mtcc, pool));
140 SVN_ERR(svn_client__mtcc_add_mkdir("tags/1.0", mtcc, pool));
141 SVN_ERR(svn_client__mtcc_add_mkdir("tags/1.1", mtcc, pool));
142
143 SVN_ERR(verify_mtcc_commit(mtcc, 1, pool));
144
145 return SVN_NO_ERROR;
146 }
147
148 static svn_error_t *
test_mkgreek(const svn_test_opts_t * opts,apr_pool_t * pool)149 test_mkgreek(const svn_test_opts_t *opts,
150 apr_pool_t *pool)
151 {
152 svn_client__mtcc_t *mtcc;
153 svn_client_ctx_t *ctx;
154 const char *repos_url;
155
156 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-mkgreek",
157 opts, pool, pool));
158
159 SVN_ERR(make_greek_tree(repos_url, pool));
160
161 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
162 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
163
164 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 1, ctx, pool, pool));
165
166 SVN_ERR(svn_client__mtcc_add_copy("A", 1, "greek_A", mtcc, pool));
167
168 SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
169
170 return SVN_NO_ERROR;
171 }
172
173 static svn_error_t *
test_swap(const svn_test_opts_t * opts,apr_pool_t * pool)174 test_swap(const svn_test_opts_t *opts,
175 apr_pool_t *pool)
176 {
177 svn_client__mtcc_t *mtcc;
178 svn_client_ctx_t *ctx;
179 const char *repos_url;
180
181 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-swap",
182 opts, pool, pool));
183
184 SVN_ERR(make_greek_tree(repos_url, pool));
185
186 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
187 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
188
189 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 1, ctx, pool, pool));
190
191 SVN_ERR(svn_client__mtcc_add_move("A/B", "B", mtcc, pool));
192 SVN_ERR(svn_client__mtcc_add_move("A/D", "A/B", mtcc, pool));
193 SVN_ERR(svn_client__mtcc_add_copy("A/B", 1, "A/D", mtcc, pool));
194
195 SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
196
197 return SVN_NO_ERROR;
198 }
199
200 static svn_error_t *
test_propset(const svn_test_opts_t * opts,apr_pool_t * pool)201 test_propset(const svn_test_opts_t *opts,
202 apr_pool_t *pool)
203 {
204 svn_client__mtcc_t *mtcc;
205 svn_client_ctx_t *ctx;
206 const char *repos_url;
207
208 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-propset",
209 opts, pool, pool));
210
211 SVN_ERR(make_greek_tree(repos_url, pool));
212
213 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
214 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
215
216 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 1, ctx, pool, pool));
217
218 SVN_ERR(svn_client__mtcc_add_propset("iota", "key",
219 svn_string_create("val", pool), FALSE,
220 mtcc, pool));
221 SVN_ERR(svn_client__mtcc_add_propset("A", "A-key",
222 svn_string_create("val-A", pool), FALSE,
223 mtcc, pool));
224 SVN_ERR(svn_client__mtcc_add_propset("A/B", "B-key",
225 svn_string_create("val-B", pool), FALSE,
226 mtcc, pool));
227
228 /* The repository ignores propdeletes of properties that aren't there,
229 so this just works */
230 SVN_ERR(svn_client__mtcc_add_propset("A/D", "D-key", NULL, FALSE,
231 mtcc, pool));
232
233 SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
234
235 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 2, ctx, pool, pool));
236 SVN_TEST_ASSERT_ERROR(
237 svn_client__mtcc_add_propset("A", SVN_PROP_MIME_TYPE,
238 svn_string_create("text/plain", pool),
239 FALSE, mtcc, pool),
240 SVN_ERR_ILLEGAL_TARGET);
241
242 SVN_TEST_ASSERT_ERROR(
243 svn_client__mtcc_add_propset("iota", SVN_PROP_IGNORE,
244 svn_string_create("iota", pool),
245 FALSE, mtcc, pool),
246 SVN_ERR_ILLEGAL_TARGET);
247
248 SVN_ERR(svn_client__mtcc_add_propset("iota", SVN_PROP_EOL_STYLE,
249 svn_string_create("LF", pool),
250 FALSE, mtcc, pool));
251
252 SVN_ERR(svn_client__mtcc_add_add_file("ok", cstr_stream("line\nline\n", pool),
253 NULL, mtcc, pool));
254 SVN_ERR(svn_client__mtcc_add_add_file("bad", cstr_stream("line\nno\r\n", pool),
255 NULL, mtcc, pool));
256
257 SVN_ERR(svn_client__mtcc_add_propset("ok", SVN_PROP_EOL_STYLE,
258 svn_string_create("LF", pool),
259 FALSE, mtcc, pool));
260
261 SVN_TEST_ASSERT_ERROR(
262 svn_client__mtcc_add_propset("bad", SVN_PROP_EOL_STYLE,
263 svn_string_create("LF", pool),
264 FALSE, mtcc, pool),
265 SVN_ERR_ILLEGAL_TARGET);
266
267 SVN_ERR(verify_mtcc_commit(mtcc, 3, pool));
268
269 return SVN_NO_ERROR;
270 }
271
272 static svn_error_t *
test_update_files(const svn_test_opts_t * opts,apr_pool_t * pool)273 test_update_files(const svn_test_opts_t *opts,
274 apr_pool_t *pool)
275 {
276 svn_client__mtcc_t *mtcc;
277 svn_client_ctx_t *ctx;
278 const char *repos_url;
279
280 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-update-files",
281 opts, pool, pool));
282 SVN_ERR(make_greek_tree(repos_url, pool));
283
284 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
285 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
286
287 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 1, ctx, pool, pool));
288
289 /* Update iota with knowledge of the old data */
290 SVN_ERR(svn_client__mtcc_add_update_file(svn_test__greek_tree_nodes[0].path,
291 cstr_stream("new-iota", pool),
292 NULL,
293 cstr_stream(
294 svn_test__greek_tree_nodes[0]
295 .contents,
296 pool),
297 NULL,
298 mtcc, pool));
299
300 SVN_ERR(svn_client__mtcc_add_update_file("A/mu",
301 cstr_stream("new-MU", pool),
302 NULL,
303 NULL, NULL,
304 mtcc, pool));
305
306 /* Set a property on the same node */
307 SVN_ERR(svn_client__mtcc_add_propset("A/mu", "mu-key",
308 svn_string_create("mu-A", pool), FALSE,
309 mtcc, pool));
310 /* And some other node */
311 SVN_ERR(svn_client__mtcc_add_propset("A/B", "B-key",
312 svn_string_create("val-B", pool), FALSE,
313 mtcc, pool));
314
315 SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
316 return SVN_NO_ERROR;
317 }
318
319 static svn_error_t *
test_overwrite(const svn_test_opts_t * opts,apr_pool_t * pool)320 test_overwrite(const svn_test_opts_t *opts,
321 apr_pool_t *pool)
322 {
323 svn_client__mtcc_t *mtcc;
324 svn_client_ctx_t *ctx;
325 const char *repos_url;
326
327 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-overwrite",
328 opts, pool, pool));
329
330 SVN_ERR(make_greek_tree(repos_url, pool));
331
332 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
333 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
334
335 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 1, ctx, pool, pool));
336
337 SVN_ERR(svn_client__mtcc_add_copy("A", 1, "AA", mtcc, pool));
338
339 SVN_TEST_ASSERT_ERROR(svn_client__mtcc_add_mkdir("AA/B", mtcc, pool),
340 SVN_ERR_FS_ALREADY_EXISTS);
341
342 SVN_TEST_ASSERT_ERROR(svn_client__mtcc_add_mkdir("AA/D/H/chi", mtcc, pool),
343 SVN_ERR_FS_ALREADY_EXISTS);
344
345 SVN_ERR(svn_client__mtcc_add_mkdir("AA/BB", mtcc, pool));
346
347 SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
348 return SVN_NO_ERROR;
349 }
350
351 static svn_error_t *
test_anchoring(const svn_test_opts_t * opts,apr_pool_t * pool)352 test_anchoring(const svn_test_opts_t *opts,
353 apr_pool_t *pool)
354 {
355 svn_client__mtcc_t *mtcc;
356 svn_client_ctx_t *ctx;
357 const char *repos_url;
358
359 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-anchoring",
360 opts, pool, pool));
361
362 SVN_ERR(make_greek_tree(repos_url, pool));
363
364 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
365 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
366
367 /* Update a file as root operation */
368 SVN_ERR(svn_client__mtcc_create(&mtcc,
369 svn_path_url_add_component2(repos_url, "iota",
370 pool),
371 1, ctx, pool, pool));
372 SVN_ERR(svn_client__mtcc_add_update_file("",
373 cstr_stream("new-iota", pool),
374 NULL, NULL, NULL,
375 mtcc, pool));
376 SVN_ERR(svn_client__mtcc_add_propset("", "key",
377 svn_string_create("value", pool),
378 FALSE, mtcc, pool));
379
380 SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
381
382 /* Add a directory as root operation */
383 SVN_ERR(svn_client__mtcc_create(&mtcc,
384 svn_path_url_add_component2(repos_url, "BB",
385 pool),
386 2, ctx, pool, pool));
387 SVN_ERR(svn_client__mtcc_add_mkdir("", mtcc, pool));
388 SVN_ERR(verify_mtcc_commit(mtcc, 3, pool));
389
390 /* Add a file as root operation */
391 SVN_ERR(svn_client__mtcc_create(&mtcc,
392 svn_path_url_add_component2(repos_url, "new",
393 pool),
394 3, ctx, pool, pool));
395 SVN_ERR(svn_client__mtcc_add_add_file("", cstr_stream("new", pool), NULL,
396 mtcc, pool));
397 SVN_ERR(verify_mtcc_commit(mtcc, 4, pool));
398
399 /* Delete as root operation */
400 SVN_ERR(svn_client__mtcc_create(&mtcc,
401 svn_path_url_add_component2(repos_url, "new",
402 pool),
403 4, ctx, pool, pool));
404 SVN_ERR(svn_client__mtcc_add_delete("", mtcc, pool));
405 SVN_ERR(verify_mtcc_commit(mtcc, 5, pool));
406
407 /* Propset file as root operation */
408 SVN_ERR(svn_client__mtcc_create(&mtcc,
409 svn_path_url_add_component2(repos_url, "A/mu",
410 pool),
411 5, ctx, pool, pool));
412 SVN_ERR(svn_client__mtcc_add_propset("", "key",
413 svn_string_create("val", pool),
414 FALSE, mtcc, pool));
415 SVN_ERR(verify_mtcc_commit(mtcc, 6, pool));
416
417 /* Propset dir as root operation */
418 SVN_ERR(svn_client__mtcc_create(&mtcc,
419 svn_path_url_add_component2(repos_url, "A",
420 pool),
421 6, ctx, pool, pool));
422 SVN_ERR(svn_client__mtcc_add_propset("", "key",
423 svn_string_create("val", pool),
424 FALSE, mtcc, pool));
425 SVN_ERR(verify_mtcc_commit(mtcc, 7, pool));
426
427 /* Propset reposroot as root operation */
428 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 7, ctx, pool, pool));
429 SVN_ERR(svn_client__mtcc_add_propset("", "key",
430 svn_string_create("val", pool),
431 FALSE, mtcc, pool));
432 SVN_ERR(verify_mtcc_commit(mtcc, 8, pool));
433
434 return SVN_NO_ERROR;
435 }
436
437 static svn_error_t *
test_replace_tree(const svn_test_opts_t * opts,apr_pool_t * pool)438 test_replace_tree(const svn_test_opts_t *opts,
439 apr_pool_t *pool)
440 {
441 svn_client__mtcc_t *mtcc;
442 svn_client_ctx_t *ctx;
443 const char *repos_url;
444
445 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-replace_tree",
446 opts, pool, pool));
447
448 SVN_ERR(make_greek_tree(repos_url, pool));
449
450 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
451 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
452
453 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 1, ctx, pool, pool));
454
455 SVN_ERR(svn_client__mtcc_add_delete("A", mtcc, pool));
456 SVN_ERR(svn_client__mtcc_add_delete("iota", mtcc, pool));
457 SVN_ERR(svn_client__mtcc_add_mkdir("A", mtcc, pool));
458 SVN_ERR(svn_client__mtcc_add_mkdir("A/B", mtcc, pool));
459 SVN_ERR(svn_client__mtcc_add_mkdir("A/B/C", mtcc, pool));
460 SVN_ERR(svn_client__mtcc_add_mkdir("M", mtcc, pool));
461 SVN_ERR(svn_client__mtcc_add_mkdir("M/N", mtcc, pool));
462 SVN_ERR(svn_client__mtcc_add_mkdir("M/N/O", mtcc, pool));
463
464 SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
465
466 return SVN_NO_ERROR;
467 }
468
469 /* Baton for handle_rev */
470 struct handle_rev_baton
471 {
472 svn_revnum_t last;
473 svn_boolean_t up;
474 svn_boolean_t first;
475
476 /* Per revision handler */
477 svn_txdelta_window_handler_t inner_handler;
478 void *inner_baton;
479
480 /* Swapped between revisions to reconstruct data */
481 svn_stringbuf_t *cur;
482 svn_stringbuf_t *prev;
483
484 /* Pool for some test stuff */
485 apr_pool_t *pool;
486 };
487
488 /* Implement svn_txdelta_window_handler_t */
489 static svn_error_t *
handle_rev_delta(svn_txdelta_window_t * window,void * baton)490 handle_rev_delta(svn_txdelta_window_t *window,
491 void * baton)
492 {
493 struct handle_rev_baton *hrb = baton;
494
495 SVN_ERR(hrb->inner_handler(window, hrb->inner_baton));
496
497 if (!window)
498 {
499 int expected_rev;
500 const char *expected;
501
502 /* Some revisions don't update the revision body */
503 switch (hrb->last)
504 {
505 case 5:
506 expected_rev = 4;
507 break;
508 case 7: /* Not reported */
509 case 8:
510 expected_rev = 6;
511 break;
512 default:
513 expected_rev = (int)hrb->last;
514 }
515
516 expected = apr_psprintf(hrb->pool, "revision-%d", expected_rev);
517
518 SVN_TEST_STRING_ASSERT(hrb->cur->data, expected);
519 }
520
521 return SVN_NO_ERROR;
522 }
523
524 /* Helper for test_file_revs_both_ways */
525 static svn_error_t *
handle_rev(void * baton,const char * path,svn_revnum_t rev,apr_hash_t * rev_props,svn_boolean_t result_of_merge,svn_txdelta_window_handler_t * delta_handler,void ** delta_baton,apr_array_header_t * prop_diffs,apr_pool_t * pool)526 handle_rev(void *baton,
527 const char *path,
528 svn_revnum_t rev,
529 apr_hash_t *rev_props,
530 svn_boolean_t result_of_merge,
531 svn_txdelta_window_handler_t *delta_handler,
532 void **delta_baton,
533 apr_array_header_t *prop_diffs,
534 apr_pool_t *pool)
535 {
536 struct handle_rev_baton *hrb = baton;
537 svn_revnum_t expected_rev = hrb->up ? (hrb->last + 1) : (hrb->last - 1);
538
539 if (expected_rev == 7)
540 expected_rev = hrb->up ? 8 : 6;
541
542 SVN_TEST_ASSERT(rev == expected_rev);
543 SVN_TEST_ASSERT(apr_hash_count(rev_props) >= 3);
544 SVN_TEST_STRING_ASSERT(path, (rev < 5) ? "/iota" : "/mu");
545
546 if (!hrb->first
547 && (rev == (hrb->up ? 5 : 4) || rev == (hrb->up ? 8 : 6)))
548 SVN_TEST_ASSERT(delta_handler == NULL);
549 else
550 SVN_TEST_ASSERT(delta_handler != NULL);
551
552 if (delta_handler)
553 {
554 svn_stringbuf_t *tmp;
555
556 *delta_handler = handle_rev_delta;
557 *delta_baton = hrb;
558
559 /* Swap string buffers, to use previous as original */
560 tmp = hrb->prev;
561 hrb->prev = hrb->cur;
562 hrb->cur = tmp;
563
564 svn_stringbuf_setempty(hrb->cur);
565
566 svn_txdelta_apply(svn_stream_from_stringbuf(hrb->prev, pool),
567 svn_stream_from_stringbuf(hrb->cur, pool),
568 NULL, NULL, pool,
569 &hrb->inner_handler,
570 &hrb->inner_baton);
571 }
572
573 hrb->last = rev;
574 hrb->first = FALSE;
575
576 return SVN_NO_ERROR;
577 }
578
579 static svn_error_t *
test_file_revs_both_ways(const svn_test_opts_t * opts,apr_pool_t * pool)580 test_file_revs_both_ways(const svn_test_opts_t *opts,
581 apr_pool_t *pool)
582 {
583 svn_client__mtcc_t *mtcc;
584 svn_client_ctx_t *ctx;
585 apr_pool_t *subpool = svn_pool_create(pool);
586 const char *repos_url;
587 svn_ra_session_t *ra;
588 struct handle_rev_baton hrb;
589
590 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-file-revs",
591 opts, pool, subpool));
592
593 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
594 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
595
596 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 0, ctx, subpool, subpool));
597 SVN_ERR(svn_client__mtcc_add_add_file("iota",
598 cstr_stream("revision-1", subpool),
599 NULL /* src_checksum */,
600 mtcc, subpool));
601 SVN_ERR(verify_mtcc_commit(mtcc, 1, subpool));
602 svn_pool_clear(subpool);
603
604 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 1, ctx, subpool, subpool));
605 SVN_ERR(svn_client__mtcc_add_update_file("iota",
606 cstr_stream("revision-2", subpool),
607 NULL /* src_checksum */, NULL, NULL,
608 mtcc, subpool));
609 SVN_ERR(verify_mtcc_commit(mtcc, 2, subpool));
610 svn_pool_clear(subpool);
611
612 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 2, ctx, subpool, subpool));
613 SVN_ERR(svn_client__mtcc_add_update_file("iota",
614 cstr_stream("revision-3", subpool),
615 NULL /* src_checksum */, NULL, NULL,
616 mtcc, subpool));
617 SVN_ERR(verify_mtcc_commit(mtcc, 3, subpool));
618 svn_pool_clear(subpool);
619
620 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 3, ctx, subpool, subpool));
621 SVN_ERR(svn_client__mtcc_add_update_file("iota",
622 cstr_stream("revision-4", subpool),
623 NULL /* src_checksum */, NULL, NULL,
624 mtcc, subpool));
625 SVN_ERR(verify_mtcc_commit(mtcc, 4, subpool));
626 svn_pool_clear(subpool);
627
628 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 4, ctx, subpool, subpool));
629 SVN_ERR(svn_client__mtcc_add_move("iota", "mu", mtcc, subpool));
630 SVN_ERR(verify_mtcc_commit(mtcc, 5, subpool));
631 svn_pool_clear(subpool);
632
633 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 5, ctx, subpool, subpool));
634 SVN_ERR(svn_client__mtcc_add_update_file("mu",
635 cstr_stream("revision-6", subpool),
636 NULL /* src_checksum */, NULL, NULL,
637 mtcc, subpool));
638 SVN_ERR(verify_mtcc_commit(mtcc, 6, subpool));
639 svn_pool_clear(subpool);
640
641 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 6, ctx, subpool, subpool));
642 SVN_ERR(svn_client__mtcc_add_delete("mu", mtcc, subpool));
643 SVN_ERR(verify_mtcc_commit(mtcc, 7, subpool));
644 svn_pool_clear(subpool);
645
646 SVN_ERR(svn_client_open_ra_session2(&ra, repos_url, NULL, ctx, pool, subpool));
647
648 hrb.prev = svn_stringbuf_create("", pool);
649 hrb.cur = svn_stringbuf_create("", pool);
650 hrb.pool = pool;
651
652 svn_pool_clear(subpool);
653 hrb.up = FALSE;
654 hrb.last = 5;
655 hrb.first = TRUE;
656 svn_stringbuf_setempty(hrb.prev);
657 svn_stringbuf_setempty(hrb.cur);
658 SVN_ERR(svn_ra_get_file_revs2(ra, "iota", 4, 1, FALSE,
659 handle_rev, &hrb,
660 subpool));
661 SVN_TEST_ASSERT(hrb.last == 1);
662
663 svn_pool_clear(subpool);
664 hrb.up = TRUE;
665 hrb.last = 0;
666 hrb.first = TRUE;
667 svn_stringbuf_setempty(hrb.prev);
668 svn_stringbuf_setempty(hrb.cur);
669 SVN_ERR(svn_ra_get_file_revs2(ra, "iota", 1, 4, FALSE,
670 handle_rev, &hrb,
671 subpool));
672 SVN_TEST_ASSERT(hrb.last == 4);
673
674 svn_pool_clear(subpool);
675 hrb.up = FALSE;
676 hrb.last = 7;
677 hrb.first = TRUE;
678 svn_stringbuf_setempty(hrb.prev);
679 svn_stringbuf_setempty(hrb.cur);
680 SVN_ERR(svn_ra_get_file_revs2(ra, "mu", 6, 1, FALSE,
681 handle_rev, &hrb,
682 subpool));
683 SVN_TEST_ASSERT(hrb.last == 1);
684
685 svn_pool_clear(subpool);
686 hrb.up = TRUE;
687 hrb.last = 0;
688 hrb.first = TRUE;
689 svn_stringbuf_setempty(hrb.prev);
690 svn_stringbuf_setempty(hrb.cur);
691 SVN_ERR(svn_ra_get_file_revs2(ra, "mu", 1, 6, FALSE,
692 handle_rev, &hrb,
693 subpool));
694 SVN_TEST_ASSERT(hrb.last == 6);
695
696 /* Ressurect mu */
697 svn_pool_clear(subpool);
698 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 7, ctx, subpool, subpool));
699 SVN_ERR(svn_client__mtcc_add_copy("mu", 6, "mu", mtcc, subpool));
700 SVN_ERR(verify_mtcc_commit(mtcc, 8, subpool));
701
702 svn_pool_clear(subpool);
703 hrb.up = TRUE;
704 hrb.last = 0;
705 hrb.first = TRUE;
706 svn_stringbuf_setempty(hrb.prev);
707 svn_stringbuf_setempty(hrb.cur);
708 SVN_ERR(svn_ra_get_file_revs2(ra, "mu", 1, SVN_INVALID_REVNUM, FALSE,
709 handle_rev, &hrb,
710 subpool));
711 SVN_TEST_ASSERT(hrb.last == 8);
712
713 svn_pool_clear(subpool);
714 hrb.up = FALSE;
715 hrb.last = 9;
716 hrb.first = TRUE;
717 svn_stringbuf_setempty(hrb.prev);
718 svn_stringbuf_setempty(hrb.cur);
719 SVN_ERR(svn_ra_get_file_revs2(ra, "mu", SVN_INVALID_REVNUM, 1, FALSE,
720 handle_rev, &hrb,
721 subpool));
722 SVN_TEST_ASSERT(hrb.last == 1);
723
724 return SVN_NO_ERROR;
725 }
726
727 static svn_error_t *
test_iprops_path_format(const svn_test_opts_t * opts,apr_pool_t * pool)728 test_iprops_path_format(const svn_test_opts_t *opts,
729 apr_pool_t *pool)
730 {
731 svn_client__mtcc_t *mtcc;
732 svn_client_ctx_t *ctx;
733 apr_pool_t *subpool = svn_pool_create(pool);
734 const char *repos_url;
735 svn_ra_session_t *ra;
736
737 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-iprops-paths",
738 opts, pool, subpool));
739
740 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
741 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
742
743 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 0, ctx, subpool, subpool));
744 SVN_ERR(svn_client__mtcc_add_mkdir("A", mtcc, subpool));
745 SVN_ERR(svn_client__mtcc_add_mkdir("A/B", mtcc, subpool));
746 SVN_ERR(svn_client__mtcc_add_mkdir("A/B/C", mtcc, subpool));
747 SVN_ERR(svn_client__mtcc_add_mkdir("A/B/C/D", mtcc, subpool));
748 SVN_ERR(svn_client__mtcc_add_propset("", "on-root",
749 svn_string_create("ROOT", subpool),
750 FALSE, mtcc, subpool));
751 SVN_ERR(svn_client__mtcc_add_propset("A/B", "on-B",
752 svn_string_create("BBBB", subpool),
753 FALSE, mtcc, subpool));
754 SVN_ERR(svn_client__mtcc_add_propset("A/B/C", "Z",
755 svn_string_create("Z", subpool),
756 FALSE, mtcc, subpool));
757 SVN_ERR(verify_mtcc_commit(mtcc, 1, subpool));
758 svn_pool_clear(subpool);
759
760 {
761 apr_array_header_t *iprops;
762 svn_prop_inherited_item_t *ip;
763
764 SVN_ERR(svn_client_open_ra_session2(&ra, repos_url, NULL, ctx,
765 pool, subpool));
766
767 SVN_ERR(svn_ra_get_inherited_props(ra, &iprops, "A/B/C/D", 1,
768 subpool, subpool));
769
770 SVN_TEST_ASSERT(iprops != NULL);
771 SVN_TEST_INT_ASSERT(iprops->nelts, 3);
772
773 ip = APR_ARRAY_IDX(iprops, 0, svn_prop_inherited_item_t *);
774 SVN_TEST_STRING_ASSERT(ip->path_or_url, "");
775
776 ip = APR_ARRAY_IDX(iprops, 1, svn_prop_inherited_item_t *);
777 SVN_TEST_STRING_ASSERT(ip->path_or_url, "A/B");
778
779 ip = APR_ARRAY_IDX(iprops, 2, svn_prop_inherited_item_t *);
780 SVN_TEST_STRING_ASSERT(ip->path_or_url, "A/B/C");
781 }
782
783 return SVN_NO_ERROR;
784 }
785
786 static svn_error_t *
test_move_and_delete_ancestor(const svn_test_opts_t * opts,apr_pool_t * pool)787 test_move_and_delete_ancestor(const svn_test_opts_t *opts,
788 apr_pool_t *pool)
789 {
790 svn_client__mtcc_t *mtcc;
791 svn_client_ctx_t *ctx;
792 const char *repos_url;
793
794 SVN_ERR(svn_test__create_repos2(NULL, &repos_url, NULL, "mtcc-move-and-delete",
795 opts, pool, pool));
796
797 SVN_ERR(make_greek_tree(repos_url, pool));
798
799 SVN_ERR(svn_client_create_context2(&ctx, NULL, pool));
800 SVN_ERR(svn_test__init_auth_baton(&ctx->auth_baton, pool));
801
802 SVN_ERR(svn_client__mtcc_create(&mtcc, repos_url, 1, ctx, pool, pool));
803
804 SVN_ERR(svn_client__mtcc_add_move("A/B", "B", mtcc, pool));
805 SVN_ERR(svn_client__mtcc_add_move("A/mu", "mu", mtcc, pool));
806 SVN_ERR(svn_client__mtcc_add_delete("A", mtcc, pool));
807
808 SVN_ERR(verify_mtcc_commit(mtcc, 2, pool));
809
810 return SVN_NO_ERROR;
811
812 }
813
814
815 /* ========================================================================== */
816
817
818 static int max_threads = 3;
819
820 static struct svn_test_descriptor_t test_funcs[] =
821 {
822 SVN_TEST_NULL,
823 SVN_TEST_OPTS_PASS(test_mkdir,
824 "test mtcc mkdir"),
825 SVN_TEST_OPTS_PASS(test_mkgreek,
826 "test making greek tree"),
827 SVN_TEST_OPTS_PASS(test_swap,
828 "swapping some trees"),
829 SVN_TEST_OPTS_PASS(test_propset,
830 "test propset and propdel"),
831 SVN_TEST_OPTS_PASS(test_update_files,
832 "test update files"),
833 SVN_TEST_OPTS_PASS(test_overwrite,
834 "test overwrite"),
835 SVN_TEST_OPTS_PASS(test_anchoring,
836 "test mtcc anchoring for root operations"),
837 SVN_TEST_OPTS_PASS(test_replace_tree,
838 "test mtcc replace tree"),
839 SVN_TEST_OPTS_PASS(test_file_revs_both_ways,
840 "test ra_get_file_revs2 both ways"),
841 SVN_TEST_OPTS_PASS(test_iprops_path_format,
842 "test iprops url format"),
843 SVN_TEST_OPTS_PASS(test_move_and_delete_ancestor,
844 "test move and delete ancestor (issue 4666)"),
845 SVN_TEST_NULL
846 };
847
848 SVN_TEST_MAIN
849