コード例 #1
0
ファイル: ra.py プロジェクト: svn2github/subversion
    def test_lock(self):

        self.calls = 0
        self.locks = 0
        self.errors = 0

        def callback(path, do_lock, lock, ra_err, pool):
            self.calls += 1
            self.assertEqual(path, "trunk/README2.txt")
            if lock:
                self.assertEqual(lock.owner, "jrandom")
                self.locks += 1
            if ra_err:
                self.assert_(
                    ra_err.apr_err == core.SVN_ERR_FS_PATH_ALREADY_LOCKED
                    or ra_err.apr_err == core.SVN_ERR_FS_NO_SUCH_LOCK)
                self.errors += 1

        providers = [core.svn_auth_get_username_provider()]
        self.callbacks.auth_baton = core.svn_auth_open(providers)
        core.svn_auth_set_parameter(self.callbacks.auth_baton,
                                    core.SVN_AUTH_PARAM_DEFAULT_USERNAME,
                                    "jrandom")
        self.ra_ctx = ra.open2(self.repos_uri, self.callbacks, {})
        rev = fs.youngest_rev(self.fs)
        ra.lock(self.ra_ctx, {"trunk/README2.txt": rev}, "sleutel", False,
                callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 1)
        self.assertEqual(self.errors, 0)

        self.calls = 0
        self.locks = 0
        ra.lock(self.ra_ctx, {"trunk/README2.txt": rev}, "sleutel", False,
                callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 0)
        self.assertEqual(self.errors, 1)

        self.calls = 0
        self.errors = 0
        the_lock = fs.get_lock(self.fs, "/trunk/README2.txt")
        ra.unlock(self.ra_ctx, {"trunk/README2.txt": the_lock.token}, False,
                  callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 0)
        self.assertEqual(self.errors, 0)

        self.calls = 0
        ra.unlock(self.ra_ctx, {"trunk/README2.txt": the_lock.token}, False,
                  callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 0)
        self.assertEqual(self.errors, 1)
コード例 #2
0
ファイル: ra.py プロジェクト: gunjanms/svnmigration
  def test_lock(self):

    self.calls = 0
    self.locks = 0
    self.errors = 0
    def callback(path, do_lock, lock, ra_err, pool):
      self.calls += 1
      self.assertEqual(path, "trunk/README2.txt")
      if lock:
        self.assertEqual(lock.owner, "jrandom")
        self.locks += 1
      if ra_err:
        self.assert_(ra_err.apr_err == core.SVN_ERR_FS_PATH_ALREADY_LOCKED
                     or ra_err.apr_err == core.SVN_ERR_FS_NO_SUCH_LOCK)
        self.errors += 1

    providers = [core.svn_auth_get_username_provider()]
    self.callbacks.auth_baton = core.svn_auth_open(providers)
    core.svn_auth_set_parameter(self.callbacks.auth_baton,
                                core.SVN_AUTH_PARAM_DEFAULT_USERNAME,
                                "jrandom")
    self.ra_ctx = ra.open2(self.repos_uri, self.callbacks, {})
    rev = fs.youngest_rev(self.fs)
    ra.lock(self.ra_ctx, {"trunk/README2.txt":rev}, "sleutel", False, callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.locks, 1)
    self.assertEqual(self.errors, 0)

    self.calls = 0
    self.locks = 0
    ra.lock(self.ra_ctx, {"trunk/README2.txt":rev}, "sleutel", False, callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.locks, 0)
    self.assertEqual(self.errors, 1)

    self.calls = 0
    self.errors = 0
    the_lock = fs.get_lock(self.fs, "/trunk/README2.txt")
    ra.unlock(self.ra_ctx, {"trunk/README2.txt":the_lock.token}, False, callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.locks, 0)
    self.assertEqual(self.errors, 0)

    self.calls = 0
    ra.unlock(self.ra_ctx, {"trunk/README2.txt":the_lock.token}, False, callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.locks, 0)
    self.assertEqual(self.errors, 1)
コード例 #3
0
ファイル: svn_repos.py プロジェクト: vitalif/viewvc-4intranet
 def dirlogs(self, path_parts, rev, entries, options):
   path = self._getpath(path_parts)
   if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
     raise vclib.Error("Path '%s' is not a directory." % path)
   fsroot = self._getroot(self._getrev(rev))
   rev = self._getrev(rev)
   for entry in entries:
     entry_path_parts = path_parts + [entry.name]
     if not vclib.check_path_access(self, entry_path_parts, entry.kind, rev):
       continue
     path = self._getpath(entry_path_parts)
     entry_rev = _get_last_history_rev(fsroot, path)
     date, author, msg, revprops, changes = self._revinfo(entry_rev)
     entry.rev = str(entry_rev)
     entry.date = date
     entry.author = author
     entry.log = msg
     if entry.kind == vclib.FILE:
       entry.size = fs.file_length(fsroot, path)
     lock = fs.get_lock(self.fs_ptr, path)
     entry.lockinfo = lock and lock.owner or None
コード例 #4
0
 def dirlogs(self, path_parts, rev, entries, options):
   path = self._getpath(path_parts)
   if self.itemtype(path_parts, rev) != vclib.DIR:  # does auth-check
     raise vclib.Error("Path '%s' is not a directory." % path)
   fsroot = self._getroot(self._getrev(rev))
   rev = self._getrev(rev)
   for entry in entries:
     entry_path_parts = path_parts + [entry.name]
     if not vclib.check_path_access(self, entry_path_parts, entry.kind, rev):
       continue
     path = self._getpath(entry_path_parts)
     entry_rev = _get_last_history_rev(fsroot, path)
     date, author, msg, revprops, changes = self._revinfo(entry_rev)
     entry.rev = str(entry_rev)
     entry.date = date
     entry.author = author
     entry.log = msg
     if entry.kind == vclib.FILE:
       entry.size = fs.file_length(fsroot, path)
     lock = fs.get_lock(self.fs_ptr, path)
     entry.lockinfo = lock and lock.owner or None
コード例 #5
0
    def test_lock_unlock(self):
        """Basic lock/unlock"""

        access = fs.create_access('jrandom')
        fs.set_access(self.fs, access)
        fs.lock(self.fs, '/trunk/README.txt', None, None, 0, 0, self.rev,
                False)
        try:
            fs.lock(self.fs, '/trunk/README.txt', None, None, 0, 0, self.rev,
                    False)
        except core.SubversionException as exc:
            self.assertEqual(exc.apr_err, core.SVN_ERR_FS_PATH_ALREADY_LOCKED)
        fs.lock(self.fs, '/trunk/README.txt', None, None, 0, 0, self.rev, True)

        self.calls = 0
        self.errors = 0

        def unlock_callback(path, lock, err, pool):
            self.assertEqual(path, '/trunk/README.txt')
            self.assertEqual(lock, None)
            self.calls += 1
            if err != None:
                self.assertEqual(err.apr_err, core.SVN_ERR_FS_NO_SUCH_LOCK)
                self.errors += 1

        the_lock = fs.get_lock(self.fs, '/trunk/README.txt')
        fs.unlock_many(self.fs, {'/trunk/README.txt': the_lock.token}, False,
                       unlock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.errors, 0)

        self.calls = 0
        fs.unlock_many(self.fs, {'/trunk/README.txt': the_lock.token}, False,
                       unlock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.errors, 1)

        self.locks = 0

        def lock_callback(path, lock, err, pool):
            self.assertEqual(path, '/trunk/README.txt')
            if lock != None:
                self.assertEqual(lock.owner, 'jrandom')
                self.locks += 1
            self.calls += 1
            if err != None:
                self.assertEqual(err.apr_err,
                                 core.SVN_ERR_FS_PATH_ALREADY_LOCKED)
                self.errors += 1

        self.calls = 0
        self.errors = 0
        target = fs.lock_target_create(None, self.rev)
        fs.lock_many(self.fs, {'trunk/README.txt': target}, None, False, 0,
                     False, lock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 1)
        self.assertEqual(self.errors, 0)

        self.calls = 0
        self.locks = 0
        fs.lock_many(self.fs, {'trunk/README.txt': target}, None, False, 0,
                     False, lock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 0)
        self.assertEqual(self.errors, 1)

        self.calls = 0
        self.errors = 0
        the_lock = fs.get_lock(self.fs, '/trunk/README.txt')
        repos.fs_unlock_many(self.repos, {'trunk/README.txt': the_lock.token},
                             False, unlock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.errors, 0)

        self.calls = 0
        repos.fs_unlock_many(self.repos, {'trunk/README.txt': the_lock.token},
                             False, unlock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.errors, 1)

        self.calls = 0
        self.errors = 0
        repos.fs_lock_many(self.repos, {'trunk/README.txt': target}, None,
                           False, 0, False, lock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 1)
        self.assertEqual(self.errors, 0)

        self.calls = 0
        self.locks = 0
        repos.fs_lock_many(self.repos, {'trunk/README.txt': target}, None,
                           False, 0, False, lock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 0)
        self.assertEqual(self.errors, 1)
コード例 #6
0
    def itemlog(self, path_parts, rev, sortby, first, limit, options):
        """see vclib.Repository.itemlog docstring

        Option values recognized by this implementation

          svn_show_all_dir_logs
            boolean, default false. if set for a directory path, will include
            revisions where files underneath the directory have changed

          svn_cross_copies
            boolean, default false. if set for a path created by a copy, will
            include revisions from before the copy

          svn_latest_log
            boolean, default false. if set will return only newest single log
            entry
        """
        assert sortby == vclib.SORTBY_DEFAULT or sortby == vclib.SORTBY_REV

        path = self._getpath(path_parts)
        path_type = self.itemtype(path_parts, rev)  # does auth-check
        rev = self._getrev(rev)
        revs = []
        lockinfo = None

        # See if this path is locked.
        try:
            lock = fs.get_lock(self.fs_ptr, path)
            if lock:
                lockinfo = _to_str(lock.owner)
        except NameError:
            pass

        # If our caller only wants the latest log, we'll invoke
        # _log_helper for just the one revision.  Otherwise, we go off
        # into history-fetching mode.  ### TODO: we could stand to have a
        # 'limit' parameter here as numeric cut-off for the depth of our
        # history search.
        if options.get("svn_latest_log", 0):
            revision = self._log_helper(path, rev, lockinfo)
            if revision:
                revision.prev = None
                revs.append(revision)
        else:
            history = self._get_history(path, rev, path_type, first + limit,
                                        options)
            if len(history) < first:
                history = []
            if limit:
                history = history[first:(first + limit)]

            for hist_rev, hist_path in history:
                revision = self._log_helper(hist_path, hist_rev, lockinfo)
                if revision:
                    # If we have unreadable copyfrom data, obscure it.
                    if revision.copy_path is not None:
                        cp_parts = _path_parts(revision.copy_path)
                        if not vclib.check_path_access(
                                self, cp_parts, path_type, revision.copy_rev):
                            revision.copy_path = revision.copy_rev = None
                    revision.prev = None
                    if len(revs):
                        revs[-1].prev = revision
                    revs.append(revision)
        return revs
コード例 #7
0
ファイル: svn_repos.py プロジェクト: vitalif/viewvc-4intranet
  def itemlog(self, path_parts, rev, sortby, first, limit, options):
    """see vclib.Repository.itemlog docstring

    Option values recognized by this implementation

      svn_show_all_dir_logs
        boolean, default false. if set for a directory path, will include
        revisions where files underneath the directory have changed

      svn_cross_copies
        boolean, default false. if set for a path created by a copy, will
        include revisions from before the copy

      svn_latest_log
        boolean, default false. if set will return only newest single log
        entry
    """
    assert sortby == vclib.SORTBY_DEFAULT or sortby == vclib.SORTBY_REV   

    path = self._getpath(path_parts)
    path_type = self.itemtype(path_parts, rev)  # does auth-check
    rev = self._getrev(rev)
    revs = []
    lockinfo = None

    # See if this path is locked.
    try:
      lock = fs.get_lock(self.fs_ptr, path)
      if lock:
        lockinfo = lock.owner
    except NameError:
      pass

    # If our caller only wants the latest log, we'll invoke
    # _log_helper for just the one revision.  Otherwise, we go off
    # into history-fetching mode.  ### TODO: we could stand to have a
    # 'limit' parameter here as numeric cut-off for the depth of our
    # history search.
    if options.get('svn_latest_log', 0):
      revision = self._log_helper(path, rev, lockinfo)
      if revision:
        revision.prev = None
        revs.append(revision)
    else:
      history = self._get_history(path, rev, path_type, first + limit, options)
      if len(history) < first:
        history = []
      if limit:
        history = history[first:first+limit]

      for hist_rev, hist_path in history:
        revision = self._log_helper(hist_path, hist_rev, lockinfo)
        if revision:
          # If we have unreadable copyfrom data, obscure it.
          if revision.copy_path is not None:
            cp_parts = _path_parts(revision.copy_path)
            if not vclib.check_path_access(self, cp_parts, path_type,
                                           revision.copy_rev):
              revision.copy_path = revision.copy_rev = None
          revision.prev = None
          if len(revs):
            revs[-1].prev = revision
          revs.append(revision)
    return revs
コード例 #8
0
ファイル: repository.py プロジェクト: svn2github/subversion
  def test_lock_unlock(self):
    """Basic lock/unlock"""

    access = fs.create_access('jrandom')
    fs.set_access(self.fs, access)
    fs.lock(self.fs, '/trunk/README.txt', None, None, 0, 0, self.rev, False)
    try:
      fs.lock(self.fs, '/trunk/README.txt', None, None, 0, 0, self.rev, False)
    except core.SubversionException as exc:
      self.assertEqual(exc.apr_err, core.SVN_ERR_FS_PATH_ALREADY_LOCKED)
    fs.lock(self.fs, '/trunk/README.txt', None, None, 0, 0, self.rev, True)

    self.calls = 0
    self.errors = 0
    def unlock_callback(path, lock, err, pool):
      self.assertEqual(path, '/trunk/README.txt')
      self.assertEqual(lock, None)
      self.calls += 1
      if err != None:
        self.assertEqual(err.apr_err, core.SVN_ERR_FS_NO_SUCH_LOCK)
        self.errors += 1

    the_lock = fs.get_lock(self.fs, '/trunk/README.txt')
    fs.unlock_many(self.fs, {'/trunk/README.txt':the_lock.token}, False,
                   unlock_callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.errors, 0)

    self.calls = 0
    fs.unlock_many(self.fs, {'/trunk/README.txt':the_lock.token}, False,
                   unlock_callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.errors, 1)

    self.locks = 0
    def lock_callback(path, lock, err, pool):
      self.assertEqual(path, '/trunk/README.txt')
      if lock != None:
        self.assertEqual(lock.owner, 'jrandom')
        self.locks += 1
      self.calls += 1
      if err != None:
        self.assertEqual(err.apr_err, core.SVN_ERR_FS_PATH_ALREADY_LOCKED)
        self.errors += 1
      
    self.calls = 0
    self.errors = 0
    target = fs.lock_target_create(None, self.rev)
    fs.lock_many(self.fs, {'trunk/README.txt':target},
                 None, False, 0, False, lock_callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.locks, 1)
    self.assertEqual(self.errors, 0)

    self.calls = 0
    self.locks = 0
    fs.lock_many(self.fs, {'trunk/README.txt':target},
                 None, False, 0, False, lock_callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.locks, 0)
    self.assertEqual(self.errors, 1)

    self.calls = 0
    self.errors = 0
    the_lock = fs.get_lock(self.fs, '/trunk/README.txt')
    repos.fs_unlock_many(self.repos, {'trunk/README.txt':the_lock.token},
                         False, unlock_callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.errors, 0)

    self.calls = 0
    repos.fs_unlock_many(self.repos, {'trunk/README.txt':the_lock.token},
                         False, unlock_callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.errors, 1)

    self.calls = 0
    self.errors = 0
    repos.fs_lock_many(self.repos, {'trunk/README.txt':target},
                       None, False, 0, False, lock_callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.locks, 1)
    self.assertEqual(self.errors, 0)

    self.calls = 0
    self.locks = 0
    repos.fs_lock_many(self.repos, {'trunk/README.txt':target},
                       None, False, 0, False, lock_callback)
    self.assertEqual(self.calls, 1)
    self.assertEqual(self.locks, 0)
    self.assertEqual(self.errors, 1)
コード例 #9
0
class SubversionRepositoryTestCase(unittest.TestCase):
    """Test cases for the Subversion repository layer"""
    def setUp(self):
        """Load a Subversion repository"""
        self.temper = utils.Temper()
        (self.repos, self.repos_path, _) = self.temper.alloc_known_repo(
            'trac/versioncontrol/tests/svnrepos.dump', suffix='-repository')
        self.fs = repos.fs(self.repos)
        self.rev = fs.youngest_rev(self.fs)

    def tearDown(self):
        self.fs = None
        self.repos = None
        self.temper.cleanup()

    def test_cease_invocation(self):
        """Test returning SVN_ERR_CEASE_INVOCATION from a callback"""

        revs = []

        def history_lookup(path, rev, pool):
            revs.append(rev)
            raise core.SubversionException(
                apr_err=core.SVN_ERR_CEASE_INVOCATION,
                message="Hi from history_lookup")

        repos.history2(self.fs, '/trunk/README2.txt', history_lookup, None, 0,
                       self.rev, True)
        self.assertEqual(len(revs), 1)

    def test_create(self):
        """Make sure that repos.create doesn't segfault when we set fs-type
       using a config hash"""
        fs_config = {"fs-type": "fsfs"}
        for i in range(5):
            path = self.temper.alloc_empty_dir(suffix='-repository-create%d' %
                                               i)
            repos.create(path, "", "", None, fs_config)

    def test_dump_fs2(self):
        """Test the dump_fs2 function"""

        self.callback_calls = 0

        def is_cancelled():
            self.callback_calls += 1
            return None

        dumpstream = StringIO()
        feedbackstream = StringIO()
        repos.dump_fs2(self.repos, dumpstream, feedbackstream, 0, self.rev, 0,
                       0, is_cancelled)

        # Check that we can dump stuff
        dump = dumpstream.getvalue()
        feedback = feedbackstream.getvalue()
        expected_feedback = "* Dumped revision " + str(self.rev)
        self.assertEquals(dump.count("Node-path: trunk/README.txt"), 2)
        self.assertEquals(feedback.count(expected_feedback), 1)
        self.assertEquals(self.callback_calls, 13)

        # Check that the dump can be cancelled
        self.assertRaises(SubversionException, repos.dump_fs2, self.repos,
                          dumpstream, feedbackstream, 0, self.rev, 0, 0,
                          lambda: 1)

        dumpstream.close()
        feedbackstream.close()

        # Check that the dump fails when the dumpstream is closed
        self.assertRaises(ValueError, repos.dump_fs2, self.repos, dumpstream,
                          feedbackstream, 0, self.rev, 0, 0, None)

        dumpstream = StringIO()
        feedbackstream = StringIO()

        # Check that we can grab the feedback stream, but not the dumpstream
        repos.dump_fs2(self.repos, None, feedbackstream, 0, self.rev, 0, 0,
                       None)
        feedback = feedbackstream.getvalue()
        self.assertEquals(feedback.count(expected_feedback), 1)

        # Check that we can grab the dumpstream, but not the feedbackstream
        repos.dump_fs2(self.repos, dumpstream, None, 0, self.rev, 0, 0, None)
        dump = dumpstream.getvalue()
        self.assertEquals(dump.count("Node-path: trunk/README.txt"), 2)

        # Check that we can ignore both the dumpstream and the feedbackstream
        repos.dump_fs2(self.repos, dumpstream, None, 0, self.rev, 0, 0, None)
        self.assertEquals(feedback.count(expected_feedback), 1)

        # FIXME: The Python bindings don't check for 'NULL' values for
        #        svn_repos_t objects, so the following call segfaults
        #repos.dump_fs2(None, None, None, 0, self.rev, 0, 0, None)

    def test_parse_fns3(self):
        self.cancel_calls = 0

        def is_cancelled():
            self.cancel_calls += 1
            return None

        dump_path = os.path.join(os.path.dirname(sys.argv[0]),
                                 "trac/versioncontrol/tests/svnrepos.dump")
        stream = open(dump_path)
        dsp = DumpStreamParser()
        ptr, baton = repos.make_parse_fns3(dsp)
        repos.parse_dumpstream3(stream, ptr, baton, False, is_cancelled)
        stream.close()
        self.assertEqual(self.cancel_calls, 76)
        expected_list = [
            ("magic-header", 2),
            ('uuid', '92ea810a-adf3-0310-b540-bef912dcf5ba'),
            ('new-revision', 0),
            ('set-revision-prop', 0, 'svn:date',
             '2005-04-01T09:57:41.312767Z'),
            ('close-revision', 0),
            ('new-revision', 1),
            ('set-revision-prop', 1, 'svn:log', 'Initial directory layout.'),
            ('set-revision-prop', 1, 'svn:author', 'john'),
            ('set-revision-prop', 1, 'svn:date',
             '2005-04-01T10:00:52.353248Z'),
            ('new-node', 1, 'branches'),
            ('remove-node-props', 1, 'branches'),
            ('close-node', 1, 'branches'),
            ('new-node', 1, 'tags'),
            ('remove-node-props', 1, 'tags'),
            ('close-node', 1, 'tags'),
            ('new-node', 1, 'trunk'),
            ('remove-node-props', 1, 'trunk'),
            ('close-node', 1, 'trunk'),
            ('close-revision', 1),
            ('new-revision', 2),
            ('set-revision-prop', 2, 'svn:log', 'Added README.'),
            ('set-revision-prop', 2, 'svn:author', 'john'),
            ('set-revision-prop', 2, 'svn:date',
             '2005-04-01T13:12:18.216267Z'),
            ('new-node', 2, 'trunk/README.txt'),
            ('remove-node-props', 2, 'trunk/README.txt'),
            ('set-fulltext', 2, 'trunk/README.txt'),
            ('close-node', 2, 'trunk/README.txt'),
            ('close-revision', 2),
            ('new-revision', 3),
            ('set-revision-prop', 3, 'svn:log', 'Fixed README.\n'),
            ('set-revision-prop', 3, 'svn:author', 'kate'),
            ('set-revision-prop', 3, 'svn:date',
             '2005-04-01T13:24:58.234643Z'),
            ('new-node', 3, 'trunk/README.txt'),
            ('remove-node-props', 3, 'trunk/README.txt'),
            ('set-node-prop', 3, 'trunk/README.txt', 'svn:mime-type',
             'text/plain'),
            ('set-node-prop', 3, 'trunk/README.txt', 'svn:eol-style',
             'native'),
            ('set-fulltext', 3, 'trunk/README.txt'),
            ('close-node', 3, 'trunk/README.txt'),
            ('close-revision', 3),
        ]
        # Compare only the first X nodes described in the expected list - otherwise
        # the comparison list gets too long.
        self.assertEqual(dsp.ops[:len(expected_list)], expected_list)

    def test_get_logs(self):
        """Test scope of get_logs callbacks"""
        logs = []

        def addLog(paths, revision, author, date, message, pool):
            if paths is not None:
                logs.append(paths)

        # Run get_logs
        repos.get_logs(self.repos, ['/'], self.rev, 0, True, 0, addLog)

        # Count and verify changes
        change_count = 0
        for log in logs:
            for path_changed in log.values():
                change_count += 1
                path_changed.assert_valid()
        self.assertEqual(logs[2]["/tags/v1.1"].action, "A")
        self.assertEqual(logs[2]["/tags/v1.1"].copyfrom_path, "/branches/v1x")
        self.assertEqual(len(logs), 12)
        self.assertEqual(change_count, 19)

    def test_dir_delta(self):
        """Test scope of dir_delta callbacks"""
        # Run dir_delta
        this_root = fs.revision_root(self.fs, self.rev)
        prev_root = fs.revision_root(self.fs, self.rev - 1)
        editor = ChangeReceiver(this_root, prev_root)
        e_ptr, e_baton = delta.make_editor(editor)
        repos.dir_delta(prev_root, '', '', this_root, '', e_ptr, e_baton,
                        _authz_callback, 1, 1, 0, 0)

        # Check results.
        # Ignore the order in which the editor delivers the two sibling files.
        self.assertEqual(
            set([editor.textdeltas[0].new_data,
                 editor.textdeltas[1].new_data]),
            set(["This is a test.\n", "A test.\n"]))
        self.assertEqual(len(editor.textdeltas), 2)

    def test_unnamed_editor(self):
        """Test editor object without reference from interpreter"""
        # Check that the delta.Editor object has proper lifetime. Without
        # increment of the refcount in make_baton, the object was destroyed
        # immediately because the interpreter does not hold a reference to it.
        this_root = fs.revision_root(self.fs, self.rev)
        prev_root = fs.revision_root(self.fs, self.rev - 1)
        e_ptr, e_baton = delta.make_editor(ChangeReceiver(
            this_root, prev_root))
        repos.dir_delta(prev_root, '', '', this_root, '', e_ptr, e_baton,
                        _authz_callback, 1, 1, 0, 0)

    def test_retrieve_and_change_rev_prop(self):
        """Test playing with revprops"""
        self.assertEqual(
            repos.fs_revision_prop(self.repos, self.rev, "svn:log",
                                   _authz_callback),
            "''(a few years later)'' Argh... v1.1 was buggy, "
            "after all")

        # We expect this to complain because we have no pre-revprop-change
        # hook script for the repository.
        self.assertRaises(SubversionException, repos.fs_change_rev_prop3,
                          self.repos, self.rev, "jrandom", "svn:log",
                          "Youngest revision", True, True, _authz_callback)

        repos.fs_change_rev_prop3(self.repos, self.rev, "jrandom", "svn:log",
                                  "Youngest revision", False, False,
                                  _authz_callback)

        self.assertEqual(
            repos.fs_revision_prop(self.repos, self.rev, "svn:log",
                                   _authz_callback), "Youngest revision")

    def freeze_body(self, pool):
        self.freeze_invoked += 1

    def test_freeze(self):
        """Test repository freeze"""

        self.freeze_invoked = 0
        repos.freeze([self.repos_path], self.freeze_body)
        self.assertEqual(self.freeze_invoked, 1)

    def test_lock_unlock(self):
        """Basic lock/unlock"""

        access = fs.create_access('jrandom')
        fs.set_access(self.fs, access)
        fs.lock(self.fs, '/trunk/README.txt', None, None, 0, 0, self.rev,
                False)
        try:
            fs.lock(self.fs, '/trunk/README.txt', None, None, 0, 0, self.rev,
                    False)
        except core.SubversionException, exc:
            self.assertEqual(exc.apr_err, core.SVN_ERR_FS_PATH_ALREADY_LOCKED)
        fs.lock(self.fs, '/trunk/README.txt', None, None, 0, 0, self.rev, True)

        self.calls = 0
        self.errors = 0

        def unlock_callback(path, lock, err, pool):
            self.assertEqual(path, '/trunk/README.txt')
            self.assertEqual(lock, None)
            self.calls += 1
            if err != None:
                self.assertEqual(err.apr_err, core.SVN_ERR_FS_NO_SUCH_LOCK)
                self.errors += 1

        the_lock = fs.get_lock(self.fs, '/trunk/README.txt')
        fs.unlock_many(self.fs, {'/trunk/README.txt': the_lock.token}, False,
                       unlock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.errors, 0)

        self.calls = 0
        fs.unlock_many(self.fs, {'/trunk/README.txt': the_lock.token}, False,
                       unlock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.errors, 1)

        self.locks = 0

        def lock_callback(path, lock, err, pool):
            self.assertEqual(path, '/trunk/README.txt')
            if lock != None:
                self.assertEqual(lock.owner, 'jrandom')
                self.locks += 1
            self.calls += 1
            if err != None:
                self.assertEqual(err.apr_err,
                                 core.SVN_ERR_FS_PATH_ALREADY_LOCKED)
                self.errors += 1

        self.calls = 0
        self.errors = 0
        target = fs.lock_target_create(None, self.rev)
        fs.lock_many(self.fs, {'trunk/README.txt': target}, None, False, 0,
                     False, lock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 1)
        self.assertEqual(self.errors, 0)

        self.calls = 0
        self.locks = 0
        fs.lock_many(self.fs, {'trunk/README.txt': target}, None, False, 0,
                     False, lock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 0)
        self.assertEqual(self.errors, 1)

        self.calls = 0
        self.errors = 0
        the_lock = fs.get_lock(self.fs, '/trunk/README.txt')
        repos.fs_unlock_many(self.repos, {'trunk/README.txt': the_lock.token},
                             False, unlock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.errors, 0)

        self.calls = 0
        repos.fs_unlock_many(self.repos, {'trunk/README.txt': the_lock.token},
                             False, unlock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.errors, 1)

        self.calls = 0
        self.errors = 0
        repos.fs_lock_many(self.repos, {'trunk/README.txt': target}, None,
                           False, 0, False, lock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 1)
        self.assertEqual(self.errors, 0)

        self.calls = 0
        self.locks = 0
        repos.fs_lock_many(self.repos, {'trunk/README.txt': target}, None,
                           False, 0, False, lock_callback)
        self.assertEqual(self.calls, 1)
        self.assertEqual(self.locks, 0)
        self.assertEqual(self.errors, 1)