Merge lp:~spiv/bzr/stacking-friendly-revision-history-verb into lp:~bzr/bzr/trunk-old

Proposed by Andrew Bennetts
Status: Merged
Merge reported by: Martin Pool
Merged at revision: not available
Proposed branch: lp:~spiv/bzr/stacking-friendly-revision-history-verb
Merge into: lp:~bzr/bzr/trunk-old
Diff against target: 492 lines
To merge this branch: bzr merge lp:~spiv/bzr/stacking-friendly-revision-history-verb
Reviewer Review Type Date Requested Status
Martin Pool Approve
Review via email: mp+7314@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Andrew Bennetts (spiv) wrote :

This fixes bug 380314. It is a cheap fix that simply falls back to VFS for
RemoteBranch._gen_revision_history if the branch is stacked. I've added tests
for both the blackbox case of "'bzr pull -r 123' from stacked" and a per-branch
test for .revision_history when there is stacking.

I have a followup patch in the works that defines a new RPC that avoids VFS
entirely in this case, but it's close to the release and getting the correctness
fix merged is more urgent.

Revision history for this message
Andrew Bennetts (spiv) wrote :

To clarify: this proposal is only for r4423 of my branch. The diff shown inline on Launchpad has this content. The longer (>400 line diff) you can download via the librarian includes in the (not quite ready) followup work.

Revision history for this message
Martin Pool (mbp) wrote :

Does this need a NEWS entry?

Please put the bug url in a comment in the tests to give more context.

The rest of these are general comments are needn't delay merging:

65 + # This figure represent the amount of work to perform this use case. It
66 + # is entirely ok to reduce this number if a test fails due to rpc_count
67 + # being too low. If rpc_count increases, more network roundtrips have
68 + # become necessary for this use case. Please do not adjust this number
69 + # upwards without agreement from bzr's network support maintainers.
70 + self.assertLength(43, self.hpss_calls)

This feels like it should be a specific assertion rather than copy and pasted so many times...

It's unfortunate to hardcode 1.9 in these tests but we should probably scan for them later.

88 + except unstackable_format_errors, e:
89 + raise TestNotApplicable('Format does not support stacking.')

Some people would say you should check at the start of the test whether it promises to support stacking.

Looks good.

review: Approve
Revision history for this message
Andrew Bennetts (spiv) wrote :

> Does this need a NEWS entry?

Yes, I'll add one.

> Please put the bug url in a comment in the tests to give more context.

Ok.

> The rest of these are general comments are needn't delay merging:
>
> 65 + # This figure represent the amount of work to perform this use case.
> It
> 66 + # is entirely ok to reduce this number if a test fails due to
> rpc_count
> 67 + # being too low. If rpc_count increases, more network roundtrips
> have
> 68 + # become necessary for this use case. Please do not adjust this
> number
> 69 + # upwards without agreement from bzr's network support maintainers.
> 70 + self.assertLength(43, self.hpss_calls)
>
> This feels like it should be a specific assertion rather than copy and pasted
> so many times...

Yeah. Another possibility is a centralised list of ratchet values somewhere, and then the scary "DO NOT CHANGE UPWARDS" comment can be at that one place.

> It's unfortunate to hardcode 1.9 in these tests but we should probably scan
> for them later.

Yeah. That's how Robert and I feel about the hardcoded 1.9 in these tests too.

> 88 + except unstackable_format_errors, e:
> 89 + raise TestNotApplicable('Format does not support stacking.')
>
> Some people would say you should check at the start of the test whether it
> promises to support stacking.

Well, I'm doing what nearby tests do. (Also, you can't do it at the very start, because at least for the Remote* tests you can't ask the format if it supports stacking unless there is an underlying object for the Remote*Format to ask).

> Looks good.

Thanks!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bzrlib/branch.py'
--- bzrlib/branch.py 2009-06-10 03:56:49 +0000
+++ bzrlib/branch.py 2009-06-11 19:35:21 +0000
@@ -91,6 +91,7 @@
91 self._revision_history_cache = None91 self._revision_history_cache = None
92 self._revision_id_to_revno_cache = None92 self._revision_id_to_revno_cache = None
93 self._partial_revision_id_to_revno_cache = {}93 self._partial_revision_id_to_revno_cache = {}
94 self._partial_revision_history_cache = []
94 self._last_revision_info_cache = None95 self._last_revision_info_cache = None
95 self._merge_sorted_revisions_cache = None96 self._merge_sorted_revisions_cache = None
96 self._open_hook()97 self._open_hook()
@@ -125,6 +126,27 @@
125 raise errors.UnstackableRepositoryFormat(self.repository._format,126 raise errors.UnstackableRepositoryFormat(self.repository._format,
126 self.repository.base)127 self.repository.base)
127128
129 def _extend_partial_history(self, stop_index=None, stop_revision=None):
130 """Extend the partial history to include a given index
131
132 If a stop_index is supplied, stop when that index has been reached.
133 If a stop_revision is supplied, stop when that revision is
134 encountered. Otherwise, stop when the beginning of history is
135 reached.
136
137 :param stop_index: The index which should be present. When it is
138 present, history extension will stop.
139 :param stop_revision: The revision id which should be present. When
140 it is encountered, history extension will stop.
141 """
142 if len(self._partial_revision_history_cache) == 0:
143 self._partial_revision_history_cache = [self.last_revision()]
144 repository._iter_for_revno(
145 self.repository, self._partial_revision_history_cache,
146 stop_index=stop_index, stop_revision=stop_revision)
147 if self._partial_revision_history_cache[-1] == _mod_revision.NULL_REVISION:
148 self._partial_revision_history_cache.pop()
149
128 @staticmethod150 @staticmethod
129 def open(base, _unsupported=False, possible_transports=None):151 def open(base, _unsupported=False, possible_transports=None):
130 """Open the branch rooted at base.152 """Open the branch rooted at base.
@@ -698,6 +720,8 @@
698 self._revision_id_to_revno_cache = None720 self._revision_id_to_revno_cache = None
699 self._last_revision_info_cache = None721 self._last_revision_info_cache = None
700 self._merge_sorted_revisions_cache = None722 self._merge_sorted_revisions_cache = None
723 self._partial_revision_history_cache = []
724 self._partial_revision_id_to_revno_cache = {}
701725
702 def _gen_revision_history(self):726 def _gen_revision_history(self):
703 """Return sequence of revision hashes on to this branch.727 """Return sequence of revision hashes on to this branch.
@@ -831,15 +855,20 @@
831 except ValueError:855 except ValueError:
832 raise errors.NoSuchRevision(self, revision_id)856 raise errors.NoSuchRevision(self, revision_id)
833857
858 @needs_read_lock
834 def get_rev_id(self, revno, history=None):859 def get_rev_id(self, revno, history=None):
835 """Find the revision id of the specified revno."""860 """Find the revision id of the specified revno."""
836 if revno == 0:861 if revno == 0:
837 return _mod_revision.NULL_REVISION862 return _mod_revision.NULL_REVISION
838 if history is None:863 last_revno, last_revid = self.last_revision_info()
839 history = self.revision_history()864 if revno == last_revno:
840 if revno <= 0 or revno > len(history):865 return last_revid
866 if revno <= 0 or revno > last_revno:
841 raise errors.NoSuchRevision(self, revno)867 raise errors.NoSuchRevision(self, revno)
842 return history[revno - 1]868 distance_from_last = last_revno - revno
869 if len(self._partial_revision_history_cache) <= distance_from_last:
870 self._extend_partial_history(revno)
871 return self._partial_revision_history_cache[revno]
843872
844 @needs_write_lock873 @needs_write_lock
845 def pull(self, source, overwrite=False, stop_revision=None,874 def pull(self, source, overwrite=False, stop_revision=None,
@@ -2376,13 +2405,11 @@
2376 self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)2405 self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
2377 super(BzrBranch8, self).__init__(*args, **kwargs)2406 super(BzrBranch8, self).__init__(*args, **kwargs)
2378 self._last_revision_info_cache = None2407 self._last_revision_info_cache = None
2379 self._partial_revision_history_cache = []
2380 self._reference_info = None2408 self._reference_info = None
23812409
2382 def _clear_cached_state(self):2410 def _clear_cached_state(self):
2383 super(BzrBranch8, self)._clear_cached_state()2411 super(BzrBranch8, self)._clear_cached_state()
2384 self._last_revision_info_cache = None2412 self._last_revision_info_cache = None
2385 self._partial_revision_history_cache = []
2386 self._reference_info = None2413 self._reference_info = None
23872414
2388 def _last_revision_info(self):2415 def _last_revision_info(self):
@@ -2444,35 +2471,6 @@
2444 self._extend_partial_history(stop_index=last_revno-1)2471 self._extend_partial_history(stop_index=last_revno-1)
2445 return list(reversed(self._partial_revision_history_cache))2472 return list(reversed(self._partial_revision_history_cache))
24462473
2447 def _extend_partial_history(self, stop_index=None, stop_revision=None):
2448 """Extend the partial history to include a given index
2449
2450 If a stop_index is supplied, stop when that index has been reached.
2451 If a stop_revision is supplied, stop when that revision is
2452 encountered. Otherwise, stop when the beginning of history is
2453 reached.
2454
2455 :param stop_index: The index which should be present. When it is
2456 present, history extension will stop.
2457 :param revision_id: The revision id which should be present. When
2458 it is encountered, history extension will stop.
2459 """
2460 repo = self.repository
2461 if len(self._partial_revision_history_cache) == 0:
2462 iterator = repo.iter_reverse_revision_history(self.last_revision())
2463 else:
2464 start_revision = self._partial_revision_history_cache[-1]
2465 iterator = repo.iter_reverse_revision_history(start_revision)
2466 #skip the last revision in the list
2467 next_revision = iterator.next()
2468 for revision_id in iterator:
2469 self._partial_revision_history_cache.append(revision_id)
2470 if (stop_index is not None and
2471 len(self._partial_revision_history_cache) > stop_index):
2472 break
2473 if revision_id == stop_revision:
2474 break
2475
2476 def _write_revision_history(self, history):2474 def _write_revision_history(self, history):
2477 """Factored out of set_revision_history.2475 """Factored out of set_revision_history.
24782476
24792477
=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py 2009-06-11 06:54:33 +0000
+++ bzrlib/builtins.py 2009-06-11 19:35:21 +0000
@@ -946,29 +946,36 @@
946 if branch_to.get_parent() is None or remember:946 if branch_to.get_parent() is None or remember:
947 branch_to.set_parent(branch_from.base)947 branch_to.set_parent(branch_from.base)
948948
949 if revision is not None:949 if branch_from is not branch_to:
950 revision_id = revision.as_revision_id(branch_from)950 branch_from.lock_read()
951
952 branch_to.lock_write()
953 try:951 try:
954 if tree_to is not None:952 if revision is not None:
955 view_info = _get_view_info_for_change_reporter(tree_to)953 revision_id = revision.as_revision_id(branch_from)
956 change_reporter = delta._ChangeReporter(954
957 unversioned_filter=tree_to.is_ignored, view_info=view_info)955 branch_to.lock_write()
958 result = tree_to.pull(branch_from, overwrite, revision_id,956 try:
959 change_reporter,957 if tree_to is not None:
960 possible_transports=possible_transports,958 view_info = _get_view_info_for_change_reporter(tree_to)
961 local=local)959 change_reporter = delta._ChangeReporter(
962 else:960 unversioned_filter=tree_to.is_ignored,
963 result = branch_to.pull(branch_from, overwrite, revision_id,961 view_info=view_info)
964 local=local)962 result = tree_to.pull(
965963 branch_from, overwrite, revision_id, change_reporter,
966 result.report(self.outf)964 possible_transports=possible_transports, local=local)
967 if verbose and result.old_revid != result.new_revid:965 else:
968 log.show_branch_change(branch_to, self.outf, result.old_revno,966 result = branch_to.pull(
969 result.old_revid)967 branch_from, overwrite, revision_id, local=local)
968
969 result.report(self.outf)
970 if verbose and result.old_revid != result.new_revid:
971 log.show_branch_change(
972 branch_to, self.outf, result.old_revno,
973 result.old_revid)
974 finally:
975 branch_to.unlock()
970 finally:976 finally:
971 branch_to.unlock()977 if branch_from is not branch_to:
978 branch_from.unlock()
972979
973980
974class cmd_push(Command):981class cmd_push(Command):
975982
=== modified file 'bzrlib/remote.py'
--- bzrlib/remote.py 2009-06-11 09:11:21 +0000
+++ bzrlib/remote.py 2009-06-11 19:35:22 +0000
@@ -28,12 +28,10 @@
28 errors,28 errors,
29 graph,29 graph,
30 lockdir,30 lockdir,
31 pack,
32 repository,31 repository,
33 revision,32 revision,
34 revision as _mod_revision,33 revision as _mod_revision,
35 symbol_versioning,34 symbol_versioning,
36 urlutils,
37)35)
38from bzrlib.branch import BranchReferenceFormat36from bzrlib.branch import BranchReferenceFormat
39from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat37from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
@@ -675,6 +673,24 @@
675 return self._real_repository.get_missing_parent_inventories(673 return self._real_repository.get_missing_parent_inventories(
676 check_for_missing_texts=check_for_missing_texts)674 check_for_missing_texts=check_for_missing_texts)
677675
676 def get_rev_id_for_revno(self, revno, known_pair):
677 """See Repository.get_rev_id_for_revno."""
678 path = self.bzrdir._path_for_remote_call(self._client)
679 try:
680 response = self._call(
681 'Repository.get_rev_id_for_revno', path, revno, known_pair)
682 except errors.UnknownSmartMethod:
683 self._client.medium._remember_remote_is_before((1, 16))
684 self._ensure_real()
685 return self._real_repository.get_rev_id_for_revno(
686 revno, known_pair)
687 if response[0] == 'ok':
688 return True, response[1]
689 elif response[0] == 'history-incomplete':
690 return False, response[1:3]
691 else:
692 raise errors.UnexpectedSmartServerResponse(response)
693
678 def _ensure_real(self):694 def _ensure_real(self):
679 """Ensure that there is a _real_repository set.695 """Ensure that there is a _real_repository set.
680696
@@ -1919,11 +1935,6 @@
1919 # We intentionally don't call the parent class's __init__, because it1935 # We intentionally don't call the parent class's __init__, because it
1920 # will try to assign to self.tags, which is a property in this subclass.1936 # will try to assign to self.tags, which is a property in this subclass.
1921 # And the parent's __init__ doesn't do much anyway.1937 # And the parent's __init__ doesn't do much anyway.
1922 self._revision_id_to_revno_cache = None
1923 self._partial_revision_id_to_revno_cache = {}
1924 self._revision_history_cache = None
1925 self._last_revision_info_cache = None
1926 self._merge_sorted_revisions_cache = None
1927 self.bzrdir = remote_bzrdir1938 self.bzrdir = remote_bzrdir
1928 if _client is not None:1939 if _client is not None:
1929 self._client = _client1940 self._client = _client
@@ -1943,6 +1954,7 @@
1943 else:1954 else:
1944 self._real_branch = None1955 self._real_branch = None
1945 # Fill out expected attributes of branch for bzrlib API users.1956 # Fill out expected attributes of branch for bzrlib API users.
1957 self._clear_cached_state()
1946 self.base = self.bzrdir.root_transport.base1958 self.base = self.bzrdir.root_transport.base
1947 self._control_files = None1959 self._control_files = None
1948 self._lock_mode = None1960 self._lock_mode = None
@@ -2229,6 +2241,17 @@
2229 raise NotImplementedError(self.dont_leave_lock_in_place)2241 raise NotImplementedError(self.dont_leave_lock_in_place)
2230 self._leave_lock = False2242 self._leave_lock = False
22312243
2244 def get_rev_id(self, revno, history=None):
2245 last_revision_info = self.last_revision_info()
2246 result = last_revision_info
2247 for repo in [self.repository] + self.repository._fallback_repositories:
2248 ok, result = repo.get_rev_id_for_revno(revno, result)
2249 if ok:
2250 return result
2251 closest = result[1]
2252 missing_parent = self.repository.get_parent_map([closest])[closest][0]
2253 raise errors.RevisionNotPresent(missing_parent, self.repository)
2254
2232 def _last_revision_info(self):2255 def _last_revision_info(self):
2233 response = self._call('Branch.last_revision_info', self._remote_path())2256 response = self._call('Branch.last_revision_info', self._remote_path())
2234 if response[0] != 'ok':2257 if response[0] != 'ok':
22352258
=== modified file 'bzrlib/repository.py'
--- bzrlib/repository.py 2009-06-10 03:56:49 +0000
+++ bzrlib/repository.py 2009-06-11 19:35:22 +0000
@@ -2234,6 +2234,41 @@
2234 """2234 """
2235 return self.get_revision(revision_id).inventory_sha12235 return self.get_revision(revision_id).inventory_sha1
22362236
2237 def get_rev_id_for_revno(self, revno, known_pair):
2238 """Return the revision id of a revno, given a later (revno, revid)
2239 pair in the same history.
2240
2241 :return: if found (True, revid). If the available history ran out
2242 before reaching the revno, then this returns
2243 (False, (closest_revno, closest_revid)).
2244 """
2245 known_revno, known_revid = known_pair
2246 partial_history = [known_revid]
2247 distance_from_known = known_revno - revno
2248 if distance_from_known < 0:
2249 raise ValueError(
2250 'requested revno (%d) is later than given known revno (%d)'
2251 % (revno, known_revno))
2252 # XXX: handle distance_from_known < 0, etc
2253 try:
2254 _iter_for_revno(self, partial_history, stop_index=revno)
2255 except errors.RevisionNotPresent, err:
2256 if err.revision_id == known_revid:
2257 # The start revision (known_revid) wasn't found.
2258 raise
2259 # This is a stacked repository with no fallbacks, or a there's a
2260 # left-hand ghost. Either way, even though the revision named in
2261 # the error isn't in this repo, we know it's the next step in this
2262 # left-hand history.
2263 partial_history.append(err.revision_id)
2264 if len(partial_history) <= distance_from_known:
2265 # Didn't find enough history to get a revid for the revno.
2266 earliest_revno = known_revno - len(partial_history) + 1
2267 return (False, (earliest_revno, partial_history[-1]))
2268 if len(partial_history) - 1 > distance_from_known:
2269 raise AssertionError('_iter_for_revno returned too much history')
2270 return (True, partial_history[-1])
2271
2237 def iter_reverse_revision_history(self, revision_id):2272 def iter_reverse_revision_history(self, revision_id):
2238 """Iterate backwards through revision ids in the lefthand history2273 """Iterate backwards through revision ids in the lefthand history
22392274
@@ -4412,3 +4447,35 @@
4412 yield versionedfile.FulltextContentFactory(4447 yield versionedfile.FulltextContentFactory(
4413 key, parent_keys, None, as_bytes)4448 key, parent_keys, None, as_bytes)
44144449
4450
4451def _iter_for_revno(repo, partial_history_cache, stop_index=None,
4452 stop_revision=None):
4453 """Extend the partial history to include a given index
4454
4455 If a stop_index is supplied, stop when that index has been reached.
4456 If a stop_revision is supplied, stop when that revision is
4457 encountered. Otherwise, stop when the beginning of history is
4458 reached.
4459
4460 :param stop_index: The index which should be present. When it is
4461 present, history extension will stop.
4462 :param stop_revision: The revision id which should be present. When
4463 it is encountered, history extension will stop.
4464 """
4465 start_revision = partial_history_cache[-1]
4466 iterator = repo.iter_reverse_revision_history(start_revision)
4467 try:
4468 #skip the last revision in the list
4469 next_revision = iterator.next()
4470 while True:
4471 if (stop_index is not None and
4472 len(partial_history_cache) > stop_index):
4473 break
4474 revision_id = iterator.next()
4475 partial_history_cache.append(revision_id)
4476 if revision_id == stop_revision:
4477 break
4478 except StopIteration:
4479 # No more history
4480 return
4481
44154482
=== modified file 'bzrlib/smart/repository.py'
--- bzrlib/smart/repository.py 2009-06-10 03:56:49 +0000
+++ bzrlib/smart/repository.py 2009-06-11 19:35:22 +0000
@@ -19,7 +19,6 @@
19import bz219import bz2
20import os20import os
21import Queue21import Queue
22import struct
23import sys22import sys
24import tarfile23import tarfile
25import tempfile24import tempfile
@@ -284,6 +283,31 @@
284 return SuccessfulSmartServerResponse(('ok', ), '\n'.join(lines))283 return SuccessfulSmartServerResponse(('ok', ), '\n'.join(lines))
285284
286285
286class SmartServerRepositoryGetRevIdForRevno(SmartServerRepositoryReadLocked):
287
288 def do_readlocked_repository_request(self, repository, revno,
289 known_pair):
290 """Find the revid for a given revno, given a known revno/revid pair.
291
292 New in 1.16.
293 """
294 try:
295 found_flag, result = repository.get_rev_id_for_revno(revno, known_pair)
296 except errors.RevisionNotPresent, err:
297 if err.revision_id != known_pair[1]:
298 raise AssertionError(
299 'get_rev_id_for_revno raised RevisionNotPresent for '
300 'non-initial revision: ' + err.revision_id)
301 return FailedSmartServerResponse(
302 ('nosuchrevision', err.revision_id))
303 if found_flag:
304 return SuccessfulSmartServerResponse(('ok', result))
305 else:
306 earliest_revno, earliest_revid = result
307 return SuccessfulSmartServerResponse(
308 ('history-incomplete', earliest_revno, earliest_revid))
309
310
287class SmartServerRequestHasRevision(SmartServerRepositoryRequest):311class SmartServerRequestHasRevision(SmartServerRepositoryRequest):
288312
289 def do_repository_request(self, repository, revision_id):313 def do_repository_request(self, repository, revision_id):
290314
=== modified file 'bzrlib/smart/request.py'
--- bzrlib/smart/request.py 2009-04-24 05:08:51 +0000
+++ bzrlib/smart/request.py 2009-06-11 19:35:22 +0000
@@ -555,6 +555,9 @@
555request_handlers.register_lazy(555request_handlers.register_lazy(
556 'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')556 'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
557request_handlers.register_lazy(557request_handlers.register_lazy(
558 'Repository.get_rev_id_for_revno', 'bzrlib.smart.repository',
559 'SmartServerRepositoryGetRevIdForRevno')
560request_handlers.register_lazy(
558 'Repository.get_stream', 'bzrlib.smart.repository',561 'Repository.get_stream', 'bzrlib.smart.repository',
559 'SmartServerRepositoryGetStream')562 'SmartServerRepositoryGetStream')
560request_handlers.register_lazy(563request_handlers.register_lazy(
561564
=== modified file 'bzrlib/tests/blackbox/test_pull.py'
--- bzrlib/tests/blackbox/test_pull.py 2009-06-11 07:43:56 +0000
+++ bzrlib/tests/blackbox/test_pull.py 2009-06-11 19:35:22 +0000
@@ -368,8 +368,12 @@
368 See <https://launchpad.net/bugs/380314>368 See <https://launchpad.net/bugs/380314>
369 """369 """
370 self.setup_smart_server_with_call_log()370 self.setup_smart_server_with_call_log()
371 # Make a stacked-on branch with two commits so that the
372 # revision-history can't be determined just by looking at the parent
373 # field in the revision in the stacked repo.
371 parent = self.make_branch_and_tree('parent', format='1.9')374 parent = self.make_branch_and_tree('parent', format='1.9')
372 parent.commit(message='first commit')375 parent.commit(message='first commit')
376 parent.commit(message='second commit')
373 local = parent.bzrdir.sprout('local').open_workingtree()377 local = parent.bzrdir.sprout('local').open_workingtree()
374 local.commit(message='local commit')378 local.commit(message='local commit')
375 local.branch.create_clone_on_transport(379 local.branch.create_clone_on_transport(
@@ -383,7 +387,7 @@
383 # being too low. If rpc_count increases, more network roundtrips have387 # being too low. If rpc_count increases, more network roundtrips have
384 # become necessary for this use case. Please do not adjust this number388 # become necessary for this use case. Please do not adjust this number
385 # upwards without agreement from bzr's network support maintainers.389 # upwards without agreement from bzr's network support maintainers.
386 self.assertLength(43, self.hpss_calls)390 self.assertLength(18, self.hpss_calls)
387 remote = Branch.open('stacked')391 remote = Branch.open('stacked')
388 self.assertEndsWith(remote.get_stacked_on_url(), '/parent')392 self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
389393
390394
=== modified file 'bzrlib/tests/test_smart.py'
--- bzrlib/tests/test_smart.py 2009-06-11 07:10:44 +0000
+++ bzrlib/tests/test_smart.py 2009-06-11 19:35:22 +0000
@@ -1161,6 +1161,47 @@
1161 request.execute('', 'missingrevision'))1161 request.execute('', 'missingrevision'))
11621162
11631163
1164class TestSmartServerRepositoryGetRevIdForRevno(tests.TestCaseWithMemoryTransport):
1165
1166 def test_revno_found(self):
1167 backing = self.get_transport()
1168 request = smart.repository.SmartServerRepositoryGetRevIdForRevno(backing)
1169 tree = self.make_branch_and_memory_tree('.')
1170 tree.lock_write()
1171 tree.add('')
1172 rev1_id_utf8 = u'\xc8'.encode('utf-8')
1173 rev2_id_utf8 = u'\xc9'.encode('utf-8')
1174 tree.commit('1st commit', rev_id=rev1_id_utf8)
1175 tree.commit('2nd commit', rev_id=rev2_id_utf8)
1176 tree.unlock()
1177
1178 self.assertEqual(SmartServerResponse(('ok', rev1_id_utf8)),
1179 request.execute('', 1, (2, rev2_id_utf8)))
1180
1181 def test_known_revid_missing(self):
1182 backing = self.get_transport()
1183 request = smart.repository.SmartServerRepositoryGetRevIdForRevno(backing)
1184 repo = self.make_repository('.')
1185 self.assertEqual(
1186 FailedSmartServerResponse(('nosuchrevision', 'ghost')),
1187 request.execute('', 1, (2, 'ghost')))
1188
1189 def test_history_incomplete(self):
1190 backing = self.get_transport()
1191 request = smart.repository.SmartServerRepositoryGetRevIdForRevno(backing)
1192 parent = self.make_branch_and_memory_tree('parent', format='1.9')
1193 r1 = parent.commit(message='first commit')
1194 r2 = parent.commit(message='second commit')
1195 local = self.make_branch_and_memory_tree('local', format='1.9')
1196 local.branch.pull(parent.branch)
1197 local.set_parent_ids([r2])
1198 r3 = local.commit(message='local commit')
1199 local.branch.create_clone_on_transport(
1200 self.get_transport('stacked'), stacked_on=self.get_url('parent'))
1201 self.assertEqual(
1202 SmartServerResponse(('history-incomplete', 2, r2)),
1203 request.execute('stacked', 1, (3, r3)))
1204
1164class TestSmartServerRepositoryGetStream(tests.TestCaseWithMemoryTransport):1205class TestSmartServerRepositoryGetStream(tests.TestCaseWithMemoryTransport):
11651206
1166 def make_two_commit_repo(self):1207 def make_two_commit_repo(self):
@@ -1576,6 +1617,8 @@
1576 smart.repository.SmartServerRepositoryGatherStats)1617 smart.repository.SmartServerRepositoryGatherStats)
1577 self.assertHandlerEqual('Repository.get_parent_map',1618 self.assertHandlerEqual('Repository.get_parent_map',
1578 smart.repository.SmartServerRepositoryGetParentMap)1619 smart.repository.SmartServerRepositoryGetParentMap)
1620 self.assertHandlerEqual('Repository.get_rev_id_for_revno',
1621 smart.repository.SmartServerRepositoryGetRevIdForRevno)
1579 self.assertHandlerEqual('Repository.get_revision_graph',1622 self.assertHandlerEqual('Repository.get_revision_graph',
1580 smart.repository.SmartServerRepositoryGetRevisionGraph)1623 smart.repository.SmartServerRepositoryGetRevisionGraph)
1581 self.assertHandlerEqual('Repository.get_stream',1624 self.assertHandlerEqual('Repository.get_stream',