/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
1
# Copyright (C) 2006 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
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
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
19
from bzrlib import bzrdir, errors, smart, tests
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
20
from bzrlib.smart.request import SmartServerResponse
21
import bzrlib.smart.bzrdir
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
22
import bzrlib.smart.branch
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
23
import bzrlib.smart.repository
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
24
25
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
26
class TestCaseWithSmartMedium(tests.TestCaseWithTransport):
27
28
    def setUp(self):
29
        super(TestCaseWithSmartMedium, self).setUp()
30
        # We're allowed to set  the transport class here, so that we don't use
31
        # the default or a parameterized class, but rather use the
32
        # TestCaseWithTransport infrastructure to set up a smart server and
33
        # transport.
34
        self.transport_server = smart.server.SmartTCPServer_for_testing
35
36
    def get_smart_medium(self):
37
        """Get a smart medium to use in tests."""
38
        return self.get_transport().get_smart_medium()
39
40
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
41
class TestSmartServerResponse(tests.TestCase):
42
43
    def test__eq__(self):
44
        self.assertEqual(SmartServerResponse(('ok', )),
45
            SmartServerResponse(('ok', )))
46
        self.assertEqual(SmartServerResponse(('ok', ), 'body'),
47
            SmartServerResponse(('ok', ), 'body'))
48
        self.assertNotEqual(SmartServerResponse(('ok', )),
49
            SmartServerResponse(('notok', )))
50
        self.assertNotEqual(SmartServerResponse(('ok', ), 'body'),
51
            SmartServerResponse(('ok', )))
2018.5.41 by Robert Collins
Fix SmartServerResponse.__eq__ to handle None.
52
        self.assertNotEqual(None,
53
            SmartServerResponse(('ok', )))
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
54
55
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
56
class TestSmartServerRequestFindRepository(tests.TestCaseWithTransport):
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
57
    """Tests for BzrDir.find_repository."""
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
58
59
    def test_no_repository(self):
60
        """When there is no repository to be found, ('norepository', ) is returned."""
61
        backing = self.get_transport()
62
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
63
        self.make_bzrdir('.')
64
        self.assertEqual(SmartServerResponse(('norepository', )),
65
            request.execute(backing.local_abspath('')))
66
67
    def test_nonshared_repository(self):
68
        # nonshared repositorys only allow 'find' to return a handle when the 
69
        # path the repository is being searched on is the same as that that 
70
        # the repository is at.
71
        backing = self.get_transport()
72
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
73
        result = self._make_repository_and_result()
74
        self.assertEqual(result, request.execute(backing.local_abspath('')))
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
75
        self.make_bzrdir('subdir')
76
        self.assertEqual(SmartServerResponse(('norepository', )),
77
            request.execute(backing.local_abspath('subdir')))
78
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
79
    def _make_repository_and_result(self, shared=False, format=None):
80
        """Convenience function to setup a repository.
81
82
        :result: The SmartServerResponse to expect when opening it.
83
        """
84
        repo = self.make_repository('.', shared=shared, format=format)
85
        if repo.supports_rich_root():
86
            rich_root = 'True'
87
        else:
88
            rich_root = 'False'
89
        if repo._format.support_tree_reference:
90
            subtrees = 'True'
91
        else:
92
            subtrees = 'False'
93
        return SmartServerResponse(('ok', '', rich_root, subtrees))
94
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
95
    def test_shared_repository(self):
96
        """When there is a shared repository, we get 'ok', 'relpath-to-repo'."""
97
        backing = self.get_transport()
98
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
99
        result = self._make_repository_and_result(shared=True)
100
        self.assertEqual(result, request.execute(backing.local_abspath('')))
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
101
        self.make_bzrdir('subdir')
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
102
        result2 = SmartServerResponse(result.args[0:1] + ('..', ) + result.args[2:])
103
        self.assertEqual(result2,
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
104
            request.execute(backing.local_abspath('subdir')))
105
        self.make_bzrdir('subdir/deeper')
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
106
        result3 = SmartServerResponse(result.args[0:1] + ('../..', ) + result.args[2:])
107
        self.assertEqual(result3,
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
108
            request.execute(backing.local_abspath('subdir/deeper')))
109
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and support_tree_reference.
110
    def test_rich_root_and_subtree_encoding(self):
111
        """Test for the format attributes for rich root and subtree support."""
112
        backing = self.get_transport()
113
        request = smart.bzrdir.SmartServerRequestFindRepository(backing)
114
        result = self._make_repository_and_result(format='dirstate-with-subtree')
115
        # check the test will be valid
116
        self.assertEqual('True', result.args[2])
117
        self.assertEqual('True', result.args[3])
118
        self.assertEqual(result, request.execute(backing.local_abspath('')))
119
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
120
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
121
class TestSmartServerRequestInitializeBzrDir(tests.TestCaseWithTransport):
122
123
    def test_empty_dir(self):
124
        """Initializing an empty dir should succeed and do it."""
125
        backing = self.get_transport()
126
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
127
        self.assertEqual(SmartServerResponse(('ok', )),
128
            request.execute(backing.local_abspath('.')))
129
        made_dir = bzrdir.BzrDir.open_from_transport(backing)
130
        # no branch, tree or repository is expected with the current 
131
        # default formart.
132
        self.assertRaises(errors.NoWorkingTree, made_dir.open_workingtree)
133
        self.assertRaises(errors.NotBranchError, made_dir.open_branch)
134
        self.assertRaises(errors.NoRepositoryPresent, made_dir.open_repository)
135
136
    def test_missing_dir(self):
137
        """Initializing a missing directory should fail like the bzrdir api."""
138
        backing = self.get_transport()
139
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
140
        self.assertRaises(errors.NoSuchFile,
141
            request.execute, backing.local_abspath('subdir'))
142
143
    def test_initialized_dir(self):
144
        """Initializing an extant bzrdir should fail like the bzrdir api."""
145
        backing = self.get_transport()
146
        request = smart.bzrdir.SmartServerRequestInitializeBzrDir(backing)
147
        self.make_bzrdir('subdir')
148
        self.assertRaises(errors.FileExists,
149
            request.execute, backing.local_abspath('subdir'))
150
151
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
152
class TestSmartServerRequestOpenBranch(tests.TestCaseWithTransport):
153
154
    def test_no_branch(self):
155
        """When there is no branch, ('nobranch', ) is returned."""
156
        backing = self.get_transport()
157
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
158
        self.make_bzrdir('.')
159
        self.assertEqual(SmartServerResponse(('nobranch', )),
160
            request.execute(backing.local_abspath('')))
161
162
    def test_branch(self):
163
        """When there is a branch, 'ok' is returned."""
164
        backing = self.get_transport()
165
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
166
        self.make_branch('.')
167
        self.assertEqual(SmartServerResponse(('ok', '')),
168
            request.execute(backing.local_abspath('')))
169
170
    def test_branch_reference(self):
171
        """When there is a branch reference, the reference URL is returned."""
172
        backing = self.get_transport()
173
        request = smart.bzrdir.SmartServerRequestOpenBranch(backing)
174
        branch = self.make_branch('branch')
175
        checkout = branch.create_checkout('reference',lightweight=True)
176
        # TODO: once we have an API to probe for references of any sort, we
177
        # can use it here.
178
        reference_url = backing.abspath('branch') + '/'
179
        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
180
        self.assertEqual(SmartServerResponse(('ok', reference_url)),
181
            request.execute(backing.local_abspath('reference')))
182
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
183
184
class TestSmartServerRequestRevisionHistory(tests.TestCaseWithTransport):
185
186
    def test_empty(self):
187
        """For an empty branch, the body is empty."""
188
        backing = self.get_transport()
189
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
190
        self.make_branch('.')
191
        self.assertEqual(SmartServerResponse(('ok', ), ''),
192
            request.execute(backing.local_abspath('')))
193
194
    def test_not_empty(self):
195
        """For a non-empty branch, the body is empty."""
196
        backing = self.get_transport()
197
        request = smart.branch.SmartServerRequestRevisionHistory(backing)
198
        tree = self.make_branch_and_memory_tree('.')
199
        tree.lock_write()
200
        tree.add('')
201
        r1 = tree.commit('1st commit')
202
        r2 = tree.commit('2nd commit', rev_id=u'\xc8')
203
        tree.unlock()
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
204
        self.assertEqual(
205
            SmartServerResponse(('ok', ), ('\x00'.join([r1, r2]))),
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
206
            request.execute(backing.local_abspath('')))
207
2018.5.49 by Wouter van Heyst
Refactor SmartServerBranchRequest out from SmartServerRequestRevisionHistory to
208
209
class TestSmartServerBranchRequest(tests.TestCaseWithTransport):
210
211
    def test_no_branch(self):
212
        """When there is a bzrdir and no branch, NotBranchError is raised."""
213
        backing = self.get_transport()
214
        request = smart.branch.SmartServerBranchRequest(backing)
215
        self.make_bzrdir('.')
216
        self.assertRaises(errors.NotBranchError,
217
            request.execute, backing.local_abspath(''))
218
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
219
    def test_branch_reference(self):
220
        """When there is a branch reference, NotBranchError is raised."""
221
        backing = self.get_transport()
2018.5.49 by Wouter van Heyst
Refactor SmartServerBranchRequest out from SmartServerRequestRevisionHistory to
222
        request = smart.branch.SmartServerBranchRequest(backing)
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
223
        branch = self.make_branch('branch')
224
        checkout = branch.create_checkout('reference',lightweight=True)
225
        self.assertRaises(errors.NotBranchError,
226
            request.execute, backing.local_abspath('checkout'))
227
228
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
229
class TestSmartServerBranchRequestLastRevisionInfo(tests.TestCaseWithTransport):
230
231
    def test_empty(self):
232
        """For an empty branch, the result is ('ok', '0', '')."""
233
        backing = self.get_transport()
234
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
235
        self.make_branch('.')
236
        self.assertEqual(SmartServerResponse(('ok', '0', '')),
237
            request.execute(backing.local_abspath('')))
238
239
    def test_not_empty(self):
240
        """For a non-empty branch, the result is ('ok', 'revno', 'revid')."""
241
        backing = self.get_transport()
242
        request = smart.branch.SmartServerBranchRequestLastRevisionInfo(backing)
243
        tree = self.make_branch_and_memory_tree('.')
244
        tree.lock_write()
245
        tree.add('')
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
246
        rev_id = u'\xc8'
247
        rev_id_utf8 = rev_id.encode('utf-8')
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
248
        r1 = tree.commit('1st commit')
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
249
        r2 = tree.commit('2nd commit', rev_id=rev_id)
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
250
        tree.unlock()
251
        self.assertEqual(
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
252
            SmartServerResponse(('ok', '2', rev_id_utf8)),
2018.5.50 by Wouter van Heyst
Add SmartServerBranchRequestLastRevisionInfo method.
253
            request.execute(backing.local_abspath('')))
254
255
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
256
class TestSmartServerBranchRequestGetConfigFile(tests.TestCaseWithTransport):
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
257
258
    def test_default(self):
259
        """With no file, we get empty content."""
260
        backing = self.get_transport()
261
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
262
        branch = self.make_branch('.')
263
        # there should be no file by default
264
        content = ''
265
        self.assertEqual(SmartServerResponse(('ok', ), content),
266
            request.execute(backing.local_abspath('')))
267
268
    def test_with_content(self):
269
        # SmartServerBranchGetConfigFile should return the content from
270
        # branch.control_files.get('branch.conf') for now - in the future it may
271
        # perform more complex processing. 
272
        backing = self.get_transport()
273
        request = smart.branch.SmartServerBranchGetConfigFile(backing)
274
        branch = self.make_branch('.')
275
        branch.control_files.put_utf8('branch.conf', 'foo bar baz')
276
        self.assertEqual(SmartServerResponse(('ok', ), 'foo bar baz'),
277
            request.execute(backing.local_abspath('')))
278
279
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
280
class TestSmartServerBranchRequestSetLastRevision(tests.TestCaseWithTransport):
281
282
    def test_empty(self):
283
        backing = self.get_transport()
284
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
285
        b = self.make_branch('.')
286
        branch_token, repo_token = b.lock_write()
287
        try:
288
            self.assertEqual(SmartServerResponse(('ok',)),
289
                request.execute(
290
                    backing.local_abspath(''), branch_token, repo_token, ''))
291
        finally:
292
            b.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
293
294
    def test_not_present_revision_id(self):
295
        backing = self.get_transport()
296
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
297
        b = self.make_branch('.')
298
        branch_token, repo_token = b.lock_write()
299
        try:
300
            revision_id = 'non-existent revision'
301
            self.assertEqual(
302
                SmartServerResponse(('NoSuchRevision', revision_id)),
303
                request.execute(
304
                    backing.local_abspath(''), branch_token, repo_token,
305
                    revision_id))
306
        finally:
307
            b.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
308
309
    def test_revision_id_present(self):
310
        backing = self.get_transport()
311
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
312
        tree = self.make_branch_and_memory_tree('.')
313
        tree.lock_write()
314
        tree.add('')
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
315
        rev_id = u'\xc8'
316
        rev_id_utf8 = rev_id.encode('utf-8')
317
        r1 = tree.commit('1st commit', rev_id=rev_id)
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
318
        r2 = tree.commit('2nd commit')
319
        tree.unlock()
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
320
        branch_token, repo_token = tree.branch.lock_write()
321
        try:
322
            self.assertEqual(
323
                SmartServerResponse(('ok',)),
324
                request.execute(
325
                    backing.local_abspath(''), branch_token, repo_token,
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
326
                    rev_id_utf8))
327
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
328
        finally:
329
            tree.branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
330
331
    def test_revision_id_present2(self):
332
        backing = self.get_transport()
333
        request = smart.branch.SmartServerBranchRequestSetLastRevision(backing)
334
        tree = self.make_branch_and_memory_tree('.')
335
        tree.lock_write()
336
        tree.add('')
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
337
        rev_id = u'\xc8'
338
        rev_id_utf8 = rev_id.encode('utf-8')
339
        r1 = tree.commit('1st commit', rev_id=rev_id)
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
340
        r2 = tree.commit('2nd commit')
341
        tree.unlock()
342
        tree.branch.set_revision_history([])
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
343
        branch_token, repo_token = tree.branch.lock_write()
344
        try:
345
            self.assertEqual(
346
                SmartServerResponse(('ok',)),
347
                request.execute(
348
                    backing.local_abspath(''), branch_token, repo_token,
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
349
                    rev_id_utf8))
350
            self.assertEqual([rev_id_utf8], tree.branch.revision_history())
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
351
        finally:
352
            tree.branch.unlock()
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
353
354
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
355
class TestSmartServerBranchRequestLockWrite(tests.TestCaseWithTransport):
356
357
    def setUp(self):
358
        tests.TestCaseWithTransport.setUp(self)
359
        self.reduceLockdirTimeout()
360
361
    def test_lock_write_on_unlocked_branch(self):
362
        backing = self.get_transport()
363
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
364
        branch = self.make_branch('.')
365
        repository = branch.repository
366
        response = request.execute(backing.local_abspath(''))
367
        branch_nonce = branch.control_files._lock.peek().get('nonce')
368
        repository_nonce = repository.control_files._lock.peek().get('nonce')
369
        self.assertEqual(
370
            SmartServerResponse(('ok', branch_nonce, repository_nonce)),
371
            response)
372
        # The branch (and associated repository) is now locked.  Verify that
373
        # with a new branch object.
374
        new_branch = repository.bzrdir.open_branch()
375
        self.assertRaises(errors.LockContention, new_branch.lock_write)
376
377
    def test_lock_write_on_locked_branch(self):
378
        backing = self.get_transport()
379
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
380
        branch = self.make_branch('.')
381
        branch.lock_write()
382
        branch.leave_lock_in_place()
383
        branch.unlock()
384
        response = request.execute(backing.local_abspath(''))
385
        self.assertEqual(
386
            SmartServerResponse(('LockContention',)), response)
387
388
    def test_lock_write_with_tokens_on_locked_branch(self):
389
        backing = self.get_transport()
390
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
391
        branch = self.make_branch('.')
392
        branch_token, repo_token = branch.lock_write()
393
        branch.leave_lock_in_place()
394
        branch.repository.leave_lock_in_place()
395
        branch.unlock()
396
        response = request.execute(backing.local_abspath(''),
397
                                   branch_token, repo_token)
398
        self.assertEqual(
399
            SmartServerResponse(('ok', branch_token, repo_token)), response)
400
401
    def test_lock_write_with_mismatched_tokens_on_locked_branch(self):
402
        backing = self.get_transport()
403
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
404
        branch = self.make_branch('.')
405
        branch_token, repo_token = branch.lock_write()
406
        branch.leave_lock_in_place()
407
        branch.repository.leave_lock_in_place()
408
        branch.unlock()
409
        response = request.execute(backing.local_abspath(''),
410
                                   branch_token+'xxx', repo_token)
411
        self.assertEqual(
412
            SmartServerResponse(('TokenMismatch',)), response)
413
414
    def test_lock_write_on_locked_repo(self):
415
        backing = self.get_transport()
416
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
417
        branch = self.make_branch('.')
418
        branch.repository.lock_write()
419
        branch.repository.leave_lock_in_place()
420
        branch.repository.unlock()
421
        response = request.execute(backing.local_abspath(''))
422
        self.assertEqual(
423
            SmartServerResponse(('LockContention',)), response)
424
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
425
    def test_lock_write_on_readonly_transport(self):
426
        backing = self.get_readonly_transport()
427
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
428
        branch = self.make_branch('.')
429
        response = request.execute('')
430
        self.assertEqual(
431
            SmartServerResponse(('UnlockableTransport',)), response)
432
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
433
434
class TestSmartServerBranchRequestUnlock(tests.TestCaseWithTransport):
435
436
    def setUp(self):
437
        tests.TestCaseWithTransport.setUp(self)
438
        self.reduceLockdirTimeout()
439
440
    def test_unlock_on_locked_branch_and_repo(self):
441
        backing = self.get_transport()
442
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
443
        branch = self.make_branch('.')
444
        # Lock the branch
445
        branch_token, repo_token = branch.lock_write()
446
        # Unlock the branch (and repo) object, leaving the physical locks
447
        # in place.
448
        branch.leave_lock_in_place()
449
        branch.repository.leave_lock_in_place()
450
        branch.unlock()
451
        response = request.execute(backing.local_abspath(''),
452
                                   branch_token, repo_token)
453
        self.assertEqual(
454
            SmartServerResponse(('ok',)), response)
455
        # The branch is now unlocked.  Verify that with a new branch
456
        # object.
457
        new_branch = branch.bzrdir.open_branch()
458
        new_branch.lock_write()
459
        new_branch.unlock()
460
461
    def test_unlock_on_unlocked_branch_unlocked_repo(self):
462
        backing = self.get_transport()
463
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
464
        branch = self.make_branch('.')
465
        response = request.execute(
466
            backing.local_abspath(''), 'branch token', 'repo token')
467
        self.assertEqual(
468
            SmartServerResponse(('TokenMismatch',)), response)
469
470
    def test_unlock_on_unlocked_branch_locked_repo(self):
471
        backing = self.get_transport()
472
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
473
        branch = self.make_branch('.')
474
        # Lock the repository.
475
        repo_token = branch.repository.lock_write()
476
        branch.repository.leave_lock_in_place()
477
        branch.repository.unlock()
478
        # Issue branch lock_write request on the unlocked branch (with locked
479
        # repo).
480
        response = request.execute(
481
            backing.local_abspath(''), 'branch token', repo_token)
482
        self.assertEqual(
483
            SmartServerResponse(('TokenMismatch',)), response)
484
485
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
486
class TestSmartServerRepositoryRequest(tests.TestCaseWithTransport):
487
488
    def test_no_repository(self):
489
        """Raise NoRepositoryPresent when there is a bzrdir and no repo."""
490
        # we test this using a shared repository above the named path,
491
        # thus checking the right search logic is used - that is, that
492
        # its the exact path being looked at and the server is not
493
        # searching.
494
        backing = self.get_transport()
2018.5.58 by Wouter van Heyst
Small test fixes to reflect naming and documentation
495
        request = smart.repository.SmartServerRepositoryRequest(backing)
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
496
        self.make_repository('.', shared=True)
497
        self.make_bzrdir('subdir')
498
        self.assertRaises(errors.NoRepositoryPresent,
2018.5.58 by Wouter van Heyst
Small test fixes to reflect naming and documentation
499
            request.execute, backing.local_abspath('subdir'))
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
500
501
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
502
class TestSmartServerRepositoryGetRevisionGraph(tests.TestCaseWithTransport):
503
504
    def test_none_argument(self):
505
        backing = self.get_transport()
506
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
507
        tree = self.make_branch_and_memory_tree('.')
508
        tree.lock_write()
509
        tree.add('')
510
        r1 = tree.commit('1st commit')
511
        r2 = tree.commit('2nd commit', rev_id=u'\xc8')
512
        tree.unlock()
513
514
        # the lines of revision_id->revision_parent_list has no guaranteed
515
        # order coming out of a dict, so sort both our test and response
516
        lines = sorted([' '.join([r2, r1]), r1])
517
        response = request.execute(backing.local_abspath(''), '')
518
        response.body = '\n'.join(sorted(response.body.split('\n')))
519
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
520
        self.assertEqual(
521
            SmartServerResponse(('ok', ), '\n'.join(lines)), response)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
522
523
    def test_specific_revision_argument(self):
524
        backing = self.get_transport()
525
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
526
        tree = self.make_branch_and_memory_tree('.')
527
        tree.lock_write()
528
        tree.add('')
529
        r1 = tree.commit('1st commit', rev_id=u'\xc9')
530
        r2 = tree.commit('2nd commit', rev_id=u'\xc8')
531
        tree.unlock()
532
533
        self.assertEqual(SmartServerResponse(('ok', ),
534
            u'\xc9'.encode('utf8')),
535
            request.execute(backing.local_abspath(''), u'\xc9'.encode('utf8')))
536
    
537
    def test_no_such_revision(self):
538
        backing = self.get_transport()
539
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
540
        tree = self.make_branch_and_memory_tree('.')
541
        tree.lock_write()
542
        tree.add('')
543
        r1 = tree.commit('1st commit')
544
        tree.unlock()
545
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
546
        # Note that it still returns body (of zero bytes).
547
        self.assertEqual(
548
            SmartServerResponse(('nosuchrevision', 'missingrevision', ), ''),
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
549
            request.execute(backing.local_abspath(''), 'missingrevision'))
550
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
551
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
552
class TestSmartServerRequestHasRevision(tests.TestCaseWithTransport):
553
554
    def test_missing_revision(self):
555
        """For a missing revision, ('no', ) is returned."""
556
        backing = self.get_transport()
557
        request = smart.repository.SmartServerRequestHasRevision(backing)
558
        self.make_repository('.')
559
        self.assertEqual(SmartServerResponse(('no', )),
560
            request.execute(backing.local_abspath(''), 'revid'))
561
562
    def test_present_revision(self):
563
        """For a present revision, ('ok', ) is returned."""
564
        backing = self.get_transport()
565
        request = smart.repository.SmartServerRequestHasRevision(backing)
566
        tree = self.make_branch_and_memory_tree('.')
567
        tree.lock_write()
568
        tree.add('')
569
        r1 = tree.commit('a commit', rev_id=u'\xc8abc')
570
        tree.unlock()
571
        self.assertTrue(tree.branch.repository.has_revision(u'\xc8abc'))
572
        self.assertEqual(SmartServerResponse(('ok', )),
573
            request.execute(backing.local_abspath(''),
574
                u'\xc8abc'.encode('utf8')))
575
576
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
577
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithTransport):
578
579
    def test_empty_revid(self):
580
        """With an empty revid, we get only size an number and revisions"""
581
        backing = self.get_transport()
582
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
583
        repository = self.make_repository('.')
584
        stats = repository.gather_stats()
585
        size = stats['size']
586
        expected_body = 'revisions: 0\nsize: %d\n' % size
587
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
588
                         request.execute(backing.local_abspath(''), '', 'no'))
589
590
    def test_revid_with_committers(self):
591
        """For a revid we get more infos."""
592
        backing = self.get_transport()
593
        rev_id = u'\xc8abc'
594
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
595
        tree = self.make_branch_and_memory_tree('.')
596
        tree.lock_write()
597
        tree.add('')
598
        # Let's build a predictable result
599
        tree.commit('a commit', timestamp=123456.2, timezone=3600)
600
        tree.commit('a commit', timestamp=654321.4, timezone=0, rev_id=rev_id)
601
        tree.unlock()
602
603
        stats = tree.branch.repository.gather_stats()
604
        size = stats['size']
605
        expected_body = ('firstrev: 123456.200 3600\n'
606
                         'latestrev: 654321.400 0\n'
607
                         'revisions: 2\n'
608
                         'size: %d\n' % size)
609
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
610
                         request.execute(backing.local_abspath(''),
611
                                         rev_id.encode('utf8'), 'no'))
612
613
    def test_not_empty_repository_with_committers(self):
614
        """For a revid and requesting committers we get the whole thing."""
615
        backing = self.get_transport()
616
        rev_id = u'\xc8abc'
617
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
618
        tree = self.make_branch_and_memory_tree('.')
619
        tree.lock_write()
620
        tree.add('')
621
        # Let's build a predictable result
622
        tree.commit('a commit', timestamp=123456.2, timezone=3600,
623
                    committer='foo')
624
        tree.commit('a commit', timestamp=654321.4, timezone=0,
625
                    committer='bar', rev_id=rev_id)
626
        tree.unlock()
627
        stats = tree.branch.repository.gather_stats()
628
629
        size = stats['size']
630
        expected_body = ('committers: 2\n'
631
                         'firstrev: 123456.200 3600\n'
632
                         'latestrev: 654321.400 0\n'
633
                         'revisions: 2\n'
634
                         'size: %d\n' % size)
635
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
636
                         request.execute(backing.local_abspath(''),
637
                                         rev_id.encode('utf8'), 'yes'))
638
639
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
640
class TestSmartServerRepositoryIsShared(tests.TestCaseWithTransport):
641
642
    def test_is_shared(self):
643
        """For a shared repository, ('yes', ) is returned."""
644
        backing = self.get_transport()
645
        request = smart.repository.SmartServerRepositoryIsShared(backing)
646
        self.make_repository('.', shared=True)
647
        self.assertEqual(SmartServerResponse(('yes', )),
648
            request.execute(backing.local_abspath(''), ))
649
650
    def test_is_not_shared(self):
2018.5.58 by Wouter van Heyst
Small test fixes to reflect naming and documentation
651
        """For a shared repository, ('no', ) is returned."""
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
652
        backing = self.get_transport()
653
        request = smart.repository.SmartServerRepositoryIsShared(backing)
654
        self.make_repository('.', shared=False)
655
        self.assertEqual(SmartServerResponse(('no', )),
656
            request.execute(backing.local_abspath(''), ))
657
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
658
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
659
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithTransport):
660
661
    def setUp(self):
662
        tests.TestCaseWithTransport.setUp(self)
663
        self.reduceLockdirTimeout()
664
665
    def test_lock_write_on_unlocked_repo(self):
666
        backing = self.get_transport()
667
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
668
        repository = self.make_repository('.')
669
        response = request.execute(backing.local_abspath(''))
670
        nonce = repository.control_files._lock.peek().get('nonce')
671
        self.assertEqual(SmartServerResponse(('ok', nonce)), response)
672
        # The repository is now locked.  Verify that with a new repository
673
        # object.
674
        new_repo = repository.bzrdir.open_repository()
675
        self.assertRaises(errors.LockContention, new_repo.lock_write)
676
677
    def test_lock_write_on_locked_repo(self):
678
        backing = self.get_transport()
679
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
680
        repository = self.make_repository('.')
681
        repository.lock_write()
682
        repository.leave_lock_in_place()
683
        repository.unlock()
684
        response = request.execute(backing.local_abspath(''))
685
        self.assertEqual(
686
            SmartServerResponse(('LockContention',)), response)
687
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
688
    def test_lock_write_on_readonly_transport(self):
689
        backing = self.get_readonly_transport()
690
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
691
        repository = self.make_repository('.')
692
        response = request.execute('')
693
        self.assertEqual(
694
            SmartServerResponse(('UnlockableTransport',)), response)
695
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
696
697
class TestSmartServerRepositoryUnlock(tests.TestCaseWithTransport):
698
699
    def setUp(self):
700
        tests.TestCaseWithTransport.setUp(self)
701
        self.reduceLockdirTimeout()
702
703
    def test_unlock_on_locked_repo(self):
704
        backing = self.get_transport()
705
        request = smart.repository.SmartServerRepositoryUnlock(backing)
706
        repository = self.make_repository('.')
707
        token = repository.lock_write()
708
        repository.leave_lock_in_place()
709
        repository.unlock()
710
        response = request.execute(backing.local_abspath(''), token)
711
        self.assertEqual(
712
            SmartServerResponse(('ok',)), response)
713
        # The repository is now unlocked.  Verify that with a new repository
714
        # object.
715
        new_repo = repository.bzrdir.open_repository()
716
        new_repo.lock_write()
717
        new_repo.unlock()
718
719
    def test_unlock_on_unlocked_repo(self):
720
        backing = self.get_transport()
721
        request = smart.repository.SmartServerRepositoryUnlock(backing)
722
        repository = self.make_repository('.')
723
        response = request.execute(backing.local_abspath(''), 'some token')
724
        self.assertEqual(
725
            SmartServerResponse(('TokenMismatch',)), response)
726
727
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
728
class TestSmartServerIsReadonly(tests.TestCaseWithTransport):
729
730
    def test_is_readonly_no(self):
731
        backing = self.get_transport()
732
        request = smart.request.SmartServerIsReadonly(backing)
733
        response = request.execute()
734
        self.assertEqual(
735
            SmartServerResponse(('no',)), response)
736
737
    def test_is_readonly_yes(self):
738
        backing = self.get_readonly_transport()
739
        request = smart.request.SmartServerIsReadonly(backing)
740
        response = request.execute()
741
        self.assertEqual(
742
            SmartServerResponse(('yes',)), response)
743
744
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
745
class TestHandlers(tests.TestCase):
746
    """Tests for the request.request_handlers object."""
747
748
    def test_registered_methods(self):
749
        """Test that known methods are registered to the correct object."""
750
        self.assertEqual(
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
751
            smart.request.request_handlers.get('Branch.get_config_file'),
752
            smart.branch.SmartServerBranchGetConfigFile)
753
        self.assertEqual(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
754
            smart.request.request_handlers.get('Branch.lock_write'),
755
            smart.branch.SmartServerBranchRequestLockWrite)
756
        self.assertEqual(
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
757
            smart.request.request_handlers.get('Branch.last_revision_info'),
758
            smart.branch.SmartServerBranchRequestLastRevisionInfo)
759
        self.assertEqual(
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
760
            smart.request.request_handlers.get('Branch.revision_history'),
761
            smart.branch.SmartServerRequestRevisionHistory)
762
        self.assertEqual(
2018.5.77 by Wouter van Heyst
Fix typo in request_handlers registration of Branch.set_last_revision, and test that registration
763
            smart.request.request_handlers.get('Branch.set_last_revision'),
764
            smart.branch.SmartServerBranchRequestSetLastRevision)
765
        self.assertEqual(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
766
            smart.request.request_handlers.get('Branch.unlock'),
767
            smart.branch.SmartServerBranchRequestUnlock)
768
        self.assertEqual(
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
769
            smart.request.request_handlers.get('BzrDir.find_repository'),
770
            smart.bzrdir.SmartServerRequestFindRepository)
771
        self.assertEqual(
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
772
            smart.request.request_handlers.get('BzrDirFormat.initialize'),
773
            smart.bzrdir.SmartServerRequestInitializeBzrDir)
774
        self.assertEqual(
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
775
            smart.request.request_handlers.get('BzrDir.open_branch'),
776
            smart.bzrdir.SmartServerRequestOpenBranch)
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
777
        self.assertEqual(
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
778
            smart.request.request_handlers.get('Repository.gather_stats'),
779
            smart.repository.SmartServerRepositoryGatherStats)
780
        self.assertEqual(
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
781
            smart.request.request_handlers.get('Repository.get_revision_graph'),
782
            smart.repository.SmartServerRepositoryGetRevisionGraph)
783
        self.assertEqual(
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
784
            smart.request.request_handlers.get('Repository.has_revision'),
785
            smart.repository.SmartServerRequestHasRevision)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
786
        self.assertEqual(
787
            smart.request.request_handlers.get('Repository.is_shared'),
788
            smart.repository.SmartServerRepositoryIsShared)
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
789
        self.assertEqual(
790
            smart.request.request_handlers.get('Repository.lock_write'),
791
            smart.repository.SmartServerRepositoryLockWrite)
792
        self.assertEqual(
793
            smart.request.request_handlers.get('Repository.unlock'),
794
            smart.repository.SmartServerRepositoryUnlock)
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
795
        self.assertEqual(
796
            smart.request.request_handlers.get('Transport.is_readonly'),
797
            smart.request.SmartServerIsReadonly)