90
93
return SVN_NO_ERROR;
97
commit_tree(svn_ra_session_t *session,
100
apr_hash_t *revprop_table = apr_hash_make(pool);
101
const svn_delta_editor_t *editor;
103
const char *repos_root_url;
104
void *root_baton, *A_baton, *B_baton, *file_baton;
106
SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
108
NULL, NULL, NULL, TRUE, pool));
109
SVN_ERR(svn_ra_get_repos_root(session, &repos_root_url, pool));
111
SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM,
113
SVN_ERR(editor->add_directory("A", root_baton, NULL, SVN_INVALID_REVNUM,
115
SVN_ERR(editor->add_directory("A/B", A_baton, NULL, SVN_INVALID_REVNUM,
117
SVN_ERR(editor->add_file("A/B/f", B_baton, NULL, SVN_INVALID_REVNUM,
119
SVN_ERR(editor->close_file(file_baton, NULL, pool));
120
SVN_ERR(editor->add_file("A/B/g", B_baton, NULL, SVN_INVALID_REVNUM,
122
SVN_ERR(editor->close_file(file_baton, NULL, pool));
123
SVN_ERR(editor->close_directory(B_baton, pool));
124
SVN_ERR(editor->add_directory("A/BB", A_baton, NULL, SVN_INVALID_REVNUM,
126
SVN_ERR(editor->add_file("A/BB/f", B_baton, NULL, SVN_INVALID_REVNUM,
128
SVN_ERR(editor->close_file(file_baton, NULL, pool));
129
SVN_ERR(editor->add_file("A/BB/g", B_baton, NULL, SVN_INVALID_REVNUM,
131
SVN_ERR(editor->close_file(file_baton, NULL, pool));
132
SVN_ERR(editor->close_directory(B_baton, pool));
133
SVN_ERR(editor->close_directory(A_baton, pool));
134
SVN_ERR(editor->close_edit(edit_baton, pool));
138
/* Baton for opening tunnels */
139
typedef struct tunnel_baton_t
141
int magic; /* TUNNEL_MAGIC */
143
svn_boolean_t last_check;
146
#define TUNNEL_MAGIC 0xF00DF00F
148
/* Baton for closing a specific tunnel */
149
typedef struct close_baton_t
156
#define CLOSE_MAGIC 0x1BADBAD1
159
check_tunnel(void *tunnel_baton, const char *tunnel_name)
161
tunnel_baton_t *b = tunnel_baton;
163
if (b->magic != TUNNEL_MAGIC)
166
b->last_check = (0 == strcmp(tunnel_name, "test"));
167
return b->last_check;
171
close_tunnel(void *tunnel_context, void *tunnel_baton);
174
open_tunnel(svn_stream_t **request, svn_stream_t **response,
175
svn_ra_close_tunnel_func_t *close_func, void **close_baton,
177
const char *tunnel_name, const char *user,
178
const char *hostname, int port,
179
svn_cancel_func_t cancel_func, void *cancel_baton,
182
svn_node_kind_t kind;
184
apr_procattr_t *attr;
186
const char *args[] = { "svnserve", "-t", "-r", ".", NULL };
187
const char *svnserve;
188
tunnel_baton_t *b = tunnel_baton;
191
SVN_TEST_ASSERT(b->magic == TUNNEL_MAGIC);
193
SVN_ERR(svn_dirent_get_absolute(&svnserve, "../../svnserve/svnserve", pool));
195
svnserve = apr_pstrcat(pool, svnserve, ".exe", SVN_VA_NULL);
197
SVN_ERR(svn_io_check_path(svnserve, &kind, pool));
198
if (kind != svn_node_file)
199
return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
200
"Could not find svnserve at %s",
201
svn_dirent_local_style(svnserve, pool));
203
status = apr_procattr_create(&attr, pool);
204
if (status == APR_SUCCESS)
205
status = apr_procattr_io_set(attr, 1, 1, 0);
206
if (status == APR_SUCCESS)
207
status = apr_procattr_cmdtype_set(attr, APR_PROGRAM);
208
proc = apr_palloc(pool, sizeof(*proc));
209
if (status == APR_SUCCESS)
210
status = apr_proc_create(proc,
211
svn_dirent_local_style(svnserve, pool),
212
args, NULL, attr, pool);
213
if (status != APR_SUCCESS)
214
return svn_error_wrap_apr(status, "Could not run svnserve");
215
apr_pool_note_subprocess(pool, proc, APR_KILL_NEVER);
217
/* APR pipe objects inherit by default. But we don't want the
218
* tunnel agent's pipes held open by future child processes
219
* (such as other ra_svn sessions), so turn that off. */
220
apr_file_inherit_unset(proc->in);
221
apr_file_inherit_unset(proc->out);
223
cb = apr_pcalloc(pool, sizeof(*cb));
224
cb->magic = CLOSE_MAGIC;
228
*request = svn_stream_from_aprfile2(proc->in, FALSE, pool);
229
*response = svn_stream_from_aprfile2(proc->out, FALSE, pool);
230
*close_func = close_tunnel;
237
close_tunnel(void *tunnel_context, void *tunnel_baton)
239
close_baton_t *b = tunnel_context;
241
if (b->magic != CLOSE_MAGIC)
243
if (--b->tb->open_count == 0)
245
apr_status_t child_exit_status;
247
apr_exit_why_e child_exit_why;
249
SVN_TEST_ASSERT_NO_RETURN(0 == apr_file_close(b->proc->in));
250
SVN_TEST_ASSERT_NO_RETURN(0 == apr_file_close(b->proc->out));
253
apr_proc_wait(b->proc, &child_exit_code, &child_exit_why, APR_WAIT);
255
SVN_TEST_ASSERT_NO_RETURN(child_exit_status == APR_CHILD_DONE);
256
SVN_TEST_ASSERT_NO_RETURN(child_exit_code == 0);
257
SVN_TEST_ASSERT_NO_RETURN(child_exit_why == APR_PROC_EXIT);
93
264
/*-------------------------------------------------------------------*/
327
/* Test ra_svn tunnel callbacks. */
330
check_tunnel_callback_test(const svn_test_opts_t *opts,
333
tunnel_baton_t b = { TUNNEL_MAGIC };
334
svn_ra_callbacks2_t *cbtable;
335
svn_ra_session_t *session;
338
SVN_ERR(svn_ra_create_callbacks(&cbtable, pool));
339
cbtable->check_tunnel_func = check_tunnel;
340
cbtable->open_tunnel_func = open_tunnel;
341
cbtable->tunnel_baton = &b;
342
SVN_ERR(svn_cmdline_create_auth_baton(&cbtable->auth_baton,
343
TRUE /* non_interactive */,
344
"jrandom", "rayjandom",
346
TRUE /* no_auth_cache */,
347
FALSE /* trust_server_cert */,
348
NULL, NULL, NULL, pool));
351
err = svn_ra_open4(&session, NULL, "svn+foo://localhost/no-repo",
352
NULL, cbtable, NULL, NULL, pool);
353
svn_error_clear(err);
354
SVN_TEST_ASSERT(err);
355
SVN_TEST_ASSERT(!b.last_check);
360
tunnel_callback_test(const svn_test_opts_t *opts,
363
tunnel_baton_t b = { TUNNEL_MAGIC };
364
apr_pool_t *scratch_pool = svn_pool_create(pool);
366
svn_ra_callbacks2_t *cbtable;
367
svn_ra_session_t *session;
369
const char tunnel_repos_name[] = "test-repo-tunnel";
371
SVN_ERR(svn_test__create_repos(NULL, tunnel_repos_name, opts, scratch_pool));
373
/* Immediately close the repository to avoid race condition with svnserve
374
(and then the cleanup code) with BDB when our pool is cleared. */
375
svn_pool_clear(scratch_pool);
377
url = apr_pstrcat(pool, "svn+test://localhost/", tunnel_repos_name,
379
SVN_ERR(svn_ra_create_callbacks(&cbtable, pool));
380
cbtable->check_tunnel_func = check_tunnel;
381
cbtable->open_tunnel_func = open_tunnel;
382
cbtable->tunnel_baton = &b;
383
SVN_ERR(svn_cmdline_create_auth_baton(&cbtable->auth_baton,
384
TRUE /* non_interactive */,
385
"jrandom", "rayjandom",
387
TRUE /* no_auth_cache */,
388
FALSE /* trust_server_cert */,
389
NULL, NULL, NULL, pool));
391
b.last_check = FALSE;
392
err = svn_ra_open4(&session, NULL, url, NULL, cbtable, NULL, NULL,
394
if (err && err->apr_err == SVN_ERR_TEST_FAILED)
396
svn_handle_error2(err, stderr, FALSE, "svn_tests: ");
397
svn_error_clear(err);
401
SVN_TEST_ASSERT(b.last_check);
402
SVN_TEST_ASSERT(b.open_count > 0);
403
svn_pool_destroy(scratch_pool);
404
SVN_TEST_ASSERT(b.open_count == 0);
408
struct lock_result_t {
413
struct lock_baton_t {
418
/* Implements svn_ra_lock_callback_t. */
422
svn_boolean_t do_lock,
423
const svn_lock_t *lock,
427
struct lock_baton_t *b = baton;
428
struct lock_result_t *result = apr_palloc(b->pool,
429
sizeof(struct lock_result_t));
433
result->lock = apr_palloc(b->pool, sizeof(svn_lock_t));
434
*result->lock = *lock;
435
result->lock->path = apr_pstrdup(b->pool, lock->path);
436
result->lock->token = apr_pstrdup(b->pool, lock->token);
437
result->lock->owner = apr_pstrdup(b->pool, lock->owner);
438
result->lock->comment = apr_pstrdup(b->pool, lock->comment);
442
result->err = ra_err;
444
svn_hash_sets(b->results, apr_pstrdup(b->pool, path), result);
450
expect_lock(const char *path,
452
svn_ra_session_t *session,
453
apr_pool_t *scratch_pool)
456
struct lock_result_t *result = svn_hash_gets(results, path);
458
SVN_TEST_ASSERT(result && result->lock && !result->err);
459
SVN_ERR(svn_ra_get_lock(session, &lock, path, scratch_pool));
460
SVN_TEST_ASSERT(lock);
465
expect_error(const char *path,
467
svn_ra_session_t *session,
468
apr_pool_t *scratch_pool)
471
struct lock_result_t *result = svn_hash_gets(results, path);
473
SVN_TEST_ASSERT(result && result->err);
474
SVN_TEST_ASSERT(!result->lock);
475
/* RA layers shouldn't report SVN_ERR_FS_NOT_FOUND */
476
SVN_ERR(svn_ra_get_lock(session, &lock, path, scratch_pool));
478
SVN_TEST_ASSERT(!lock);
483
expect_unlock(const char *path,
485
svn_ra_session_t *session,
486
apr_pool_t *scratch_pool)
489
struct lock_result_t *result = svn_hash_gets(results, path);
491
SVN_TEST_ASSERT(result && !result->err);
492
SVN_ERR(svn_ra_get_lock(session, &lock, path, scratch_pool));
493
SVN_TEST_ASSERT(!lock);
498
expect_unlock_error(const char *path,
500
svn_ra_session_t *session,
501
apr_pool_t *scratch_pool)
504
struct lock_result_t *result = svn_hash_gets(results, path);
506
SVN_TEST_ASSERT(result && result->err);
507
SVN_ERR(svn_ra_get_lock(session, &lock, path, scratch_pool));
508
SVN_TEST_ASSERT(lock);
512
/* Test svn_ra_lock(). */
514
lock_test(const svn_test_opts_t *opts,
517
svn_ra_session_t *session;
518
apr_hash_t *lock_targets = apr_hash_make(pool);
519
apr_hash_t *unlock_targets = apr_hash_make(pool);
520
svn_revnum_t rev = 1;
521
struct lock_result_t *result;
522
struct lock_baton_t baton;
523
apr_hash_index_t *hi;
525
SVN_ERR(make_and_open_repos(&session, "test-repo-lock", opts, pool));
526
SVN_ERR(commit_tree(session, pool));
528
baton.results = apr_hash_make(pool);
531
svn_hash_sets(lock_targets, "A/B/f", &rev);
532
svn_hash_sets(lock_targets, "A/B/g", &rev);
533
svn_hash_sets(lock_targets, "A/B/z", &rev);
534
svn_hash_sets(lock_targets, "A/BB/f", &rev);
535
svn_hash_sets(lock_targets, "X/z", &rev);
537
/* Lock some paths. */
538
SVN_ERR(svn_ra_lock(session, lock_targets, "foo", FALSE, lock_cb, &baton,
541
SVN_ERR(expect_lock("A/B/f", baton.results, session, pool));
542
SVN_ERR(expect_lock("A/B/g", baton.results, session, pool));
543
SVN_ERR(expect_error("A/B/z", baton.results, session, pool));
544
SVN_ERR(expect_lock("A/BB/f", baton.results, session, pool));
545
SVN_ERR(expect_error("X/z", baton.results, session, pool));
547
/* Unlock without force and wrong lock tokens */
548
for (hi = apr_hash_first(pool, lock_targets); hi; hi = apr_hash_next(hi))
549
svn_hash_sets(unlock_targets, apr_hash_this_key(hi), "wrong-token");
550
apr_hash_clear(baton.results);
551
SVN_ERR(svn_ra_unlock(session, unlock_targets, FALSE, lock_cb, &baton, pool));
553
SVN_ERR(expect_unlock_error("A/B/f", baton.results, session, pool));
554
SVN_ERR(expect_unlock_error("A/B/g", baton.results, session, pool));
555
SVN_ERR(expect_error("A/B/z", baton.results, session, pool));
556
SVN_ERR(expect_unlock_error("A/BB/f", baton.results, session, pool));
557
SVN_ERR(expect_error("X/z", baton.results, session, pool));
560
for (hi = apr_hash_first(pool, lock_targets); hi; hi = apr_hash_next(hi))
561
svn_hash_sets(unlock_targets, apr_hash_this_key(hi), "");
562
apr_hash_clear(baton.results);
563
SVN_ERR(svn_ra_unlock(session, unlock_targets, TRUE, lock_cb, &baton, pool));
565
SVN_ERR(expect_unlock("A/B/f", baton.results, session, pool));
566
SVN_ERR(expect_unlock("A/B/g", baton.results, session, pool));
567
SVN_ERR(expect_error("A/B/z", baton.results, session, pool));
568
SVN_ERR(expect_unlock("A/BB/f", baton.results, session, pool));
569
SVN_ERR(expect_error("X/z", baton.results, session, pool));
572
apr_hash_clear(baton.results);
573
SVN_ERR(svn_ra_lock(session, lock_targets, "foo", FALSE, lock_cb, &baton,
576
SVN_ERR(expect_lock("A/B/f", baton.results, session, pool));
577
SVN_ERR(expect_lock("A/B/g", baton.results, session, pool));
578
SVN_ERR(expect_error("A/B/z", baton.results, session, pool));
579
SVN_ERR(expect_lock("A/BB/f", baton.results, session, pool));
580
SVN_ERR(expect_error("X/z", baton.results, session, pool));
582
for (hi = apr_hash_first(pool, baton.results); hi; hi = apr_hash_next(hi))
584
result = apr_hash_this_val(hi);
585
svn_hash_sets(unlock_targets, apr_hash_this_key(hi),
586
result->lock ? result->lock->token : "non-existent-token");
588
apr_hash_clear(baton.results);
589
SVN_ERR(svn_ra_unlock(session, unlock_targets, FALSE, lock_cb, &baton, pool));
591
SVN_ERR(expect_unlock("A/B/f", baton.results, session, pool));
592
SVN_ERR(expect_unlock("A/B/g", baton.results, session, pool));
593
SVN_ERR(expect_error("A/B/z", baton.results, session, pool));
594
SVN_ERR(expect_unlock("A/BB/f", baton.results, session, pool));
595
SVN_ERR(expect_error("X/z", baton.results, session, pool));
600
/* Test svn_ra_get_dir2(). */
602
get_dir_test(const svn_test_opts_t *opts,
605
svn_ra_session_t *session;
608
SVN_ERR(make_and_open_repos(&session, "test-get-dir", opts, pool));
609
SVN_ERR(commit_tree(session, pool));
611
/* This call used to block on ra-svn for 1.8.0...r1656713 */
612
SVN_TEST_ASSERT_ERROR(svn_ra_get_dir2(session, &dirents, NULL, NULL,
613
"non/existing/relpath", 1,
614
SVN_DIRENT_KIND, pool),
615
SVN_ERR_FS_NOT_FOUND);
156
620
/* Implements svn_commit_callback2_t for commit_callback_failure() */
157
621
static svn_error_t *
158
622
commit_callback_with_failure(const svn_commit_info_t *info,
200
664
return SVN_NO_ERROR;
668
base_revision_above_youngest(const svn_test_opts_t *opts,
671
svn_ra_session_t *ra_session;
672
const svn_delta_editor_t *editor;
676
SVN_ERR(make_and_open_repos(&ra_session, "base_revision_above_youngest",
679
SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
680
apr_hash_make(pool), NULL,
681
NULL, NULL, FALSE, pool));
683
/* r1 doesn't exist, but we say we want to apply changes against this
684
revision to see how the ra layers behave.
686
Some will see an error directly on open_root, others in a later
689
/* ra-local and http pre-v2 will see the error here */
690
err = editor->open_root(edit_baton, 1, pool, &root_baton);
693
err = editor->change_dir_prop(root_baton, "A",
694
svn_string_create("B", pool), pool);
696
/* http v2 will notice it here (PROPPATCH) */
698
err = editor->close_directory(root_baton, pool);
700
/* ra svn only notes it at some later point. Typically here */
702
err = editor->close_edit(edit_baton, pool);
704
SVN_TEST_ASSERT_ERROR(err,
705
SVN_ERR_FS_NO_SUCH_REVISION);
707
SVN_ERR(editor->abort_edit(edit_baton, pool));
713
ra_list_has_props(const svn_test_opts_t *opts,
716
svn_ra_session_t *ra_session;
717
const svn_delta_editor_t *editor;
718
apr_pool_t *iterpool = svn_pool_create(pool);
721
const char *trunk_url;
723
SVN_ERR(make_and_open_repos(&ra_session, "ra_list_has_props",
726
SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
727
apr_hash_make(pool), NULL,
728
NULL, NULL, FALSE, iterpool));
730
/* Create initial layout*/
735
SVN_ERR(editor->open_root(edit_baton, 0, pool, &root_baton));
736
SVN_ERR(editor->add_directory("trunk", root_baton, NULL, SVN_INVALID_REVNUM,
737
iterpool, &dir_baton));
738
SVN_ERR(editor->close_directory(dir_baton, iterpool));
739
SVN_ERR(editor->add_directory("tags", root_baton, NULL, SVN_INVALID_REVNUM,
740
iterpool, &dir_baton));
741
SVN_ERR(editor->close_directory(dir_baton, iterpool));
742
SVN_ERR(editor->close_directory(root_baton, iterpool));
743
SVN_ERR(editor->close_edit(edit_baton, iterpool));
746
SVN_ERR(svn_ra_get_repos_root2(ra_session, &trunk_url, pool));
747
trunk_url = svn_path_url_add_component2(trunk_url, "trunk", pool);
749
/* Create a few tags. Using a value like 8000 will take too long for a normal
750
testrun, but produces more realistic problems */
751
for (i = 0; i < 50; i++)
757
svn_pool_clear(iterpool);
759
SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
760
apr_hash_make(pool), NULL,
761
NULL, NULL, FALSE, iterpool));
763
SVN_ERR(editor->open_root(edit_baton, i+1, pool, &root_baton));
764
SVN_ERR(editor->open_directory("tags", root_baton, i+1, iterpool,
766
SVN_ERR(editor->add_directory(apr_psprintf(iterpool, "tags/T%05d", i+1),
767
tags_baton, trunk_url, 1, iterpool,
770
SVN_ERR(editor->close_directory(dir_baton, iterpool));
771
SVN_ERR(editor->close_directory(tags_baton, iterpool));
772
SVN_ERR(editor->close_directory(root_baton, iterpool));
773
SVN_ERR(editor->close_edit(edit_baton, iterpool));
778
svn_revnum_t fetched_rev;
781
SVN_ERR(svn_ra_get_dir2(ra_session, &dirents, &fetched_rev, &props,
782
"tags", SVN_INVALID_REVNUM,
783
SVN_DIRENT_ALL, pool));
204
790
/* The test table. */
205
struct svn_test_descriptor_t test_funcs[] =
792
static int max_threads = 2;
794
static struct svn_test_descriptor_t test_funcs[] =
208
797
SVN_TEST_OPTS_PASS(location_segments_test,
209
798
"test svn_ra_get_location_segments"),
799
SVN_TEST_OPTS_PASS(check_tunnel_callback_test,
800
"test ra_svn tunnel callback check"),
801
SVN_TEST_OPTS_PASS(tunnel_callback_test,
802
"test ra_svn tunnel creation callbacks"),
803
SVN_TEST_OPTS_PASS(lock_test,
804
"lock multiple paths"),
805
SVN_TEST_OPTS_PASS(get_dir_test,
210
807
SVN_TEST_OPTS_PASS(commit_callback_failure,
211
808
"commit callback failure"),
809
SVN_TEST_OPTS_PASS(base_revision_above_youngest,
810
"base revision newer than youngest"),
811
SVN_TEST_OPTS_PASS(ra_list_has_props,
812
"check list has_props performance"),