~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart.py

  • Committer: Martin Packman
  • Date: 2011-12-23 19:38:22 UTC
  • mto: This revision was merged to the branch mainline in revision 6405.
  • Revision ID: martin.packman@canonical.com-20111223193822-hesheea4o8aqwexv
Accept and document passing the medium rather than transport for smart connections

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
 
17
 
"""Tests for the smart wire/domain protococl."""
18
 
 
19
 
from StringIO import StringIO
20
 
import tempfile
21
 
import tarfile
22
 
 
23
 
from bzrlib import bzrdir, errors, smart, tests
24
 
from bzrlib.smart.request import SmartServerResponse
25
 
import bzrlib.smart.bzrdir
26
 
import bzrlib.smart.branch
27
 
import bzrlib.smart.repository
28
 
 
29
 
 
30
 
class TestCaseWithSmartMedium(tests.TestCaseWithTransport):
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tests for the smart wire/domain protocol.
 
18
 
 
19
This module contains tests for the domain-level smart requests and responses,
 
20
such as the 'Branch.lock_write' request. Many of these use specific disk
 
21
formats to exercise calls that only make sense for formats with specific
 
22
properties.
 
23
 
 
24
Tests for low-level protocol encoding are found in test_smart_transport.
 
25
"""
 
26
 
 
27
import bz2
 
28
import zlib
 
29
 
 
30
from bzrlib import (
 
31
    branch as _mod_branch,
 
32
    bzrdir,
 
33
    errors,
 
34
    gpg,
 
35
    tests,
 
36
    transport,
 
37
    urlutils,
 
38
    versionedfile,
 
39
    )
 
40
from bzrlib.smart import (
 
41
    branch as smart_branch,
 
42
    bzrdir as smart_dir,
 
43
    repository as smart_repo,
 
44
    packrepository as smart_packrepo,
 
45
    request as smart_req,
 
46
    server,
 
47
    vfs,
 
48
    )
 
49
from bzrlib.testament import Testament
 
50
from bzrlib.tests import test_server
 
51
from bzrlib.transport import (
 
52
    chroot,
 
53
    memory,
 
54
    )
 
55
 
 
56
 
 
57
def load_tests(standard_tests, module, loader):
 
58
    """Multiply tests version and protocol consistency."""
 
59
    # FindRepository tests.
 
60
    scenarios = [
 
61
        ("find_repository", {
 
62
            "_request_class": smart_dir.SmartServerRequestFindRepositoryV1}),
 
63
        ("find_repositoryV2", {
 
64
            "_request_class": smart_dir.SmartServerRequestFindRepositoryV2}),
 
65
        ("find_repositoryV3", {
 
66
            "_request_class": smart_dir.SmartServerRequestFindRepositoryV3}),
 
67
        ]
 
68
    to_adapt, result = tests.split_suite_by_re(standard_tests,
 
69
        "TestSmartServerRequestFindRepository")
 
70
    v2_only, v1_and_2 = tests.split_suite_by_re(to_adapt,
 
71
        "_v2")
 
72
    tests.multiply_tests(v1_and_2, scenarios, result)
 
73
    # The first scenario is only applicable to v1 protocols, it is deleted
 
74
    # since.
 
75
    tests.multiply_tests(v2_only, scenarios[1:], result)
 
76
    return result
 
77
 
 
78
 
 
79
class TestCaseWithChrootedTransport(tests.TestCaseWithTransport):
 
80
 
 
81
    def setUp(self):
 
82
        self.vfs_transport_factory = memory.MemoryServer
 
83
        tests.TestCaseWithTransport.setUp(self)
 
84
        self._chroot_server = None
 
85
 
 
86
    def get_transport(self, relpath=None):
 
87
        if self._chroot_server is None:
 
88
            backing_transport = tests.TestCaseWithTransport.get_transport(self)
 
89
            self._chroot_server = chroot.ChrootServer(backing_transport)
 
90
            self.start_server(self._chroot_server)
 
91
        t = transport.get_transport_from_url(self._chroot_server.get_url())
 
92
        if relpath is not None:
 
93
            t = t.clone(relpath)
 
94
        return t
 
95
 
 
96
 
 
97
class TestCaseWithSmartMedium(tests.TestCaseWithMemoryTransport):
31
98
 
32
99
    def setUp(self):
33
100
        super(TestCaseWithSmartMedium, self).setUp()
35
102
        # the default or a parameterized class, but rather use the
36
103
        # TestCaseWithTransport infrastructure to set up a smart server and
37
104
        # transport.
38
 
        self.transport_server = smart.server.SmartTCPServer_for_testing
 
105
        self.overrideAttr(self, "transport_server", self.make_transport_server)
 
106
 
 
107
    def make_transport_server(self):
 
108
        return test_server.SmartTCPServer_for_testing('-' + self.id())
39
109
 
40
110
    def get_smart_medium(self):
41
111
        """Get a smart medium to use in tests."""
42
112
        return self.get_transport().get_smart_medium()
43
113
 
44
114
 
 
115
class TestByteStreamToStream(tests.TestCase):
 
116
 
 
117
    def test_repeated_substreams_same_kind_are_one_stream(self):
 
118
        # Make a stream - an iterable of bytestrings.
 
119
        stream = [('text', [versionedfile.FulltextContentFactory(('k1',), None,
 
120
            None, 'foo')]),('text', [
 
121
            versionedfile.FulltextContentFactory(('k2',), None, None, 'bar')])]
 
122
        fmt = bzrdir.format_registry.get('pack-0.92')().repository_format
 
123
        bytes = smart_repo._stream_to_byte_stream(stream, fmt)
 
124
        streams = []
 
125
        # Iterate the resulting iterable; checking that we get only one stream
 
126
        # out.
 
127
        fmt, stream = smart_repo._byte_stream_to_stream(bytes)
 
128
        for kind, substream in stream:
 
129
            streams.append((kind, list(substream)))
 
130
        self.assertLength(1, streams)
 
131
        self.assertLength(2, streams[0][1])
 
132
 
 
133
 
45
134
class TestSmartServerResponse(tests.TestCase):
46
135
 
47
136
    def test__eq__(self):
48
 
        self.assertEqual(SmartServerResponse(('ok', )),
49
 
            SmartServerResponse(('ok', )))
50
 
        self.assertEqual(SmartServerResponse(('ok', ), 'body'),
51
 
            SmartServerResponse(('ok', ), 'body'))
52
 
        self.assertNotEqual(SmartServerResponse(('ok', )),
53
 
            SmartServerResponse(('notok', )))
54
 
        self.assertNotEqual(SmartServerResponse(('ok', ), 'body'),
55
 
            SmartServerResponse(('ok', )))
 
137
        self.assertEqual(smart_req.SmartServerResponse(('ok', )),
 
138
            smart_req.SmartServerResponse(('ok', )))
 
139
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'body'),
 
140
            smart_req.SmartServerResponse(('ok', ), 'body'))
 
141
        self.assertNotEqual(smart_req.SmartServerResponse(('ok', )),
 
142
            smart_req.SmartServerResponse(('notok', )))
 
143
        self.assertNotEqual(smart_req.SmartServerResponse(('ok', ), 'body'),
 
144
            smart_req.SmartServerResponse(('ok', )))
56
145
        self.assertNotEqual(None,
57
 
            SmartServerResponse(('ok', )))
58
 
 
59
 
 
60
 
class TestSmartServerRequestFindRepository(tests.TestCaseWithTransport):
 
146
            smart_req.SmartServerResponse(('ok', )))
 
147
 
 
148
    def test__str__(self):
 
149
        """SmartServerResponses can be stringified."""
 
150
        self.assertEqual(
 
151
            "<SuccessfulSmartServerResponse args=('args',) body='body'>",
 
152
            str(smart_req.SuccessfulSmartServerResponse(('args',), 'body')))
 
153
        self.assertEqual(
 
154
            "<FailedSmartServerResponse args=('args',) body='body'>",
 
155
            str(smart_req.FailedSmartServerResponse(('args',), 'body')))
 
156
 
 
157
 
 
158
class TestSmartServerRequest(tests.TestCaseWithMemoryTransport):
 
159
 
 
160
    def test_translate_client_path(self):
 
161
        transport = self.get_transport()
 
162
        request = smart_req.SmartServerRequest(transport, 'foo/')
 
163
        self.assertEqual('./', request.translate_client_path('foo/'))
 
164
        self.assertRaises(
 
165
            errors.InvalidURLJoin, request.translate_client_path, 'foo/..')
 
166
        self.assertRaises(
 
167
            errors.PathNotChild, request.translate_client_path, '/')
 
168
        self.assertRaises(
 
169
            errors.PathNotChild, request.translate_client_path, 'bar/')
 
170
        self.assertEqual('./baz', request.translate_client_path('foo/baz'))
 
171
        e_acute = u'\N{LATIN SMALL LETTER E WITH ACUTE}'.encode('utf-8')
 
172
        self.assertEqual('./' + urlutils.escape(e_acute),
 
173
                         request.translate_client_path('foo/' + e_acute))
 
174
 
 
175
    def test_translate_client_path_vfs(self):
 
176
        """VfsRequests receive escaped paths rather than raw UTF-8."""
 
177
        transport = self.get_transport()
 
178
        request = vfs.VfsRequest(transport, 'foo/')
 
179
        e_acute = u'\N{LATIN SMALL LETTER E WITH ACUTE}'.encode('utf-8')
 
180
        escaped = urlutils.escape('foo/' + e_acute)
 
181
        self.assertEqual('./' + urlutils.escape(e_acute),
 
182
                         request.translate_client_path(escaped))
 
183
 
 
184
    def test_transport_from_client_path(self):
 
185
        transport = self.get_transport()
 
186
        request = smart_req.SmartServerRequest(transport, 'foo/')
 
187
        self.assertEqual(
 
188
            transport.base,
 
189
            request.transport_from_client_path('foo/').base)
 
190
 
 
191
 
 
192
class TestSmartServerBzrDirRequestCloningMetaDir(
 
193
    tests.TestCaseWithMemoryTransport):
 
194
    """Tests for BzrDir.cloning_metadir."""
 
195
 
 
196
    def test_cloning_metadir(self):
 
197
        """When there is a bzrdir present, the call succeeds."""
 
198
        backing = self.get_transport()
 
199
        dir = self.make_bzrdir('.')
 
200
        local_result = dir.cloning_metadir()
 
201
        request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
 
202
        request = request_class(backing)
 
203
        expected = smart_req.SuccessfulSmartServerResponse(
 
204
            (local_result.network_name(),
 
205
            local_result.repository_format.network_name(),
 
206
            ('branch', local_result.get_branch_format().network_name())))
 
207
        self.assertEqual(expected, request.execute('', 'False'))
 
208
 
 
209
    def test_cloning_metadir_reference(self):
 
210
        """The request fails when bzrdir contains a branch reference."""
 
211
        backing = self.get_transport()
 
212
        referenced_branch = self.make_branch('referenced')
 
213
        dir = self.make_bzrdir('.')
 
214
        local_result = dir.cloning_metadir()
 
215
        reference = _mod_branch.BranchReferenceFormat().initialize(
 
216
            dir, target_branch=referenced_branch)
 
217
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(dir)
 
218
        # The server shouldn't try to follow the branch reference, so it's fine
 
219
        # if the referenced branch isn't reachable.
 
220
        backing.rename('referenced', 'moved')
 
221
        request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
 
222
        request = request_class(backing)
 
223
        expected = smart_req.FailedSmartServerResponse(('BranchReference',))
 
224
        self.assertEqual(expected, request.execute('', 'False'))
 
225
 
 
226
 
 
227
class TestSmartServerBzrDirRequestDestroyBranch(
 
228
    tests.TestCaseWithMemoryTransport):
 
229
    """Tests for BzrDir.destroy_branch."""
 
230
 
 
231
    def test_destroy_branch_default(self):
 
232
        """The default branch can be removed."""
 
233
        backing = self.get_transport()
 
234
        dir = self.make_branch('.').bzrdir
 
235
        request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
 
236
        request = request_class(backing)
 
237
        expected = smart_req.SuccessfulSmartServerResponse(('ok',))
 
238
        self.assertEqual(expected, request.execute('', None))
 
239
 
 
240
    def test_destroy_branch_named(self):
 
241
        """A named branch can be removed."""
 
242
        backing = self.get_transport()
 
243
        dir = self.make_repository('.', format="development-colo").bzrdir
 
244
        dir.create_branch(name="branchname")
 
245
        request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
 
246
        request = request_class(backing)
 
247
        expected = smart_req.SuccessfulSmartServerResponse(('ok',))
 
248
        self.assertEqual(expected, request.execute('', "branchname"))
 
249
 
 
250
    def test_destroy_branch_missing(self):
 
251
        """An error is raised if the branch didn't exist."""
 
252
        backing = self.get_transport()
 
253
        dir = self.make_bzrdir('.', format="development-colo")
 
254
        request_class = smart_dir.SmartServerBzrDirRequestDestroyBranch
 
255
        request = request_class(backing)
 
256
        expected = smart_req.FailedSmartServerResponse(('nobranch',), None)
 
257
        self.assertEqual(expected, request.execute('', "branchname"))
 
258
 
 
259
 
 
260
class TestSmartServerBzrDirRequestHasWorkingTree(
 
261
    tests.TestCaseWithTransport):
 
262
    """Tests for BzrDir.has_workingtree."""
 
263
 
 
264
    def test_has_workingtree_yes(self):
 
265
        """A working tree is present."""
 
266
        backing = self.get_transport()
 
267
        dir = self.make_branch_and_tree('.').bzrdir
 
268
        request_class = smart_dir.SmartServerBzrDirRequestHasWorkingTree
 
269
        request = request_class(backing)
 
270
        expected = smart_req.SuccessfulSmartServerResponse(('yes',))
 
271
        self.assertEqual(expected, request.execute(''))
 
272
 
 
273
    def test_has_workingtree_no(self):
 
274
        """A working tree is missing."""
 
275
        backing = self.get_transport()
 
276
        dir = self.make_bzrdir('.')
 
277
        request_class = smart_dir.SmartServerBzrDirRequestHasWorkingTree
 
278
        request = request_class(backing)
 
279
        expected = smart_req.SuccessfulSmartServerResponse(('no',))
 
280
        self.assertEqual(expected, request.execute(''))
 
281
 
 
282
 
 
283
class TestSmartServerBzrDirRequestDestroyRepository(
 
284
    tests.TestCaseWithMemoryTransport):
 
285
    """Tests for BzrDir.destroy_repository."""
 
286
 
 
287
    def test_destroy_repository_default(self):
 
288
        """The repository can be removed."""
 
289
        backing = self.get_transport()
 
290
        dir = self.make_repository('.').bzrdir
 
291
        request_class = smart_dir.SmartServerBzrDirRequestDestroyRepository
 
292
        request = request_class(backing)
 
293
        expected = smart_req.SuccessfulSmartServerResponse(('ok',))
 
294
        self.assertEqual(expected, request.execute(''))
 
295
 
 
296
    def test_destroy_repository_missing(self):
 
297
        """An error is raised if the repository didn't exist."""
 
298
        backing = self.get_transport()
 
299
        dir = self.make_bzrdir('.')
 
300
        request_class = smart_dir.SmartServerBzrDirRequestDestroyRepository
 
301
        request = request_class(backing)
 
302
        expected = smart_req.FailedSmartServerResponse(
 
303
            ('norepository',), None)
 
304
        self.assertEqual(expected, request.execute(''))
 
305
 
 
306
 
 
307
class TestSmartServerRequestCreateRepository(tests.TestCaseWithMemoryTransport):
 
308
    """Tests for BzrDir.create_repository."""
 
309
 
 
310
    def test_makes_repository(self):
 
311
        """When there is a bzrdir present, the call succeeds."""
 
312
        backing = self.get_transport()
 
313
        self.make_bzrdir('.')
 
314
        request_class = smart_dir.SmartServerRequestCreateRepository
 
315
        request = request_class(backing)
 
316
        reference_bzrdir_format = bzrdir.format_registry.get('pack-0.92')()
 
317
        reference_format = reference_bzrdir_format.repository_format
 
318
        network_name = reference_format.network_name()
 
319
        expected = smart_req.SuccessfulSmartServerResponse(
 
320
            ('ok', 'no', 'no', 'no', network_name))
 
321
        self.assertEqual(expected, request.execute('', network_name, 'True'))
 
322
 
 
323
 
 
324
class TestSmartServerRequestFindRepository(tests.TestCaseWithMemoryTransport):
61
325
    """Tests for BzrDir.find_repository."""
62
326
 
63
327
    def test_no_repository(self):
64
328
        """When there is no repository to be found, ('norepository', ) is returned."""
65
329
        backing = self.get_transport()
66
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
330
        request = self._request_class(backing)
67
331
        self.make_bzrdir('.')
68
 
        self.assertEqual(SmartServerResponse(('norepository', )),
69
 
            request.execute(backing.local_abspath('')))
 
332
        self.assertEqual(smart_req.SmartServerResponse(('norepository', )),
 
333
            request.execute(''))
70
334
 
71
335
    def test_nonshared_repository(self):
72
 
        # nonshared repositorys only allow 'find' to return a handle when the 
73
 
        # path the repository is being searched on is the same as that that 
 
336
        # nonshared repositorys only allow 'find' to return a handle when the
 
337
        # path the repository is being searched on is the same as that that
74
338
        # the repository is at.
75
339
        backing = self.get_transport()
76
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
340
        request = self._request_class(backing)
77
341
        result = self._make_repository_and_result()
78
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
 
342
        self.assertEqual(result, request.execute(''))
79
343
        self.make_bzrdir('subdir')
80
 
        self.assertEqual(SmartServerResponse(('norepository', )),
81
 
            request.execute(backing.local_abspath('subdir')))
 
344
        self.assertEqual(smart_req.SmartServerResponse(('norepository', )),
 
345
            request.execute('subdir'))
82
346
 
83
347
    def _make_repository_and_result(self, shared=False, format=None):
84
348
        """Convenience function to setup a repository.
94
358
            subtrees = 'yes'
95
359
        else:
96
360
            subtrees = 'no'
97
 
        return SmartServerResponse(('ok', '', rich_root, subtrees))
 
361
        if repo._format.supports_external_lookups:
 
362
            external = 'yes'
 
363
        else:
 
364
            external = 'no'
 
365
        if (smart_dir.SmartServerRequestFindRepositoryV3 ==
 
366
            self._request_class):
 
367
            return smart_req.SuccessfulSmartServerResponse(
 
368
                ('ok', '', rich_root, subtrees, external,
 
369
                 repo._format.network_name()))
 
370
        elif (smart_dir.SmartServerRequestFindRepositoryV2 ==
 
371
            self._request_class):
 
372
            # All tests so far are on formats, and for non-external
 
373
            # repositories.
 
374
            return smart_req.SuccessfulSmartServerResponse(
 
375
                ('ok', '', rich_root, subtrees, external))
 
376
        else:
 
377
            return smart_req.SuccessfulSmartServerResponse(
 
378
                ('ok', '', rich_root, subtrees))
98
379
 
99
380
    def test_shared_repository(self):
100
381
        """When there is a shared repository, we get 'ok', 'relpath-to-repo'."""
101
382
        backing = self.get_transport()
102
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
 
383
        request = self._request_class(backing)
103
384
        result = self._make_repository_and_result(shared=True)
104
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
 
385
        self.assertEqual(result, request.execute(''))
105
386
        self.make_bzrdir('subdir')
106
 
        result2 = SmartServerResponse(result.args[0:1] + ('..', ) + result.args[2:])
 
387
        result2 = smart_req.SmartServerResponse(
 
388
            result.args[0:1] + ('..', ) + result.args[2:])
107
389
        self.assertEqual(result2,
108
 
            request.execute(backing.local_abspath('subdir')))
 
390
            request.execute('subdir'))
109
391
        self.make_bzrdir('subdir/deeper')
110
 
        result3 = SmartServerResponse(result.args[0:1] + ('../..', ) + result.args[2:])
 
392
        result3 = smart_req.SmartServerResponse(
 
393
            result.args[0:1] + ('../..', ) + result.args[2:])
111
394
        self.assertEqual(result3,
112
 
            request.execute(backing.local_abspath('subdir/deeper')))
 
395
            request.execute('subdir/deeper'))
113
396
 
114
397
    def test_rich_root_and_subtree_encoding(self):
115
398
        """Test for the format attributes for rich root and subtree support."""
116
399
        backing = self.get_transport()
117
 
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
118
 
        result = self._make_repository_and_result(format='dirstate-with-subtree')
 
400
        request = self._request_class(backing)
 
401
        result = self._make_repository_and_result(
 
402
            format='dirstate-with-subtree')
119
403
        # check the test will be valid
120
404
        self.assertEqual('yes', result.args[2])
121
405
        self.assertEqual('yes', result.args[3])
122
 
        self.assertEqual(result, request.execute(backing.local_abspath('')))
123
 
 
124
 
 
125
 
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithTransport):
 
406
        self.assertEqual(result, request.execute(''))
 
407
 
 
408
    def test_supports_external_lookups_no_v2(self):
 
409
        """Test for the supports_external_lookups attribute."""
 
410
        backing = self.get_transport()
 
411
        request = self._request_class(backing)
 
412
        result = self._make_repository_and_result(
 
413
            format='dirstate-with-subtree')
 
414
        # check the test will be valid
 
415
        self.assertEqual('no', result.args[4])
 
416
        self.assertEqual(result, request.execute(''))
 
417
 
 
418
 
 
419
class TestSmartServerBzrDirRequestGetConfigFile(
 
420
    tests.TestCaseWithMemoryTransport):
 
421
    """Tests for BzrDir.get_config_file."""
 
422
 
 
423
    def test_present(self):
 
424
        backing = self.get_transport()
 
425
        dir = self.make_bzrdir('.')
 
426
        dir.get_config().set_default_stack_on("/")
 
427
        local_result = dir._get_config()._get_config_file().read()
 
428
        request_class = smart_dir.SmartServerBzrDirRequestConfigFile
 
429
        request = request_class(backing)
 
430
        expected = smart_req.SuccessfulSmartServerResponse((), local_result)
 
431
        self.assertEqual(expected, request.execute(''))
 
432
 
 
433
    def test_missing(self):
 
434
        backing = self.get_transport()
 
435
        dir = self.make_bzrdir('.')
 
436
        request_class = smart_dir.SmartServerBzrDirRequestConfigFile
 
437
        request = request_class(backing)
 
438
        expected = smart_req.SuccessfulSmartServerResponse((), '')
 
439
        self.assertEqual(expected, request.execute(''))
 
440
 
 
441
 
 
442
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithMemoryTransport):
126
443
 
127
444
    def test_empty_dir(self):
128
445
        """Initializing an empty dir should succeed and do it."""
129
446
        backing = self.get_transport()
130
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
131
 
        self.assertEqual(SmartServerResponse(('ok', )),
132
 
            request.execute(backing.local_abspath('.')))
 
447
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
 
448
        self.assertEqual(smart_req.SmartServerResponse(('ok', )),
 
449
            request.execute(''))
133
450
        made_dir = bzrdir.BzrDir.open_from_transport(backing)
134
 
        # no branch, tree or repository is expected with the current 
 
451
        # no branch, tree or repository is expected with the current
135
452
        # default formart.
136
453
        self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
137
454
        self.assertRaises(errors.NotBranchError, made_dir.open_branch)
140
457
    def test_missing_dir(self):
141
458
        """Initializing a missing directory should fail like the bzrdir api."""
142
459
        backing = self.get_transport()
143
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
 
460
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
144
461
        self.assertRaises(errors.NoSuchFile,
145
 
            request.execute, backing.local_abspath('subdir'))
 
462
            request.execute, 'subdir')
146
463
 
147
464
    def test_initialized_dir(self):
148
465
        """Initializing an extant bzrdir should fail like the bzrdir api."""
149
466
        backing = self.get_transport()
150
 
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
 
467
        request = smart_dir.SmartServerRequestInitializeBzrDir(backing)
151
468
        self.make_bzrdir('subdir')
152
469
        self.assertRaises(errors.FileExists,
153
 
            request.execute, backing.local_abspath('subdir'))
154
 
 
155
 
 
156
 
class TestSmartServerRequestOpenBranch(tests.TestCaseWithTransport):
 
470
            request.execute, 'subdir')
 
471
 
 
472
 
 
473
class TestSmartServerRequestBzrDirInitializeEx(
 
474
    tests.TestCaseWithMemoryTransport):
 
475
    """Basic tests for BzrDir.initialize_ex_1.16 in the smart server.
 
476
 
 
477
    The main unit tests in test_bzrdir exercise the API comprehensively.
 
478
    """
 
479
 
 
480
    def test_empty_dir(self):
 
481
        """Initializing an empty dir should succeed and do it."""
 
482
        backing = self.get_transport()
 
483
        name = self.make_bzrdir('reference')._format.network_name()
 
484
        request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
 
485
        self.assertEqual(
 
486
            smart_req.SmartServerResponse(('', '', '', '', '', '', name,
 
487
                                           'False', '', '', '')),
 
488
            request.execute(name, '', 'True', 'False', 'False', '', '', '', '',
 
489
                            'False'))
 
490
        made_dir = bzrdir.BzrDir.open_from_transport(backing)
 
491
        # no branch, tree or repository is expected with the current
 
492
        # default format.
 
493
        self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
 
494
        self.assertRaises(errors.NotBranchError, made_dir.open_branch)
 
495
        self.assertRaises(errors.NoRepositoryPresent, made_dir.open_repository)
 
496
 
 
497
    def test_missing_dir(self):
 
498
        """Initializing a missing directory should fail like the bzrdir api."""
 
499
        backing = self.get_transport()
 
500
        name = self.make_bzrdir('reference')._format.network_name()
 
501
        request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
 
502
        self.assertRaises(errors.NoSuchFile, request.execute, name,
 
503
            'subdir/dir', 'False', 'False', 'False', '', '', '', '', 'False')
 
504
 
 
505
    def test_initialized_dir(self):
 
506
        """Initializing an extant directory should fail like the bzrdir api."""
 
507
        backing = self.get_transport()
 
508
        name = self.make_bzrdir('reference')._format.network_name()
 
509
        request = smart_dir.SmartServerRequestBzrDirInitializeEx(backing)
 
510
        self.make_bzrdir('subdir')
 
511
        self.assertRaises(errors.FileExists, request.execute, name, 'subdir',
 
512
            'False', 'False', 'False', '', '', '', '', 'False')
 
513
 
 
514
 
 
515
class TestSmartServerRequestOpenBzrDir(tests.TestCaseWithMemoryTransport):
 
516
 
 
517
    def test_no_directory(self):
 
518
        backing = self.get_transport()
 
519
        request = smart_dir.SmartServerRequestOpenBzrDir(backing)
 
520
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
521
            request.execute('does-not-exist'))
 
522
 
 
523
    def test_empty_directory(self):
 
524
        backing = self.get_transport()
 
525
        backing.mkdir('empty')
 
526
        request = smart_dir.SmartServerRequestOpenBzrDir(backing)
 
527
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
528
            request.execute('empty'))
 
529
 
 
530
    def test_outside_root_client_path(self):
 
531
        backing = self.get_transport()
 
532
        request = smart_dir.SmartServerRequestOpenBzrDir(backing,
 
533
            root_client_path='root')
 
534
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
535
            request.execute('not-root'))
 
536
 
 
537
 
 
538
class TestSmartServerRequestOpenBzrDir_2_1(tests.TestCaseWithMemoryTransport):
 
539
 
 
540
    def test_no_directory(self):
 
541
        backing = self.get_transport()
 
542
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
543
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
544
            request.execute('does-not-exist'))
 
545
 
 
546
    def test_empty_directory(self):
 
547
        backing = self.get_transport()
 
548
        backing.mkdir('empty')
 
549
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
550
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
551
            request.execute('empty'))
 
552
 
 
553
    def test_present_without_workingtree(self):
 
554
        backing = self.get_transport()
 
555
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
556
        self.make_bzrdir('.')
 
557
        self.assertEqual(smart_req.SmartServerResponse(('yes', 'no')),
 
558
            request.execute(''))
 
559
 
 
560
    def test_outside_root_client_path(self):
 
561
        backing = self.get_transport()
 
562
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing,
 
563
            root_client_path='root')
 
564
        self.assertEqual(smart_req.SmartServerResponse(('no',)),
 
565
            request.execute('not-root'))
 
566
 
 
567
 
 
568
class TestSmartServerRequestOpenBzrDir_2_1_disk(TestCaseWithChrootedTransport):
 
569
 
 
570
    def test_present_with_workingtree(self):
 
571
        self.vfs_transport_factory = test_server.LocalURLServer
 
572
        backing = self.get_transport()
 
573
        request = smart_dir.SmartServerRequestOpenBzrDir_2_1(backing)
 
574
        bd = self.make_bzrdir('.')
 
575
        bd.create_repository()
 
576
        bd.create_branch()
 
577
        bd.create_workingtree()
 
578
        self.assertEqual(smart_req.SmartServerResponse(('yes', 'yes')),
 
579
            request.execute(''))
 
580
 
 
581
 
 
582
class TestSmartServerRequestOpenBranch(TestCaseWithChrootedTransport):
157
583
 
158
584
    def test_no_branch(self):
159
585
        """When there is no branch, ('nobranch', ) is returned."""
160
586
        backing = self.get_transport()
161
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
 
587
        request = smart_dir.SmartServerRequestOpenBranch(backing)
162
588
        self.make_bzrdir('.')
163
 
        self.assertEqual(SmartServerResponse(('nobranch', )),
164
 
            request.execute(backing.local_abspath('')))
 
589
        self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
 
590
            request.execute(''))
165
591
 
166
592
    def test_branch(self):
167
593
        """When there is a branch, 'ok' is returned."""
168
594
        backing = self.get_transport()
169
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
 
595
        request = smart_dir.SmartServerRequestOpenBranch(backing)
170
596
        self.make_branch('.')
171
 
        self.assertEqual(SmartServerResponse(('ok', '')),
172
 
            request.execute(backing.local_abspath('')))
173
 
 
174
 
    def test_branch_reference(self):
175
 
        """When there is a branch reference, the reference URL is returned."""
176
 
        backing = self.get_transport()
177
 
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
178
 
        branch = self.make_branch('branch')
179
 
        checkout = branch.create_checkout('reference',lightweight=True)
180
 
        # TODO: once we have an API to probe for references of any sort, we
181
 
        # can use it here.
182
 
        reference_url = backing.abspath('branch') + '/'
183
 
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
184
 
        self.assertEqual(SmartServerResponse(('ok', reference_url)),
185
 
            request.execute(backing.local_abspath('reference')))
186
 
 
187
 
 
188
 
class TestSmartServerRequestRevisionHistory(tests.TestCaseWithTransport):
 
597
        self.assertEqual(smart_req.SmartServerResponse(('ok', '')),
 
598
            request.execute(''))
 
599
 
 
600
    def test_branch_reference(self):
 
601
        """When there is a branch reference, the reference URL is returned."""
 
602
        self.vfs_transport_factory = test_server.LocalURLServer
 
603
        backing = self.get_transport()
 
604
        request = smart_dir.SmartServerRequestOpenBranch(backing)
 
605
        branch = self.make_branch('branch')
 
606
        checkout = branch.create_checkout('reference',lightweight=True)
 
607
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(
 
608
            checkout.bzrdir)
 
609
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
 
610
        self.assertEqual(smart_req.SmartServerResponse(('ok', reference_url)),
 
611
            request.execute('reference'))
 
612
 
 
613
    def test_notification_on_branch_from_repository(self):
 
614
        """When there is a repository, the error should return details."""
 
615
        backing = self.get_transport()
 
616
        request = smart_dir.SmartServerRequestOpenBranch(backing)
 
617
        repo = self.make_repository('.')
 
618
        self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
 
619
            request.execute(''))
 
620
 
 
621
 
 
622
class TestSmartServerRequestOpenBranchV2(TestCaseWithChrootedTransport):
 
623
 
 
624
    def test_no_branch(self):
 
625
        """When there is no branch, ('nobranch', ) is returned."""
 
626
        backing = self.get_transport()
 
627
        self.make_bzrdir('.')
 
628
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
629
        self.assertEqual(smart_req.SmartServerResponse(('nobranch', )),
 
630
            request.execute(''))
 
631
 
 
632
    def test_branch(self):
 
633
        """When there is a branch, 'ok' is returned."""
 
634
        backing = self.get_transport()
 
635
        expected = self.make_branch('.')._format.network_name()
 
636
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
637
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
638
                ('branch', expected)),
 
639
                         request.execute(''))
 
640
 
 
641
    def test_branch_reference(self):
 
642
        """When there is a branch reference, the reference URL is returned."""
 
643
        self.vfs_transport_factory = test_server.LocalURLServer
 
644
        backing = self.get_transport()
 
645
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
646
        branch = self.make_branch('branch')
 
647
        checkout = branch.create_checkout('reference',lightweight=True)
 
648
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(
 
649
            checkout.bzrdir)
 
650
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
 
651
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
652
                ('ref', reference_url)),
 
653
                         request.execute('reference'))
 
654
 
 
655
    def test_stacked_branch(self):
 
656
        """Opening a stacked branch does not open the stacked-on branch."""
 
657
        trunk = self.make_branch('trunk')
 
658
        feature = self.make_branch('feature')
 
659
        feature.set_stacked_on_url(trunk.base)
 
660
        opened_branches = []
 
661
        _mod_branch.Branch.hooks.install_named_hook(
 
662
            'open', opened_branches.append, None)
 
663
        backing = self.get_transport()
 
664
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
665
        request.setup_jail()
 
666
        try:
 
667
            response = request.execute('feature')
 
668
        finally:
 
669
            request.teardown_jail()
 
670
        expected_format = feature._format.network_name()
 
671
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
672
                ('branch', expected_format)),
 
673
                         response)
 
674
        self.assertLength(1, opened_branches)
 
675
 
 
676
    def test_notification_on_branch_from_repository(self):
 
677
        """When there is a repository, the error should return details."""
 
678
        backing = self.get_transport()
 
679
        request = smart_dir.SmartServerRequestOpenBranchV2(backing)
 
680
        repo = self.make_repository('.')
 
681
        self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
 
682
            request.execute(''))
 
683
 
 
684
 
 
685
class TestSmartServerRequestOpenBranchV3(TestCaseWithChrootedTransport):
 
686
 
 
687
    def test_no_branch(self):
 
688
        """When there is no branch, ('nobranch', ) is returned."""
 
689
        backing = self.get_transport()
 
690
        self.make_bzrdir('.')
 
691
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
692
        self.assertEqual(smart_req.SmartServerResponse(('nobranch',)),
 
693
            request.execute(''))
 
694
 
 
695
    def test_branch(self):
 
696
        """When there is a branch, 'ok' is returned."""
 
697
        backing = self.get_transport()
 
698
        expected = self.make_branch('.')._format.network_name()
 
699
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
700
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
701
                ('branch', expected)),
 
702
                         request.execute(''))
 
703
 
 
704
    def test_branch_reference(self):
 
705
        """When there is a branch reference, the reference URL is returned."""
 
706
        self.vfs_transport_factory = test_server.LocalURLServer
 
707
        backing = self.get_transport()
 
708
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
709
        branch = self.make_branch('branch')
 
710
        checkout = branch.create_checkout('reference',lightweight=True)
 
711
        reference_url = _mod_branch.BranchReferenceFormat().get_reference(
 
712
            checkout.bzrdir)
 
713
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
 
714
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
715
                ('ref', reference_url)),
 
716
                         request.execute('reference'))
 
717
 
 
718
    def test_stacked_branch(self):
 
719
        """Opening a stacked branch does not open the stacked-on branch."""
 
720
        trunk = self.make_branch('trunk')
 
721
        feature = self.make_branch('feature')
 
722
        feature.set_stacked_on_url(trunk.base)
 
723
        opened_branches = []
 
724
        _mod_branch.Branch.hooks.install_named_hook(
 
725
            'open', opened_branches.append, None)
 
726
        backing = self.get_transport()
 
727
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
728
        request.setup_jail()
 
729
        try:
 
730
            response = request.execute('feature')
 
731
        finally:
 
732
            request.teardown_jail()
 
733
        expected_format = feature._format.network_name()
 
734
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
735
                ('branch', expected_format)),
 
736
                         response)
 
737
        self.assertLength(1, opened_branches)
 
738
 
 
739
    def test_notification_on_branch_from_repository(self):
 
740
        """When there is a repository, the error should return details."""
 
741
        backing = self.get_transport()
 
742
        request = smart_dir.SmartServerRequestOpenBranchV3(backing)
 
743
        repo = self.make_repository('.')
 
744
        self.assertEqual(smart_req.SmartServerResponse(
 
745
                ('nobranch', 'location is a repository')),
 
746
                         request.execute(''))
 
747
 
 
748
 
 
749
class TestSmartServerRequestRevisionHistory(tests.TestCaseWithMemoryTransport):
189
750
 
190
751
    def test_empty(self):
191
752
        """For an empty branch, the body is empty."""
192
753
        backing = self.get_transport()
193
 
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
 
754
        request = smart_branch.SmartServerRequestRevisionHistory(backing)
194
755
        self.make_branch('.')
195
 
        self.assertEqual(SmartServerResponse(('ok', ), ''),
196
 
            request.execute(backing.local_abspath('')))
 
756
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), ''),
 
757
            request.execute(''))
197
758
 
198
759
    def test_not_empty(self):
199
760
        """For a non-empty branch, the body is empty."""
200
761
        backing = self.get_transport()
201
 
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
 
762
        request = smart_branch.SmartServerRequestRevisionHistory(backing)
202
763
        tree = self.make_branch_and_memory_tree('.')
203
764
        tree.lock_write()
204
765
        tree.add('')
206
767
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
207
768
        tree.unlock()
208
769
        self.assertEqual(
209
 
            SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
210
 
            request.execute(backing.local_abspath('')))
211
 
 
212
 
 
213
 
class TestSmartServerBranchRequest(tests.TestCaseWithTransport):
 
770
            smart_req.SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
 
771
            request.execute(''))
 
772
 
 
773
 
 
774
class TestSmartServerBranchRequest(tests.TestCaseWithMemoryTransport):
214
775
 
215
776
    def test_no_branch(self):
216
777
        """When there is a bzrdir and no branch, NotBranchError is raised."""
217
778
        backing = self.get_transport()
218
 
        request = smart.branch.SmartServerBranchRequest(backing)
 
779
        request = smart_branch.SmartServerBranchRequest(backing)
219
780
        self.make_bzrdir('.')
220
781
        self.assertRaises(errors.NotBranchError,
221
 
            request.execute, backing.local_abspath(''))
 
782
            request.execute, '')
222
783
 
223
784
    def test_branch_reference(self):
224
785
        """When there is a branch reference, NotBranchError is raised."""
225
786
        backing = self.get_transport()
226
 
        request = smart.branch.SmartServerBranchRequest(backing)
 
787
        request = smart_branch.SmartServerBranchRequest(backing)
227
788
        branch = self.make_branch('branch')
228
789
        checkout = branch.create_checkout('reference',lightweight=True)
229
790
        self.assertRaises(errors.NotBranchError,
230
 
            request.execute, backing.local_abspath('checkout'))
231
 
 
232
 
 
233
 
class TestSmartServerBranchRequestLastRevisionInfo(tests.TestCaseWithTransport):
 
791
            request.execute, 'checkout')
 
792
 
 
793
 
 
794
class TestSmartServerBranchRequestLastRevisionInfo(
 
795
    tests.TestCaseWithMemoryTransport):
234
796
 
235
797
    def test_empty(self):
236
798
        """For an empty branch, the result is ('ok', '0', 'null:')."""
237
799
        backing = self.get_transport()
238
 
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
 
800
        request = smart_branch.SmartServerBranchRequestLastRevisionInfo(backing)
239
801
        self.make_branch('.')
240
 
        self.assertEqual(SmartServerResponse(('ok', '0', 'null:')),
241
 
            request.execute(backing.local_abspath('')))
 
802
        self.assertEqual(smart_req.SmartServerResponse(('ok', '0', 'null:')),
 
803
            request.execute(''))
242
804
 
243
805
    def test_not_empty(self):
244
806
        """For a non-empty branch, the result is ('ok', 'revno', 'revid')."""
245
807
        backing = self.get_transport()
246
 
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
 
808
        request = smart_branch.SmartServerBranchRequestLastRevisionInfo(backing)
247
809
        tree = self.make_branch_and_memory_tree('.')
248
810
        tree.lock_write()
249
811
        tree.add('')
252
814
        r2 = tree.commit('2nd commit', rev_id=rev_id_utf8)
253
815
        tree.unlock()
254
816
        self.assertEqual(
255
 
            SmartServerResponse(('ok', '2', rev_id_utf8)),
256
 
            request.execute(backing.local_abspath('')))
257
 
 
258
 
 
259
 
class TestSmartServerBranchRequestGetConfigFile(tests.TestCaseWithTransport):
 
817
            smart_req.SmartServerResponse(('ok', '2', rev_id_utf8)),
 
818
            request.execute(''))
 
819
 
 
820
 
 
821
class TestSmartServerBranchRequestRevisionIdToRevno(
 
822
    tests.TestCaseWithMemoryTransport):
 
823
 
 
824
    def test_null(self):
 
825
        backing = self.get_transport()
 
826
        request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
 
827
            backing)
 
828
        self.make_branch('.')
 
829
        self.assertEqual(smart_req.SmartServerResponse(('ok', '0')),
 
830
            request.execute('', 'null:'))
 
831
 
 
832
    def test_simple(self):
 
833
        backing = self.get_transport()
 
834
        request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
 
835
            backing)
 
836
        tree = self.make_branch_and_memory_tree('.')
 
837
        tree.lock_write()
 
838
        tree.add('')
 
839
        r1 = tree.commit('1st commit')
 
840
        tree.unlock()
 
841
        self.assertEqual(
 
842
            smart_req.SmartServerResponse(('ok', '1')),
 
843
            request.execute('', r1))
 
844
 
 
845
    def test_not_found(self):
 
846
        backing = self.get_transport()
 
847
        request = smart_branch.SmartServerBranchRequestRevisionIdToRevno(
 
848
            backing)
 
849
        branch = self.make_branch('.')
 
850
        self.assertEqual(
 
851
            smart_req.FailedSmartServerResponse(
 
852
                ('NoSuchRevision', 'idontexist')),
 
853
            request.execute('', 'idontexist'))
 
854
 
 
855
 
 
856
class TestSmartServerBranchRequestGetConfigFile(
 
857
    tests.TestCaseWithMemoryTransport):
260
858
 
261
859
    def test_default(self):
262
860
        """With no file, we get empty content."""
263
861
        backing = self.get_transport()
264
 
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
 
862
        request = smart_branch.SmartServerBranchGetConfigFile(backing)
265
863
        branch = self.make_branch('.')
266
864
        # there should be no file by default
267
865
        content = ''
268
 
        self.assertEqual(SmartServerResponse(('ok', ), content),
269
 
            request.execute(backing.local_abspath('')))
 
866
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), content),
 
867
            request.execute(''))
270
868
 
271
869
    def test_with_content(self):
272
870
        # SmartServerBranchGetConfigFile should return the content from
273
871
        # branch.control_files.get('branch.conf') for now - in the future it may
274
 
        # perform more complex processing. 
275
 
        backing = self.get_transport()
276
 
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
277
 
        branch = self.make_branch('.')
278
 
        branch.control_files.put_utf8('branch.conf', 'foo bar baz')
279
 
        self.assertEqual(SmartServerResponse(('ok', ), 'foo bar baz'),
280
 
            request.execute(backing.local_abspath('')))
281
 
 
282
 
 
283
 
class TestSmartServerBranchRequestSetLastRevision(tests.TestCaseWithTransport):
284
 
 
285
 
    def test_empty(self):
286
 
        backing = self.get_transport()
287
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
288
 
        b = self.make_branch('.')
289
 
        branch_token = b.lock_write()
290
 
        repo_token = b.repository.lock_write()
291
 
        b.repository.unlock()
292
 
        try:
293
 
            self.assertEqual(SmartServerResponse(('ok',)),
294
 
                request.execute(
295
 
                    backing.local_abspath(''), branch_token, repo_token,
296
 
                    'null:'))
297
 
        finally:
298
 
            b.unlock()
299
 
 
300
 
    def test_not_present_revision_id(self):
301
 
        backing = self.get_transport()
302
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
303
 
        b = self.make_branch('.')
304
 
        branch_token = b.lock_write()
305
 
        repo_token = b.repository.lock_write()
306
 
        b.repository.unlock()
307
 
        try:
308
 
            revision_id = 'non-existent revision'
309
 
            self.assertEqual(
310
 
                SmartServerResponse(('NoSuchRevision', revision_id)),
311
 
                request.execute(
312
 
                    backing.local_abspath(''), branch_token, repo_token,
313
 
                    revision_id))
314
 
        finally:
315
 
            b.unlock()
316
 
 
317
 
    def test_revision_id_present(self):
318
 
        backing = self.get_transport()
319
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
320
 
        tree = self.make_branch_and_memory_tree('.')
321
 
        tree.lock_write()
322
 
        tree.add('')
323
 
        rev_id_utf8 = u'\xc8'.encode('utf-8')
324
 
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
325
 
        r2 = tree.commit('2nd commit')
326
 
        tree.unlock()
327
 
        branch_token = tree.branch.lock_write()
328
 
        repo_token = tree.branch.repository.lock_write()
329
 
        tree.branch.repository.unlock()
330
 
        try:
331
 
            self.assertEqual(
332
 
                SmartServerResponse(('ok',)),
333
 
                request.execute(
334
 
                    backing.local_abspath(''), branch_token, repo_token,
335
 
                    rev_id_utf8))
336
 
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
337
 
        finally:
338
 
            tree.branch.unlock()
339
 
 
340
 
    def test_revision_id_present2(self):
341
 
        backing = self.get_transport()
342
 
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
343
 
        tree = self.make_branch_and_memory_tree('.')
344
 
        tree.lock_write()
345
 
        tree.add('')
346
 
        rev_id_utf8 = u'\xc8'.encode('utf-8')
347
 
        r1 = tree.commit('1st commit', rev_id=rev_id_utf8)
348
 
        r2 = tree.commit('2nd commit')
349
 
        tree.unlock()
350
 
        tree.branch.set_revision_history([])
351
 
        branch_token = tree.branch.lock_write()
352
 
        repo_token = tree.branch.repository.lock_write()
353
 
        tree.branch.repository.unlock()
354
 
        try:
355
 
            self.assertEqual(
356
 
                SmartServerResponse(('ok',)),
357
 
                request.execute(
358
 
                    backing.local_abspath(''), branch_token, repo_token,
359
 
                    rev_id_utf8))
360
 
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
361
 
        finally:
362
 
            tree.branch.unlock()
363
 
 
364
 
 
365
 
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithTransport):
366
 
 
367
 
    def setUp(self):
368
 
        tests.TestCaseWithTransport.setUp(self)
369
 
        self.reduceLockdirTimeout()
 
872
        # perform more complex processing.
 
873
        backing = self.get_transport()
 
874
        request = smart_branch.SmartServerBranchGetConfigFile(backing)
 
875
        branch = self.make_branch('.')
 
876
        branch._transport.put_bytes('branch.conf', 'foo bar baz')
 
877
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'foo bar baz'),
 
878
            request.execute(''))
 
879
 
 
880
 
 
881
class TestLockedBranch(tests.TestCaseWithMemoryTransport):
 
882
 
 
883
    def get_lock_tokens(self, branch):
 
884
        branch_token = branch.lock_write().branch_token
 
885
        repo_token = branch.repository.lock_write().repository_token
 
886
        branch.repository.unlock()
 
887
        return branch_token, repo_token
 
888
 
 
889
 
 
890
class TestSmartServerBranchRequestPutConfigFile(TestLockedBranch):
 
891
 
 
892
    def test_with_content(self):
 
893
        backing = self.get_transport()
 
894
        request = smart_branch.SmartServerBranchPutConfigFile(backing)
 
895
        branch = self.make_branch('.')
 
896
        branch_token, repo_token = self.get_lock_tokens(branch)
 
897
        self.assertIs(None, request.execute('', branch_token, repo_token))
 
898
        self.assertEqual(
 
899
            smart_req.SmartServerResponse(('ok', )),
 
900
            request.do_body('foo bar baz'))
 
901
        self.assertEquals(
 
902
            branch.control_transport.get_bytes('branch.conf'),
 
903
            'foo bar baz')
 
904
        branch.unlock()
 
905
 
 
906
 
 
907
class TestSmartServerBranchRequestSetConfigOption(TestLockedBranch):
 
908
 
 
909
    def test_value_name(self):
 
910
        branch = self.make_branch('.')
 
911
        request = smart_branch.SmartServerBranchRequestSetConfigOption(
 
912
            branch.bzrdir.root_transport)
 
913
        branch_token, repo_token = self.get_lock_tokens(branch)
 
914
        config = branch._get_config()
 
915
        result = request.execute('', branch_token, repo_token, 'bar', 'foo',
 
916
            '')
 
917
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
918
        self.assertEqual('bar', config.get_option('foo'))
 
919
        # Cleanup
 
920
        branch.unlock()
 
921
 
 
922
    def test_value_name_section(self):
 
923
        branch = self.make_branch('.')
 
924
        request = smart_branch.SmartServerBranchRequestSetConfigOption(
 
925
            branch.bzrdir.root_transport)
 
926
        branch_token, repo_token = self.get_lock_tokens(branch)
 
927
        config = branch._get_config()
 
928
        result = request.execute('', branch_token, repo_token, 'bar', 'foo',
 
929
            'gam')
 
930
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
931
        self.assertEqual('bar', config.get_option('foo', 'gam'))
 
932
        # Cleanup
 
933
        branch.unlock()
 
934
 
 
935
 
 
936
class TestSmartServerBranchRequestSetConfigOptionDict(TestLockedBranch):
 
937
 
 
938
    def setUp(self):
 
939
        TestLockedBranch.setUp(self)
 
940
        # A dict with non-ascii keys and values to exercise unicode
 
941
        # roundtripping.
 
942
        self.encoded_value_dict = (
 
943
            'd5:ascii1:a11:unicode \xe2\x8c\x9a3:\xe2\x80\xbde')
 
944
        self.value_dict = {
 
945
            'ascii': 'a', u'unicode \N{WATCH}': u'\N{INTERROBANG}'}
 
946
 
 
947
    def test_value_name(self):
 
948
        branch = self.make_branch('.')
 
949
        request = smart_branch.SmartServerBranchRequestSetConfigOptionDict(
 
950
            branch.bzrdir.root_transport)
 
951
        branch_token, repo_token = self.get_lock_tokens(branch)
 
952
        config = branch._get_config()
 
953
        result = request.execute('', branch_token, repo_token,
 
954
            self.encoded_value_dict, 'foo', '')
 
955
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
956
        self.assertEqual(self.value_dict, config.get_option('foo'))
 
957
        # Cleanup
 
958
        branch.unlock()
 
959
 
 
960
    def test_value_name_section(self):
 
961
        branch = self.make_branch('.')
 
962
        request = smart_branch.SmartServerBranchRequestSetConfigOptionDict(
 
963
            branch.bzrdir.root_transport)
 
964
        branch_token, repo_token = self.get_lock_tokens(branch)
 
965
        config = branch._get_config()
 
966
        result = request.execute('', branch_token, repo_token,
 
967
            self.encoded_value_dict, 'foo', 'gam')
 
968
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), result)
 
969
        self.assertEqual(self.value_dict, config.get_option('foo', 'gam'))
 
970
        # Cleanup
 
971
        branch.unlock()
 
972
 
 
973
 
 
974
class TestSmartServerBranchRequestSetTagsBytes(TestLockedBranch):
 
975
    # Only called when the branch format and tags match [yay factory
 
976
    # methods] so only need to test straight forward cases.
 
977
 
 
978
    def test_set_bytes(self):
 
979
        base_branch = self.make_branch('base')
 
980
        tag_bytes = base_branch._get_tags_bytes()
 
981
        # get_lock_tokens takes out a lock.
 
982
        branch_token, repo_token = self.get_lock_tokens(base_branch)
 
983
        request = smart_branch.SmartServerBranchSetTagsBytes(
 
984
            self.get_transport())
 
985
        response = request.execute('base', branch_token, repo_token)
 
986
        self.assertEqual(None, response)
 
987
        response = request.do_chunk(tag_bytes)
 
988
        self.assertEqual(None, response)
 
989
        response = request.do_end()
 
990
        self.assertEquals(
 
991
            smart_req.SuccessfulSmartServerResponse(()), response)
 
992
        base_branch.unlock()
 
993
 
 
994
    def test_lock_failed(self):
 
995
        base_branch = self.make_branch('base')
 
996
        base_branch.lock_write()
 
997
        tag_bytes = base_branch._get_tags_bytes()
 
998
        request = smart_branch.SmartServerBranchSetTagsBytes(
 
999
            self.get_transport())
 
1000
        self.assertRaises(errors.TokenMismatch, request.execute,
 
1001
            'base', 'wrong token', 'wrong token')
 
1002
        # The request handler will keep processing the message parts, so even
 
1003
        # if the request fails immediately do_chunk and do_end are still
 
1004
        # called.
 
1005
        request.do_chunk(tag_bytes)
 
1006
        request.do_end()
 
1007
        base_branch.unlock()
 
1008
 
 
1009
 
 
1010
 
 
1011
class SetLastRevisionTestBase(TestLockedBranch):
 
1012
    """Base test case for verbs that implement set_last_revision."""
 
1013
 
 
1014
    def setUp(self):
 
1015
        tests.TestCaseWithMemoryTransport.setUp(self)
 
1016
        backing_transport = self.get_transport()
 
1017
        self.request = self.request_class(backing_transport)
 
1018
        self.tree = self.make_branch_and_memory_tree('.')
 
1019
 
 
1020
    def lock_branch(self):
 
1021
        return self.get_lock_tokens(self.tree.branch)
 
1022
 
 
1023
    def unlock_branch(self):
 
1024
        self.tree.branch.unlock()
 
1025
 
 
1026
    def set_last_revision(self, revision_id, revno):
 
1027
        branch_token, repo_token = self.lock_branch()
 
1028
        response = self._set_last_revision(
 
1029
            revision_id, revno, branch_token, repo_token)
 
1030
        self.unlock_branch()
 
1031
        return response
 
1032
 
 
1033
    def assertRequestSucceeds(self, revision_id, revno):
 
1034
        response = self.set_last_revision(revision_id, revno)
 
1035
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
1036
                         response)
 
1037
 
 
1038
 
 
1039
class TestSetLastRevisionVerbMixin(object):
 
1040
    """Mixin test case for verbs that implement set_last_revision."""
 
1041
 
 
1042
    def test_set_null_to_null(self):
 
1043
        """An empty branch can have its last revision set to 'null:'."""
 
1044
        self.assertRequestSucceeds('null:', 0)
 
1045
 
 
1046
    def test_NoSuchRevision(self):
 
1047
        """If the revision_id is not present, the verb returns NoSuchRevision.
 
1048
        """
 
1049
        revision_id = 'non-existent revision'
 
1050
        self.assertEqual(smart_req.FailedSmartServerResponse(('NoSuchRevision',
 
1051
                                                              revision_id)),
 
1052
                         self.set_last_revision(revision_id, 1))
 
1053
 
 
1054
    def make_tree_with_two_commits(self):
 
1055
        self.tree.lock_write()
 
1056
        self.tree.add('')
 
1057
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
1058
        r1 = self.tree.commit('1st commit', rev_id=rev_id_utf8)
 
1059
        r2 = self.tree.commit('2nd commit', rev_id='rev-2')
 
1060
        self.tree.unlock()
 
1061
 
 
1062
    def test_branch_last_revision_info_is_updated(self):
 
1063
        """A branch's tip can be set to a revision that is present in its
 
1064
        repository.
 
1065
        """
 
1066
        # Make a branch with an empty revision history, but two revisions in
 
1067
        # its repository.
 
1068
        self.make_tree_with_two_commits()
 
1069
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
1070
        self.tree.branch.set_last_revision_info(0, 'null:')
 
1071
        self.assertEqual(
 
1072
            (0, 'null:'), self.tree.branch.last_revision_info())
 
1073
        # We can update the branch to a revision that is present in the
 
1074
        # repository.
 
1075
        self.assertRequestSucceeds(rev_id_utf8, 1)
 
1076
        self.assertEqual(
 
1077
            (1, rev_id_utf8), self.tree.branch.last_revision_info())
 
1078
 
 
1079
    def test_branch_last_revision_info_rewind(self):
 
1080
        """A branch's tip can be set to a revision that is an ancestor of the
 
1081
        current tip.
 
1082
        """
 
1083
        self.make_tree_with_two_commits()
 
1084
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
1085
        self.assertEqual(
 
1086
            (2, 'rev-2'), self.tree.branch.last_revision_info())
 
1087
        self.assertRequestSucceeds(rev_id_utf8, 1)
 
1088
        self.assertEqual(
 
1089
            (1, rev_id_utf8), self.tree.branch.last_revision_info())
 
1090
 
 
1091
    def test_TipChangeRejected(self):
 
1092
        """If a pre_change_branch_tip hook raises TipChangeRejected, the verb
 
1093
        returns TipChangeRejected.
 
1094
        """
 
1095
        rejection_message = u'rejection message\N{INTERROBANG}'
 
1096
        def hook_that_rejects(params):
 
1097
            raise errors.TipChangeRejected(rejection_message)
 
1098
        _mod_branch.Branch.hooks.install_named_hook(
 
1099
            'pre_change_branch_tip', hook_that_rejects, None)
 
1100
        self.assertEqual(
 
1101
            smart_req.FailedSmartServerResponse(
 
1102
                ('TipChangeRejected', rejection_message.encode('utf-8'))),
 
1103
            self.set_last_revision('null:', 0))
 
1104
 
 
1105
 
 
1106
class TestSmartServerBranchRequestSetLastRevision(
 
1107
        SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
 
1108
    """Tests for Branch.set_last_revision verb."""
 
1109
 
 
1110
    request_class = smart_branch.SmartServerBranchRequestSetLastRevision
 
1111
 
 
1112
    def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
 
1113
        return self.request.execute(
 
1114
            '', branch_token, repo_token, revision_id)
 
1115
 
 
1116
 
 
1117
class TestSmartServerBranchRequestSetLastRevisionInfo(
 
1118
        SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
 
1119
    """Tests for Branch.set_last_revision_info verb."""
 
1120
 
 
1121
    request_class = smart_branch.SmartServerBranchRequestSetLastRevisionInfo
 
1122
 
 
1123
    def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
 
1124
        return self.request.execute(
 
1125
            '', branch_token, repo_token, revno, revision_id)
 
1126
 
 
1127
    def test_NoSuchRevision(self):
 
1128
        """Branch.set_last_revision_info does not have to return
 
1129
        NoSuchRevision if the revision_id is absent.
 
1130
        """
 
1131
        raise tests.TestNotApplicable()
 
1132
 
 
1133
 
 
1134
class TestSmartServerBranchRequestSetLastRevisionEx(
 
1135
        SetLastRevisionTestBase, TestSetLastRevisionVerbMixin):
 
1136
    """Tests for Branch.set_last_revision_ex verb."""
 
1137
 
 
1138
    request_class = smart_branch.SmartServerBranchRequestSetLastRevisionEx
 
1139
 
 
1140
    def _set_last_revision(self, revision_id, revno, branch_token, repo_token):
 
1141
        return self.request.execute(
 
1142
            '', branch_token, repo_token, revision_id, 0, 0)
 
1143
 
 
1144
    def assertRequestSucceeds(self, revision_id, revno):
 
1145
        response = self.set_last_revision(revision_id, revno)
 
1146
        self.assertEqual(
 
1147
            smart_req.SuccessfulSmartServerResponse(('ok', revno, revision_id)),
 
1148
            response)
 
1149
 
 
1150
    def test_branch_last_revision_info_rewind(self):
 
1151
        """A branch's tip can be set to a revision that is an ancestor of the
 
1152
        current tip, but only if allow_overwrite_descendant is passed.
 
1153
        """
 
1154
        self.make_tree_with_two_commits()
 
1155
        rev_id_utf8 = u'\xc8'.encode('utf-8')
 
1156
        self.assertEqual(
 
1157
            (2, 'rev-2'), self.tree.branch.last_revision_info())
 
1158
        # If allow_overwrite_descendant flag is 0, then trying to set the tip
 
1159
        # to an older revision ID has no effect.
 
1160
        branch_token, repo_token = self.lock_branch()
 
1161
        response = self.request.execute(
 
1162
            '', branch_token, repo_token, rev_id_utf8, 0, 0)
 
1163
        self.assertEqual(
 
1164
            smart_req.SuccessfulSmartServerResponse(('ok', 2, 'rev-2')),
 
1165
            response)
 
1166
        self.assertEqual(
 
1167
            (2, 'rev-2'), self.tree.branch.last_revision_info())
 
1168
 
 
1169
        # If allow_overwrite_descendant flag is 1, then setting the tip to an
 
1170
        # ancestor works.
 
1171
        response = self.request.execute(
 
1172
            '', branch_token, repo_token, rev_id_utf8, 0, 1)
 
1173
        self.assertEqual(
 
1174
            smart_req.SuccessfulSmartServerResponse(('ok', 1, rev_id_utf8)),
 
1175
            response)
 
1176
        self.unlock_branch()
 
1177
        self.assertEqual(
 
1178
            (1, rev_id_utf8), self.tree.branch.last_revision_info())
 
1179
 
 
1180
    def make_branch_with_divergent_history(self):
 
1181
        """Make a branch with divergent history in its repo.
 
1182
 
 
1183
        The branch's tip will be 'child-2', and the repo will also contain
 
1184
        'child-1', which diverges from a common base revision.
 
1185
        """
 
1186
        self.tree.lock_write()
 
1187
        self.tree.add('')
 
1188
        r1 = self.tree.commit('1st commit')
 
1189
        revno_1, revid_1 = self.tree.branch.last_revision_info()
 
1190
        r2 = self.tree.commit('2nd commit', rev_id='child-1')
 
1191
        # Undo the second commit
 
1192
        self.tree.branch.set_last_revision_info(revno_1, revid_1)
 
1193
        self.tree.set_parent_ids([revid_1])
 
1194
        # Make a new second commit, child-2.  child-2 has diverged from
 
1195
        # child-1.
 
1196
        new_r2 = self.tree.commit('2nd commit', rev_id='child-2')
 
1197
        self.tree.unlock()
 
1198
 
 
1199
    def test_not_allow_diverged(self):
 
1200
        """If allow_diverged is not passed, then setting a divergent history
 
1201
        returns a Diverged error.
 
1202
        """
 
1203
        self.make_branch_with_divergent_history()
 
1204
        self.assertEqual(
 
1205
            smart_req.FailedSmartServerResponse(('Diverged',)),
 
1206
            self.set_last_revision('child-1', 2))
 
1207
        # The branch tip was not changed.
 
1208
        self.assertEqual('child-2', self.tree.branch.last_revision())
 
1209
 
 
1210
    def test_allow_diverged(self):
 
1211
        """If allow_diverged is passed, then setting a divergent history
 
1212
        succeeds.
 
1213
        """
 
1214
        self.make_branch_with_divergent_history()
 
1215
        branch_token, repo_token = self.lock_branch()
 
1216
        response = self.request.execute(
 
1217
            '', branch_token, repo_token, 'child-1', 1, 0)
 
1218
        self.assertEqual(
 
1219
            smart_req.SuccessfulSmartServerResponse(('ok', 2, 'child-1')),
 
1220
            response)
 
1221
        self.unlock_branch()
 
1222
        # The branch tip was changed.
 
1223
        self.assertEqual('child-1', self.tree.branch.last_revision())
 
1224
 
 
1225
 
 
1226
class TestSmartServerBranchBreakLock(tests.TestCaseWithMemoryTransport):
 
1227
 
 
1228
    def test_lock_to_break(self):
 
1229
        base_branch = self.make_branch('base')
 
1230
        request = smart_branch.SmartServerBranchBreakLock(
 
1231
            self.get_transport())
 
1232
        base_branch.lock_write()
 
1233
        self.assertEqual(
 
1234
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1235
            request.execute('base'))
 
1236
 
 
1237
    def test_nothing_to_break(self):
 
1238
        base_branch = self.make_branch('base')
 
1239
        request = smart_branch.SmartServerBranchBreakLock(
 
1240
            self.get_transport())
 
1241
        self.assertEqual(
 
1242
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1243
            request.execute('base'))
 
1244
 
 
1245
 
 
1246
class TestSmartServerBranchRequestGetParent(tests.TestCaseWithMemoryTransport):
 
1247
 
 
1248
    def test_get_parent_none(self):
 
1249
        base_branch = self.make_branch('base')
 
1250
        request = smart_branch.SmartServerBranchGetParent(self.get_transport())
 
1251
        response = request.execute('base')
 
1252
        self.assertEquals(
 
1253
            smart_req.SuccessfulSmartServerResponse(('',)), response)
 
1254
 
 
1255
    def test_get_parent_something(self):
 
1256
        base_branch = self.make_branch('base')
 
1257
        base_branch.set_parent(self.get_url('foo'))
 
1258
        request = smart_branch.SmartServerBranchGetParent(self.get_transport())
 
1259
        response = request.execute('base')
 
1260
        self.assertEquals(
 
1261
            smart_req.SuccessfulSmartServerResponse(("../foo",)),
 
1262
            response)
 
1263
 
 
1264
 
 
1265
class TestSmartServerBranchRequestSetParent(TestLockedBranch):
 
1266
 
 
1267
    def test_set_parent_none(self):
 
1268
        branch = self.make_branch('base', format="1.9")
 
1269
        branch.lock_write()
 
1270
        branch._set_parent_location('foo')
 
1271
        branch.unlock()
 
1272
        request = smart_branch.SmartServerBranchRequestSetParentLocation(
 
1273
            self.get_transport())
 
1274
        branch_token, repo_token = self.get_lock_tokens(branch)
 
1275
        try:
 
1276
            response = request.execute('base', branch_token, repo_token, '')
 
1277
        finally:
 
1278
            branch.unlock()
 
1279
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
 
1280
        self.assertEqual(None, branch.get_parent())
 
1281
 
 
1282
    def test_set_parent_something(self):
 
1283
        branch = self.make_branch('base', format="1.9")
 
1284
        request = smart_branch.SmartServerBranchRequestSetParentLocation(
 
1285
            self.get_transport())
 
1286
        branch_token, repo_token = self.get_lock_tokens(branch)
 
1287
        try:
 
1288
            response = request.execute('base', branch_token, repo_token,
 
1289
            'http://bar/')
 
1290
        finally:
 
1291
            branch.unlock()
 
1292
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response)
 
1293
        self.assertEqual('http://bar/', branch.get_parent())
 
1294
 
 
1295
 
 
1296
class TestSmartServerBranchRequestGetTagsBytes(
 
1297
    tests.TestCaseWithMemoryTransport):
 
1298
    # Only called when the branch format and tags match [yay factory
 
1299
    # methods] so only need to test straight forward cases.
 
1300
 
 
1301
    def test_get_bytes(self):
 
1302
        base_branch = self.make_branch('base')
 
1303
        request = smart_branch.SmartServerBranchGetTagsBytes(
 
1304
            self.get_transport())
 
1305
        response = request.execute('base')
 
1306
        self.assertEquals(
 
1307
            smart_req.SuccessfulSmartServerResponse(('',)), response)
 
1308
 
 
1309
 
 
1310
class TestSmartServerBranchRequestGetStackedOnURL(tests.TestCaseWithMemoryTransport):
 
1311
 
 
1312
    def test_get_stacked_on_url(self):
 
1313
        base_branch = self.make_branch('base', format='1.6')
 
1314
        stacked_branch = self.make_branch('stacked', format='1.6')
 
1315
        # typically should be relative
 
1316
        stacked_branch.set_stacked_on_url('../base')
 
1317
        request = smart_branch.SmartServerBranchRequestGetStackedOnURL(
 
1318
            self.get_transport())
 
1319
        response = request.execute('stacked')
 
1320
        self.assertEquals(
 
1321
            smart_req.SmartServerResponse(('ok', '../base')),
 
1322
            response)
 
1323
 
 
1324
 
 
1325
class TestSmartServerBranchRequestLockWrite(TestLockedBranch):
 
1326
 
 
1327
    def setUp(self):
 
1328
        tests.TestCaseWithMemoryTransport.setUp(self)
370
1329
 
371
1330
    def test_lock_write_on_unlocked_branch(self):
372
1331
        backing = self.get_transport()
373
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
374
 
        branch = self.make_branch('.')
 
1332
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1333
        branch = self.make_branch('.', format='knit')
375
1334
        repository = branch.repository
376
 
        response = request.execute(backing.local_abspath(''))
 
1335
        response = request.execute('')
377
1336
        branch_nonce = branch.control_files._lock.peek().get('nonce')
378
1337
        repository_nonce = repository.control_files._lock.peek().get('nonce')
379
 
        self.assertEqual(
380
 
            SmartServerResponse(('ok', branch_nonce, repository_nonce)),
381
 
            response)
 
1338
        self.assertEqual(smart_req.SmartServerResponse(
 
1339
                ('ok', branch_nonce, repository_nonce)),
 
1340
                         response)
382
1341
        # The branch (and associated repository) is now locked.  Verify that
383
1342
        # with a new branch object.
384
1343
        new_branch = repository.bzrdir.open_branch()
385
1344
        self.assertRaises(errors.LockContention, new_branch.lock_write)
 
1345
        # Cleanup
 
1346
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1347
        response = request.execute('', branch_nonce, repository_nonce)
386
1348
 
387
1349
    def test_lock_write_on_locked_branch(self):
388
1350
        backing = self.get_transport()
389
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
 
1351
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
390
1352
        branch = self.make_branch('.')
391
 
        branch.lock_write()
 
1353
        branch_token = branch.lock_write().branch_token
392
1354
        branch.leave_lock_in_place()
393
1355
        branch.unlock()
394
 
        response = request.execute(backing.local_abspath(''))
 
1356
        response = request.execute('')
395
1357
        self.assertEqual(
396
 
            SmartServerResponse(('LockContention',)), response)
 
1358
            smart_req.SmartServerResponse(('LockContention',)), response)
 
1359
        # Cleanup
 
1360
        branch.lock_write(branch_token)
 
1361
        branch.dont_leave_lock_in_place()
 
1362
        branch.unlock()
397
1363
 
398
1364
    def test_lock_write_with_tokens_on_locked_branch(self):
399
1365
        backing = self.get_transport()
400
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
401
 
        branch = self.make_branch('.')
402
 
        branch_token = branch.lock_write()
403
 
        repo_token = branch.repository.lock_write()
404
 
        branch.repository.unlock()
 
1366
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1367
        branch = self.make_branch('.', format='knit')
 
1368
        branch_token, repo_token = self.get_lock_tokens(branch)
405
1369
        branch.leave_lock_in_place()
406
1370
        branch.repository.leave_lock_in_place()
407
1371
        branch.unlock()
408
 
        response = request.execute(backing.local_abspath(''),
 
1372
        response = request.execute('',
409
1373
                                   branch_token, repo_token)
410
1374
        self.assertEqual(
411
 
            SmartServerResponse(('ok', branch_token, repo_token)), response)
 
1375
            smart_req.SmartServerResponse(('ok', branch_token, repo_token)),
 
1376
            response)
 
1377
        # Cleanup
 
1378
        branch.repository.lock_write(repo_token)
 
1379
        branch.repository.dont_leave_lock_in_place()
 
1380
        branch.repository.unlock()
 
1381
        branch.lock_write(branch_token)
 
1382
        branch.dont_leave_lock_in_place()
 
1383
        branch.unlock()
412
1384
 
413
1385
    def test_lock_write_with_mismatched_tokens_on_locked_branch(self):
414
1386
        backing = self.get_transport()
415
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
416
 
        branch = self.make_branch('.')
417
 
        branch_token = branch.lock_write()
418
 
        repo_token = branch.repository.lock_write()
419
 
        branch.repository.unlock()
 
1387
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1388
        branch = self.make_branch('.', format='knit')
 
1389
        branch_token, repo_token = self.get_lock_tokens(branch)
420
1390
        branch.leave_lock_in_place()
421
1391
        branch.repository.leave_lock_in_place()
422
1392
        branch.unlock()
423
 
        response = request.execute(backing.local_abspath(''),
 
1393
        response = request.execute('',
424
1394
                                   branch_token+'xxx', repo_token)
425
1395
        self.assertEqual(
426
 
            SmartServerResponse(('TokenMismatch',)), response)
 
1396
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
1397
        # Cleanup
 
1398
        branch.repository.lock_write(repo_token)
 
1399
        branch.repository.dont_leave_lock_in_place()
 
1400
        branch.repository.unlock()
 
1401
        branch.lock_write(branch_token)
 
1402
        branch.dont_leave_lock_in_place()
 
1403
        branch.unlock()
427
1404
 
428
1405
    def test_lock_write_on_locked_repo(self):
429
1406
        backing = self.get_transport()
430
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
431
 
        branch = self.make_branch('.')
432
 
        branch.repository.lock_write()
433
 
        branch.repository.leave_lock_in_place()
434
 
        branch.repository.unlock()
435
 
        response = request.execute(backing.local_abspath(''))
 
1407
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1408
        branch = self.make_branch('.', format='knit')
 
1409
        repo = branch.repository
 
1410
        repo_token = repo.lock_write().repository_token
 
1411
        repo.leave_lock_in_place()
 
1412
        repo.unlock()
 
1413
        response = request.execute('')
436
1414
        self.assertEqual(
437
 
            SmartServerResponse(('LockContention',)), response)
 
1415
            smart_req.SmartServerResponse(('LockContention',)), response)
 
1416
        # Cleanup
 
1417
        repo.lock_write(repo_token)
 
1418
        repo.dont_leave_lock_in_place()
 
1419
        repo.unlock()
438
1420
 
439
1421
    def test_lock_write_on_readonly_transport(self):
440
1422
        backing = self.get_readonly_transport()
441
 
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
442
 
        branch = self.make_branch('.')
443
 
        response = request.execute('')
444
 
        self.assertEqual(
445
 
            SmartServerResponse(('UnlockableTransport',)), response)
446
 
 
447
 
 
448
 
class TestSmartServerBranchRequestUnlock(tests.TestCaseWithTransport):
449
 
 
450
 
    def setUp(self):
451
 
        tests.TestCaseWithTransport.setUp(self)
452
 
        self.reduceLockdirTimeout()
 
1423
        request = smart_branch.SmartServerBranchRequestLockWrite(backing)
 
1424
        branch = self.make_branch('.')
 
1425
        root = self.get_transport().clone('/')
 
1426
        path = urlutils.relative_url(root.base, self.get_transport().base)
 
1427
        response = request.execute(path)
 
1428
        error_name, lock_str, why_str = response.args
 
1429
        self.assertFalse(response.is_successful())
 
1430
        self.assertEqual('LockFailed', error_name)
 
1431
 
 
1432
 
 
1433
class TestSmartServerBranchRequestGetPhysicalLockStatus(TestLockedBranch):
 
1434
 
 
1435
    def setUp(self):
 
1436
        tests.TestCaseWithMemoryTransport.setUp(self)
 
1437
 
 
1438
    def test_true(self):
 
1439
        backing = self.get_transport()
 
1440
        request = smart_branch.SmartServerBranchRequestGetPhysicalLockStatus(
 
1441
            backing)
 
1442
        branch = self.make_branch('.')
 
1443
        branch_token, repo_token = self.get_lock_tokens(branch)
 
1444
        self.assertEquals(True, branch.get_physical_lock_status())
 
1445
        response = request.execute('')
 
1446
        self.assertEqual(
 
1447
            smart_req.SmartServerResponse(('yes',)), response)
 
1448
        branch.unlock()
 
1449
 
 
1450
    def test_false(self):
 
1451
        backing = self.get_transport()
 
1452
        request = smart_branch.SmartServerBranchRequestGetPhysicalLockStatus(
 
1453
            backing)
 
1454
        branch = self.make_branch('.')
 
1455
        self.assertEquals(False, branch.get_physical_lock_status())
 
1456
        response = request.execute('')
 
1457
        self.assertEqual(
 
1458
            smart_req.SmartServerResponse(('no',)), response)
 
1459
 
 
1460
 
 
1461
class TestSmartServerBranchRequestUnlock(TestLockedBranch):
 
1462
 
 
1463
    def setUp(self):
 
1464
        tests.TestCaseWithMemoryTransport.setUp(self)
453
1465
 
454
1466
    def test_unlock_on_locked_branch_and_repo(self):
455
1467
        backing = self.get_transport()
456
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
457
 
        branch = self.make_branch('.')
 
1468
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1469
        branch = self.make_branch('.', format='knit')
458
1470
        # Lock the branch
459
 
        branch_token = branch.lock_write()
460
 
        repo_token = branch.repository.lock_write()
461
 
        branch.repository.unlock()
 
1471
        branch_token, repo_token = self.get_lock_tokens(branch)
462
1472
        # Unlock the branch (and repo) object, leaving the physical locks
463
1473
        # in place.
464
1474
        branch.leave_lock_in_place()
465
1475
        branch.repository.leave_lock_in_place()
466
1476
        branch.unlock()
467
 
        response = request.execute(backing.local_abspath(''),
 
1477
        response = request.execute('',
468
1478
                                   branch_token, repo_token)
469
1479
        self.assertEqual(
470
 
            SmartServerResponse(('ok',)), response)
 
1480
            smart_req.SmartServerResponse(('ok',)), response)
471
1481
        # The branch is now unlocked.  Verify that with a new branch
472
1482
        # object.
473
1483
        new_branch = branch.bzrdir.open_branch()
476
1486
 
477
1487
    def test_unlock_on_unlocked_branch_unlocked_repo(self):
478
1488
        backing = self.get_transport()
479
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
480
 
        branch = self.make_branch('.')
 
1489
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1490
        branch = self.make_branch('.', format='knit')
481
1491
        response = request.execute(
482
 
            backing.local_abspath(''), 'branch token', 'repo token')
 
1492
            '', 'branch token', 'repo token')
483
1493
        self.assertEqual(
484
 
            SmartServerResponse(('TokenMismatch',)), response)
 
1494
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
485
1495
 
486
1496
    def test_unlock_on_unlocked_branch_locked_repo(self):
487
1497
        backing = self.get_transport()
488
 
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
489
 
        branch = self.make_branch('.')
 
1498
        request = smart_branch.SmartServerBranchRequestUnlock(backing)
 
1499
        branch = self.make_branch('.', format='knit')
490
1500
        # Lock the repository.
491
 
        repo_token = branch.repository.lock_write()
 
1501
        repo_token = branch.repository.lock_write().repository_token
492
1502
        branch.repository.leave_lock_in_place()
493
1503
        branch.repository.unlock()
494
1504
        # Issue branch lock_write request on the unlocked branch (with locked
495
1505
        # repo).
496
 
        response = request.execute(
497
 
            backing.local_abspath(''), 'branch token', repo_token)
 
1506
        response = request.execute('', 'branch token', repo_token)
498
1507
        self.assertEqual(
499
 
            SmartServerResponse(('TokenMismatch',)), response)
500
 
 
501
 
 
502
 
class TestSmartServerRepositoryRequest(tests.TestCaseWithTransport):
 
1508
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
1509
        # Cleanup
 
1510
        branch.repository.lock_write(repo_token)
 
1511
        branch.repository.dont_leave_lock_in_place()
 
1512
        branch.repository.unlock()
 
1513
 
 
1514
 
 
1515
class TestSmartServerRepositoryRequest(tests.TestCaseWithMemoryTransport):
503
1516
 
504
1517
    def test_no_repository(self):
505
1518
        """Raise NoRepositoryPresent when there is a bzrdir and no repo."""
508
1521
        # its the exact path being looked at and the server is not
509
1522
        # searching.
510
1523
        backing = self.get_transport()
511
 
        request = smart.repository.SmartServerRepositoryRequest(backing)
 
1524
        request = smart_repo.SmartServerRepositoryRequest(backing)
512
1525
        self.make_repository('.', shared=True)
513
1526
        self.make_bzrdir('subdir')
514
1527
        self.assertRaises(errors.NoRepositoryPresent,
515
 
            request.execute, backing.local_abspath('subdir'))
516
 
 
517
 
 
518
 
class TestSmartServerRepositoryGetRevisionGraph(tests.TestCaseWithTransport):
 
1528
            request.execute, 'subdir')
 
1529
 
 
1530
 
 
1531
class TestSmartServerRepositoryAddSignatureText(tests.TestCaseWithMemoryTransport):
 
1532
 
 
1533
    def test_add_text(self):
 
1534
        backing = self.get_transport()
 
1535
        request = smart_repo.SmartServerRepositoryAddSignatureText(backing)
 
1536
        tree = self.make_branch_and_memory_tree('.')
 
1537
        write_token = tree.lock_write()
 
1538
        self.addCleanup(tree.unlock)
 
1539
        tree.add('')
 
1540
        tree.commit("Message", rev_id='rev1')
 
1541
        tree.branch.repository.start_write_group()
 
1542
        write_group_tokens = tree.branch.repository.suspend_write_group()
 
1543
        self.assertEqual(None, request.execute('', write_token,
 
1544
            'rev1', *write_group_tokens))
 
1545
        response = request.do_body('somesignature')
 
1546
        self.assertTrue(response.is_successful())
 
1547
        self.assertEqual(response.args[0], 'ok')
 
1548
        write_group_tokens = response.args[1:]
 
1549
        tree.branch.repository.resume_write_group(write_group_tokens)
 
1550
        tree.branch.repository.commit_write_group()
 
1551
        tree.unlock()
 
1552
        self.assertEqual("somesignature",
 
1553
            tree.branch.repository.get_signature_text("rev1"))
 
1554
 
 
1555
 
 
1556
class TestSmartServerRepositoryAllRevisionIds(
 
1557
    tests.TestCaseWithMemoryTransport):
 
1558
 
 
1559
    def test_empty(self):
 
1560
        """An empty body should be returned for an empty repository."""
 
1561
        backing = self.get_transport()
 
1562
        request = smart_repo.SmartServerRepositoryAllRevisionIds(backing)
 
1563
        self.make_repository('.')
 
1564
        self.assertEquals(
 
1565
            smart_req.SuccessfulSmartServerResponse(("ok", ), ""),
 
1566
            request.execute(''))
 
1567
 
 
1568
    def test_some_revisions(self):
 
1569
        """An empty body should be returned for an empty repository."""
 
1570
        backing = self.get_transport()
 
1571
        request = smart_repo.SmartServerRepositoryAllRevisionIds(backing)
 
1572
        tree = self.make_branch_and_memory_tree('.')
 
1573
        tree.lock_write()
 
1574
        tree.add('')
 
1575
        tree.commit(rev_id='origineel', message="message")
 
1576
        tree.commit(rev_id='nog-een-revisie', message="message")
 
1577
        tree.unlock()
 
1578
        self.assertEquals(
 
1579
            smart_req.SuccessfulSmartServerResponse(("ok", ),
 
1580
                "origineel\nnog-een-revisie"),
 
1581
            request.execute(''))
 
1582
 
 
1583
 
 
1584
class TestSmartServerRepositoryBreakLock(tests.TestCaseWithMemoryTransport):
 
1585
 
 
1586
    def test_lock_to_break(self):
 
1587
        backing = self.get_transport()
 
1588
        request = smart_repo.SmartServerRepositoryBreakLock(backing)
 
1589
        tree = self.make_branch_and_memory_tree('.')
 
1590
        tree.branch.repository.lock_write()
 
1591
        self.assertEqual(
 
1592
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1593
            request.execute(''))
 
1594
 
 
1595
    def test_nothing_to_break(self):
 
1596
        backing = self.get_transport()
 
1597
        request = smart_repo.SmartServerRepositoryBreakLock(backing)
 
1598
        tree = self.make_branch_and_memory_tree('.')
 
1599
        self.assertEqual(
 
1600
            smart_req.SuccessfulSmartServerResponse(('ok', ), None),
 
1601
            request.execute(''))
 
1602
 
 
1603
 
 
1604
class TestSmartServerRepositoryGetParentMap(tests.TestCaseWithMemoryTransport):
 
1605
 
 
1606
    def test_trivial_bzipped(self):
 
1607
        # This tests that the wire encoding is actually bzipped
 
1608
        backing = self.get_transport()
 
1609
        request = smart_repo.SmartServerRepositoryGetParentMap(backing)
 
1610
        tree = self.make_branch_and_memory_tree('.')
 
1611
 
 
1612
        self.assertEqual(None,
 
1613
            request.execute('', 'missing-id'))
 
1614
        # Note that it returns a body that is bzipped.
 
1615
        self.assertEqual(
 
1616
            smart_req.SuccessfulSmartServerResponse(('ok', ), bz2.compress('')),
 
1617
            request.do_body('\n\n0\n'))
 
1618
 
 
1619
    def test_trivial_include_missing(self):
 
1620
        backing = self.get_transport()
 
1621
        request = smart_repo.SmartServerRepositoryGetParentMap(backing)
 
1622
        tree = self.make_branch_and_memory_tree('.')
 
1623
 
 
1624
        self.assertEqual(None,
 
1625
            request.execute('', 'missing-id', 'include-missing:'))
 
1626
        self.assertEqual(
 
1627
            smart_req.SuccessfulSmartServerResponse(('ok', ),
 
1628
                bz2.compress('missing:missing-id')),
 
1629
            request.do_body('\n\n0\n'))
 
1630
 
 
1631
 
 
1632
class TestSmartServerRepositoryGetRevisionGraph(
 
1633
    tests.TestCaseWithMemoryTransport):
519
1634
 
520
1635
    def test_none_argument(self):
521
1636
        backing = self.get_transport()
522
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1637
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
523
1638
        tree = self.make_branch_and_memory_tree('.')
524
1639
        tree.lock_write()
525
1640
        tree.add('')
530
1645
        # the lines of revision_id->revision_parent_list has no guaranteed
531
1646
        # order coming out of a dict, so sort both our test and response
532
1647
        lines = sorted([' '.join([r2, r1]), r1])
533
 
        response = request.execute(backing.local_abspath(''), '')
 
1648
        response = request.execute('', '')
534
1649
        response.body = '\n'.join(sorted(response.body.split('\n')))
535
1650
 
536
1651
        self.assertEqual(
537
 
            SmartServerResponse(('ok', ), '\n'.join(lines)), response)
 
1652
            smart_req.SmartServerResponse(('ok', ), '\n'.join(lines)), response)
538
1653
 
539
1654
    def test_specific_revision_argument(self):
540
1655
        backing = self.get_transport()
541
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1656
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
542
1657
        tree = self.make_branch_and_memory_tree('.')
543
1658
        tree.lock_write()
544
1659
        tree.add('')
547
1662
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
548
1663
        tree.unlock()
549
1664
 
550
 
        self.assertEqual(SmartServerResponse(('ok', ), rev_id_utf8),
551
 
            request.execute(backing.local_abspath(''), rev_id_utf8))
552
 
    
 
1665
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), rev_id_utf8),
 
1666
            request.execute('', rev_id_utf8))
 
1667
 
553
1668
    def test_no_such_revision(self):
554
1669
        backing = self.get_transport()
555
 
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
 
1670
        request = smart_repo.SmartServerRepositoryGetRevisionGraph(backing)
556
1671
        tree = self.make_branch_and_memory_tree('.')
557
1672
        tree.lock_write()
558
1673
        tree.add('')
560
1675
        tree.unlock()
561
1676
 
562
1677
        # Note that it still returns body (of zero bytes).
563
 
        self.assertEqual(
564
 
            SmartServerResponse(('nosuchrevision', 'missingrevision', ), ''),
565
 
            request.execute(backing.local_abspath(''), 'missingrevision'))
566
 
 
567
 
 
568
 
class TestSmartServerRequestHasRevision(tests.TestCaseWithTransport):
 
1678
        self.assertEqual(smart_req.SmartServerResponse(
 
1679
                ('nosuchrevision', 'missingrevision', ), ''),
 
1680
                         request.execute('', 'missingrevision'))
 
1681
 
 
1682
 
 
1683
class TestSmartServerRepositoryGetRevIdForRevno(
 
1684
    tests.TestCaseWithMemoryTransport):
 
1685
 
 
1686
    def test_revno_found(self):
 
1687
        backing = self.get_transport()
 
1688
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1689
        tree = self.make_branch_and_memory_tree('.')
 
1690
        tree.lock_write()
 
1691
        tree.add('')
 
1692
        rev1_id_utf8 = u'\xc8'.encode('utf-8')
 
1693
        rev2_id_utf8 = u'\xc9'.encode('utf-8')
 
1694
        tree.commit('1st commit', rev_id=rev1_id_utf8)
 
1695
        tree.commit('2nd commit', rev_id=rev2_id_utf8)
 
1696
        tree.unlock()
 
1697
 
 
1698
        self.assertEqual(smart_req.SmartServerResponse(('ok', rev1_id_utf8)),
 
1699
            request.execute('', 1, (2, rev2_id_utf8)))
 
1700
 
 
1701
    def test_known_revid_missing(self):
 
1702
        backing = self.get_transport()
 
1703
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1704
        repo = self.make_repository('.')
 
1705
        self.assertEqual(
 
1706
            smart_req.FailedSmartServerResponse(('nosuchrevision', 'ghost')),
 
1707
            request.execute('', 1, (2, 'ghost')))
 
1708
 
 
1709
    def test_history_incomplete(self):
 
1710
        backing = self.get_transport()
 
1711
        request = smart_repo.SmartServerRepositoryGetRevIdForRevno(backing)
 
1712
        parent = self.make_branch_and_memory_tree('parent', format='1.9')
 
1713
        parent.lock_write()
 
1714
        parent.add([''], ['TREE_ROOT'])
 
1715
        r1 = parent.commit(message='first commit')
 
1716
        r2 = parent.commit(message='second commit')
 
1717
        parent.unlock()
 
1718
        local = self.make_branch_and_memory_tree('local', format='1.9')
 
1719
        local.branch.pull(parent.branch)
 
1720
        local.set_parent_ids([r2])
 
1721
        r3 = local.commit(message='local commit')
 
1722
        local.branch.create_clone_on_transport(
 
1723
            self.get_transport('stacked'), stacked_on=self.get_url('parent'))
 
1724
        self.assertEqual(
 
1725
            smart_req.SmartServerResponse(('history-incomplete', 2, r2)),
 
1726
            request.execute('stacked', 1, (3, r3)))
 
1727
 
 
1728
 
 
1729
class TestSmartServerRepositoryIterRevisions(
 
1730
    tests.TestCaseWithMemoryTransport):
 
1731
 
 
1732
    def test_basic(self):
 
1733
        backing = self.get_transport()
 
1734
        request = smart_repo.SmartServerRepositoryIterRevisions(backing)
 
1735
        tree = self.make_branch_and_memory_tree('.', format='2a')
 
1736
        tree.lock_write()
 
1737
        tree.add('')
 
1738
        tree.commit('1st commit', rev_id="rev1")
 
1739
        tree.commit('2nd commit', rev_id="rev2")
 
1740
        tree.unlock()
 
1741
 
 
1742
        self.assertIs(None, request.execute(''))
 
1743
        response = request.do_body("rev1\nrev2")
 
1744
        self.assertTrue(response.is_successful())
 
1745
        # Format 2a uses serializer format 10
 
1746
        self.assertEquals(response.args, ("ok", "10"))
 
1747
 
 
1748
        self.addCleanup(tree.branch.lock_read().unlock)
 
1749
        entries = [zlib.compress(record.get_bytes_as("fulltext")) for record in
 
1750
            tree.branch.repository.revisions.get_record_stream(
 
1751
            [("rev1", ), ("rev2", )], "unordered", True)]
 
1752
 
 
1753
        contents = "".join(response.body_stream)
 
1754
        self.assertTrue(contents in (
 
1755
            "".join([entries[0], entries[1]]),
 
1756
            "".join([entries[1], entries[0]])))
 
1757
 
 
1758
    def test_missing(self):
 
1759
        backing = self.get_transport()
 
1760
        request = smart_repo.SmartServerRepositoryIterRevisions(backing)
 
1761
        tree = self.make_branch_and_memory_tree('.', format='2a')
 
1762
 
 
1763
        self.assertIs(None, request.execute(''))
 
1764
        response = request.do_body("rev1\nrev2")
 
1765
        self.assertTrue(response.is_successful())
 
1766
        # Format 2a uses serializer format 10
 
1767
        self.assertEquals(response.args, ("ok", "10"))
 
1768
 
 
1769
        contents = "".join(response.body_stream)
 
1770
        self.assertEquals(contents, "")
 
1771
 
 
1772
 
 
1773
class GetStreamTestBase(tests.TestCaseWithMemoryTransport):
 
1774
 
 
1775
    def make_two_commit_repo(self):
 
1776
        tree = self.make_branch_and_memory_tree('.')
 
1777
        tree.lock_write()
 
1778
        tree.add('')
 
1779
        r1 = tree.commit('1st commit')
 
1780
        r2 = tree.commit('2nd commit', rev_id=u'\xc8'.encode('utf-8'))
 
1781
        tree.unlock()
 
1782
        repo = tree.branch.repository
 
1783
        return repo, r1, r2
 
1784
 
 
1785
 
 
1786
class TestSmartServerRepositoryGetStream(GetStreamTestBase):
 
1787
 
 
1788
    def test_ancestry_of(self):
 
1789
        """The search argument may be a 'ancestry-of' some heads'."""
 
1790
        backing = self.get_transport()
 
1791
        request = smart_repo.SmartServerRepositoryGetStream(backing)
 
1792
        repo, r1, r2 = self.make_two_commit_repo()
 
1793
        fetch_spec = ['ancestry-of', r2]
 
1794
        lines = '\n'.join(fetch_spec)
 
1795
        request.execute('', repo._format.network_name())
 
1796
        response = request.do_body(lines)
 
1797
        self.assertEqual(('ok',), response.args)
 
1798
        stream_bytes = ''.join(response.body_stream)
 
1799
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1800
 
 
1801
    def test_search(self):
 
1802
        """The search argument may be a 'search' of some explicit keys."""
 
1803
        backing = self.get_transport()
 
1804
        request = smart_repo.SmartServerRepositoryGetStream(backing)
 
1805
        repo, r1, r2 = self.make_two_commit_repo()
 
1806
        fetch_spec = ['search', '%s %s' % (r1, r2), 'null:', '2']
 
1807
        lines = '\n'.join(fetch_spec)
 
1808
        request.execute('', repo._format.network_name())
 
1809
        response = request.do_body(lines)
 
1810
        self.assertEqual(('ok',), response.args)
 
1811
        stream_bytes = ''.join(response.body_stream)
 
1812
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1813
 
 
1814
    def test_search_everything(self):
 
1815
        """A search of 'everything' returns a stream."""
 
1816
        backing = self.get_transport()
 
1817
        request = smart_repo.SmartServerRepositoryGetStream_1_19(backing)
 
1818
        repo, r1, r2 = self.make_two_commit_repo()
 
1819
        serialised_fetch_spec = 'everything'
 
1820
        request.execute('', repo._format.network_name())
 
1821
        response = request.do_body(serialised_fetch_spec)
 
1822
        self.assertEqual(('ok',), response.args)
 
1823
        stream_bytes = ''.join(response.body_stream)
 
1824
        self.assertStartsWith(stream_bytes, 'Bazaar pack format 1')
 
1825
 
 
1826
 
 
1827
class TestSmartServerRequestHasRevision(tests.TestCaseWithMemoryTransport):
569
1828
 
570
1829
    def test_missing_revision(self):
571
1830
        """For a missing revision, ('no', ) is returned."""
572
1831
        backing = self.get_transport()
573
 
        request = smart.repository.SmartServerRequestHasRevision(backing)
 
1832
        request = smart_repo.SmartServerRequestHasRevision(backing)
574
1833
        self.make_repository('.')
575
 
        self.assertEqual(SmartServerResponse(('no', )),
576
 
            request.execute(backing.local_abspath(''), 'revid'))
 
1834
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
1835
            request.execute('', 'revid'))
577
1836
 
578
1837
    def test_present_revision(self):
579
1838
        """For a present revision, ('yes', ) is returned."""
580
1839
        backing = self.get_transport()
581
 
        request = smart.repository.SmartServerRequestHasRevision(backing)
 
1840
        request = smart_repo.SmartServerRequestHasRevision(backing)
582
1841
        tree = self.make_branch_and_memory_tree('.')
583
1842
        tree.lock_write()
584
1843
        tree.add('')
586
1845
        r1 = tree.commit('a commit', rev_id=rev_id_utf8)
587
1846
        tree.unlock()
588
1847
        self.assertTrue(tree.branch.repository.has_revision(rev_id_utf8))
589
 
        self.assertEqual(SmartServerResponse(('yes', )),
590
 
            request.execute(backing.local_abspath(''), rev_id_utf8))
591
 
 
592
 
 
593
 
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithTransport):
 
1848
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
1849
            request.execute('', rev_id_utf8))
 
1850
 
 
1851
 
 
1852
class TestSmartServerRepositoryIterFilesBytes(tests.TestCaseWithTransport):
 
1853
 
 
1854
    def test_single(self):
 
1855
        backing = self.get_transport()
 
1856
        request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
 
1857
        t = self.make_branch_and_tree('.')
 
1858
        self.addCleanup(t.lock_write().unlock)
 
1859
        self.build_tree_contents([("file", "somecontents")])
 
1860
        t.add(["file"], ["thefileid"])
 
1861
        t.commit(rev_id='somerev', message="add file")
 
1862
        self.assertIs(None, request.execute(''))
 
1863
        response = request.do_body("thefileid\0somerev\n")
 
1864
        self.assertTrue(response.is_successful())
 
1865
        self.assertEquals(response.args, ("ok", ))
 
1866
        self.assertEquals("".join(response.body_stream),
 
1867
            "ok\x000\n" + zlib.compress("somecontents"))
 
1868
 
 
1869
    def test_missing(self):
 
1870
        backing = self.get_transport()
 
1871
        request = smart_repo.SmartServerRepositoryIterFilesBytes(backing)
 
1872
        t = self.make_branch_and_tree('.')
 
1873
        self.addCleanup(t.lock_write().unlock)
 
1874
        self.assertIs(None, request.execute(''))
 
1875
        response = request.do_body("thefileid\0revision\n")
 
1876
        self.assertTrue(response.is_successful())
 
1877
        self.assertEquals(response.args, ("ok", ))
 
1878
        self.assertEquals("".join(response.body_stream),
 
1879
            "absent\x00thefileid\x00revision\x000\n")
 
1880
 
 
1881
 
 
1882
class TestSmartServerRequestHasSignatureForRevisionId(
 
1883
        tests.TestCaseWithMemoryTransport):
 
1884
 
 
1885
    def test_missing_revision(self):
 
1886
        """For a missing revision, NoSuchRevision is returned."""
 
1887
        backing = self.get_transport()
 
1888
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1889
            backing)
 
1890
        self.make_repository('.')
 
1891
        self.assertEqual(
 
1892
            smart_req.FailedSmartServerResponse(
 
1893
                ('nosuchrevision', 'revid'), None),
 
1894
            request.execute('', 'revid'))
 
1895
 
 
1896
    def test_missing_signature(self):
 
1897
        """For a missing signature, ('no', ) is returned."""
 
1898
        backing = self.get_transport()
 
1899
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1900
            backing)
 
1901
        tree = self.make_branch_and_memory_tree('.')
 
1902
        tree.lock_write()
 
1903
        tree.add('')
 
1904
        r1 = tree.commit('a commit', rev_id='A')
 
1905
        tree.unlock()
 
1906
        self.assertTrue(tree.branch.repository.has_revision('A'))
 
1907
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
1908
            request.execute('', 'A'))
 
1909
 
 
1910
    def test_present_signature(self):
 
1911
        """For a present signature, ('yes', ) is returned."""
 
1912
        backing = self.get_transport()
 
1913
        request = smart_repo.SmartServerRequestHasSignatureForRevisionId(
 
1914
            backing)
 
1915
        strategy = gpg.LoopbackGPGStrategy(None)
 
1916
        tree = self.make_branch_and_memory_tree('.')
 
1917
        tree.lock_write()
 
1918
        tree.add('')
 
1919
        r1 = tree.commit('a commit', rev_id='A')
 
1920
        tree.branch.repository.start_write_group()
 
1921
        tree.branch.repository.sign_revision('A', strategy)
 
1922
        tree.branch.repository.commit_write_group()
 
1923
        tree.unlock()
 
1924
        self.assertTrue(tree.branch.repository.has_revision('A'))
 
1925
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
1926
            request.execute('', 'A'))
 
1927
 
 
1928
 
 
1929
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithMemoryTransport):
594
1930
 
595
1931
    def test_empty_revid(self):
596
1932
        """With an empty revid, we get only size an number and revisions"""
597
1933
        backing = self.get_transport()
598
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
1934
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
599
1935
        repository = self.make_repository('.')
600
1936
        stats = repository.gather_stats()
601
 
        size = stats['size']
602
 
        expected_body = 'revisions: 0\nsize: %d\n' % size
603
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
604
 
                         request.execute(backing.local_abspath(''), '', 'no'))
 
1937
        expected_body = 'revisions: 0\n'
 
1938
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
1939
                         request.execute('', '', 'no'))
605
1940
 
606
1941
    def test_revid_with_committers(self):
607
1942
        """For a revid we get more infos."""
608
1943
        backing = self.get_transport()
609
1944
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
610
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
1945
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
611
1946
        tree = self.make_branch_and_memory_tree('.')
612
1947
        tree.lock_write()
613
1948
        tree.add('')
618
1953
        tree.unlock()
619
1954
 
620
1955
        stats = tree.branch.repository.gather_stats()
621
 
        size = stats['size']
622
1956
        expected_body = ('firstrev: 123456.200 3600\n'
623
1957
                         'latestrev: 654321.400 0\n'
624
 
                         'revisions: 2\n'
625
 
                         'size: %d\n' % size)
626
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
627
 
                         request.execute(backing.local_abspath(''),
 
1958
                         'revisions: 2\n')
 
1959
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
1960
                         request.execute('',
628
1961
                                         rev_id_utf8, 'no'))
629
1962
 
630
1963
    def test_not_empty_repository_with_committers(self):
631
1964
        """For a revid and requesting committers we get the whole thing."""
632
1965
        backing = self.get_transport()
633
1966
        rev_id_utf8 = u'\xc8abc'.encode('utf-8')
634
 
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
 
1967
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
635
1968
        tree = self.make_branch_and_memory_tree('.')
636
1969
        tree.lock_write()
637
1970
        tree.add('')
643
1976
        tree.unlock()
644
1977
        stats = tree.branch.repository.gather_stats()
645
1978
 
646
 
        size = stats['size']
647
1979
        expected_body = ('committers: 2\n'
648
1980
                         'firstrev: 123456.200 3600\n'
649
1981
                         'latestrev: 654321.400 0\n'
650
 
                         'revisions: 2\n'
651
 
                         'size: %d\n' % size)
652
 
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
653
 
                         request.execute(backing.local_abspath(''),
 
1982
                         'revisions: 2\n')
 
1983
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), expected_body),
 
1984
                         request.execute('',
654
1985
                                         rev_id_utf8, 'yes'))
655
1986
 
656
 
 
657
 
class TestSmartServerRepositoryIsShared(tests.TestCaseWithTransport):
 
1987
    def test_unknown_revid(self):
 
1988
        """An unknown revision id causes a 'nosuchrevision' error."""
 
1989
        backing = self.get_transport()
 
1990
        request = smart_repo.SmartServerRepositoryGatherStats(backing)
 
1991
        repository = self.make_repository('.')
 
1992
        expected_body = 'revisions: 0\n'
 
1993
        self.assertEqual(
 
1994
            smart_req.FailedSmartServerResponse(
 
1995
                ('nosuchrevision', 'mia'), None),
 
1996
            request.execute('', 'mia', 'yes'))
 
1997
 
 
1998
 
 
1999
class TestSmartServerRepositoryIsShared(tests.TestCaseWithMemoryTransport):
658
2000
 
659
2001
    def test_is_shared(self):
660
2002
        """For a shared repository, ('yes', ) is returned."""
661
2003
        backing = self.get_transport()
662
 
        request = smart.repository.SmartServerRepositoryIsShared(backing)
 
2004
        request = smart_repo.SmartServerRepositoryIsShared(backing)
663
2005
        self.make_repository('.', shared=True)
664
 
        self.assertEqual(SmartServerResponse(('yes', )),
665
 
            request.execute(backing.local_abspath(''), ))
 
2006
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
2007
            request.execute('', ))
666
2008
 
667
2009
    def test_is_not_shared(self):
668
2010
        """For a shared repository, ('no', ) is returned."""
669
2011
        backing = self.get_transport()
670
 
        request = smart.repository.SmartServerRepositoryIsShared(backing)
 
2012
        request = smart_repo.SmartServerRepositoryIsShared(backing)
671
2013
        self.make_repository('.', shared=False)
672
 
        self.assertEqual(SmartServerResponse(('no', )),
673
 
            request.execute(backing.local_abspath(''), ))
674
 
 
675
 
 
676
 
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithTransport):
677
 
 
678
 
    def setUp(self):
679
 
        tests.TestCaseWithTransport.setUp(self)
680
 
        self.reduceLockdirTimeout()
 
2014
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
2015
            request.execute('', ))
 
2016
 
 
2017
 
 
2018
class TestSmartServerRepositoryGetRevisionSignatureText(
 
2019
        tests.TestCaseWithMemoryTransport):
 
2020
 
 
2021
    def test_get_signature(self):
 
2022
        backing = self.get_transport()
 
2023
        request = smart_repo.SmartServerRepositoryGetRevisionSignatureText(
 
2024
            backing)
 
2025
        bb = self.make_branch_builder('.')
 
2026
        bb.build_commit(rev_id='A')
 
2027
        repo = bb.get_branch().repository
 
2028
        strategy = gpg.LoopbackGPGStrategy(None)
 
2029
        self.addCleanup(repo.lock_write().unlock)
 
2030
        repo.start_write_group()
 
2031
        repo.sign_revision('A', strategy)
 
2032
        repo.commit_write_group()
 
2033
        expected_body = (
 
2034
            '-----BEGIN PSEUDO-SIGNED CONTENT-----\n' +
 
2035
            Testament.from_revision(repo, 'A').as_short_text() +
 
2036
            '-----END PSEUDO-SIGNED CONTENT-----\n')
 
2037
        self.assertEqual(
 
2038
            smart_req.SmartServerResponse(('ok', ), expected_body),
 
2039
            request.execute('', 'A'))
 
2040
 
 
2041
 
 
2042
class TestSmartServerRepositoryMakeWorkingTrees(
 
2043
        tests.TestCaseWithMemoryTransport):
 
2044
 
 
2045
    def test_make_working_trees(self):
 
2046
        """For a repository with working trees, ('yes', ) is returned."""
 
2047
        backing = self.get_transport()
 
2048
        request = smart_repo.SmartServerRepositoryMakeWorkingTrees(backing)
 
2049
        r = self.make_repository('.')
 
2050
        r.set_make_working_trees(True)
 
2051
        self.assertEqual(smart_req.SmartServerResponse(('yes', )),
 
2052
            request.execute('', ))
 
2053
 
 
2054
    def test_is_not_shared(self):
 
2055
        """For a repository with working trees, ('no', ) is returned."""
 
2056
        backing = self.get_transport()
 
2057
        request = smart_repo.SmartServerRepositoryMakeWorkingTrees(backing)
 
2058
        r = self.make_repository('.')
 
2059
        r.set_make_working_trees(False)
 
2060
        self.assertEqual(smart_req.SmartServerResponse(('no', )),
 
2061
            request.execute('', ))
 
2062
 
 
2063
 
 
2064
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithMemoryTransport):
681
2065
 
682
2066
    def test_lock_write_on_unlocked_repo(self):
683
2067
        backing = self.get_transport()
684
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
685
 
        repository = self.make_repository('.')
686
 
        response = request.execute(backing.local_abspath(''))
 
2068
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
 
2069
        repository = self.make_repository('.', format='knit')
 
2070
        response = request.execute('')
687
2071
        nonce = repository.control_files._lock.peek().get('nonce')
688
 
        self.assertEqual(SmartServerResponse(('ok', nonce)), response)
 
2072
        self.assertEqual(smart_req.SmartServerResponse(('ok', nonce)), response)
689
2073
        # The repository is now locked.  Verify that with a new repository
690
2074
        # object.
691
2075
        new_repo = repository.bzrdir.open_repository()
692
2076
        self.assertRaises(errors.LockContention, new_repo.lock_write)
 
2077
        # Cleanup
 
2078
        request = smart_repo.SmartServerRepositoryUnlock(backing)
 
2079
        response = request.execute('', nonce)
693
2080
 
694
2081
    def test_lock_write_on_locked_repo(self):
695
2082
        backing = self.get_transport()
696
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
697
 
        repository = self.make_repository('.')
698
 
        repository.lock_write()
 
2083
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
 
2084
        repository = self.make_repository('.', format='knit')
 
2085
        repo_token = repository.lock_write().repository_token
699
2086
        repository.leave_lock_in_place()
700
2087
        repository.unlock()
701
 
        response = request.execute(backing.local_abspath(''))
 
2088
        response = request.execute('')
702
2089
        self.assertEqual(
703
 
            SmartServerResponse(('LockContention',)), response)
 
2090
            smart_req.SmartServerResponse(('LockContention',)), response)
 
2091
        # Cleanup
 
2092
        repository.lock_write(repo_token)
 
2093
        repository.dont_leave_lock_in_place()
 
2094
        repository.unlock()
704
2095
 
705
2096
    def test_lock_write_on_readonly_transport(self):
706
2097
        backing = self.get_readonly_transport()
707
 
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
 
2098
        request = smart_repo.SmartServerRepositoryLockWrite(backing)
 
2099
        repository = self.make_repository('.', format='knit')
 
2100
        response = request.execute('')
 
2101
        self.assertFalse(response.is_successful())
 
2102
        self.assertEqual('LockFailed', response.args[0])
 
2103
 
 
2104
 
 
2105
class TestInsertStreamBase(tests.TestCaseWithMemoryTransport):
 
2106
 
 
2107
    def make_empty_byte_stream(self, repo):
 
2108
        byte_stream = smart_repo._stream_to_byte_stream([], repo._format)
 
2109
        return ''.join(byte_stream)
 
2110
 
 
2111
 
 
2112
class TestSmartServerRepositoryInsertStream(TestInsertStreamBase):
 
2113
 
 
2114
    def test_insert_stream_empty(self):
 
2115
        backing = self.get_transport()
 
2116
        request = smart_repo.SmartServerRepositoryInsertStream(backing)
708
2117
        repository = self.make_repository('.')
709
 
        response = request.execute('')
710
 
        self.assertEqual(
711
 
            SmartServerResponse(('UnlockableTransport',)), response)
712
 
 
713
 
 
714
 
class TestSmartServerRepositoryUnlock(tests.TestCaseWithTransport):
 
2118
        response = request.execute('', '')
 
2119
        self.assertEqual(None, response)
 
2120
        response = request.do_chunk(self.make_empty_byte_stream(repository))
 
2121
        self.assertEqual(None, response)
 
2122
        response = request.do_end()
 
2123
        self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
 
2124
 
 
2125
 
 
2126
class TestSmartServerRepositoryInsertStreamLocked(TestInsertStreamBase):
 
2127
 
 
2128
    def test_insert_stream_empty(self):
 
2129
        backing = self.get_transport()
 
2130
        request = smart_repo.SmartServerRepositoryInsertStreamLocked(
 
2131
            backing)
 
2132
        repository = self.make_repository('.', format='knit')
 
2133
        lock_token = repository.lock_write().repository_token
 
2134
        response = request.execute('', '', lock_token)
 
2135
        self.assertEqual(None, response)
 
2136
        response = request.do_chunk(self.make_empty_byte_stream(repository))
 
2137
        self.assertEqual(None, response)
 
2138
        response = request.do_end()
 
2139
        self.assertEqual(smart_req.SmartServerResponse(('ok', )), response)
 
2140
        repository.unlock()
 
2141
 
 
2142
    def test_insert_stream_with_wrong_lock_token(self):
 
2143
        backing = self.get_transport()
 
2144
        request = smart_repo.SmartServerRepositoryInsertStreamLocked(
 
2145
            backing)
 
2146
        repository = self.make_repository('.', format='knit')
 
2147
        lock_token = repository.lock_write().repository_token
 
2148
        self.assertRaises(
 
2149
            errors.TokenMismatch, request.execute, '', '', 'wrong-token')
 
2150
        repository.unlock()
 
2151
 
 
2152
 
 
2153
class TestSmartServerRepositoryUnlock(tests.TestCaseWithMemoryTransport):
715
2154
 
716
2155
    def setUp(self):
717
 
        tests.TestCaseWithTransport.setUp(self)
718
 
        self.reduceLockdirTimeout()
 
2156
        tests.TestCaseWithMemoryTransport.setUp(self)
719
2157
 
720
2158
    def test_unlock_on_locked_repo(self):
721
2159
        backing = self.get_transport()
722
 
        request = smart.repository.SmartServerRepositoryUnlock(backing)
723
 
        repository = self.make_repository('.')
724
 
        token = repository.lock_write()
 
2160
        request = smart_repo.SmartServerRepositoryUnlock(backing)
 
2161
        repository = self.make_repository('.', format='knit')
 
2162
        token = repository.lock_write().repository_token
725
2163
        repository.leave_lock_in_place()
726
2164
        repository.unlock()
727
 
        response = request.execute(backing.local_abspath(''), token)
 
2165
        response = request.execute('', token)
728
2166
        self.assertEqual(
729
 
            SmartServerResponse(('ok',)), response)
 
2167
            smart_req.SmartServerResponse(('ok',)), response)
730
2168
        # The repository is now unlocked.  Verify that with a new repository
731
2169
        # object.
732
2170
        new_repo = repository.bzrdir.open_repository()
735
2173
 
736
2174
    def test_unlock_on_unlocked_repo(self):
737
2175
        backing = self.get_transport()
738
 
        request = smart.repository.SmartServerRepositoryUnlock(backing)
739
 
        repository = self.make_repository('.')
740
 
        response = request.execute(backing.local_abspath(''), 'some token')
 
2176
        request = smart_repo.SmartServerRepositoryUnlock(backing)
 
2177
        repository = self.make_repository('.', format='knit')
 
2178
        response = request.execute('', 'some token')
741
2179
        self.assertEqual(
742
 
            SmartServerResponse(('TokenMismatch',)), response)
743
 
 
744
 
 
745
 
class TestSmartServerRepositoryTarball(tests.TestCaseWithTransport):
746
 
 
747
 
    def test_repository_tarball(self):
748
 
        backing = self.get_transport()
749
 
        request = smart.repository.SmartServerRepositoryTarball(backing)
750
 
        repository = self.make_repository('.')
751
 
        # make some extraneous junk in the repository directory which should
752
 
        # not be copied
753
 
        self.build_tree(['.bzr/repository/extra-junk'])
754
 
        response = request.execute(backing.local_abspath(''), 'bz2')
755
 
        self.assertEqual(('ok',), response.args)
756
 
        # body should be a tbz2
757
 
        body_file = StringIO(response.body)
758
 
        body_tar = tarfile.open('body_tar.tbz2', fileobj=body_file,
759
 
            mode='r|bz2')
760
 
        # let's make sure there are some key repository components inside it.
761
 
        # the tarfile returns directories with trailing slashes...
762
 
        names = set([n.rstrip('/') for n in body_tar.getnames()])
763
 
        self.assertTrue('.bzr/repository/lock' in names)
764
 
        self.assertTrue('.bzr/repository/format' in names)
765
 
        self.assertTrue('.bzr/repository/extra-junk' not in names,
766
 
            "extraneous file present in tar file")
767
 
 
768
 
 
769
 
class TestSmartServerIsReadonly(tests.TestCaseWithTransport):
 
2180
            smart_req.SmartServerResponse(('TokenMismatch',)), response)
 
2181
 
 
2182
 
 
2183
class TestSmartServerRepositoryGetPhysicalLockStatus(
 
2184
    tests.TestCaseWithTransport):
 
2185
 
 
2186
    def test_with_write_lock(self):
 
2187
        backing = self.get_transport()
 
2188
        repo = self.make_repository('.')
 
2189
        self.addCleanup(repo.lock_write().unlock)
 
2190
        # lock_write() doesn't necessarily actually take a physical
 
2191
        # lock out.
 
2192
        if repo.get_physical_lock_status():
 
2193
            expected = 'yes'
 
2194
        else:
 
2195
            expected = 'no'
 
2196
        request_class = smart_repo.SmartServerRepositoryGetPhysicalLockStatus
 
2197
        request = request_class(backing)
 
2198
        self.assertEqual(smart_req.SuccessfulSmartServerResponse((expected,)),
 
2199
            request.execute('', ))
 
2200
 
 
2201
    def test_without_write_lock(self):
 
2202
        backing = self.get_transport()
 
2203
        repo = self.make_repository('.')
 
2204
        self.assertEquals(False, repo.get_physical_lock_status())
 
2205
        request_class = smart_repo.SmartServerRepositoryGetPhysicalLockStatus
 
2206
        request = request_class(backing)
 
2207
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('no',)),
 
2208
            request.execute('', ))
 
2209
 
 
2210
 
 
2211
class TestSmartServerRepositoryReconcile(tests.TestCaseWithTransport):
 
2212
 
 
2213
    def test_reconcile(self):
 
2214
        backing = self.get_transport()
 
2215
        repo = self.make_repository('.')
 
2216
        token = repo.lock_write().repository_token
 
2217
        self.addCleanup(repo.unlock)
 
2218
        request_class = smart_repo.SmartServerRepositoryReconcile
 
2219
        request = request_class(backing)
 
2220
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(
 
2221
            ('ok', ),
 
2222
             'garbage_inventories: 0\n'
 
2223
             'inconsistent_parents: 0\n'),
 
2224
            request.execute('', token))
 
2225
 
 
2226
 
 
2227
class TestSmartServerIsReadonly(tests.TestCaseWithMemoryTransport):
770
2228
 
771
2229
    def test_is_readonly_no(self):
772
2230
        backing = self.get_transport()
773
 
        request = smart.request.SmartServerIsReadonly(backing)
 
2231
        request = smart_req.SmartServerIsReadonly(backing)
774
2232
        response = request.execute()
775
2233
        self.assertEqual(
776
 
            SmartServerResponse(('no',)), response)
 
2234
            smart_req.SmartServerResponse(('no',)), response)
777
2235
 
778
2236
    def test_is_readonly_yes(self):
779
2237
        backing = self.get_readonly_transport()
780
 
        request = smart.request.SmartServerIsReadonly(backing)
 
2238
        request = smart_req.SmartServerIsReadonly(backing)
781
2239
        response = request.execute()
782
2240
        self.assertEqual(
783
 
            SmartServerResponse(('yes',)), response)
 
2241
            smart_req.SmartServerResponse(('yes',)), response)
 
2242
 
 
2243
 
 
2244
class TestSmartServerRepositorySetMakeWorkingTrees(
 
2245
    tests.TestCaseWithMemoryTransport):
 
2246
 
 
2247
    def test_set_false(self):
 
2248
        backing = self.get_transport()
 
2249
        repo = self.make_repository('.', shared=True)
 
2250
        repo.set_make_working_trees(True)
 
2251
        request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
 
2252
        request = request_class(backing)
 
2253
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2254
            request.execute('', 'False'))
 
2255
        repo = repo.bzrdir.open_repository()
 
2256
        self.assertFalse(repo.make_working_trees())
 
2257
 
 
2258
    def test_set_true(self):
 
2259
        backing = self.get_transport()
 
2260
        repo = self.make_repository('.', shared=True)
 
2261
        repo.set_make_working_trees(False)
 
2262
        request_class = smart_repo.SmartServerRepositorySetMakeWorkingTrees
 
2263
        request = request_class(backing)
 
2264
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2265
            request.execute('', 'True'))
 
2266
        repo = repo.bzrdir.open_repository()
 
2267
        self.assertTrue(repo.make_working_trees())
 
2268
 
 
2269
 
 
2270
class TestSmartServerRepositoryGetSerializerFormat(
 
2271
    tests.TestCaseWithMemoryTransport):
 
2272
 
 
2273
    def test_get_serializer_format(self):
 
2274
        backing = self.get_transport()
 
2275
        repo = self.make_repository('.', format='2a')
 
2276
        request_class = smart_repo.SmartServerRepositoryGetSerializerFormat
 
2277
        request = request_class(backing)
 
2278
        self.assertEqual(
 
2279
            smart_req.SuccessfulSmartServerResponse(('ok', '10')),
 
2280
            request.execute(''))
 
2281
 
 
2282
 
 
2283
class TestSmartServerRepositoryWriteGroup(
 
2284
    tests.TestCaseWithMemoryTransport):
 
2285
 
 
2286
    def test_start_write_group(self):
 
2287
        backing = self.get_transport()
 
2288
        repo = self.make_repository('.')
 
2289
        lock_token = repo.lock_write().repository_token
 
2290
        self.addCleanup(repo.unlock)
 
2291
        request_class = smart_repo.SmartServerRepositoryStartWriteGroup
 
2292
        request = request_class(backing)
 
2293
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok', [])),
 
2294
            request.execute('', lock_token))
 
2295
 
 
2296
    def test_start_write_group_unsuspendable(self):
 
2297
        backing = self.get_transport()
 
2298
        repo = self.make_repository('.', format='knit')
 
2299
        lock_token = repo.lock_write().repository_token
 
2300
        self.addCleanup(repo.unlock)
 
2301
        request_class = smart_repo.SmartServerRepositoryStartWriteGroup
 
2302
        request = request_class(backing)
 
2303
        self.assertEqual(
 
2304
            smart_req.FailedSmartServerResponse(('UnsuspendableWriteGroup',)),
 
2305
            request.execute('', lock_token))
 
2306
 
 
2307
    def test_commit_write_group(self):
 
2308
        backing = self.get_transport()
 
2309
        repo = self.make_repository('.')
 
2310
        lock_token = repo.lock_write().repository_token
 
2311
        self.addCleanup(repo.unlock)
 
2312
        repo.start_write_group()
 
2313
        tokens = repo.suspend_write_group()
 
2314
        request_class = smart_repo.SmartServerRepositoryCommitWriteGroup
 
2315
        request = request_class(backing)
 
2316
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2317
            request.execute('', lock_token, tokens))
 
2318
 
 
2319
    def test_abort_write_group(self):
 
2320
        backing = self.get_transport()
 
2321
        repo = self.make_repository('.')
 
2322
        lock_token = repo.lock_write().repository_token
 
2323
        repo.start_write_group()
 
2324
        tokens = repo.suspend_write_group()
 
2325
        self.addCleanup(repo.unlock)
 
2326
        request_class = smart_repo.SmartServerRepositoryAbortWriteGroup
 
2327
        request = request_class(backing)
 
2328
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2329
            request.execute('', lock_token, tokens))
 
2330
 
 
2331
    def test_check_write_group(self):
 
2332
        backing = self.get_transport()
 
2333
        repo = self.make_repository('.')
 
2334
        lock_token = repo.lock_write().repository_token
 
2335
        repo.start_write_group()
 
2336
        tokens = repo.suspend_write_group()
 
2337
        self.addCleanup(repo.unlock)
 
2338
        request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
 
2339
        request = request_class(backing)
 
2340
        self.assertEqual(smart_req.SuccessfulSmartServerResponse(('ok',)),
 
2341
            request.execute('', lock_token, tokens))
 
2342
 
 
2343
    def test_check_write_group_invalid(self):
 
2344
        backing = self.get_transport()
 
2345
        repo = self.make_repository('.')
 
2346
        lock_token = repo.lock_write().repository_token
 
2347
        self.addCleanup(repo.unlock)
 
2348
        request_class = smart_repo.SmartServerRepositoryCheckWriteGroup
 
2349
        request = request_class(backing)
 
2350
        self.assertEqual(smart_req.FailedSmartServerResponse(
 
2351
            ('UnresumableWriteGroup', ['random'],
 
2352
                'Malformed write group token')),
 
2353
            request.execute('', lock_token, ["random"]))
 
2354
 
 
2355
 
 
2356
class TestSmartServerPackRepositoryAutopack(tests.TestCaseWithTransport):
 
2357
 
 
2358
    def make_repo_needing_autopacking(self, path='.'):
 
2359
        # Make a repo in need of autopacking.
 
2360
        tree = self.make_branch_and_tree('.', format='pack-0.92')
 
2361
        repo = tree.branch.repository
 
2362
        # monkey-patch the pack collection to disable autopacking
 
2363
        repo._pack_collection._max_pack_count = lambda count: count
 
2364
        for x in range(10):
 
2365
            tree.commit('commit %s' % x)
 
2366
        self.assertEqual(10, len(repo._pack_collection.names()))
 
2367
        del repo._pack_collection._max_pack_count
 
2368
        return repo
 
2369
 
 
2370
    def test_autopack_needed(self):
 
2371
        repo = self.make_repo_needing_autopacking()
 
2372
        repo.lock_write()
 
2373
        self.addCleanup(repo.unlock)
 
2374
        backing = self.get_transport()
 
2375
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
2376
            backing)
 
2377
        response = request.execute('')
 
2378
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
2379
        repo._pack_collection.reload_pack_names()
 
2380
        self.assertEqual(1, len(repo._pack_collection.names()))
 
2381
 
 
2382
    def test_autopack_not_needed(self):
 
2383
        tree = self.make_branch_and_tree('.', format='pack-0.92')
 
2384
        repo = tree.branch.repository
 
2385
        repo.lock_write()
 
2386
        self.addCleanup(repo.unlock)
 
2387
        for x in range(9):
 
2388
            tree.commit('commit %s' % x)
 
2389
        backing = self.get_transport()
 
2390
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
2391
            backing)
 
2392
        response = request.execute('')
 
2393
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
2394
        repo._pack_collection.reload_pack_names()
 
2395
        self.assertEqual(9, len(repo._pack_collection.names()))
 
2396
 
 
2397
    def test_autopack_on_nonpack_format(self):
 
2398
        """A request to autopack a non-pack repo is a no-op."""
 
2399
        repo = self.make_repository('.', format='knit')
 
2400
        backing = self.get_transport()
 
2401
        request = smart_packrepo.SmartServerPackRepositoryAutopack(
 
2402
            backing)
 
2403
        response = request.execute('')
 
2404
        self.assertEqual(smart_req.SmartServerResponse(('ok',)), response)
 
2405
 
 
2406
 
 
2407
class TestSmartServerVfsGet(tests.TestCaseWithMemoryTransport):
 
2408
 
 
2409
    def test_unicode_path(self):
 
2410
        """VFS requests expect unicode paths to be escaped."""
 
2411
        filename = u'foo\N{INTERROBANG}'
 
2412
        filename_escaped = urlutils.escape(filename)
 
2413
        backing = self.get_transport()
 
2414
        request = vfs.GetRequest(backing)
 
2415
        backing.put_bytes_non_atomic(filename_escaped, 'contents')
 
2416
        self.assertEqual(smart_req.SmartServerResponse(('ok', ), 'contents'),
 
2417
            request.execute(filename_escaped))
784
2418
 
785
2419
 
786
2420
class TestHandlers(tests.TestCase):
787
2421
    """Tests for the request.request_handlers object."""
788
2422
 
 
2423
    def test_all_registrations_exist(self):
 
2424
        """All registered request_handlers can be found."""
 
2425
        # If there's a typo in a register_lazy call, this loop will fail with
 
2426
        # an AttributeError.
 
2427
        for key in smart_req.request_handlers.keys():
 
2428
            try:
 
2429
                item = smart_req.request_handlers.get(key)
 
2430
            except AttributeError, e:
 
2431
                raise AttributeError('failed to get %s: %s' % (key, e))
 
2432
 
 
2433
    def assertHandlerEqual(self, verb, handler):
 
2434
        self.assertEqual(smart_req.request_handlers.get(verb), handler)
 
2435
 
789
2436
    def test_registered_methods(self):
790
2437
        """Test that known methods are registered to the correct object."""
791
 
        self.assertEqual(
792
 
            smart.request.request_handlers.get('Branch.get_config_file'),
793
 
            smart.branch.SmartServerBranchGetConfigFile)
794
 
        self.assertEqual(
795
 
            smart.request.request_handlers.get('Branch.lock_write'),
796
 
            smart.branch.SmartServerBranchRequestLockWrite)
797
 
        self.assertEqual(
798
 
            smart.request.request_handlers.get('Branch.last_revision_info'),
799
 
            smart.branch.SmartServerBranchRequestLastRevisionInfo)
800
 
        self.assertEqual(
801
 
            smart.request.request_handlers.get('Branch.revision_history'),
802
 
            smart.branch.SmartServerRequestRevisionHistory)
803
 
        self.assertEqual(
804
 
            smart.request.request_handlers.get('Branch.set_last_revision'),
805
 
            smart.branch.SmartServerBranchRequestSetLastRevision)
806
 
        self.assertEqual(
807
 
            smart.request.request_handlers.get('Branch.unlock'),
808
 
            smart.branch.SmartServerBranchRequestUnlock)
809
 
        self.assertEqual(
810
 
            smart.request.request_handlers.get('BzrDir.find_repository'),
811
 
            smart.bzrdir.SmartServerRequestFindRepository)
812
 
        self.assertEqual(
813
 
            smart.request.request_handlers.get('BzrDirFormat.initialize'),
814
 
            smart.bzrdir.SmartServerRequestInitializeBzrDir)
815
 
        self.assertEqual(
816
 
            smart.request.request_handlers.get('BzrDir.open_branch'),
817
 
            smart.bzrdir.SmartServerRequestOpenBranch)
818
 
        self.assertEqual(
819
 
            smart.request.request_handlers.get('Repository.gather_stats'),
820
 
            smart.repository.SmartServerRepositoryGatherStats)
821
 
        self.assertEqual(
822
 
            smart.request.request_handlers.get('Repository.get_revision_graph'),
823
 
            smart.repository.SmartServerRepositoryGetRevisionGraph)
824
 
        self.assertEqual(
825
 
            smart.request.request_handlers.get('Repository.has_revision'),
826
 
            smart.repository.SmartServerRequestHasRevision)
827
 
        self.assertEqual(
828
 
            smart.request.request_handlers.get('Repository.is_shared'),
829
 
            smart.repository.SmartServerRepositoryIsShared)
830
 
        self.assertEqual(
831
 
            smart.request.request_handlers.get('Repository.lock_write'),
832
 
            smart.repository.SmartServerRepositoryLockWrite)
833
 
        self.assertEqual(
834
 
            smart.request.request_handlers.get('Repository.unlock'),
835
 
            smart.repository.SmartServerRepositoryUnlock)
836
 
        self.assertEqual(
837
 
            smart.request.request_handlers.get('Repository.tarball'),
838
 
            smart.repository.SmartServerRepositoryTarball)
839
 
        self.assertEqual(
840
 
            smart.request.request_handlers.get('Transport.is_readonly'),
841
 
            smart.request.SmartServerIsReadonly)
 
2438
        self.assertHandlerEqual('Branch.break_lock',
 
2439
            smart_branch.SmartServerBranchBreakLock)
 
2440
        self.assertHandlerEqual('Branch.get_config_file',
 
2441
            smart_branch.SmartServerBranchGetConfigFile)
 
2442
        self.assertHandlerEqual('Branch.put_config_file',
 
2443
            smart_branch.SmartServerBranchPutConfigFile)
 
2444
        self.assertHandlerEqual('Branch.get_parent',
 
2445
            smart_branch.SmartServerBranchGetParent)
 
2446
        self.assertHandlerEqual('Branch.get_physical_lock_status',
 
2447
            smart_branch.SmartServerBranchRequestGetPhysicalLockStatus)
 
2448
        self.assertHandlerEqual('Branch.get_tags_bytes',
 
2449
            smart_branch.SmartServerBranchGetTagsBytes)
 
2450
        self.assertHandlerEqual('Branch.lock_write',
 
2451
            smart_branch.SmartServerBranchRequestLockWrite)
 
2452
        self.assertHandlerEqual('Branch.last_revision_info',
 
2453
            smart_branch.SmartServerBranchRequestLastRevisionInfo)
 
2454
        self.assertHandlerEqual('Branch.revision_history',
 
2455
            smart_branch.SmartServerRequestRevisionHistory)
 
2456
        self.assertHandlerEqual('Branch.revision_id_to_revno',
 
2457
            smart_branch.SmartServerBranchRequestRevisionIdToRevno)
 
2458
        self.assertHandlerEqual('Branch.set_config_option',
 
2459
            smart_branch.SmartServerBranchRequestSetConfigOption)
 
2460
        self.assertHandlerEqual('Branch.set_last_revision',
 
2461
            smart_branch.SmartServerBranchRequestSetLastRevision)
 
2462
        self.assertHandlerEqual('Branch.set_last_revision_info',
 
2463
            smart_branch.SmartServerBranchRequestSetLastRevisionInfo)
 
2464
        self.assertHandlerEqual('Branch.set_last_revision_ex',
 
2465
            smart_branch.SmartServerBranchRequestSetLastRevisionEx)
 
2466
        self.assertHandlerEqual('Branch.set_parent_location',
 
2467
            smart_branch.SmartServerBranchRequestSetParentLocation)
 
2468
        self.assertHandlerEqual('Branch.unlock',
 
2469
            smart_branch.SmartServerBranchRequestUnlock)
 
2470
        self.assertHandlerEqual('BzrDir.destroy_branch',
 
2471
            smart_dir.SmartServerBzrDirRequestDestroyBranch)
 
2472
        self.assertHandlerEqual('BzrDir.find_repository',
 
2473
            smart_dir.SmartServerRequestFindRepositoryV1)
 
2474
        self.assertHandlerEqual('BzrDir.find_repositoryV2',
 
2475
            smart_dir.SmartServerRequestFindRepositoryV2)
 
2476
        self.assertHandlerEqual('BzrDirFormat.initialize',
 
2477
            smart_dir.SmartServerRequestInitializeBzrDir)
 
2478
        self.assertHandlerEqual('BzrDirFormat.initialize_ex_1.16',
 
2479
            smart_dir.SmartServerRequestBzrDirInitializeEx)
 
2480
        self.assertHandlerEqual('BzrDir.cloning_metadir',
 
2481
            smart_dir.SmartServerBzrDirRequestCloningMetaDir)
 
2482
        self.assertHandlerEqual('BzrDir.get_config_file',
 
2483
            smart_dir.SmartServerBzrDirRequestConfigFile)
 
2484
        self.assertHandlerEqual('BzrDir.open_branch',
 
2485
            smart_dir.SmartServerRequestOpenBranch)
 
2486
        self.assertHandlerEqual('BzrDir.open_branchV2',
 
2487
            smart_dir.SmartServerRequestOpenBranchV2)
 
2488
        self.assertHandlerEqual('BzrDir.open_branchV3',
 
2489
            smart_dir.SmartServerRequestOpenBranchV3)
 
2490
        self.assertHandlerEqual('PackRepository.autopack',
 
2491
            smart_packrepo.SmartServerPackRepositoryAutopack)
 
2492
        self.assertHandlerEqual('Repository.add_signature_text',
 
2493
            smart_repo.SmartServerRepositoryAddSignatureText)
 
2494
        self.assertHandlerEqual('Repository.all_revision_ids',
 
2495
            smart_repo.SmartServerRepositoryAllRevisionIds)
 
2496
        self.assertHandlerEqual('Repository.break_lock',
 
2497
            smart_repo.SmartServerRepositoryBreakLock)
 
2498
        self.assertHandlerEqual('Repository.gather_stats',
 
2499
            smart_repo.SmartServerRepositoryGatherStats)
 
2500
        self.assertHandlerEqual('Repository.get_parent_map',
 
2501
            smart_repo.SmartServerRepositoryGetParentMap)
 
2502
        self.assertHandlerEqual('Repository.get_physical_lock_status',
 
2503
            smart_repo.SmartServerRepositoryGetPhysicalLockStatus)
 
2504
        self.assertHandlerEqual('Repository.get_rev_id_for_revno',
 
2505
            smart_repo.SmartServerRepositoryGetRevIdForRevno)
 
2506
        self.assertHandlerEqual('Repository.get_revision_graph',
 
2507
            smart_repo.SmartServerRepositoryGetRevisionGraph)
 
2508
        self.assertHandlerEqual('Repository.get_revision_signature_text',
 
2509
            smart_repo.SmartServerRepositoryGetRevisionSignatureText)
 
2510
        self.assertHandlerEqual('Repository.get_stream',
 
2511
            smart_repo.SmartServerRepositoryGetStream)
 
2512
        self.assertHandlerEqual('Repository.get_stream_1.19',
 
2513
            smart_repo.SmartServerRepositoryGetStream_1_19)
 
2514
        self.assertHandlerEqual('Repository.iter_revisions',
 
2515
            smart_repo.SmartServerRepositoryIterRevisions)
 
2516
        self.assertHandlerEqual('Repository.has_revision',
 
2517
            smart_repo.SmartServerRequestHasRevision)
 
2518
        self.assertHandlerEqual('Repository.insert_stream',
 
2519
            smart_repo.SmartServerRepositoryInsertStream)
 
2520
        self.assertHandlerEqual('Repository.insert_stream_locked',
 
2521
            smart_repo.SmartServerRepositoryInsertStreamLocked)
 
2522
        self.assertHandlerEqual('Repository.is_shared',
 
2523
            smart_repo.SmartServerRepositoryIsShared)
 
2524
        self.assertHandlerEqual('Repository.iter_files_bytes',
 
2525
            smart_repo.SmartServerRepositoryIterFilesBytes)
 
2526
        self.assertHandlerEqual('Repository.lock_write',
 
2527
            smart_repo.SmartServerRepositoryLockWrite)
 
2528
        self.assertHandlerEqual('Repository.make_working_trees',
 
2529
            smart_repo.SmartServerRepositoryMakeWorkingTrees)
 
2530
        self.assertHandlerEqual('Repository.pack',
 
2531
            smart_repo.SmartServerRepositoryPack)
 
2532
        self.assertHandlerEqual('Repository.reconcile',
 
2533
            smart_repo.SmartServerRepositoryReconcile)
 
2534
        self.assertHandlerEqual('Repository.tarball',
 
2535
            smart_repo.SmartServerRepositoryTarball)
 
2536
        self.assertHandlerEqual('Repository.unlock',
 
2537
            smart_repo.SmartServerRepositoryUnlock)
 
2538
        self.assertHandlerEqual('Repository.start_write_group',
 
2539
            smart_repo.SmartServerRepositoryStartWriteGroup)
 
2540
        self.assertHandlerEqual('Repository.check_write_group',
 
2541
            smart_repo.SmartServerRepositoryCheckWriteGroup)
 
2542
        self.assertHandlerEqual('Repository.commit_write_group',
 
2543
            smart_repo.SmartServerRepositoryCommitWriteGroup)
 
2544
        self.assertHandlerEqual('Repository.abort_write_group',
 
2545
            smart_repo.SmartServerRepositoryAbortWriteGroup)
 
2546
        self.assertHandlerEqual('VersionedFileRepository.get_serializer_format',
 
2547
            smart_repo.SmartServerRepositoryGetSerializerFormat)
 
2548
        self.assertHandlerEqual('Transport.is_readonly',
 
2549
            smart_req.SmartServerIsReadonly)
 
2550
 
 
2551
 
 
2552
class SmartTCPServerHookTests(tests.TestCaseWithMemoryTransport):
 
2553
    """Tests for SmartTCPServer hooks."""
 
2554
 
 
2555
    def setUp(self):
 
2556
        super(SmartTCPServerHookTests, self).setUp()
 
2557
        self.server = server.SmartTCPServer(self.get_transport())
 
2558
 
 
2559
    def test_run_server_started_hooks(self):
 
2560
        """Test the server started hooks get fired properly."""
 
2561
        started_calls = []
 
2562
        server.SmartTCPServer.hooks.install_named_hook('server_started',
 
2563
            lambda backing_urls, url: started_calls.append((backing_urls, url)),
 
2564
            None)
 
2565
        started_ex_calls = []
 
2566
        server.SmartTCPServer.hooks.install_named_hook('server_started_ex',
 
2567
            lambda backing_urls, url: started_ex_calls.append((backing_urls, url)),
 
2568
            None)
 
2569
        self.server._sockname = ('example.com', 42)
 
2570
        self.server.run_server_started_hooks()
 
2571
        self.assertEquals(started_calls,
 
2572
            [([self.get_transport().base], 'bzr://example.com:42/')])
 
2573
        self.assertEquals(started_ex_calls,
 
2574
            [([self.get_transport().base], self.server)])
 
2575
 
 
2576
    def test_run_server_started_hooks_ipv6(self):
 
2577
        """Test that socknames can contain 4-tuples."""
 
2578
        self.server._sockname = ('::', 42, 0, 0)
 
2579
        started_calls = []
 
2580
        server.SmartTCPServer.hooks.install_named_hook('server_started',
 
2581
            lambda backing_urls, url: started_calls.append((backing_urls, url)),
 
2582
            None)
 
2583
        self.server.run_server_started_hooks()
 
2584
        self.assertEquals(started_calls,
 
2585
                [([self.get_transport().base], 'bzr://:::42/')])
 
2586
 
 
2587
    def test_run_server_stopped_hooks(self):
 
2588
        """Test the server stopped hooks."""
 
2589
        self.server._sockname = ('example.com', 42)
 
2590
        stopped_calls = []
 
2591
        server.SmartTCPServer.hooks.install_named_hook('server_stopped',
 
2592
            lambda backing_urls, url: stopped_calls.append((backing_urls, url)),
 
2593
            None)
 
2594
        self.server.run_server_stopped_hooks()
 
2595
        self.assertEquals(stopped_calls,
 
2596
            [([self.get_transport().base], 'bzr://example.com:42/')])
 
2597
 
 
2598
 
 
2599
class TestSmartServerRepositoryPack(tests.TestCaseWithMemoryTransport):
 
2600
 
 
2601
    def test_pack(self):
 
2602
        backing = self.get_transport()
 
2603
        request = smart_repo.SmartServerRepositoryPack(backing)
 
2604
        tree = self.make_branch_and_memory_tree('.')
 
2605
        repo_token = tree.branch.repository.lock_write().repository_token
 
2606
 
 
2607
        self.assertIs(None, request.execute('', repo_token, False))
 
2608
 
 
2609
        self.assertEqual(
 
2610
            smart_req.SuccessfulSmartServerResponse(('ok', ), ),
 
2611
            request.do_body(''))
 
2612