~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/tests/libsvn_ra/ra-test.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
 
26
26
#include <apr_general.h>
27
27
#include <apr_pools.h>
28
 
 
 
28
#include <apr_file_io.h>
 
29
#include <assert.h>
29
30
#define SVN_DEPRECATED
30
31
 
31
32
#include "svn_error.h"
33
34
#include "svn_ra.h"
34
35
#include "svn_time.h"
35
36
#include "svn_pools.h"
 
37
#include "svn_cmdline.h"
 
38
#include "svn_dirent_uri.h"
 
39
#include "svn_hash.h"
36
40
 
37
41
#include "../svn_test.h"
38
42
#include "../svn_test_fs.h"
44
48
 
45
49
 
46
50
static svn_error_t *
47
 
make_and_open_local_repos(svn_ra_session_t **session,
48
 
                          const char *repos_name,
49
 
                          const svn_test_opts_t *opts,
50
 
                          apr_pool_t *pool)
 
51
make_and_open_repos(svn_ra_session_t **session,
 
52
                    const char *repos_name,
 
53
                    const svn_test_opts_t *opts,
 
54
                    apr_pool_t *pool)
51
55
{
52
 
  svn_repos_t *repos;
53
56
  const char *url;
54
57
  svn_ra_callbacks2_t *cbtable;
55
58
 
56
59
  SVN_ERR(svn_ra_create_callbacks(&cbtable, pool));
 
60
  SVN_ERR(svn_test__init_auth_baton(&cbtable->auth_baton, pool));
57
61
 
58
 
  SVN_ERR(svn_test__create_repos(&repos, repos_name, opts, pool));
 
62
  SVN_ERR(svn_test__create_repos2(NULL, &url, NULL, repos_name, opts,
 
63
                                  pool, pool));
59
64
  SVN_ERR(svn_ra_initialize(pool));
60
65
 
61
 
  SVN_ERR(svn_uri_get_file_url_from_dirent(&url, repos_name, pool));
62
 
 
63
 
  SVN_ERR(svn_ra_open3(session, url, NULL, cbtable, NULL, NULL, pool));
 
66
  SVN_ERR(svn_ra_open4(session, NULL, url, NULL, cbtable, NULL, NULL, pool));
64
67
 
65
68
  return SVN_NO_ERROR;
66
69
}
90
93
  return SVN_NO_ERROR;
91
94
}
92
95
 
 
96
static svn_error_t *
 
97
commit_tree(svn_ra_session_t *session,
 
98
            apr_pool_t *pool)
 
99
{
 
100
  apr_hash_t *revprop_table = apr_hash_make(pool);
 
101
  const svn_delta_editor_t *editor;
 
102
  void *edit_baton;
 
103
  const char *repos_root_url;
 
104
  void *root_baton, *A_baton, *B_baton, *file_baton;
 
105
 
 
106
  SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
 
107
                                    revprop_table,
 
108
                                    NULL, NULL, NULL, TRUE, pool));
 
109
  SVN_ERR(svn_ra_get_repos_root(session, &repos_root_url, pool));
 
110
 
 
111
  SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM,
 
112
                            pool, &root_baton));
 
113
  SVN_ERR(editor->add_directory("A", root_baton, NULL, SVN_INVALID_REVNUM,
 
114
                                pool, &A_baton));
 
115
  SVN_ERR(editor->add_directory("A/B", A_baton, NULL, SVN_INVALID_REVNUM,
 
116
                                pool, &B_baton));
 
117
  SVN_ERR(editor->add_file("A/B/f", B_baton, NULL, SVN_INVALID_REVNUM,
 
118
                           pool, &file_baton));
 
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,
 
121
                           pool, &file_baton));
 
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,
 
125
                                pool, &B_baton));
 
126
  SVN_ERR(editor->add_file("A/BB/f", B_baton, NULL, SVN_INVALID_REVNUM,
 
127
                           pool, &file_baton));
 
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,
 
130
                           pool, &file_baton));
 
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));
 
135
  return SVN_NO_ERROR;
 
136
}
 
137
 
 
138
/* Baton for opening tunnels */
 
139
typedef struct tunnel_baton_t
 
140
{
 
141
  int magic; /* TUNNEL_MAGIC */
 
142
  int open_count;
 
143
  svn_boolean_t last_check;
 
144
} tunnel_baton_t;
 
145
 
 
146
#define TUNNEL_MAGIC 0xF00DF00F
 
147
 
 
148
/* Baton for closing a specific tunnel */
 
149
typedef struct close_baton_t
 
150
{
 
151
  int magic;
 
152
  tunnel_baton_t *tb;
 
153
  apr_proc_t *proc;
 
154
} close_baton_t;
 
155
 
 
156
#define CLOSE_MAGIC 0x1BADBAD1
 
157
 
 
158
static svn_boolean_t
 
159
check_tunnel(void *tunnel_baton, const char *tunnel_name)
 
160
{
 
161
  tunnel_baton_t *b = tunnel_baton;
 
162
 
 
163
  if (b->magic != TUNNEL_MAGIC)
 
164
    abort();
 
165
 
 
166
  b->last_check = (0 == strcmp(tunnel_name, "test"));
 
167
  return b->last_check;
 
168
}
 
169
 
 
170
static void
 
171
close_tunnel(void *tunnel_context, void *tunnel_baton);
 
172
 
 
173
static svn_error_t *
 
174
open_tunnel(svn_stream_t **request, svn_stream_t **response,
 
175
            svn_ra_close_tunnel_func_t *close_func, void **close_baton,
 
176
            void *tunnel_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,
 
180
            apr_pool_t *pool)
 
181
{
 
182
  svn_node_kind_t kind;
 
183
  apr_proc_t *proc;
 
184
  apr_procattr_t *attr;
 
185
  apr_status_t status;
 
186
  const char *args[] = { "svnserve", "-t", "-r", ".", NULL };
 
187
  const char *svnserve;
 
188
  tunnel_baton_t *b = tunnel_baton;
 
189
  close_baton_t *cb;
 
190
 
 
191
  SVN_TEST_ASSERT(b->magic == TUNNEL_MAGIC);
 
192
 
 
193
  SVN_ERR(svn_dirent_get_absolute(&svnserve, "../../svnserve/svnserve", pool));
 
194
#ifdef WIN32
 
195
  svnserve = apr_pstrcat(pool, svnserve, ".exe", SVN_VA_NULL);
 
196
#endif
 
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));
 
202
 
 
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);
 
216
 
 
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);
 
222
 
 
223
  cb = apr_pcalloc(pool, sizeof(*cb));
 
224
  cb->magic = CLOSE_MAGIC;
 
225
  cb->tb = b;
 
226
  cb->proc = proc;
 
227
 
 
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;
 
231
  *close_baton = cb;
 
232
  ++b->open_count;
 
233
  return SVN_NO_ERROR;
 
234
}
 
235
 
 
236
static void
 
237
close_tunnel(void *tunnel_context, void *tunnel_baton)
 
238
{
 
239
  close_baton_t *b = tunnel_context;
 
240
 
 
241
  if (b->magic != CLOSE_MAGIC)
 
242
    abort();
 
243
  if (--b->tb->open_count == 0)
 
244
    {
 
245
      apr_status_t child_exit_status;
 
246
      int child_exit_code;
 
247
      apr_exit_why_e child_exit_why;
 
248
 
 
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));
 
251
 
 
252
      child_exit_status =
 
253
        apr_proc_wait(b->proc, &child_exit_code, &child_exit_why, APR_WAIT);
 
254
 
 
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);
 
258
    }
 
259
}
 
260
 
 
261
 
 
262
 
 
263
 
93
264
/*-------------------------------------------------------------------*/
94
265
 
95
266
/** The tests **/
130
301
  b.segments = segments;
131
302
  b.pool = pool;
132
303
 
133
 
  SVN_ERR(make_and_open_local_repos(&session,
134
 
                                    "test-repo-locsegs", opts,
135
 
                                    pool));
 
304
  SVN_ERR(make_and_open_repos(&session,
 
305
                              "test-repo-locsegs", opts,
 
306
                              pool));
136
307
 
137
308
  /* ### This currently tests only a small subset of what's possible. */
138
309
  SVN_ERR(commit_changes(session, pool));
153
324
}
154
325
 
155
326
 
 
327
/* Test ra_svn tunnel callbacks. */
 
328
 
 
329
static svn_error_t *
 
330
check_tunnel_callback_test(const svn_test_opts_t *opts,
 
331
                           apr_pool_t *pool)
 
332
{
 
333
  tunnel_baton_t b = { TUNNEL_MAGIC };
 
334
  svn_ra_callbacks2_t *cbtable;
 
335
  svn_ra_session_t *session;
 
336
  svn_error_t *err;
 
337
 
 
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",
 
345
                                        NULL,
 
346
                                        TRUE  /* no_auth_cache */,
 
347
                                        FALSE /* trust_server_cert */,
 
348
                                        NULL, NULL, NULL, pool));
 
349
 
 
350
  b.last_check = TRUE;
 
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);
 
356
  return SVN_NO_ERROR;
 
357
}
 
358
 
 
359
static svn_error_t *
 
360
tunnel_callback_test(const svn_test_opts_t *opts,
 
361
                     apr_pool_t *pool)
 
362
{
 
363
  tunnel_baton_t b = { TUNNEL_MAGIC };
 
364
  apr_pool_t *scratch_pool = svn_pool_create(pool);
 
365
  const char *url;
 
366
  svn_ra_callbacks2_t *cbtable;
 
367
  svn_ra_session_t *session;
 
368
  svn_error_t *err;
 
369
  const char tunnel_repos_name[] = "test-repo-tunnel";
 
370
 
 
371
  SVN_ERR(svn_test__create_repos(NULL, tunnel_repos_name, opts, scratch_pool));
 
372
 
 
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);
 
376
 
 
377
  url = apr_pstrcat(pool, "svn+test://localhost/", tunnel_repos_name,
 
378
                    SVN_VA_NULL);
 
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",
 
386
                                        NULL,
 
387
                                        TRUE  /* no_auth_cache */,
 
388
                                        FALSE /* trust_server_cert */,
 
389
                                        NULL, NULL, NULL, pool));
 
390
 
 
391
  b.last_check = FALSE;
 
392
  err = svn_ra_open4(&session, NULL, url, NULL, cbtable, NULL, NULL,
 
393
                     scratch_pool);
 
394
  if (err && err->apr_err == SVN_ERR_TEST_FAILED)
 
395
    {
 
396
      svn_handle_error2(err, stderr, FALSE, "svn_tests: ");
 
397
      svn_error_clear(err);
 
398
      return SVN_NO_ERROR;
 
399
    }
 
400
  SVN_ERR(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);
 
405
  return SVN_NO_ERROR;
 
406
}
 
407
 
 
408
struct lock_result_t {
 
409
  svn_lock_t *lock;
 
410
  svn_error_t *err;
 
411
};
 
412
 
 
413
struct lock_baton_t {
 
414
  apr_hash_t *results;
 
415
  apr_pool_t *pool;
 
416
};
 
417
 
 
418
/* Implements svn_ra_lock_callback_t. */
 
419
static svn_error_t *
 
420
lock_cb(void *baton,
 
421
        const char *path,
 
422
        svn_boolean_t do_lock,
 
423
        const svn_lock_t *lock,
 
424
        svn_error_t *ra_err,
 
425
        apr_pool_t *pool)
 
426
{
 
427
  struct lock_baton_t *b = baton;
 
428
  struct lock_result_t *result = apr_palloc(b->pool,
 
429
                                            sizeof(struct lock_result_t));
 
430
 
 
431
  if (lock)
 
432
    {
 
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);
 
439
    }
 
440
  else
 
441
    result->lock = NULL;
 
442
  result->err = ra_err;
 
443
 
 
444
  svn_hash_sets(b->results, apr_pstrdup(b->pool, path), result);
 
445
 
 
446
  return SVN_NO_ERROR;
 
447
}
 
448
 
 
449
static svn_error_t *
 
450
expect_lock(const char *path,
 
451
            apr_hash_t *results,
 
452
            svn_ra_session_t *session,
 
453
            apr_pool_t *scratch_pool)
 
454
{
 
455
  svn_lock_t *lock;
 
456
  struct lock_result_t *result = svn_hash_gets(results, path);
 
457
 
 
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);
 
461
  return SVN_NO_ERROR;
 
462
}
 
463
 
 
464
static svn_error_t *
 
465
expect_error(const char *path,
 
466
             apr_hash_t *results,
 
467
             svn_ra_session_t *session,
 
468
             apr_pool_t *scratch_pool)
 
469
{
 
470
  svn_lock_t *lock;
 
471
  struct lock_result_t *result = svn_hash_gets(results, path);
 
472
 
 
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));
 
477
 
 
478
  SVN_TEST_ASSERT(!lock);
 
479
  return SVN_NO_ERROR;
 
480
}
 
481
 
 
482
static svn_error_t *
 
483
expect_unlock(const char *path,
 
484
              apr_hash_t *results,
 
485
              svn_ra_session_t *session,
 
486
              apr_pool_t *scratch_pool)
 
487
{
 
488
  svn_lock_t *lock;
 
489
  struct lock_result_t *result = svn_hash_gets(results, path);
 
490
 
 
491
  SVN_TEST_ASSERT(result && !result->err);
 
492
  SVN_ERR(svn_ra_get_lock(session, &lock, path, scratch_pool));
 
493
  SVN_TEST_ASSERT(!lock);
 
494
  return SVN_NO_ERROR;
 
495
}
 
496
 
 
497
static svn_error_t *
 
498
expect_unlock_error(const char *path,
 
499
                    apr_hash_t *results,
 
500
                    svn_ra_session_t *session,
 
501
                    apr_pool_t *scratch_pool)
 
502
{
 
503
  svn_lock_t *lock;
 
504
  struct lock_result_t *result = svn_hash_gets(results, path);
 
505
 
 
506
  SVN_TEST_ASSERT(result && result->err);
 
507
  SVN_ERR(svn_ra_get_lock(session, &lock, path, scratch_pool));
 
508
  SVN_TEST_ASSERT(lock);
 
509
  return SVN_NO_ERROR;
 
510
}
 
511
 
 
512
/* Test svn_ra_lock(). */
 
513
static svn_error_t *
 
514
lock_test(const svn_test_opts_t *opts,
 
515
          apr_pool_t *pool)
 
516
{
 
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;
 
524
 
 
525
  SVN_ERR(make_and_open_repos(&session, "test-repo-lock", opts, pool));
 
526
  SVN_ERR(commit_tree(session, pool));
 
527
 
 
528
  baton.results = apr_hash_make(pool);
 
529
  baton.pool = pool;
 
530
 
 
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);
 
536
 
 
537
  /* Lock some paths. */
 
538
  SVN_ERR(svn_ra_lock(session, lock_targets, "foo", FALSE, lock_cb, &baton,
 
539
                      pool));
 
540
 
 
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));
 
546
 
 
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));
 
552
 
 
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));
 
558
 
 
559
  /* Force unlock */
 
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));
 
564
 
 
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));
 
570
 
 
571
  /* Lock again. */
 
572
  apr_hash_clear(baton.results);
 
573
  SVN_ERR(svn_ra_lock(session, lock_targets, "foo", FALSE, lock_cb, &baton,
 
574
                      pool));
 
575
 
 
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));
 
581
 
 
582
  for (hi = apr_hash_first(pool, baton.results); hi; hi = apr_hash_next(hi))
 
583
    {
 
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");
 
587
    }
 
588
  apr_hash_clear(baton.results);
 
589
  SVN_ERR(svn_ra_unlock(session, unlock_targets, FALSE, lock_cb, &baton, pool));
 
590
 
 
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));
 
596
 
 
597
  return SVN_NO_ERROR;
 
598
}
 
599
 
 
600
/* Test svn_ra_get_dir2(). */
 
601
static svn_error_t *
 
602
get_dir_test(const svn_test_opts_t *opts,
 
603
             apr_pool_t *pool)
 
604
{
 
605
  svn_ra_session_t *session;
 
606
  apr_hash_t *dirents;
 
607
 
 
608
  SVN_ERR(make_and_open_repos(&session, "test-get-dir", opts, pool));
 
609
  SVN_ERR(commit_tree(session, pool));
 
610
 
 
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);
 
616
 
 
617
  return SVN_NO_ERROR;
 
618
}
 
619
 
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,
162
626
  apr_time_t timetemp;
163
627
 
164
628
  SVN_TEST_ASSERT(info != NULL);
165
 
  SVN_TEST_STRING_ASSERT(info->author, "");  /* No auth baton supplied. */
 
629
  SVN_TEST_STRING_ASSERT(info->author, "jrandom");
166
630
  SVN_TEST_STRING_ASSERT(info->post_commit_err, NULL);
167
631
 
168
632
  SVN_ERR(svn_time_from_cstring(&timetemp, info->date, scratch_pool));
169
 
  SVN_TEST_ASSERT(info->date != 0);
 
633
  SVN_TEST_ASSERT(timetemp != 0);
170
634
  SVN_TEST_ASSERT(info->repos_root != NULL);
171
635
  SVN_TEST_ASSERT(info->revision == 1);
172
636
 
181
645
  const svn_delta_editor_t *editor;
182
646
  void *edit_baton;
183
647
  void *root_baton;
184
 
  SVN_ERR(make_and_open_local_repos(&ra_session, "commit_cb_failure", opts, pool));
 
648
  SVN_ERR(make_and_open_repos(&ra_session, "commit_cb_failure", opts, pool));
185
649
 
186
650
  SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
187
651
                                    apr_hash_make(pool), commit_callback_with_failure,
188
652
                                    NULL, NULL, FALSE, pool));
189
653
 
190
 
  SVN_ERR(editor->open_root(edit_baton, 1, pool, &root_baton));
 
654
  SVN_ERR(editor->open_root(edit_baton, 0, pool, &root_baton));
191
655
  SVN_ERR(editor->change_dir_prop(root_baton, "A",
192
656
                                  svn_string_create("B", pool), pool));
193
657
  SVN_ERR(editor->close_directory(root_baton, pool));
200
664
  return SVN_NO_ERROR;
201
665
}
202
666
 
 
667
static svn_error_t *
 
668
base_revision_above_youngest(const svn_test_opts_t *opts,
 
669
                              apr_pool_t *pool)
 
670
{
 
671
  svn_ra_session_t *ra_session;
 
672
  const svn_delta_editor_t *editor;
 
673
  void *edit_baton;
 
674
  void *root_baton;
 
675
  svn_error_t *err;
 
676
  SVN_ERR(make_and_open_repos(&ra_session, "base_revision_above_youngest",
 
677
                              opts, pool));
 
678
 
 
679
  SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
 
680
                                    apr_hash_make(pool), NULL,
 
681
                                    NULL, NULL, FALSE, pool));
 
682
 
 
683
  /* r1 doesn't exist, but we say we want to apply changes against this
 
684
     revision to see how the ra layers behave.
 
685
 
 
686
     Some will see an error directly on open_root, others in a later
 
687
     state. */
 
688
 
 
689
  /* ra-local and http pre-v2 will see the error here */
 
690
  err = editor->open_root(edit_baton, 1, pool, &root_baton);
 
691
 
 
692
  if (!err)
 
693
    err = editor->change_dir_prop(root_baton, "A",
 
694
                                  svn_string_create("B", pool), pool);
 
695
 
 
696
  /* http v2 will notice it here (PROPPATCH) */
 
697
  if (!err)
 
698
    err = editor->close_directory(root_baton, pool);
 
699
 
 
700
  /* ra svn only notes it at some later point. Typically here */
 
701
  if (!err)
 
702
    err = editor->close_edit(edit_baton, pool);
 
703
 
 
704
  SVN_TEST_ASSERT_ERROR(err,
 
705
                        SVN_ERR_FS_NO_SUCH_REVISION);
 
706
 
 
707
  SVN_ERR(editor->abort_edit(edit_baton, pool));
 
708
  return SVN_NO_ERROR;
 
709
}
 
710
 
 
711
 
 
712
static svn_error_t *
 
713
ra_list_has_props(const svn_test_opts_t *opts,
 
714
                  apr_pool_t *pool)
 
715
{
 
716
  svn_ra_session_t *ra_session;
 
717
  const svn_delta_editor_t *editor;
 
718
  apr_pool_t *iterpool = svn_pool_create(pool);
 
719
  int i;
 
720
  void *edit_baton;
 
721
  const char *trunk_url;
 
722
 
 
723
  SVN_ERR(make_and_open_repos(&ra_session, "ra_list_has_props",
 
724
                              opts, pool));
 
725
 
 
726
  SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
 
727
                                    apr_hash_make(pool), NULL,
 
728
                                    NULL, NULL, FALSE, iterpool));
 
729
 
 
730
  /* Create initial layout*/
 
731
  {
 
732
    void *root_baton;
 
733
    void *dir_baton;
 
734
 
 
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));
 
744
  }
 
745
 
 
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);
 
748
 
 
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++)
 
752
    {
 
753
      void *root_baton;
 
754
      void *tags_baton;
 
755
      void *dir_baton;
 
756
 
 
757
      svn_pool_clear(iterpool);
 
758
 
 
759
      SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
 
760
                                        apr_hash_make(pool), NULL,
 
761
                                        NULL, NULL, FALSE, iterpool));
 
762
 
 
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,
 
765
                                     &tags_baton));
 
766
      SVN_ERR(editor->add_directory(apr_psprintf(iterpool, "tags/T%05d", i+1),
 
767
                                    tags_baton, trunk_url, 1, iterpool,
 
768
                                    &dir_baton));
 
769
 
 
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));
 
774
    }
 
775
 
 
776
  {
 
777
    apr_hash_t *dirents;
 
778
    svn_revnum_t fetched_rev;
 
779
    apr_hash_t *props;
 
780
 
 
781
    SVN_ERR(svn_ra_get_dir2(ra_session, &dirents, &fetched_rev, &props,
 
782
                            "tags", SVN_INVALID_REVNUM,
 
783
                            SVN_DIRENT_ALL, pool));
 
784
  }
 
785
 
 
786
  return SVN_NO_ERROR;
 
787
}
 
788
 
203
789
 
204
790
/* The test table.  */
205
 
struct svn_test_descriptor_t test_funcs[] =
 
791
 
 
792
static int max_threads = 2;
 
793
 
 
794
static struct svn_test_descriptor_t test_funcs[] =
206
795
  {
207
796
    SVN_TEST_NULL,
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,
 
806
                       "test ra_get_dir2"),
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"),
212
813
    SVN_TEST_NULL
213
814
  };
 
815
 
 
816
SVN_TEST_MAIN