def verify_only_refs(**kwargs): for kind, refs in kwargs.items(): if kind == 'heads': abs_refs = [b'refs/heads/' + ref for ref in refs] karg = b'--heads' elif kind == 'tags': abs_refs = [b'refs/tags/' + ref for ref in refs] karg = b'--tags' else: raise TypeError('unexpected keyword argument %r' % kind) if abs_refs: verify_rcz([b'git', b'--git-dir', b'get-dest', b'show-ref', b'--verify', karg] + abs_refs) exr = exo((b'git', b'--git-dir', b'get-dest', b'show-ref', karg), check=False) wvpasseq(0, exr.rc) expected_refs = sorted(abs_refs) repo_refs = sorted([x.split()[1] for x in exr.out.splitlines()]) wvpasseq(expected_refs, repo_refs) else: # FIXME: can we just check "git show-ref --heads == ''"? exr = exo((b'git', b'--git-dir', b'get-dest', b'show-ref', karg), check=False) wvpasseq(1, exr.rc) wvpasseq(b'', exr.out.strip())
def validate_tree(src_id, dest_id): rmrf(b'restore-src') rmrf(b'restore-dest') mkdir(b'restore-src') mkdir(b'restore-dest') commit_env = merge_dict(environ, {b'GIT_COMMITTER_DATE': b'2014-01-01 01:01'}) # Create a commit so the archive contents will have matching timestamps. src_c = exo((b'git', b'--git-dir', b'get-src', b'commit-tree', b'-m', b'foo', src_id), env=commit_env).out.strip() dest_c = exo((b'git', b'--git-dir', b'get-dest', b'commit-tree', b'-m', b'foo', dest_id), env=commit_env).out.strip() exr = verify_rcz(b'git --git-dir get-src archive %s | tar xvf - -C restore-src' % bquote(src_c), shell=True) if exr.rc != 0: return False exr = verify_rcz(b'git --git-dir get-dest archive %s | tar xvf - -C restore-dest' % bquote(dest_c), shell=True) if exr.rc != 0: return False # git archive doesn't include an entry for ./. unlink(b'restore-src/pax_global_header') unlink(b'restore-dest/pax_global_header') ex((b'touch', b'-r', b'restore-src', b'restore-dest')) verify_trees_match(b'restore-src/', b'restore-dest/') rmrf(b'restore-src') rmrf(b'restore-dest')
def test_misc(): with no_lingering_errors(): with test_tempdir(b'bup-tvfs-') as tmpdir: bup_dir = tmpdir + b'/bup' environ[b'GIT_DIR'] = bup_dir environ[b'BUP_DIR'] = bup_dir git.repodir = bup_dir data_path = tmpdir + b'/src' os.mkdir(data_path) with open(data_path + b'/file', 'wb+') as tmpfile: tmpfile.write(b'canary\n') symlink(b'file', data_path + b'/symlink') ex((bup_path, b'init')) ex((bup_path, b'index', b'-v', data_path)) ex((bup_path, b'save', b'-d', b'100000', b'-tvvn', b'test', b'--strip', data_path)) repo = LocalRepo() wvstart('readlink') ls_tree = exo((b'git', b'ls-tree', b'test', b'symlink')).out mode, typ, oidx, name = ls_tree.strip().split(None, 3) assert name == b'symlink' link_item = vfs.Item(oid=unhexlify(oidx), meta=int(mode, 8)) wvpasseq(b'file', vfs.readlink(repo, link_item)) ls_tree = exo((b'git', b'ls-tree', b'test', b'file')).out mode, typ, oidx, name = ls_tree.strip().split(None, 3) assert name == b'file' file_item = vfs.Item(oid=unhexlify(oidx), meta=int(mode, 8)) wvexcept(Exception, vfs.readlink, repo, file_item) wvstart('item_size') wvpasseq(4, vfs.item_size(repo, link_item)) wvpasseq(7, vfs.item_size(repo, file_item)) meta = metadata.from_path(fsencode(__file__)) meta.size = 42 fake_item = file_item._replace(meta=meta) wvpasseq(42, vfs.item_size(repo, fake_item)) _, fakelink_item = vfs.resolve(repo, b'/test/latest', follow=False)[-1] wvpasseq(17, vfs.item_size(repo, fakelink_item)) wvstart('augment_item_meta') run_augment_item_meta_tests(repo, b'/test/latest/file', 7, b'/test/latest/symlink', b'file') wvstart('copy_item') # FIXME: this caused StopIteration #_, file_item = vfs.resolve(repo, '/file')[-1] _, file_item = vfs.resolve(repo, b'/test/latest/file')[-1] file_copy = vfs.copy_item(file_item) wvpass(file_copy is not file_item) wvpass(file_copy.meta is not file_item.meta) wvpass(isinstance(file_copy, tuple)) wvpass(file_item.meta.user) wvpass(file_copy.meta.user) file_copy.meta.user = None wvpass(file_item.meta.user)
def test_misc(): with no_lingering_errors(): with test_tempdir('bup-tvfs-') as tmpdir: bup_dir = tmpdir + '/bup' environ['GIT_DIR'] = bup_dir environ['BUP_DIR'] = bup_dir git.repodir = bup_dir data_path = tmpdir + '/src' os.mkdir(data_path) with open(data_path + '/file', 'w+') as tmpfile: tmpfile.write(b'canary\n') symlink('file', data_path + '/symlink') ex((bup_path, 'init')) ex((bup_path, 'index', '-v', data_path)) ex((bup_path, 'save', '-d', '100000', '-tvvn', 'test', '--strip', data_path)) repo = LocalRepo() wvstart('readlink') ls_tree = exo(('git', 'ls-tree', 'test', 'symlink')).out mode, typ, oidx, name = ls_tree.strip().split(None, 3) assert name == 'symlink' link_item = vfs.Item(oid=oidx.decode('hex'), meta=int(mode, 8)) wvpasseq('file', vfs.readlink(repo, link_item)) ls_tree = exo(('git', 'ls-tree', 'test', 'file')).out mode, typ, oidx, name = ls_tree.strip().split(None, 3) assert name == 'file' file_item = vfs.Item(oid=oidx.decode('hex'), meta=int(mode, 8)) wvexcept(Exception, vfs.readlink, repo, file_item) wvstart('item_size') wvpasseq(4, vfs.item_size(repo, link_item)) wvpasseq(7, vfs.item_size(repo, file_item)) meta = metadata.from_path(__file__) meta.size = 42 fake_item = file_item._replace(meta=meta) wvpasseq(42, vfs.item_size(repo, fake_item)) wvstart('augment_item_meta') run_augment_item_meta_tests(repo, '/test/latest/file', 7, '/test/latest/symlink', 'file') wvstart('copy_item') # FIXME: this caused StopIteration #_, file_item = vfs.resolve(repo, '/file')[-1] _, file_item = vfs.resolve(repo, '/test/latest/file')[-1] file_copy = vfs.copy_item(file_item) wvpass(file_copy is not file_item) wvpass(file_copy.meta is not file_item.meta) wvpass(isinstance(file_copy, tuple)) wvpass(file_item.meta.user) wvpass(file_copy.meta.user) file_copy.meta.user = None wvpass(file_item.meta.user)
def _run_get(disposition, method, what): print('run_get:', repr((disposition, method, what)), file=sys.stderr) global bup_cmd if disposition == 'get': get_cmd = (bup_cmd, b'-d', b'get-dest', b'get', b'-vvct', b'--print-tags', b'-s', b'get-src') elif disposition == 'get-on': get_cmd = (bup_cmd, b'-d', b'get-dest', b'on', b'-', b'get', b'-vvct', b'--print-tags', b'-s', b'get-src') elif disposition == 'get-to': get_cmd = (bup_cmd, b'-d', b'get-dest', b'get', b'-vvct', b'--print-tags', b'-s', b'get-src', b'-r', b'-:' + getcwd() + b'/get-dest') else: raise Exception('error: unexpected get disposition ' + repr(disposition)) if isinstance(what, bytes): cmd = get_cmd + (method, what) else: assert not isinstance(what, str) # python 3 sanity check if method in (b'--ff', b'--append', b'--pick', b'--force-pick', b'--new-tag', b'--replace'): method += b':' src, dest = what cmd = get_cmd + (method, src, dest) result = exo(cmd, check=False, stderr=PIPE) fsck = ex((bup_cmd, b'-d', b'get-dest', b'fsck'), check=False) wvpasseq(0, fsck.rc) return result
def verify_rcz(cmd, **kwargs): assert not kwargs.get('check') kwargs['check'] = False result = exo(cmd, **kwargs) stdout.write(result.out) rc = result.proc.returncode wvcheck(rc == 0, 'process exit %d == 0' % rc) return result
def test_contents_with_mismatched_bupm_git_ordering(): with no_lingering_errors(): with test_tempdir(b'bup-tvfs-') as tmpdir: bup_dir = tmpdir + b'/bup' environ[b'GIT_DIR'] = bup_dir environ[b'BUP_DIR'] = bup_dir git.repodir = bup_dir data_path = tmpdir + b'/src' os.mkdir(data_path) os.mkdir(data_path + b'/foo') with open(data_path + b'/foo.', 'wb+') as tmpfile: tmpfile.write(b'canary\n') ex((bup_path, b'init')) ex((bup_path, b'index', b'-v', data_path)) save_utc = 100000 save_name = strftime('%Y-%m-%d-%H%M%S', localtime(save_utc)).encode('ascii') ex((bup_path, b'save', b'-tvvn', b'test', b'-d', b'%d' % save_utc, b'--strip', data_path)) repo = LocalRepo() tip_sref = exo((b'git', b'show-ref', b'refs/heads/test')).out tip_oidx = tip_sref.strip().split()[0] tip_tree_oidx = exo((b'git', b'log', b'--pretty=%T', b'-n1', tip_oidx)).out.strip() tip_tree_oid = unhexlify(tip_tree_oidx) tip_tree = tree_dict(repo, tip_tree_oid) name, item = vfs.resolve(repo, b'/test/latest')[2] wvpasseq(save_name, name) expected = frozenset( (x.name, vfs.Item(oid=x.oid, meta=x.meta)) for x in (tip_tree[name] for name in (b'.', b'foo', b'foo.'))) contents = tuple(vfs.contents(repo, item)) wvpasseq(expected, frozenset(contents)) # Spot check, in case tree_dict shares too much code with the vfs name, item = next(((n, i) for n, i in contents if n == b'foo')) wvpass(S_ISDIR(item.meta)) name, item = next(((n, i) for n, i in contents if n == b'foo.')) wvpass(S_ISREG(item.meta.mode))
def test_contents_with_mismatched_bupm_git_ordering(): with no_lingering_errors(): with test_tempdir('bup-tvfs-') as tmpdir: bup_dir = tmpdir + '/bup' environ['GIT_DIR'] = bup_dir environ['BUP_DIR'] = bup_dir git.repodir = bup_dir data_path = tmpdir + '/src' os.mkdir(data_path) os.mkdir(data_path + '/foo') with open(data_path + '/foo.', 'w+') as tmpfile: tmpfile.write(b'canary\n') ex((bup_path, 'init')) ex((bup_path, 'index', '-v', data_path)) save_utc = 100000 save_name = strftime('%Y-%m-%d-%H%M%S', localtime(save_utc)) ex((bup_path, 'save', '-tvvn', 'test', '-d', str(save_utc), '--strip', data_path)) repo = LocalRepo() tip_sref = exo(('git', 'show-ref', 'refs/heads/test')).out tip_oidx = tip_sref.strip().split()[0] tip_tree_oidx = exo(('git', 'log', '--pretty=%T', '-n1', tip_oidx)).out.strip() tip_tree_oid = tip_tree_oidx.decode('hex') tip_tree = tree_dict(repo, tip_tree_oid) name, item = vfs.resolve(repo, '/test/latest')[2] wvpasseq(save_name, name) expected = frozenset((x.name, vfs.Item(oid=x.oid, meta=x.meta)) for x in (tip_tree[name] for name in ('.', 'foo', 'foo.'))) contents = tuple(vfs.contents(repo, item)) wvpasseq(expected, frozenset(contents)) # Spot check, in case tree_dict shares too much code with the vfs name, item = next(((n, i) for n, i in contents if n == 'foo')) wvpass(S_ISDIR(item.meta)) name, item = next(((n, i) for n, i in contents if n == 'foo.')) wvpass(S_ISREG(item.meta.mode))
def validate_tagged_save(tag_name, restore_subpath, commit_id, tree_id, orig_value, get_out): out = get_out.splitlines() wvpasseq(1, len(out)) get_tag_id = out[0] wvpasseq(commit_id, get_tag_id) # Make sure tmp doesn't already exist. exr = exo((b'git', b'--git-dir', b'get-dest', b'show-ref', b'tmp-branch-for-tag'), check=False) wvpasseq(1, exr.rc) ex((b'git', b'--git-dir', b'get-dest', b'branch', b'tmp-branch-for-tag', b'refs/tags/' + tag_name)) _validate_save(orig_value, b'tmp-branch-for-tag/latest' + restore_subpath, commit_id, tree_id) ex((b'git', b'--git-dir', b'get-dest', b'branch', b'-D', b'tmp-branch-for-tag'))
def check_prune_result(expected): actual = sorted([int(x) for x in exo([b'git', b'log', b'--pretty=format:%at']).out.splitlines()]) if expected != actual: for x in expected: print('ex:', x, strftime('%Y-%m-%d-%H%M%S', localtime(x)), file=stderr) for line in diff_bytes(unified_diff, [result_diffline(x) for x in expected], [result_diffline(x) for x in actual], fromfile=b'expected', tofile=b'actual'): sys.stderr.flush() byte_stream(sys.stderr).write(line) wvpass(expected == actual)
def verify_trees_match(path1, path2): global top exr = exo((top + b'/dev/compare-trees', b'-c', path1, path2), check=False) stdout.write(exr.out) sys.stdout.flush() wvcheck(exr.rc == 0, 'process exit %d == 0' % exr.rc)
def test_resolve(repo, tmpdir): data_path = tmpdir + b'/src' resolve = repo.resolve save_time = 100000 save_time_str = strftime('%Y-%m-%d-%H%M%S', localtime(save_time)).encode('ascii') os.mkdir(data_path) os.mkdir(data_path + b'/dir') with open(data_path + b'/file', 'wb+') as tmpfile: tmpfile.write(b'canary\n') symlink(b'file', data_path + b'/file-symlink') symlink(b'dir', data_path + b'/dir-symlink') symlink(b'not-there', data_path + b'/bad-symlink') ex((bup_path, b'index', b'-v', data_path)) ex((bup_path, b'save', b'-d', b'%d' % save_time, b'-tvvn', b'test', b'--strip', data_path)) ex((bup_path, b'tag', b'test-tag', b'test')) tip_hash = exo((b'git', b'show-ref', b'refs/heads/test'))[0] tip_oidx = tip_hash.strip().split()[0] tip_oid = unhexlify(tip_oidx) tip_tree_oidx = exo((b'git', b'log', b'--pretty=%T', b'-n1', tip_oidx))[0].strip() tip_tree_oid = unhexlify(tip_tree_oidx) tip_tree = tree_dict(repo, tip_tree_oid) test_revlist_w_meta = vfs.RevList(meta=tip_tree[b'.'].meta, oid=tip_oid) expected_latest_item = vfs.Commit(meta=S_IFDIR | 0o755, oid=tip_tree_oid, coid=tip_oid) expected_latest_item_w_meta = vfs.Commit(meta=tip_tree[b'.'].meta, oid=tip_tree_oid, coid=tip_oid) expected_latest_link = vfs.FakeLink(meta=vfs.default_symlink_mode, target=save_time_str) expected_test_tag_item = expected_latest_item wvstart('resolve: /') vfs.clear_cache() res = resolve(b'/') wvpasseq(1, len(res)) wvpasseq(((b'', vfs._root),), res) ignore, root_item = res[0] root_content = frozenset(vfs.contents(repo, root_item)) wvpasseq(frozenset([(b'.', root_item), (b'.tag', vfs._tags), (b'test', test_revlist_w_meta)]), root_content) for path in (b'//', b'/.', b'/./', b'/..', b'/../', b'/test/latest/dir/../../..', b'/test/latest/dir/../../../', b'/test/latest/dir/../../../.', b'/test/latest/dir/../../..//', b'/test//latest/dir/../../..', b'/test/./latest/dir/../../..', b'/test/././latest/dir/../../..', b'/test/.//./latest/dir/../../..', b'/test//.//.//latest/dir/../../..' b'/test//./latest/dir/../../..'): wvstart('resolve: ' + path_msg(path)) vfs.clear_cache() res = resolve(path) wvpasseq(((b'', vfs._root),), res) wvstart('resolve: /.tag') vfs.clear_cache() res = resolve(b'/.tag') wvpasseq(2, len(res)) wvpasseq(((b'', vfs._root), (b'.tag', vfs._tags)), res) ignore, tag_item = res[1] tag_content = frozenset(vfs.contents(repo, tag_item)) wvpasseq(frozenset([(b'.', tag_item), (b'test-tag', expected_test_tag_item)]), tag_content) wvstart('resolve: /test') vfs.clear_cache() res = resolve(b'/test') wvpasseq(2, len(res)) wvpasseq(((b'', vfs._root), (b'test', test_revlist_w_meta)), res) ignore, test_item = res[1] test_content = frozenset(vfs.contents(repo, test_item)) # latest has metadata here due to caching wvpasseq(frozenset([(b'.', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), (b'latest', expected_latest_link)]), test_content) wvstart('resolve: /test/latest') vfs.clear_cache() res = resolve(b'/test/latest') wvpasseq(3, len(res)) expected_latest_item_w_meta = vfs.Commit(meta=tip_tree[b'.'].meta, oid=tip_tree_oid, coid=tip_oid) expected = ((b'', vfs._root), (b'test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta)) wvpasseq(expected, res) ignore, latest_item = res[2] latest_content = frozenset(vfs.contents(repo, latest_item)) expected = frozenset((x.name, vfs.Item(oid=x.oid, meta=x.meta)) for x in (tip_tree[name] for name in (b'.', b'bad-symlink', b'dir', b'dir-symlink', b'file', b'file-symlink'))) wvpasseq(expected, latest_content) wvstart('resolve: /test/latest/file') vfs.clear_cache() res = resolve(b'/test/latest/file') wvpasseq(4, len(res)) expected_file_item_w_meta = vfs.Item(meta=tip_tree[b'file'].meta, oid=tip_tree[b'file'].oid) expected = ((b'', vfs._root), (b'test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), (b'file', expected_file_item_w_meta)) wvpasseq(expected, res) wvstart('resolve: /test/latest/bad-symlink') vfs.clear_cache() res = resolve(b'/test/latest/bad-symlink') wvpasseq(4, len(res)) expected = ((b'', vfs._root), (b'test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), (b'not-there', None)) wvpasseq(expected, res) wvstart('resolve nofollow: /test/latest/bad-symlink') vfs.clear_cache() res = resolve(b'/test/latest/bad-symlink', follow=False) wvpasseq(4, len(res)) bad_symlink_value = tip_tree[b'bad-symlink'] expected_bad_symlink_item_w_meta = vfs.Item(meta=bad_symlink_value.meta, oid=bad_symlink_value.oid) expected = ((b'', vfs._root), (b'test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), (b'bad-symlink', expected_bad_symlink_item_w_meta)) wvpasseq(expected, res) wvstart('resolve: /test/latest/file-symlink') vfs.clear_cache() res = resolve(b'/test/latest/file-symlink') wvpasseq(4, len(res)) expected = ((b'', vfs._root), (b'test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), (b'file', expected_file_item_w_meta)) wvpasseq(expected, res) wvstart('resolve nofollow: /test/latest/file-symlink') vfs.clear_cache() res = resolve(b'/test/latest/file-symlink', follow=False) wvpasseq(4, len(res)) file_symlink_value = tip_tree[b'file-symlink'] expected_file_symlink_item_w_meta = vfs.Item(meta=file_symlink_value.meta, oid=file_symlink_value.oid) expected = ((b'', vfs._root), (b'test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), (b'file-symlink', expected_file_symlink_item_w_meta)) wvpasseq(expected, res) wvstart('resolve: /test/latest/missing') vfs.clear_cache() res = resolve(b'/test/latest/missing') wvpasseq(4, len(res)) name, item = res[-1] wvpasseq(b'missing', name) wvpass(item is None) for path in (b'/test/latest/file/', b'/test/latest/file/.', b'/test/latest/file/..', b'/test/latest/file/../', b'/test/latest/file/../.', b'/test/latest/file/../..', b'/test/latest/file/foo'): wvstart('resolve: ' + path_msg(path)) vfs.clear_cache() try: resolve(path) except vfs.IOError as res_ex: wvpasseq(ENOTDIR, res_ex.errno) wvpasseq([b'', b'test', save_time_str, b'file'], [name for name, item in res_ex.terminus]) for path in (b'/test/latest/file-symlink/', b'/test/latest/file-symlink/.', b'/test/latest/file-symlink/..', b'/test/latest/file-symlink/../', b'/test/latest/file-symlink/../.', b'/test/latest/file-symlink/../..'): wvstart('resolve nofollow: ' + path_msg(path)) vfs.clear_cache() try: resolve(path, follow=False) except vfs.IOError as res_ex: wvpasseq(ENOTDIR, res_ex.errno) wvpasseq([b'', b'test', save_time_str, b'file'], [name for name, item in res_ex.terminus]) wvstart('resolve: non-directory parent') vfs.clear_cache() file_res = resolve(b'/test/latest/file') try: resolve(b'foo', parent=file_res) except vfs.IOError as res_ex: wvpasseq(ENOTDIR, res_ex.errno) wvpasseq(None, res_ex.terminus) wvstart('resolve nofollow: /test/latest/dir-symlink') vfs.clear_cache() res = resolve(b'/test/latest/dir-symlink', follow=False) wvpasseq(4, len(res)) dir_symlink_value = tip_tree[b'dir-symlink'] expected_dir_symlink_item_w_meta = vfs.Item(meta=dir_symlink_value.meta, oid=dir_symlink_value.oid) expected = ((b'', vfs._root), (b'test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), (b'dir-symlink', expected_dir_symlink_item_w_meta)) wvpasseq(expected, res) dir_value = tip_tree[b'dir'] expected_dir_item = vfs.Item(oid=dir_value.oid, meta=tree_dict(repo, dir_value.oid)[b'.'].meta) expected = ((b'', vfs._root), (b'test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), (b'dir', expected_dir_item)) def lresolve(*args, **keys): return resolve(*args, **dict(keys, follow=False)) for resname, resolver in (('resolve', resolve), ('resolve nofollow', lresolve)): for path in (b'/test/latest/dir-symlink/', b'/test/latest/dir-symlink/.'): wvstart(resname + ': ' + path_msg(path)) vfs.clear_cache() res = resolver(path) wvpasseq(4, len(res)) wvpasseq(expected, res) wvstart('resolve: /test/latest/dir-symlink') vfs.clear_cache() res = resolve(path) wvpasseq(4, len(res)) wvpasseq(expected, res)
def test_ftp(tmpdir): environ[b'BUP_DIR'] = tmpdir + b'/repo' environ[b'GIT_DIR'] = tmpdir + b'/repo' environ[b'TZ'] = b'UTC' tzset() chdir(tmpdir) mkdir(b'src') chdir(b'src') mkdir(b'dir') with open(b'file-1', 'wb') as f: f.write(b'excitement!\n') with open(b'dir/file-2', 'wb') as f: f.write(b'more excitement!\n') symlink(b'file-1', b'file-symlink') symlink(b'dir', b'dir-symlink') symlink(b'not-there', b'bad-symlink') chdir(tmpdir) bup(b'init') bup(b'index', b'src') bup(b'save', b'-n', b'src', b'--strip', b'src') save_utc = int( exo((b'git', b'show', b'-s', b'--format=%at', b'src')).out.strip()) save_name = strftime('%Y-%m-%d-%H%M%S', localtime(save_utc)).encode('ascii') wvstart('help') wvpasseq(b'Commands: ls cd pwd cat get mget help quit\n', exo((bup_cmd, b'ftp'), input=b'help\n', stderr=PIPE).out) wvstart('pwd/cd') wvpasseq(b'/\n', bup(b'ftp', input=b'pwd\n').out) wvpasseq(b'', bup(b'ftp', input=b'cd src\n').out) wvpasseq(b'/src\n', bup(b'ftp', input=jl(b'cd src', b'pwd')).out) wvpasseq(b'/src\n/\n', bup(b'ftp', input=jl(b'cd src', b'pwd', b'cd ..', b'pwd')).out) wvpasseq( b'/src\n/\n', bup(b'ftp', input=jl(b'cd src', b'pwd', b'cd ..', b'cd ..', b'pwd')).out) wvpasseq(b'/src/%s/dir\n' % save_name, bup(b'ftp', input=jl(b'cd src/latest/dir-symlink', b'pwd')).out) wvpasseq(b'/src/%s/dir\n' % save_name, bup(b'ftp', input=jl(b'cd src latest dir-symlink', b'pwd')).out) wvpassne( 0, bup(b'ftp', input=jl(b'cd src/latest/bad-symlink', b'pwd'), check=False, stdout=None).rc) wvpassne( 0, bup(b'ftp', input=jl(b'cd src/latest/not-there', b'pwd'), check=False, stdout=None).rc) wvstart('ls') # FIXME: elaborate wvpasseq(b'src\n', bup(b'ftp', input=b'ls\n').out) wvpasseq(save_name + b'\nlatest\n', bup(b'ftp', input=b'ls src\n').out) wvstart('cat') wvpasseq(b'excitement!\n', bup(b'ftp', input=b'cat src/latest/file-1\n').out) wvpasseq( b'excitement!\nmore excitement!\n', bup(b'ftp', input=b'cat src/latest/file-1 src/latest/dir/file-2\n').out) wvstart('get') bup(b'ftp', input=jl(b'get src/latest/file-1 dest')) with open(b'dest', 'rb') as f: wvpasseq(b'excitement!\n', f.read()) unlink(b'dest') bup(b'ftp', input=jl(b'get src/latest/file-symlink dest')) with open(b'dest', 'rb') as f: wvpasseq(b'excitement!\n', f.read()) unlink(b'dest') wvpassne( 0, bup(b'ftp', input=jl(b'get src/latest/bad-symlink dest'), check=False, stdout=None).rc) wvpassne( 0, bup(b'ftp', input=jl(b'get src/latest/not-there'), check=False, stdout=None).rc) wvstart('mget') unlink_if_exists(b'file-1') bup(b'ftp', input=jl(b'mget src/latest/file-1')) with open(b'file-1', 'rb') as f: wvpasseq(b'excitement!\n', f.read()) unlink_if_exists(b'file-1') unlink_if_exists(b'file-2') bup(b'ftp', input=jl(b'mget src/latest/file-1 src/latest/dir/file-2')) with open(b'file-1', 'rb') as f: wvpasseq(b'excitement!\n', f.read()) with open(b'file-2', 'rb') as f: wvpasseq(b'more excitement!\n', f.read()) unlink_if_exists(b'file-symlink') bup(b'ftp', input=jl(b'mget src/latest/file-symlink')) with open(b'file-symlink', 'rb') as f: wvpasseq(b'excitement!\n', f.read()) wvpassne( 0, bup(b'ftp', input=jl(b'mget src/latest/bad-symlink dest'), check=False, stdout=None).rc) # bup mget currently always does pattern matching bup(b'ftp', input=b'mget src/latest/not-there\n')
def bup(*args, **kwargs): if 'stdout' not in kwargs: return exo((bup_cmd, ) + args, **kwargs) return ex((bup_cmd, ) + args, **kwargs)
def test_resolve(): with no_lingering_errors(): with test_tempdir('bup-tvfs-') as tmpdir: resolve = vfs.resolve bup_dir = tmpdir + '/bup' environ['GIT_DIR'] = bup_dir environ['BUP_DIR'] = bup_dir git.repodir = bup_dir data_path = tmpdir + '/src' save_time = 100000 save_time_str = strftime('%Y-%m-%d-%H%M%S', localtime(save_time)) os.mkdir(data_path) os.mkdir(data_path + '/dir') with open(data_path + '/file', 'w+') as tmpfile: print('canary', file=tmpfile) symlink('file', data_path + '/file-symlink') symlink('dir', data_path + '/dir-symlink') symlink('not-there', data_path + '/bad-symlink') ex((bup_path, 'init')) ex((bup_path, 'index', '-v', data_path)) ex((bup_path, 'save', '-d', str(save_time), '-tvvn', 'test', '--strip', data_path)) ex((bup_path, 'tag', 'test-tag', 'test')) repo = LocalRepo() tip_hash = exo(('git', 'show-ref', 'refs/heads/test'))[0] tip_oidx = tip_hash.strip().split()[0] tip_oid = tip_oidx.decode('hex') tip_tree_oidx = exo( ('git', 'log', '--pretty=%T', '-n1', tip_oidx))[0].strip() tip_tree_oid = tip_tree_oidx.decode('hex') tip_tree = tree_dict(repo, tip_tree_oid) test_revlist_w_meta = vfs.RevList(meta=tip_tree['.'].meta, oid=tip_oid) expected_latest_item = vfs.Commit(meta=S_IFDIR | 0o755, oid=tip_tree_oid, coid=tip_oid) expected_latest_item_w_meta = vfs.Commit(meta=tip_tree['.'].meta, oid=tip_tree_oid, coid=tip_oid) expected_latest_link = vfs.FakeLink(meta=vfs.default_symlink_mode, target=save_time_str) expected_test_tag_item = expected_latest_item wvstart('resolve: /') vfs.clear_cache() res = resolve(repo, '/') wvpasseq(1, len(res)) wvpasseq((('', vfs._root), ), res) ignore, root_item = res[0] root_content = frozenset(vfs.contents(repo, root_item)) wvpasseq( frozenset([('.', root_item), ('.tag', vfs._tags), ('test', test_revlist_w_meta)]), root_content) for path in ('//', '/.', '/./', '/..', '/../', '/test/latest/dir/../../..', '/test/latest/dir/../../../', '/test/latest/dir/../../../.', '/test/latest/dir/../../..//', '/test//latest/dir/../../..', '/test/./latest/dir/../../..', '/test/././latest/dir/../../..', '/test/.//./latest/dir/../../..', '/test//.//.//latest/dir/../../..' '/test//./latest/dir/../../..'): wvstart('resolve: ' + path) vfs.clear_cache() res = resolve(repo, path) wvpasseq((('', vfs._root), ), res) wvstart('resolve: /.tag') vfs.clear_cache() res = resolve(repo, '/.tag') wvpasseq(2, len(res)) wvpasseq((('', vfs._root), ('.tag', vfs._tags)), res) ignore, tag_item = res[1] tag_content = frozenset(vfs.contents(repo, tag_item)) wvpasseq( frozenset([('.', tag_item), ('test-tag', expected_test_tag_item)]), tag_content) wvstart('resolve: /test') vfs.clear_cache() res = resolve(repo, '/test') wvpasseq(2, len(res)) wvpasseq((('', vfs._root), ('test', test_revlist_w_meta)), res) ignore, test_item = res[1] test_content = frozenset(vfs.contents(repo, test_item)) # latest has metadata here due to caching wvpasseq( frozenset([('.', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('latest', expected_latest_link)]), test_content) wvstart('resolve: /test/latest') vfs.clear_cache() res = resolve(repo, '/test/latest') wvpasseq(3, len(res)) expected_latest_item_w_meta = vfs.Commit(meta=tip_tree['.'].meta, oid=tip_tree_oid, coid=tip_oid) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta)) wvpasseq(expected, res) ignore, latest_item = res[2] latest_content = frozenset(vfs.contents(repo, latest_item)) expected = frozenset( (x.name, vfs.Item(oid=x.oid, meta=x.meta)) for x in (tip_tree[name] for name in ('.', 'bad-symlink', 'dir', 'dir-symlink', 'file', 'file-symlink'))) wvpasseq(expected, latest_content) wvstart('resolve: /test/latest/file') vfs.clear_cache() res = resolve(repo, '/test/latest/file') wvpasseq(4, len(res)) expected_file_item_w_meta = vfs.Item(meta=tip_tree['file'].meta, oid=tip_tree['file'].oid) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('file', expected_file_item_w_meta)) wvpasseq(expected, res) wvstart('resolve: /test/latest/bad-symlink') vfs.clear_cache() res = resolve(repo, '/test/latest/bad-symlink') wvpasseq(4, len(res)) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('not-there', None)) wvpasseq(expected, res) wvstart('resolve nofollow: /test/latest/bad-symlink') vfs.clear_cache() res = resolve(repo, '/test/latest/bad-symlink', follow=False) wvpasseq(4, len(res)) bad_symlink_value = tip_tree['bad-symlink'] expected_bad_symlink_item_w_meta = vfs.Item( meta=bad_symlink_value.meta, oid=bad_symlink_value.oid) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('bad-symlink', expected_bad_symlink_item_w_meta)) wvpasseq(expected, res) wvstart('resolve: /test/latest/file-symlink') vfs.clear_cache() res = resolve(repo, '/test/latest/file-symlink') wvpasseq(4, len(res)) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('file', expected_file_item_w_meta)) wvpasseq(expected, res) wvstart('resolve nofollow: /test/latest/file-symlink') vfs.clear_cache() res = resolve(repo, '/test/latest/file-symlink', follow=False) wvpasseq(4, len(res)) file_symlink_value = tip_tree['file-symlink'] expected_file_symlink_item_w_meta = vfs.Item( meta=file_symlink_value.meta, oid=file_symlink_value.oid) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('file-symlink', expected_file_symlink_item_w_meta)) wvpasseq(expected, res) wvstart('resolve: /test/latest/missing') vfs.clear_cache() res = resolve(repo, '/test/latest/missing') wvpasseq(4, len(res)) name, item = res[-1] wvpasseq('missing', name) wvpass(item is None) for path in ('/test/latest/file/', '/test/latest/file/.', '/test/latest/file/..', '/test/latest/file/../', '/test/latest/file/../.', '/test/latest/file/../..', '/test/latest/file/foo'): wvstart('resolve: ' + path) vfs.clear_cache() try: resolve(repo, path) except vfs.IOError as res_ex: wvpasseq(ENOTDIR, res_ex.errno) wvpasseq(['', 'test', save_time_str, 'file'], [name for name, item in res_ex.terminus]) for path in ('/test/latest/file-symlink/', '/test/latest/file-symlink/.', '/test/latest/file-symlink/..', '/test/latest/file-symlink/../', '/test/latest/file-symlink/../.', '/test/latest/file-symlink/../..'): wvstart('resolve nofollow: ' + path) vfs.clear_cache() try: resolve(repo, path, follow=False) except vfs.IOError as res_ex: wvpasseq(ENOTDIR, res_ex.errno) wvpasseq(['', 'test', save_time_str, 'file'], [name for name, item in res_ex.terminus]) wvstart('resolve: non-directory parent') vfs.clear_cache() file_res = resolve(repo, '/test/latest/file') try: resolve(repo, 'foo', parent=file_res) except vfs.IOError as res_ex: wvpasseq(ENOTDIR, res_ex.errno) wvpasseq(None, res_ex.terminus) wvstart('resolve nofollow: /test/latest/dir-symlink') vfs.clear_cache() res = resolve(repo, '/test/latest/dir-symlink', follow=False) wvpasseq(4, len(res)) dir_symlink_value = tip_tree['dir-symlink'] expected_dir_symlink_item_w_meta = vfs.Item( meta=dir_symlink_value.meta, oid=dir_symlink_value.oid) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('dir-symlink', expected_dir_symlink_item_w_meta)) wvpasseq(expected, res) dir_value = tip_tree['dir'] expected_dir_item = vfs.Item(oid=dir_value.oid, meta=tree_dict( repo, dir_value.oid)['.'].meta) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('dir', expected_dir_item)) def lresolve(*args, **keys): return resolve(*args, **dict(keys, follow=False)) for resname, resolver in (('resolve', resolve), ('resolve nofollow', lresolve)): for path in ('/test/latest/dir-symlink/', '/test/latest/dir-symlink/.'): wvstart(resname + ': ' + path) vfs.clear_cache() res = resolver(repo, path) wvpasseq(4, len(res)) wvpasseq(expected, res) wvstart('resolve: /test/latest/dir-symlink') vfs.clear_cache() res = resolve(repo, path) wvpasseq(4, len(res)) wvpasseq(expected, res)
def test_prune_older(tmpdir): environ[b'GIT_AUTHOR_NAME'] = b'bup test' environ[b'GIT_COMMITTER_NAME'] = b'bup test' environ[b'GIT_AUTHOR_EMAIL'] = b'bup@a425bc70a02811e49bdf73ee56450e6f' environ[b'GIT_COMMITTER_EMAIL'] = b'bup@a425bc70a02811e49bdf73ee56450e6f' seed = int(environ.get(b'BUP_TEST_SEED', time())) random.seed(seed) print('random seed:', seed, file=stderr) save_population = int(environ.get(b'BUP_TEST_PRUNE_OLDER_SAVES', 2000)) prune_cycles = int(environ.get(b'BUP_TEST_PRUNE_OLDER_CYCLES', 20)) prune_gc_cycles = int(environ.get(b'BUP_TEST_PRUNE_OLDER_GC_CYCLES', 10)) bup_cmd = bup.path.exe() environ[b'BUP_DIR'] = tmpdir + b'/work/.git' environ[b'GIT_DIR'] = tmpdir + b'/work/.git' now = int(time()) three_years_ago = now - (60 * 60 * 24 * 366 * 3) chdir(tmpdir) ex([b'git', b'init', b'work']) ex([b'git', b'config', b'gc.autoDetach', b'false']) wvstart('generating ' + str(save_population) + ' random saves') chdir(tmpdir + b'/work') save_utcs = create_older_random_saves(save_population, three_years_ago, now) chdir(tmpdir) test_set_hash = exo([b'git', b'show-ref', b'-s', b'master']).out.rstrip() ls_saves = exo((bup_cmd, b'ls', b'master')).out.splitlines() wvpasseq(save_population + 1, len(ls_saves)) wvstart('ensure everything kept, if no keep arguments') ex([b'git', b'reset', b'--hard', test_set_hash]) proc = ex((bup_cmd, b'prune-older', b'-v', b'--unsafe', b'--no-gc', b'--wrt', b'%d' % now) \ + (b'master',), stdout=None, stderr=PIPE, check=False) wvpassne(proc.rc, 0) wvpass(b'at least one keep argument is required' in proc.err) check_prune_result(save_utcs) wvstart('running %d generative no-gc tests on %d saves' % (prune_cycles, save_population)) for spec in unique_period_specs(prune_cycles, # Make it more likely we'll have # some outside the save range. three_years_ago - period_scale[b'm'], now): ex([b'git', b'reset', b'--hard', test_set_hash]) expected = sorted(expected_retentions(save_utcs, now, spec)) ex((bup_cmd, b'prune-older', b'-v', b'--unsafe', b'--no-gc', b'--wrt', b'%d' % now) \ + period_spec_to_period_args(spec) \ + (b'master',)) check_prune_result(expected) # More expensive because we have to recreate the repo each time wvstart('running %d generative gc tests on %d saves' % (prune_gc_cycles, save_population)) ex([b'git', b'reset', b'--hard', test_set_hash]) copytree(b'work/.git', b'clean-test-repo', symlinks=True) for spec in unique_period_specs(prune_gc_cycles, # Make it more likely we'll have # some outside the save range. three_years_ago - period_scale[b'm'], now): rmtree(b'work/.git') copytree(b'clean-test-repo', b'work/.git') expected = sorted(expected_retentions(save_utcs, now, spec)) ex((bup_cmd, b'prune-older', b'-v', b'--unsafe', b'--wrt', b'%d' % now) \ + period_spec_to_period_args(spec) \ + (b'master',)) check_prune_result(expected)
def create_get_src(): global bup_cmd, src_info wvstart('preparing') ex((bup_cmd, b'-d', b'get-src', b'init')) mkdir(b'src') open(b'src/unrelated', 'a').close() ex((bup_cmd, b'-d', b'get-src', b'index', b'src')) ex((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'unrelated-branch', b'src')) ex((bup_cmd, b'-d', b'get-src', b'index', b'--clear')) rmrf(b'src') mkdir(b'src') open(b'src/zero', 'a').close() ex((bup_cmd, b'-d', b'get-src', b'index', b'src')) exr = exo((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'src', b'src')) out = exr.out.splitlines() tree_0_id = out[0] commit_0_id = out[-1] exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src')) save_0 = exr.out.splitlines()[0] ex((b'git', b'--git-dir', b'get-src', b'branch', b'src-0', b'src')) ex((b'cp', b'-RPp', b'src', b'src-0')) rmrf(b'src') mkdir(b'src') mkdir(b'src/x') mkdir(b'src/x/y') ex((bup_cmd + b' -d get-src random 1k > src/1'), shell=True) ex((bup_cmd + b' -d get-src random 1k > src/x/2'), shell=True) ex((bup_cmd, b'-d', b'get-src', b'index', b'src')) exr = exo((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'src', b'src')) out = exr.out.splitlines() tree_1_id = out[0] commit_1_id = out[-1] exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src')) save_1 = exr.out.splitlines()[1] ex((b'git', b'--git-dir', b'get-src', b'branch', b'src-1', b'src')) ex((b'cp', b'-RPp', b'src', b'src-1')) # Make a copy the current state of src so we'll have an ancestor. ex((b'cp', b'-RPp', b'get-src/refs/heads/src', b'get-src/refs/heads/src-ancestor')) with open(b'src/tiny-file', 'ab') as f: f.write(b'xyzzy') ex((bup_cmd, b'-d', b'get-src', b'index', b'src')) ex((bup_cmd, b'-d', b'get-src', b'tick')) # Ensure the save names differ exr = exo((bup_cmd, b'-d', b'get-src', b'save', b'-tcn', b'src', b'src')) out = exr.out.splitlines() tree_2_id = out[0] commit_2_id = out[-1] exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'src')) save_2 = exr.out.splitlines()[2] rename(b'src', b'src-2') src_root = getcwd() + b'/src' subtree_path = b'src-2/x' subtree_vfs_path = src_root + b'/x' # No support for "ls -d", so grep... exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'-s', b'src/latest' + src_root)) out = exr.out.splitlines() subtree_id = None for line in out: if b'x' in line: subtree_id = line.split()[0] assert(subtree_id) # With a tiny file, we'll get a single blob, not a chunked tree tinyfile_path = src_root + b'/tiny-file' exr = exo((bup_cmd, b'-d', b'get-src', b'ls', b'-s', b'src/latest' + tinyfile_path)) tinyfile_id = exr.out.splitlines()[0].split()[0] ex((bup_cmd, b'-d', b'get-src', b'tag', b'tinyfile', tinyfile_id)) ex((bup_cmd, b'-d', b'get-src', b'tag', b'subtree', subtree_id)) ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-0', tree_0_id)) ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-1', tree_1_id)) ex((bup_cmd, b'-d', b'get-src', b'tag', b'tree-2', tree_2_id)) ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-0', commit_0_id)) ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-1', commit_1_id)) ex((bup_cmd, b'-d', b'get-src', b'tag', b'commit-2', commit_2_id)) ex((b'git', b'--git-dir', b'get-src', b'branch', b'commit-1', commit_1_id)) ex((b'git', b'--git-dir', b'get-src', b'branch', b'commit-2', commit_2_id)) return {'tinyfile-path' : tinyfile_path, 'tinyfile-id' : tinyfile_id, 'subtree-id' : subtree_id, 'tree-0-id' : tree_0_id, 'tree-1-id' : tree_1_id, 'tree-2-id' : tree_2_id, 'commit-0-id' : commit_0_id, 'commit-1-id' : commit_1_id, 'commit-2-id' : commit_2_id, 'save-1' : save_1, 'save-2' : save_2, 'subtree-path' : subtree_path, 'subtree-vfs-path' : subtree_vfs_path}
def test_resolve(repo, tmpdir): data_path = tmpdir + '/src' resolve = repo.resolve save_time = 100000 save_time_str = strftime('%Y-%m-%d-%H%M%S', localtime(save_time)) os.mkdir(data_path) os.mkdir(data_path + '/dir') with open(data_path + '/file', 'w+') as tmpfile: print('canary', file=tmpfile) symlink('file', data_path + '/file-symlink') symlink('dir', data_path + '/dir-symlink') symlink('not-there', data_path + '/bad-symlink') ex((bup_path, 'index', '-v', data_path)) ex((bup_path, 'save', '-d', str(save_time), '-tvvn', 'test', '--strip', data_path)) ex((bup_path, 'tag', 'test-tag', 'test')) tip_hash = exo(('git', 'show-ref', 'refs/heads/test'))[0] tip_oidx = tip_hash.strip().split()[0] tip_oid = tip_oidx.decode('hex') tip_tree_oidx = exo(('git', 'log', '--pretty=%T', '-n1', tip_oidx))[0].strip() tip_tree_oid = tip_tree_oidx.decode('hex') tip_tree = tree_dict(repo, tip_tree_oid) test_revlist_w_meta = vfs.RevList(meta=tip_tree['.'].meta, oid=tip_oid) expected_latest_item = vfs.Commit(meta=S_IFDIR | 0o755, oid=tip_tree_oid, coid=tip_oid) expected_latest_item_w_meta = vfs.Commit(meta=tip_tree['.'].meta, oid=tip_tree_oid, coid=tip_oid) expected_latest_link = vfs.FakeLink(meta=vfs.default_symlink_mode, target=save_time_str) expected_test_tag_item = expected_latest_item wvstart('resolve: /') vfs.clear_cache() res = resolve('/') wvpasseq(1, len(res)) wvpasseq((('', vfs._root),), res) ignore, root_item = res[0] root_content = frozenset(vfs.contents(repo, root_item)) wvpasseq(frozenset([('.', root_item), ('.tag', vfs._tags), ('test', test_revlist_w_meta)]), root_content) for path in ('//', '/.', '/./', '/..', '/../', '/test/latest/dir/../../..', '/test/latest/dir/../../../', '/test/latest/dir/../../../.', '/test/latest/dir/../../..//', '/test//latest/dir/../../..', '/test/./latest/dir/../../..', '/test/././latest/dir/../../..', '/test/.//./latest/dir/../../..', '/test//.//.//latest/dir/../../..' '/test//./latest/dir/../../..'): wvstart('resolve: ' + path) vfs.clear_cache() res = resolve(path) wvpasseq((('', vfs._root),), res) wvstart('resolve: /.tag') vfs.clear_cache() res = resolve('/.tag') wvpasseq(2, len(res)) wvpasseq((('', vfs._root), ('.tag', vfs._tags)), res) ignore, tag_item = res[1] tag_content = frozenset(vfs.contents(repo, tag_item)) wvpasseq(frozenset([('.', tag_item), ('test-tag', expected_test_tag_item)]), tag_content) wvstart('resolve: /test') vfs.clear_cache() res = resolve('/test') wvpasseq(2, len(res)) wvpasseq((('', vfs._root), ('test', test_revlist_w_meta)), res) ignore, test_item = res[1] test_content = frozenset(vfs.contents(repo, test_item)) # latest has metadata here due to caching wvpasseq(frozenset([('.', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('latest', expected_latest_link)]), test_content) wvstart('resolve: /test/latest') vfs.clear_cache() res = resolve('/test/latest') wvpasseq(3, len(res)) expected_latest_item_w_meta = vfs.Commit(meta=tip_tree['.'].meta, oid=tip_tree_oid, coid=tip_oid) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta)) wvpasseq(expected, res) ignore, latest_item = res[2] latest_content = frozenset(vfs.contents(repo, latest_item)) expected = frozenset((x.name, vfs.Item(oid=x.oid, meta=x.meta)) for x in (tip_tree[name] for name in ('.', 'bad-symlink', 'dir', 'dir-symlink', 'file', 'file-symlink'))) wvpasseq(expected, latest_content) wvstart('resolve: /test/latest/file') vfs.clear_cache() res = resolve('/test/latest/file') wvpasseq(4, len(res)) expected_file_item_w_meta = vfs.Item(meta=tip_tree['file'].meta, oid=tip_tree['file'].oid) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('file', expected_file_item_w_meta)) wvpasseq(expected, res) wvstart('resolve: /test/latest/bad-symlink') vfs.clear_cache() res = resolve('/test/latest/bad-symlink') wvpasseq(4, len(res)) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('not-there', None)) wvpasseq(expected, res) wvstart('resolve nofollow: /test/latest/bad-symlink') vfs.clear_cache() res = resolve('/test/latest/bad-symlink', follow=False) wvpasseq(4, len(res)) bad_symlink_value = tip_tree['bad-symlink'] expected_bad_symlink_item_w_meta = vfs.Item(meta=bad_symlink_value.meta, oid=bad_symlink_value.oid) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('bad-symlink', expected_bad_symlink_item_w_meta)) wvpasseq(expected, res) wvstart('resolve: /test/latest/file-symlink') vfs.clear_cache() res = resolve('/test/latest/file-symlink') wvpasseq(4, len(res)) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('file', expected_file_item_w_meta)) wvpasseq(expected, res) wvstart('resolve nofollow: /test/latest/file-symlink') vfs.clear_cache() res = resolve('/test/latest/file-symlink', follow=False) wvpasseq(4, len(res)) file_symlink_value = tip_tree['file-symlink'] expected_file_symlink_item_w_meta = vfs.Item(meta=file_symlink_value.meta, oid=file_symlink_value.oid) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('file-symlink', expected_file_symlink_item_w_meta)) wvpasseq(expected, res) wvstart('resolve: /test/latest/missing') vfs.clear_cache() res = resolve('/test/latest/missing') wvpasseq(4, len(res)) name, item = res[-1] wvpasseq('missing', name) wvpass(item is None) for path in ('/test/latest/file/', '/test/latest/file/.', '/test/latest/file/..', '/test/latest/file/../', '/test/latest/file/../.', '/test/latest/file/../..', '/test/latest/file/foo'): wvstart('resolve: ' + path) vfs.clear_cache() try: resolve(path) except vfs.IOError as res_ex: wvpasseq(ENOTDIR, res_ex.errno) wvpasseq(['', 'test', save_time_str, 'file'], [name for name, item in res_ex.terminus]) for path in ('/test/latest/file-symlink/', '/test/latest/file-symlink/.', '/test/latest/file-symlink/..', '/test/latest/file-symlink/../', '/test/latest/file-symlink/../.', '/test/latest/file-symlink/../..'): wvstart('resolve nofollow: ' + path) vfs.clear_cache() try: resolve(path, follow=False) except vfs.IOError as res_ex: wvpasseq(ENOTDIR, res_ex.errno) wvpasseq(['', 'test', save_time_str, 'file'], [name for name, item in res_ex.terminus]) wvstart('resolve: non-directory parent') vfs.clear_cache() file_res = resolve('/test/latest/file') try: resolve('foo', parent=file_res) except vfs.IOError as res_ex: wvpasseq(ENOTDIR, res_ex.errno) wvpasseq(None, res_ex.terminus) wvstart('resolve nofollow: /test/latest/dir-symlink') vfs.clear_cache() res = resolve('/test/latest/dir-symlink', follow=False) wvpasseq(4, len(res)) dir_symlink_value = tip_tree['dir-symlink'] expected_dir_symlink_item_w_meta = vfs.Item(meta=dir_symlink_value.meta, oid=dir_symlink_value.oid) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('dir-symlink', expected_dir_symlink_item_w_meta)) wvpasseq(expected, res) dir_value = tip_tree['dir'] expected_dir_item = vfs.Item(oid=dir_value.oid, meta=tree_dict(repo, dir_value.oid)['.'].meta) expected = (('', vfs._root), ('test', test_revlist_w_meta), (save_time_str, expected_latest_item_w_meta), ('dir', expected_dir_item)) def lresolve(*args, **keys): return resolve(*args, **dict(keys, follow=False)) for resname, resolver in (('resolve', resolve), ('resolve nofollow', lresolve)): for path in ('/test/latest/dir-symlink/', '/test/latest/dir-symlink/.'): wvstart(resname + ': ' + path) vfs.clear_cache() res = resolver(path) wvpasseq(4, len(res)) wvpasseq(expected, res) wvstart('resolve: /test/latest/dir-symlink') vfs.clear_cache() res = resolve(path) wvpasseq(4, len(res)) wvpasseq(expected, res)