/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'
2018.5.138 by Robert Collins
Merge bzr.dev.
89
        if repo._format.supports_tree_reference:
2018.5.118 by Robert Collins
Fix RemoteRepositoryFormat to have appropriate rich_root_data and 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('.')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
392
        branch_token = branch.lock_write()
393
        repo_token = branch.repository.lock_write()
394
        branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
395
        branch.leave_lock_in_place()
396
        branch.repository.leave_lock_in_place()
397
        branch.unlock()
398
        response = request.execute(backing.local_abspath(''),
399
                                   branch_token, repo_token)
400
        self.assertEqual(
401
            SmartServerResponse(('ok', branch_token, repo_token)), response)
402
403
    def test_lock_write_with_mismatched_tokens_on_locked_branch(self):
404
        backing = self.get_transport()
405
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
406
        branch = self.make_branch('.')
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
407
        branch_token = branch.lock_write()
408
        repo_token = branch.repository.lock_write()
409
        branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
410
        branch.leave_lock_in_place()
411
        branch.repository.leave_lock_in_place()
412
        branch.unlock()
413
        response = request.execute(backing.local_abspath(''),
414
                                   branch_token+'xxx', repo_token)
415
        self.assertEqual(
416
            SmartServerResponse(('TokenMismatch',)), response)
417
418
    def test_lock_write_on_locked_repo(self):
419
        backing = self.get_transport()
420
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
421
        branch = self.make_branch('.')
422
        branch.repository.lock_write()
423
        branch.repository.leave_lock_in_place()
424
        branch.repository.unlock()
425
        response = request.execute(backing.local_abspath(''))
426
        self.assertEqual(
427
            SmartServerResponse(('LockContention',)), response)
428
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.
429
    def test_lock_write_on_readonly_transport(self):
430
        backing = self.get_readonly_transport()
431
        request = smart.branch.SmartServerBranchRequestLockWrite(backing)
432
        branch = self.make_branch('.')
433
        response = request.execute('')
434
        self.assertEqual(
435
            SmartServerResponse(('UnlockableTransport',)), response)
436
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
437
438
class TestSmartServerBranchRequestUnlock(tests.TestCaseWithTransport):
439
440
    def setUp(self):
441
        tests.TestCaseWithTransport.setUp(self)
442
        self.reduceLockdirTimeout()
443
444
    def test_unlock_on_locked_branch_and_repo(self):
445
        backing = self.get_transport()
446
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
447
        branch = self.make_branch('.')
448
        # Lock the branch
2018.5.142 by Andrew Bennetts
Change Branch.lock_token to only accept and receive the branch lock token (rather than the branch and repo lock tokens).
449
        branch_token = branch.lock_write()
450
        repo_token = branch.repository.lock_write()
451
        branch.repository.unlock()
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
452
        # Unlock the branch (and repo) object, leaving the physical locks
453
        # in place.
454
        branch.leave_lock_in_place()
455
        branch.repository.leave_lock_in_place()
456
        branch.unlock()
457
        response = request.execute(backing.local_abspath(''),
458
                                   branch_token, repo_token)
459
        self.assertEqual(
460
            SmartServerResponse(('ok',)), response)
461
        # The branch is now unlocked.  Verify that with a new branch
462
        # object.
463
        new_branch = branch.bzrdir.open_branch()
464
        new_branch.lock_write()
465
        new_branch.unlock()
466
467
    def test_unlock_on_unlocked_branch_unlocked_repo(self):
468
        backing = self.get_transport()
469
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
470
        branch = self.make_branch('.')
471
        response = request.execute(
472
            backing.local_abspath(''), 'branch token', 'repo token')
473
        self.assertEqual(
474
            SmartServerResponse(('TokenMismatch',)), response)
475
476
    def test_unlock_on_unlocked_branch_locked_repo(self):
477
        backing = self.get_transport()
478
        request = smart.branch.SmartServerBranchRequestUnlock(backing)
479
        branch = self.make_branch('.')
480
        # Lock the repository.
481
        repo_token = branch.repository.lock_write()
482
        branch.repository.leave_lock_in_place()
483
        branch.repository.unlock()
484
        # Issue branch lock_write request on the unlocked branch (with locked
485
        # repo).
486
        response = request.execute(
487
            backing.local_abspath(''), 'branch token', repo_token)
488
        self.assertEqual(
489
            SmartServerResponse(('TokenMismatch',)), response)
490
491
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
492
class TestSmartServerRepositoryRequest(tests.TestCaseWithTransport):
493
494
    def test_no_repository(self):
495
        """Raise NoRepositoryPresent when there is a bzrdir and no repo."""
496
        # we test this using a shared repository above the named path,
497
        # thus checking the right search logic is used - that is, that
498
        # its the exact path being looked at and the server is not
499
        # searching.
500
        backing = self.get_transport()
2018.5.58 by Wouter van Heyst
Small test fixes to reflect naming and documentation
501
        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).
502
        self.make_repository('.', shared=True)
503
        self.make_bzrdir('subdir')
504
        self.assertRaises(errors.NoRepositoryPresent,
2018.5.58 by Wouter van Heyst
Small test fixes to reflect naming and documentation
505
            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).
506
507
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
508
class TestSmartServerRepositoryGetRevisionGraph(tests.TestCaseWithTransport):
509
510
    def test_none_argument(self):
511
        backing = self.get_transport()
512
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
513
        tree = self.make_branch_and_memory_tree('.')
514
        tree.lock_write()
515
        tree.add('')
516
        r1 = tree.commit('1st commit')
517
        r2 = tree.commit('2nd commit', rev_id=u'\xc8')
518
        tree.unlock()
519
520
        # the lines of revision_id->revision_parent_list has no guaranteed
521
        # order coming out of a dict, so sort both our test and response
522
        lines = sorted([' '.join([r2, r1]), r1])
523
        response = request.execute(backing.local_abspath(''), '')
524
        response.body = '\n'.join(sorted(response.body.split('\n')))
525
2018.5.83 by Andrew Bennetts
Fix some test failures caused by the switch from unicode to UTF-8-encoded strs for revision IDs.
526
        self.assertEqual(
527
            SmartServerResponse(('ok', ), '\n'.join(lines)), response)
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
528
529
    def test_specific_revision_argument(self):
530
        backing = self.get_transport()
531
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
532
        tree = self.make_branch_and_memory_tree('.')
533
        tree.lock_write()
534
        tree.add('')
535
        r1 = tree.commit('1st commit', rev_id=u'\xc9')
536
        r2 = tree.commit('2nd commit', rev_id=u'\xc8')
537
        tree.unlock()
538
539
        self.assertEqual(SmartServerResponse(('ok', ),
540
            u'\xc9'.encode('utf8')),
541
            request.execute(backing.local_abspath(''), u'\xc9'.encode('utf8')))
542
    
543
    def test_no_such_revision(self):
544
        backing = self.get_transport()
545
        request = smart.repository.SmartServerRepositoryGetRevisionGraph(backing)
546
        tree = self.make_branch_and_memory_tree('.')
547
        tree.lock_write()
548
        tree.add('')
549
        r1 = tree.commit('1st commit')
550
        tree.unlock()
551
2018.14.1 by Andrew Bennetts
Update to current hpss branch? Fix lots of test failures.
552
        # Note that it still returns body (of zero bytes).
553
        self.assertEqual(
554
            SmartServerResponse(('nosuchrevision', 'missingrevision', ), ''),
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
555
            request.execute(backing.local_abspath(''), 'missingrevision'))
556
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
557
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
558
class TestSmartServerRequestHasRevision(tests.TestCaseWithTransport):
559
560
    def test_missing_revision(self):
561
        """For a missing revision, ('no', ) is returned."""
562
        backing = self.get_transport()
563
        request = smart.repository.SmartServerRequestHasRevision(backing)
564
        self.make_repository('.')
565
        self.assertEqual(SmartServerResponse(('no', )),
566
            request.execute(backing.local_abspath(''), 'revid'))
567
568
    def test_present_revision(self):
569
        """For a present revision, ('ok', ) is returned."""
570
        backing = self.get_transport()
571
        request = smart.repository.SmartServerRequestHasRevision(backing)
572
        tree = self.make_branch_and_memory_tree('.')
573
        tree.lock_write()
574
        tree.add('')
575
        r1 = tree.commit('a commit', rev_id=u'\xc8abc')
576
        tree.unlock()
577
        self.assertTrue(tree.branch.repository.has_revision(u'\xc8abc'))
578
        self.assertEqual(SmartServerResponse(('ok', )),
579
            request.execute(backing.local_abspath(''),
580
                u'\xc8abc'.encode('utf8')))
581
582
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
583
class TestSmartServerRepositoryGatherStats(tests.TestCaseWithTransport):
584
585
    def test_empty_revid(self):
586
        """With an empty revid, we get only size an number and revisions"""
587
        backing = self.get_transport()
588
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
589
        repository = self.make_repository('.')
590
        stats = repository.gather_stats()
591
        size = stats['size']
592
        expected_body = 'revisions: 0\nsize: %d\n' % size
593
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
594
                         request.execute(backing.local_abspath(''), '', 'no'))
595
596
    def test_revid_with_committers(self):
597
        """For a revid we get more infos."""
598
        backing = self.get_transport()
599
        rev_id = u'\xc8abc'
600
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
601
        tree = self.make_branch_and_memory_tree('.')
602
        tree.lock_write()
603
        tree.add('')
604
        # Let's build a predictable result
605
        tree.commit('a commit', timestamp=123456.2, timezone=3600)
606
        tree.commit('a commit', timestamp=654321.4, timezone=0, rev_id=rev_id)
607
        tree.unlock()
608
609
        stats = tree.branch.repository.gather_stats()
610
        size = stats['size']
611
        expected_body = ('firstrev: 123456.200 3600\n'
612
                         'latestrev: 654321.400 0\n'
613
                         'revisions: 2\n'
614
                         'size: %d\n' % size)
615
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
616
                         request.execute(backing.local_abspath(''),
617
                                         rev_id.encode('utf8'), 'no'))
618
619
    def test_not_empty_repository_with_committers(self):
620
        """For a revid and requesting committers we get the whole thing."""
621
        backing = self.get_transport()
622
        rev_id = u'\xc8abc'
623
        request = smart.repository.SmartServerRepositoryGatherStats(backing)
624
        tree = self.make_branch_and_memory_tree('.')
625
        tree.lock_write()
626
        tree.add('')
627
        # Let's build a predictable result
628
        tree.commit('a commit', timestamp=123456.2, timezone=3600,
629
                    committer='foo')
630
        tree.commit('a commit', timestamp=654321.4, timezone=0,
631
                    committer='bar', rev_id=rev_id)
632
        tree.unlock()
633
        stats = tree.branch.repository.gather_stats()
634
635
        size = stats['size']
636
        expected_body = ('committers: 2\n'
637
                         'firstrev: 123456.200 3600\n'
638
                         'latestrev: 654321.400 0\n'
639
                         'revisions: 2\n'
640
                         'size: %d\n' % size)
641
        self.assertEqual(SmartServerResponse(('ok', ), expected_body),
642
                         request.execute(backing.local_abspath(''),
643
                                         rev_id.encode('utf8'), 'yes'))
644
645
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
646
class TestSmartServerRepositoryIsShared(tests.TestCaseWithTransport):
647
648
    def test_is_shared(self):
649
        """For a shared repository, ('yes', ) is returned."""
650
        backing = self.get_transport()
651
        request = smart.repository.SmartServerRepositoryIsShared(backing)
652
        self.make_repository('.', shared=True)
653
        self.assertEqual(SmartServerResponse(('yes', )),
654
            request.execute(backing.local_abspath(''), ))
655
656
    def test_is_not_shared(self):
2018.5.58 by Wouter van Heyst
Small test fixes to reflect naming and documentation
657
        """For a shared repository, ('no', ) is returned."""
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
658
        backing = self.get_transport()
659
        request = smart.repository.SmartServerRepositoryIsShared(backing)
660
        self.make_repository('.', shared=False)
661
        self.assertEqual(SmartServerResponse(('no', )),
662
            request.execute(backing.local_abspath(''), ))
663
2018.5.56 by Robert Collins
Factor out code we expect to be common in SmartServerRequestHasRevision to SmartServerRepositoryRequest (Robert Collins, Vincent Ladeuil).
664
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
665
class TestSmartServerRepositoryLockWrite(tests.TestCaseWithTransport):
666
667
    def setUp(self):
668
        tests.TestCaseWithTransport.setUp(self)
669
        self.reduceLockdirTimeout()
670
671
    def test_lock_write_on_unlocked_repo(self):
672
        backing = self.get_transport()
673
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
674
        repository = self.make_repository('.')
675
        response = request.execute(backing.local_abspath(''))
676
        nonce = repository.control_files._lock.peek().get('nonce')
677
        self.assertEqual(SmartServerResponse(('ok', nonce)), response)
678
        # The repository is now locked.  Verify that with a new repository
679
        # object.
680
        new_repo = repository.bzrdir.open_repository()
681
        self.assertRaises(errors.LockContention, new_repo.lock_write)
682
683
    def test_lock_write_on_locked_repo(self):
684
        backing = self.get_transport()
685
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
686
        repository = self.make_repository('.')
687
        repository.lock_write()
688
        repository.leave_lock_in_place()
689
        repository.unlock()
690
        response = request.execute(backing.local_abspath(''))
691
        self.assertEqual(
692
            SmartServerResponse(('LockContention',)), response)
693
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.
694
    def test_lock_write_on_readonly_transport(self):
695
        backing = self.get_readonly_transport()
696
        request = smart.repository.SmartServerRepositoryLockWrite(backing)
697
        repository = self.make_repository('.')
698
        response = request.execute('')
699
        self.assertEqual(
700
            SmartServerResponse(('UnlockableTransport',)), response)
701
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
702
703
class TestSmartServerRepositoryUnlock(tests.TestCaseWithTransport):
704
705
    def setUp(self):
706
        tests.TestCaseWithTransport.setUp(self)
707
        self.reduceLockdirTimeout()
708
709
    def test_unlock_on_locked_repo(self):
710
        backing = self.get_transport()
711
        request = smart.repository.SmartServerRepositoryUnlock(backing)
712
        repository = self.make_repository('.')
713
        token = repository.lock_write()
714
        repository.leave_lock_in_place()
715
        repository.unlock()
716
        response = request.execute(backing.local_abspath(''), token)
717
        self.assertEqual(
718
            SmartServerResponse(('ok',)), response)
719
        # The repository is now unlocked.  Verify that with a new repository
720
        # object.
721
        new_repo = repository.bzrdir.open_repository()
722
        new_repo.lock_write()
723
        new_repo.unlock()
724
725
    def test_unlock_on_unlocked_repo(self):
726
        backing = self.get_transport()
727
        request = smart.repository.SmartServerRepositoryUnlock(backing)
728
        repository = self.make_repository('.')
729
        response = request.execute(backing.local_abspath(''), 'some token')
730
        self.assertEqual(
731
            SmartServerResponse(('TokenMismatch',)), response)
732
733
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.
734
class TestSmartServerIsReadonly(tests.TestCaseWithTransport):
735
736
    def test_is_readonly_no(self):
737
        backing = self.get_transport()
738
        request = smart.request.SmartServerIsReadonly(backing)
739
        response = request.execute()
740
        self.assertEqual(
741
            SmartServerResponse(('no',)), response)
742
743
    def test_is_readonly_yes(self):
744
        backing = self.get_readonly_transport()
745
        request = smart.request.SmartServerIsReadonly(backing)
746
        response = request.execute()
747
        self.assertEqual(
748
            SmartServerResponse(('yes',)), response)
749
750
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
751
class TestHandlers(tests.TestCase):
752
    """Tests for the request.request_handlers object."""
753
754
    def test_registered_methods(self):
755
        """Test that known methods are registered to the correct object."""
756
        self.assertEqual(
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
757
            smart.request.request_handlers.get('Branch.get_config_file'),
758
            smart.branch.SmartServerBranchGetConfigFile)
759
        self.assertEqual(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
760
            smart.request.request_handlers.get('Branch.lock_write'),
761
            smart.branch.SmartServerBranchRequestLockWrite)
762
        self.assertEqual(
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
763
            smart.request.request_handlers.get('Branch.last_revision_info'),
764
            smart.branch.SmartServerBranchRequestLastRevisionInfo)
765
        self.assertEqual(
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
766
            smart.request.request_handlers.get('Branch.revision_history'),
767
            smart.branch.SmartServerRequestRevisionHistory)
768
        self.assertEqual(
2018.5.77 by Wouter van Heyst
Fix typo in request_handlers registration of Branch.set_last_revision, and test that registration
769
            smart.request.request_handlers.get('Branch.set_last_revision'),
770
            smart.branch.SmartServerBranchRequestSetLastRevision)
771
        self.assertEqual(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
772
            smart.request.request_handlers.get('Branch.unlock'),
773
            smart.branch.SmartServerBranchRequestUnlock)
774
        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.
775
            smart.request.request_handlers.get('BzrDir.find_repository'),
776
            smart.bzrdir.SmartServerRequestFindRepository)
777
        self.assertEqual(
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
778
            smart.request.request_handlers.get('BzrDirFormat.initialize'),
779
            smart.bzrdir.SmartServerRequestInitializeBzrDir)
780
        self.assertEqual(
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
781
            smart.request.request_handlers.get('BzrDir.open_branch'),
782
            smart.bzrdir.SmartServerRequestOpenBranch)
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
783
        self.assertEqual(
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
784
            smart.request.request_handlers.get('Repository.gather_stats'),
785
            smart.repository.SmartServerRepositoryGatherStats)
786
        self.assertEqual(
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
787
            smart.request.request_handlers.get('Repository.get_revision_graph'),
788
            smart.repository.SmartServerRepositoryGetRevisionGraph)
789
        self.assertEqual(
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
790
            smart.request.request_handlers.get('Repository.has_revision'),
791
            smart.repository.SmartServerRequestHasRevision)
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
792
        self.assertEqual(
793
            smart.request.request_handlers.get('Repository.is_shared'),
794
            smart.repository.SmartServerRepositoryIsShared)
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
795
        self.assertEqual(
796
            smart.request.request_handlers.get('Repository.lock_write'),
797
            smart.repository.SmartServerRepositoryLockWrite)
798
        self.assertEqual(
799
            smart.request.request_handlers.get('Repository.unlock'),
800
            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.
801
        self.assertEqual(
802
            smart.request.request_handlers.get('Transport.is_readonly'),
803
            smart.request.SmartServerIsReadonly)