~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/per_branch/test_tags.py

  • Committer: Jelmer Vernooij
  • Date: 2010-12-20 11:57:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5577.
  • Revision ID: jelmer@samba.org-20101220115714-2ru3hfappjweeg7q
Don't use no-plugins.

Show diffs side-by-side

added added

removed removed

Lines of Context:
96
96
        # removed when we merge them
97
97
        b2.tags.set_tag('in-destination', 'revid')
98
98
        result = b1.tags.merge_to(b2.tags)
99
 
        self.assertEquals(result, [])
 
99
        self.assertEquals(list(result), [])
100
100
        self.assertEquals(b2.tags.lookup_tag('in-destination'), 'revid')
101
101
        # if there's a conflicting tag, it's reported -- the command line
102
102
        # interface will say "these tags couldn't be copied"
103
103
        b1.tags.set_tag('conflicts', 'revid-1')
104
104
        b2.tags.set_tag('conflicts', 'revid-2')
105
105
        result = b1.tags.merge_to(b2.tags)
106
 
        self.assertEquals(result,
 
106
        self.assertEquals(list(result),
107
107
            [('conflicts', 'revid-1', 'revid-2')])
108
108
        # and it keeps the same value
109
109
        self.assertEquals(b2.tags.lookup_tag('conflicts'), 'revid-2')
110
110
 
111
 
 
112
111
    def test_unicode_tag(self):
113
112
        b1 = self.make_branch('b')
114
113
        tag_name = u'\u3070'
143
142
        b2 = self.make_branch('b2')
144
143
        b1.tags.merge_to(b2.tags)
145
144
 
 
145
    def test_read_lock_caches_tags(self):
 
146
        """Tags are read from a branch only once during a read-lock."""
 
147
        # Open the same branch twice.  Read-lock one, and then mutate the tags
 
148
        # in the second.  The read-locked branch never re-reads the tags, so it
 
149
        # never observes the changed/new tags.
 
150
        b1 = self.make_branch('b')
 
151
        b1.tags.set_tag('one', 'rev-1')
 
152
        b2 = b1.bzrdir.open_branch()
 
153
        b1.lock_read()
 
154
        self.assertEqual({'one': 'rev-1'}, b1.tags.get_tag_dict())
 
155
        # Add a tag and modify a tag in b2.  b1 is read-locked and has already
 
156
        # read the tags, so it is unaffected.
 
157
        b2.tags.set_tag('one', 'rev-1-changed')
 
158
        b2.tags.set_tag('two', 'rev-2')
 
159
        self.assertEqual({'one': 'rev-1'}, b1.tags.get_tag_dict())
 
160
        b1.unlock()
 
161
        # Once unlocked the cached value is forgotten, so now the latest tags
 
162
        # will be retrieved.
 
163
        self.assertEqual(
 
164
            {'one': 'rev-1-changed', 'two': 'rev-2'}, b1.tags.get_tag_dict())
 
165
 
 
166
    def test_unlocked_does_not_cache_tags(self):
 
167
        """Unlocked branches do not cache tags."""
 
168
        # Open the same branch twice.
 
169
        b1 = self.make_branch('b')
 
170
        b1.tags.set_tag('one', 'rev-1')
 
171
        b2 = b1.bzrdir.open_branch()
 
172
        self.assertEqual({'one': 'rev-1'}, b1.tags.get_tag_dict())
 
173
        # Add a tag and modify a tag in b2.  b1 isn't locked, so it will
 
174
        # immediately return the new tags too.
 
175
        b2.tags.set_tag('one', 'rev-1-changed')
 
176
        b2.tags.set_tag('two', 'rev-2')
 
177
        self.assertEqual(
 
178
            {'one': 'rev-1-changed', 'two': 'rev-2'}, b1.tags.get_tag_dict())
 
179
 
 
180
    def test_cached_tag_dict_not_accidentally_mutable(self):
 
181
        """When there's a cached version of the tags, b.tags.get_tag_dict
 
182
        returns a copy of the cached data so that callers cannot accidentally
 
183
        corrupt the cache.
 
184
        """
 
185
        b = self.make_branch('b')
 
186
        b.tags.set_tag('one', 'rev-1')
 
187
        self.addCleanup(b.lock_read().unlock)
 
188
        # The first time the data returned will not be in the cache
 
189
        tags_dict = b.tags.get_tag_dict()
 
190
        tags_dict['two'] = 'rev-2'
 
191
        # The second time the data comes from the cache
 
192
        tags_dict = b.tags.get_tag_dict()
 
193
        tags_dict['three'] = 'rev-3'
 
194
        # The get_tag_dict() result should still be unchanged, even though we
 
195
        # mutated its earlier return values.
 
196
        self.assertEqual({'one': 'rev-1'}, b.tags.get_tag_dict())
 
197
 
 
198
    def make_write_locked_branch_with_one_tag(self):
 
199
        b = self.make_branch('b')
 
200
        b.tags.set_tag('one', 'rev-1')
 
201
        self.addCleanup(b.lock_write().unlock)
 
202
        # Populate the cache
 
203
        b.tags.get_tag_dict()
 
204
        return b
 
205
 
 
206
    def test_set_tag_invalides_cache(self):
 
207
        b = self.make_write_locked_branch_with_one_tag()
 
208
        b.tags.set_tag('one', 'rev-1-changed')
 
209
        self.assertEqual({'one': 'rev-1-changed'}, b.tags.get_tag_dict())
 
210
 
 
211
    def test_delete_tag_invalides_cache(self):
 
212
        b = self.make_write_locked_branch_with_one_tag()
 
213
        b.tags.delete_tag('one')
 
214
        self.assertEqual({}, b.tags.get_tag_dict())
 
215
 
 
216
    def test_merge_to_invalides_cache(self):
 
217
        b1 = self.make_write_locked_branch_with_one_tag()
 
218
        b2 = self.make_branch('b2')
 
219
        b2.tags.set_tag('two', 'rev-2')
 
220
        b2.tags.merge_to(b1.tags)
 
221
        self.assertEqual(
 
222
            {'one': 'rev-1', 'two': 'rev-2'}, b1.tags.get_tag_dict())
 
223
 
 
224
    def test_rename_revisions_invalides_cache(self):
 
225
        b = self.make_write_locked_branch_with_one_tag()
 
226
        b.tags.rename_revisions({'rev-1': 'rev-1-changed'})
 
227
        self.assertEqual({'one': 'rev-1-changed'}, b.tags.get_tag_dict())
 
228
 
 
229
 
 
230
class TestTagsMergeToInCheckouts(per_branch.TestCaseWithBranch):
 
231
    """Tests for checkout.branch.tags.merge_to.
 
232
    
 
233
    In particular this exercises variations in tag conflicts in the master
 
234
    branch and/or the checkout (child).  It may seem strange to have different
 
235
    tags in the child and master, but 'bzr merge' intentionally updates the
 
236
    child and not the master (instead the next 'bzr commit', if the user
 
237
    decides to commit, will update the master).  Also, merge_to in bzr < 2.3
 
238
    didn't propagate changes to the master, and current bzr versions may find
 
239
    themselves operating on checkouts touched by older bzrs
 
240
    
 
241
    So we need to make sure bzr copes gracefully with differing tags in the
 
242
    master versus the child.
 
243
 
 
244
    See also <https://bugs.launchpad.net/bzr/+bug/603395>.
 
245
    """
 
246
 
 
247
    def setUp(self):
 
248
        super(TestTagsMergeToInCheckouts, self).setUp()
 
249
        branch1 = self.make_branch('tags-probe')
 
250
        if not branch1._format.supports_tags():
 
251
            raise tests.TestSkipped(
 
252
                "format %s doesn't support tags" % branch1._format)
 
253
        branch2 = self.make_branch('bind-probe')
 
254
        try:
 
255
            branch2.bind(branch1)
 
256
        except errors.UpgradeRequired:
 
257
            raise tests.TestNotApplicable(
 
258
                "format %s doesn't support bound branches" % branch2._format)
 
259
 
 
260
    def test_merge_to_propagates_tags(self):
 
261
        """merge_to(child) also merges tags to the master."""
 
262
        master = self.make_branch('master')
 
263
        other = self.make_branch('other')
 
264
        other.tags.set_tag('foo', 'rev-1')
 
265
        child = self.make_branch('child')
 
266
        child.bind(master)
 
267
        child.update()
 
268
        other.tags.merge_to(child.tags)
 
269
        self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
 
270
        self.assertEquals('rev-1', master.tags.lookup_tag('foo'))
 
271
 
 
272
    def test_ignore_master_disables_tag_propagation(self):
 
273
        """merge_to(child, ignore_master=True) does not merge tags to the
 
274
        master.
 
275
        """
 
276
        master = self.make_branch('master')
 
277
        other = self.make_branch('other')
 
278
        other.tags.set_tag('foo', 'rev-1')
 
279
        child = self.make_branch('child')
 
280
        child.bind(master)
 
281
        child.update()
 
282
        other.tags.merge_to(child.tags, ignore_master=True)
 
283
        self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
 
284
        self.assertRaises(errors.NoSuchTag, master.tags.lookup_tag, 'foo')
 
285
 
 
286
    def test_merge_to_overwrite_conflict_in_master(self):
 
287
        """merge_to(child, overwrite=True) overwrites any conflicting tags in
 
288
        the master.
 
289
        """
 
290
        master = self.make_branch('master')
 
291
        other = self.make_branch('other')
 
292
        other.tags.set_tag('foo', 'rev-1')
 
293
        child = self.make_branch('child')
 
294
        child.bind(master)
 
295
        child.update()
 
296
        master.tags.set_tag('foo', 'rev-2')
 
297
        tag_conflicts = other.tags.merge_to(child.tags, overwrite=True)
 
298
        self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
 
299
        self.assertEquals('rev-1', master.tags.lookup_tag('foo'))
 
300
        self.assertLength(0, tag_conflicts)
 
301
 
 
302
    def test_merge_to_overwrite_conflict_in_child_and_master(self):
 
303
        """merge_to(child, overwrite=True) overwrites any conflicting tags in
 
304
        both the child and the master.
 
305
        """
 
306
        master = self.make_branch('master')
 
307
        master.tags.set_tag('foo', 'rev-2')
 
308
        other = self.make_branch('other')
 
309
        other.tags.set_tag('foo', 'rev-1')
 
310
        child = self.make_branch('child')
 
311
        child.bind(master)
 
312
        child.update()
 
313
        tag_conflicts = other.tags.merge_to(child.tags, overwrite=True)
 
314
        self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
 
315
        self.assertEquals('rev-1', master.tags.lookup_tag('foo'))
 
316
        self.assertLength(0, tag_conflicts)
 
317
 
 
318
    def test_merge_to_conflict_in_child_only(self):
 
319
        """When new_tags.merge_to(child.tags) conflicts with the child but not
 
320
        the master, a conflict is reported and the child receives the new tag.
 
321
        """
 
322
        master = self.make_branch('master')
 
323
        master.tags.set_tag('foo', 'rev-2')
 
324
        other = self.make_branch('other')
 
325
        other.tags.set_tag('foo', 'rev-1')
 
326
        child = self.make_branch('child')
 
327
        child.bind(master)
 
328
        child.update()
 
329
        master.tags.delete_tag('foo')
 
330
        tag_conflicts = other.tags.merge_to(child.tags)
 
331
        # Conflict in child, so it is unchanged.
 
332
        self.assertEquals('rev-2', child.tags.lookup_tag('foo'))
 
333
        # No conflict in the master, so the 'foo' tag equals other's value here.
 
334
        self.assertEquals('rev-1', master.tags.lookup_tag('foo'))
 
335
        # The conflict is reported.
 
336
        self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))
 
337
 
 
338
    def test_merge_to_conflict_in_master_only(self):
 
339
        """When new_tags.merge_to(child.tags) conflicts with the master but not
 
340
        the child, a conflict is reported and the child receives the new tag.
 
341
        """
 
342
        master = self.make_branch('master')
 
343
        other = self.make_branch('other')
 
344
        other.tags.set_tag('foo', 'rev-1')
 
345
        child = self.make_branch('child')
 
346
        child.bind(master)
 
347
        child.update()
 
348
        master.tags.set_tag('foo', 'rev-2')
 
349
        tag_conflicts = other.tags.merge_to(child.tags)
 
350
        # No conflict in the child, so the 'foo' tag equals other's value here.
 
351
        self.assertEquals('rev-1', child.tags.lookup_tag('foo'))
 
352
        # Conflict in master, so it is unchanged.
 
353
        self.assertEquals('rev-2', master.tags.lookup_tag('foo'))
 
354
        # The conflict is reported.
 
355
        self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))
 
356
 
 
357
    def test_merge_to_same_conflict_in_master_and_child(self):
 
358
        """When new_tags.merge_to(child.tags) conflicts the same way with the
 
359
        master and the child a single conflict is reported.
 
360
        """
 
361
        master = self.make_branch('master')
 
362
        master.tags.set_tag('foo', 'rev-2')
 
363
        other = self.make_branch('other')
 
364
        other.tags.set_tag('foo', 'rev-1')
 
365
        child = self.make_branch('child')
 
366
        child.bind(master)
 
367
        child.update()
 
368
        tag_conflicts = other.tags.merge_to(child.tags)
 
369
        # Both master and child conflict, so both stay as rev-2
 
370
        self.assertEquals('rev-2', child.tags.lookup_tag('foo'))
 
371
        self.assertEquals('rev-2', master.tags.lookup_tag('foo'))
 
372
        # The conflict is reported exactly once, even though it occurs in both
 
373
        # master and child.
 
374
        self.assertEquals([(u'foo', 'rev-1', 'rev-2')], list(tag_conflicts))
 
375
 
 
376
    def test_merge_to_different_conflict_in_master_and_child(self):
 
377
        """When new_tags.merge_to(child.tags) conflicts differently in the
 
378
        master and the child both conflicts are reported.
 
379
        """
 
380
        master = self.make_branch('master')
 
381
        master.tags.set_tag('foo', 'rev-2')
 
382
        other = self.make_branch('other')
 
383
        other.tags.set_tag('foo', 'rev-1')
 
384
        child = self.make_branch('child')
 
385
        child.bind(master)
 
386
        child.update()
 
387
        # We use the private method _set_tag_dict because normally bzr tries to
 
388
        # avoid this scenario.
 
389
        child.tags._set_tag_dict({'foo': 'rev-3'})
 
390
        tag_conflicts = other.tags.merge_to(child.tags)
 
391
        # Both master and child conflict, so both stay as they were.
 
392
        self.assertEquals('rev-3', child.tags.lookup_tag('foo'))
 
393
        self.assertEquals('rev-2', master.tags.lookup_tag('foo'))
 
394
        # Both conflicts are reported.
 
395
        self.assertEquals(
 
396
            [(u'foo', 'rev-1', 'rev-2'), (u'foo', 'rev-1', 'rev-3')],
 
397
            sorted(tag_conflicts))
 
398
 
146
399
 
147
400
class TestUnsupportedTags(per_branch.TestCaseWithBranch):
148
401
    """Formats that don't support tags should give reasonable errors."""