view tests/test-tags.t @ 24760:410f3856196f

tags: change format of tags cache files .hgtags fnodes are now written to a shared cache file. They don't need to exist in the per-filter tags cache files. Stop writing them. The format of the tags cache file has changed in a backwards incompatible way. This should be acceptable, as we just established per-filter tags cache files and no client should have per-filter tags cache files that will need to be read. So no backwards compatbility concern is present. The new format has a single header line followed by resolved tags entries. The header line is similar to the old first line with a major difference: we now compute and store a hash of the filtered revisions. Before, if the set of filtered revs changed, we may return incorrect results. We now detect that. A test for verifying filtered rev change is handled properly has been added.
author Gregory Szorc <gregory.szorc@gmail.com>
date Thu, 16 Apr 2015 12:01:00 -0400
parents d082c6ef9ec3
children 1062663808ce
line wrap: on
line source

setup

  $ cat >> $HGRCPATH << EOF
  > [extensions]
  > blackbox=
  > mock=$TESTDIR/mockblackbox.py
  > EOF

Helper functions:

  $ cacheexists() {
  >   [ -f .hg/cache/tags-visible ] && echo "tag cache exists" || echo "no tag cache"
  > }

  $ fnodescacheexists() {
  >   [ -f .hg/cache/hgtagsfnodes1 ] && echo "fnodes cache exists" || echo "no fnodes cache"
  > }

  $ dumptags() {
  >     rev=$1
  >     echo "rev $rev: .hgtags:"
  >     hg cat -r$rev .hgtags
  > }

# XXX need to test that the tag cache works when we strip an old head
# and add a new one rooted off non-tip: i.e. node and rev of tip are the
# same, but stuff has changed behind tip.

Setup:

  $ hg init t
  $ cd t
  $ cacheexists
  no tag cache
  $ fnodescacheexists
  no fnodes cache
  $ hg id
  000000000000 tip
  $ cacheexists
  no tag cache
  $ fnodescacheexists
  no fnodes cache
  $ echo a > a
  $ hg add a
  $ hg commit -m "test"
  $ hg co
  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
  $ hg identify
  acb14030fe0a tip
  $ cacheexists
  tag cache exists
No fnodes cache because .hgtags file doesn't exist
(this is an implementation detail)
  $ fnodescacheexists
  no fnodes cache

Try corrupting the cache

  $ printf 'a b' > .hg/cache/tags-visible
  $ hg identify
  acb14030fe0a tip
  $ cacheexists
  tag cache exists
  $ fnodescacheexists
  no fnodes cache
  $ hg identify
  acb14030fe0a tip

Create local tag with long name:

  $ T=`hg identify --debug --id`
  $ hg tag -l "This is a local tag with a really long name!"
  $ hg tags
  tip                                0:acb14030fe0a
  This is a local tag with a really long name!     0:acb14030fe0a
  $ rm .hg/localtags

Create a tag behind hg's back:

  $ echo "$T first" > .hgtags
  $ cat .hgtags
  acb14030fe0a21b60322c440ad2d20cf7685a376 first
  $ hg add .hgtags
  $ hg commit -m "add tags"
  $ hg tags
  tip                                1:b9154636be93
  first                              0:acb14030fe0a
  $ hg identify
  b9154636be93 tip

We should have a fnodes cache now that we have a real tag
The cache should have an empty entry for rev 0 and a valid entry for rev 1.


  $ fnodescacheexists
  fnodes cache exists
  $ f --size --hexdump .hg/cache/hgtagsfnodes1
  .hg/cache/hgtagsfnodes1: size=48
  0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
  0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...|
  0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y|

Repeat with cold tag cache:

  $ rm -f .hg/cache/tags-visible .hg/cache/hgtagsfnodes1
  $ hg identify
  b9154636be93 tip

  $ fnodescacheexists
  fnodes cache exists
  $ f --size --hexdump .hg/cache/hgtagsfnodes1
  .hg/cache/hgtagsfnodes1: size=48
  0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
  0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...|
  0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y|

And again, but now unable to write tag cache:

#if unix-permissions
  $ rm -f .hg/cache/tags-visible .hg/cache/hgtagsfnodes1
  $ chmod 555 .hg/cache
  $ hg identify
  b9154636be93 tip
  $ chmod 755 .hg/cache
#endif

Tag cache debug info written to blackbox log

  $ rm -f .hg/cache/tags-visible .hg/cache/hgtagsfnodes1
  $ hg identify
  b9154636be93 tip
  $ hg blackbox -l 5
  1970/01/01 00:00:00 bob> identify
  1970/01/01 00:00:00 bob> writing 48 bytes to cache/hgtagsfnodes1
  1970/01/01 00:00:00 bob> 0/1 cache hits/lookups in * seconds (glob)
  1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
  1970/01/01 00:00:00 bob> identify exited 0 after ?.?? seconds (glob)

Failure to acquire lock results in no write

  $ rm -f .hg/cache/tags-visible .hg/cache/hgtagsfnodes1
  $ echo 'foo:1' > .hg/wlock
  $ hg identify
  b9154636be93 tip
  $ hg blackbox -l 5
  1970/01/01 00:00:00 bob> identify
  1970/01/01 00:00:00 bob> not writing .hg/cache/hgtagsfnodes1 because lock held
  1970/01/01 00:00:00 bob> 0/1 cache hits/lookups in * seconds (glob)
  1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
  1970/01/01 00:00:00 bob> identify exited 0 after * seconds (glob)

  $ fnodescacheexists
  no fnodes cache

  $ rm .hg/wlock

  $ rm -f .hg/cache/tags-visible .hg/cache/hgtagsfnodes1
  $ hg identify
  b9154636be93 tip

Create a branch:

  $ echo bb > a
  $ hg status
  M a
  $ hg identify
  b9154636be93+ tip
  $ hg co first
  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
  $ hg id
  acb14030fe0a+ first
  $ hg -v id
  acb14030fe0a+ first
  $ hg status
  M a
  $ echo 1 > b
  $ hg add b
  $ hg commit -m "branch"
  created new head

Creating a new commit shouldn't append the .hgtags fnodes cache until
tags info is accessed

  $ f --size --hexdump .hg/cache/hgtagsfnodes1
  .hg/cache/hgtagsfnodes1: size=48
  0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
  0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...|
  0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y|

  $ hg id
  c8edf04160c7 tip

First 4 bytes of record 3 are changeset fragment

  $ f --size --hexdump .hg/cache/hgtagsfnodes1
  .hg/cache/hgtagsfnodes1: size=72
  0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
  0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...|
  0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y|
  0030: c8 ed f0 41 00 00 00 00 00 00 00 00 00 00 00 00 |...A............|
  0040: 00 00 00 00 00 00 00 00                         |........|

Merge the two heads:

  $ hg merge 1
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ hg id
  c8edf04160c7+b9154636be93+ tip
  $ hg status
  M .hgtags
  $ hg commit -m "merge"

Create a fake head, make sure tag not visible afterwards:

  $ cp .hgtags tags
  $ hg tag last
  $ hg rm .hgtags
  $ hg commit -m "remove"

  $ mv tags .hgtags
  $ hg add .hgtags
  $ hg commit -m "readd"
  $ 
  $ hg tags
  tip                                6:35ff301afafe
  first                              0:acb14030fe0a

Add invalid tags:

  $ echo "spam" >> .hgtags
  $ echo >> .hgtags
  $ echo "foo bar" >> .hgtags
  $ echo "a5a5 invalid" >> .hg/localtags
  $ cat .hgtags
  acb14030fe0a21b60322c440ad2d20cf7685a376 first
  spam
  
  foo bar
  $ hg commit -m "tags"

Report tag parse error on other head:

  $ hg up 3
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  $ echo 'x y' >> .hgtags
  $ hg commit -m "head"
  created new head

  $ hg tags
  .hgtags@75d9f02dfe28, line 2: cannot parse entry
  .hgtags@75d9f02dfe28, line 4: node 'foo' is not well formed
  .hgtags@c4be69a18c11, line 2: node 'x' is not well formed
  tip                                8:c4be69a18c11
  first                              0:acb14030fe0a
  $ hg tip
  changeset:   8:c4be69a18c11
  tag:         tip
  parent:      3:ac5e980c4dc0
  user:        test
  date:        Thu Jan 01 00:00:00 1970 +0000
  summary:     head
  

Test tag precedence rules:

  $ cd ..
  $ hg init t2
  $ cd t2
  $ echo foo > foo
  $ hg add foo
  $ hg ci -m 'add foo'      # rev 0
  $ hg tag bar              # rev 1
  $ echo >> foo
  $ hg ci -m 'change foo 1' # rev 2
  $ hg up -C 1
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  $ hg tag -r 1 -f bar      # rev 3
  $ hg up -C 1
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  $ echo >> foo
  $ hg ci -m 'change foo 2' # rev 4
  created new head
  $ hg tags
  tip                                4:0c192d7d5e6b
  bar                                1:78391a272241

Repeat in case of cache effects:

  $ hg tags
  tip                                4:0c192d7d5e6b
  bar                                1:78391a272241

Detailed dump of tag info:

  $ hg heads -q             # expect 4, 3, 2
  4:0c192d7d5e6b
  3:6fa450212aeb
  2:7a94127795a3
  $ dumptags 2
  rev 2: .hgtags:
  bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
  $ dumptags 3
  rev 3: .hgtags:
  bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
  bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
  78391a272241d70354aa14c874552cad6b51bb42 bar
  $ dumptags 4
  rev 4: .hgtags:
  bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar

Dump cache:

  $ cat .hg/cache/tags-visible
  4 0c192d7d5e6b78a714de54a2e9627952a877e25a
  bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
  bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
  78391a272241d70354aa14c874552cad6b51bb42 bar

  $ f --size --hexdump .hg/cache/hgtagsfnodes1
  .hg/cache/hgtagsfnodes1: size=120
  0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
  0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
  0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
  0030: 7a 94 12 77 0c 04 f2 a8 af 31 de 17 fa b7 42 28 |z..w.....1....B(|
  0040: 78 ee 5a 2d ad bc 94 3d 6f a4 50 21 7d 3b 71 8c |x.Z-...=o.P!};q.|
  0050: 96 4e f3 7b 89 e5 50 eb da fd 57 89 e7 6c e1 b0 |.N.{..P...W..l..|
  0060: 0c 19 2d 7d 0c 04 f2 a8 af 31 de 17 fa b7 42 28 |..-}.....1....B(|
  0070: 78 ee 5a 2d ad bc 94 3d                         |x.Z-...=|

Corrupt the .hgtags fnodes cache
Extra junk data at the end should get overwritten on next cache update

  $ echo extra >> .hg/cache/hgtagsfnodes1
  $ echo dummy1 > foo
  $ hg commit -m throwaway1

  $ hg tags
  tip                                5:8dbfe60eff30
  bar                                1:78391a272241

  $ hg blackbox -l 5
  1970/01/01 00:00:00 bob> tags
  1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1
  1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
  1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)

#if unix-permissions no-root
Errors writing to .hgtags fnodes cache are silently ignored

  $ echo dummy2 > foo
  $ hg commit -m throwaway2

  $ chmod a-w .hg/cache/hgtagsfnodes1
  $ rm -f .hg/cache/tags-visible

  $ hg tags
  tip                                6:b968051b5cf3
  bar                                1:78391a272241

  $ hg blackbox -l 5
  1970/01/01 00:00:00 bob> tags
  1970/01/01 00:00:00 bob> couldn't write cache/hgtagsfnodes1: [Errno 13] Permission denied: '$TESTTMP/t2/.hg/cache/hgtagsfnodes1'
  1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
  1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)

  $ chmod a+w .hg/cache/hgtagsfnodes1
#endif

  $ rm -f .hg/cache/tags-visible
  $ hg tags
  tip                                6:b968051b5cf3
  bar                                1:78391a272241

  $ hg blackbox -l 5
  1970/01/01 00:00:00 bob> tags
  1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1
  1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
  1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)

  $ f --size .hg/cache/hgtagsfnodes1
  .hg/cache/hgtagsfnodes1: size=168

Stripping doesn't truncate the tags cache until new data is available

  $ hg -q --config extensions.strip= strip -r 5 --no-backup
  $ hg tags
  tip                                4:0c192d7d5e6b
  bar                                1:78391a272241

  $ hg blackbox -l 4
  1970/01/01 00:00:00 bob> tags
  1970/01/01 00:00:00 bob> 3/3 cache hits/lookups in * seconds (glob)
  1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)

  $ f --size .hg/cache/hgtagsfnodes1
  .hg/cache/hgtagsfnodes1: size=168

  $ echo dummy > foo
  $ hg commit -m throwaway3

  $ hg tags
  tip                                5:035f65efb448
  bar                                1:78391a272241

  $ hg blackbox -l 5
  1970/01/01 00:00:00 bob> tags
  1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1
  1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob)
  1970/01/01 00:00:00 bob> writing tags cache file with 1 tags
  1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob)
  $ f --size .hg/cache/hgtagsfnodes1
  .hg/cache/hgtagsfnodes1: size=144

  $ hg -q --config extensions.strip= strip -r 5 --no-backup

Test tag removal:

  $ hg tag --remove bar     # rev 5
  $ hg tip -vp
  changeset:   5:5f6e8655b1c7
  tag:         tip
  user:        test
  date:        Thu Jan 01 00:00:00 1970 +0000
  files:       .hgtags
  description:
  Removed tag bar
  
  
  diff -r 0c192d7d5e6b -r 5f6e8655b1c7 .hgtags
  --- a/.hgtags	Thu Jan 01 00:00:00 1970 +0000
  +++ b/.hgtags	Thu Jan 01 00:00:00 1970 +0000
  @@ -1,1 +1,3 @@
   bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar
  +78391a272241d70354aa14c874552cad6b51bb42 bar
  +0000000000000000000000000000000000000000 bar
  
  $ hg tags
  tip                                5:5f6e8655b1c7
  $ hg tags                 # again, try to expose cache bugs
  tip                                5:5f6e8655b1c7

Remove nonexistent tag:

  $ hg tag --remove foobar
  abort: tag 'foobar' does not exist
  [255]
  $ hg tip
  changeset:   5:5f6e8655b1c7
  tag:         tip
  user:        test
  date:        Thu Jan 01 00:00:00 1970 +0000
  summary:     Removed tag bar
  

Undo a tag with rollback:

  $ hg rollback             # destroy rev 5 (restore bar)
  repository tip rolled back to revision 4 (undo commit)
  working directory now based on revision 4
  $ hg tags
  tip                                4:0c192d7d5e6b
  bar                                1:78391a272241
  $ hg tags
  tip                                4:0c192d7d5e6b
  bar                                1:78391a272241

Test tag rank:

  $ cd ..
  $ hg init t3
  $ cd t3
  $ echo foo > foo
  $ hg add foo
  $ hg ci -m 'add foo'       # rev 0
  $ hg tag -f bar            # rev 1 bar -> 0
  $ hg tag -f bar            # rev 2 bar -> 1
  $ hg tag -fr 0 bar         # rev 3 bar -> 0
  $ hg tag -fr 1 bar         # rev 4 bar -> 1
  $ hg tag -fr 0 bar         # rev 5 bar -> 0
  $ hg tags
  tip                                5:85f05169d91d
  bar                                0:bbd179dfa0a7
  $ hg co 3
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  $ echo barbar > foo
  $ hg ci -m 'change foo'    # rev 6
  created new head
  $ hg tags
  tip                                6:735c3ca72986
  bar                                0:bbd179dfa0a7

Don't allow moving tag without -f:

  $ hg tag -r 3 bar
  abort: tag 'bar' already exists (use -f to force)
  [255]
  $ hg tags
  tip                                6:735c3ca72986
  bar                                0:bbd179dfa0a7

Strip 1: expose an old head:

  $ hg --config extensions.mq= strip 5
  saved backup bundle to $TESTTMP/t3/.hg/strip-backup/*-backup.hg (glob)
  $ hg tags                  # partly stale cache
  tip                                5:735c3ca72986
  bar                                1:78391a272241
  $ hg tags                  # up-to-date cache
  tip                                5:735c3ca72986
  bar                                1:78391a272241

Strip 2: destroy whole branch, no old head exposed

  $ hg --config extensions.mq= strip 4
  saved backup bundle to $TESTTMP/t3/.hg/strip-backup/*-backup.hg (glob)
  $ hg tags                  # partly stale
  tip                                4:735c3ca72986
  bar                                0:bbd179dfa0a7
  $ rm -f .hg/cache/tags-visible
  $ hg tags                  # cold cache
  tip                                4:735c3ca72986
  bar                                0:bbd179dfa0a7

Test tag rank with 3 heads:

  $ cd ..
  $ hg init t4
  $ cd t4
  $ echo foo > foo
  $ hg add
  adding foo
  $ hg ci -m 'add foo'                 # rev 0
  $ hg tag bar                         # rev 1 bar -> 0
  $ hg tag -f bar                      # rev 2 bar -> 1
  $ hg up -qC 0
  $ hg tag -fr 2 bar                   # rev 3 bar -> 2
  $ hg tags
  tip                                3:197c21bbbf2c
  bar                                2:6fa450212aeb
  $ hg up -qC 0
  $ hg tag -m 'retag rev 0' -fr 0 bar  # rev 4 bar -> 0, but bar stays at 2

Bar should still point to rev 2:

  $ hg tags
  tip                                4:3b4b14ed0202
  bar                                2:6fa450212aeb

Test that removing global/local tags does not get confused when trying
to remove a tag of type X which actually only exists as a type Y:

  $ cd ..
  $ hg init t5
  $ cd t5
  $ echo foo > foo
  $ hg add
  adding foo
  $ hg ci -m 'add foo'                 # rev 0

  $ hg tag -r 0 -l localtag
  $ hg tag --remove localtag
  abort: tag 'localtag' is not a global tag
  [255]
  $ 
  $ hg tag -r 0 globaltag
  $ hg tag --remove -l globaltag
  abort: tag 'globaltag' is not a local tag
  [255]
  $ hg tags -v
  tip                                1:a0b6fe111088
  localtag                           0:bbd179dfa0a7 local
  globaltag                          0:bbd179dfa0a7

Test for issue3911

  $ hg tag -r 0 -l localtag2
  $ hg tag -l --remove localtag2
  $ hg tags -v
  tip                                1:a0b6fe111088
  localtag                           0:bbd179dfa0a7 local
  globaltag                          0:bbd179dfa0a7

  $ hg tag -r 1 -f localtag
  $ hg tags -v
  tip                                2:5c70a037bb37
  localtag                           1:a0b6fe111088
  globaltag                          0:bbd179dfa0a7

  $ hg tags -v
  tip                                2:5c70a037bb37
  localtag                           1:a0b6fe111088
  globaltag                          0:bbd179dfa0a7

  $ hg tag -r 1 localtag2
  $ hg tags -v
  tip                                3:bbfb8cd42be2
  localtag2                          1:a0b6fe111088
  localtag                           1:a0b6fe111088
  globaltag                          0:bbd179dfa0a7

  $ hg tags -v
  tip                                3:bbfb8cd42be2
  localtag2                          1:a0b6fe111088
  localtag                           1:a0b6fe111088
  globaltag                          0:bbd179dfa0a7

  $ cd ..