cmdline_tests := \
test/ext/test.sh \
- test/ext/test-argv \
test/ext/test-cat-file.sh \
test/ext/test-command-without-init-fails.sh \
test/ext/test-compression.sh \
test/ext/test-drecurse.sh \
test/ext/test-fsck.sh \
test/ext/test-fuse.sh \
- test/ext/test-ftp \
test/ext/test-help \
test/ext/test-web.sh \
test/ext/test-gc.sh \
test/ext/test-meta.sh \
test/ext/test-on.sh \
test/ext/test-packsizelimit \
- test/ext/test-prune-older \
test/ext/test-redundant-saves.sh \
test/ext/test-restore-map-owner.sh \
test/ext/test-restore-single-file.sh \
test/ext/test-tz.sh \
test/ext/test-xdev.sh
-tmp-target-run-test-get-%: all test/tmp
- $(pf); cd $$(pwd -P); TMPDIR="$(test_tmp)" \
- test/ext/test-get $* 2>&1 | tee -a test/tmp/test-log/$$$$.log
-
-test_get_targets += \
- tmp-target-run-test-get-replace \
- tmp-target-run-test-get-universal \
- tmp-target-run-test-get-ff \
- tmp-target-run-test-get-append \
- tmp-target-run-test-get-pick \
- tmp-target-run-test-get-new-tag \
- tmp-target-run-test-get-unnamed
-
# For parallel runs.
# The "pwd -P" here may not be appropriate in the long run, but we
# need it until we settle the relevant drecurse/exclusion questions:
$(pf); cd $$(pwd -P); TMPDIR="$(test_tmp)" \
test/ext/test$* 2>&1 | tee -a test/tmp/test-log/$$$$.log
-runtests-cmdline: $(test_get_targets) $(subst test/ext/test,tmp-target-run-test,$(cmdline_tests))
+runtests-cmdline: $(subst test/ext/test,tmp-target-run-test,$(cmdline_tests))
stupid:
PATH=/bin:/usr/bin $(MAKE) test
import os, sys
script_home = abspath(dirname(__file__))
-sys.path[:0] = [abspath(script_home + '/../lib'), abspath(script_home + '/..')]
+sys.path[:0] = [abspath(script_home + '/../../lib'), abspath(script_home + '/../..')]
from bup import compat
from __future__ import absolute_import, print_function
import os, stat, sys
+sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/../lib']
+
from bup import compat
from bup.io import byte_stream
from __future__ import absolute_import
import os.path, sys
-sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/../lib']
+sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/../../lib']
from bup.compat import argv_bytes
from bup.helpers import handle_ctrl_c, saved_errors
from sys import stderr, stdout
import os, sys
+sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/../lib']
+
from bup.io import byte_stream
def smaller_region(max_offset):
from __future__ import absolute_import, print_function
import os.path, sys
+sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/../lib']
+
from bup.compat import argv_bytes
from bup.helpers import handle_ctrl_c, readpipe
from bup.io import byte_stream
+++ /dev/null
-#!/bin/sh
-"""": # -*-python-*-
-bup_python="$(dirname "$0")/../../config/bin/python" || exit $?
-exec "$bup_python" "$0" ${1+"$@"}
-"""
-# end of bup preamble
-
-from __future__ import absolute_import, print_function
-
-from os.path import abspath, dirname
-from random import randint
-from subprocess import check_output
-from sys import stderr, stdout
-import sys
-
-script_home = abspath(dirname(__file__))
-sys.path[:0] = [abspath(script_home + '/../../lib'), abspath(script_home + '/../..')]
-
-from wvtest import wvcheck, wvfail, wvmsg, wvpass, wvpasseq, wvpassne, wvstart
-
-wvstart('command line arguments are not mangled')
-
-def rand_bytes(n):
- return bytes([randint(1, 255) for x in range(n)])
-
-for trial in range(100):
- cmd = [b'dev/echo-argv-bytes', rand_bytes(randint(1, 32))]
- out = check_output(cmd)
- wvpasseq(b'\0\n'.join(cmd) + b'\0\n', out)
+++ /dev/null
-#!/bin/sh
-"""": # -*-python-*-
-bup_python="$(dirname "$0")/../../dev/bup-python" || exit $?
-exec "$bup_python" "$0" ${1+"$@"}
-"""
-# end of bup preamble
-
-from __future__ import absolute_import, print_function
-from os import chdir, mkdir, symlink, unlink
-from os.path import abspath, dirname
-from subprocess import PIPE
-from time import localtime, strftime, tzset
-import os, sys
-
-# For buptest, wvtest, ...
-sys.path[:0] = (abspath(os.path.dirname(__file__) + '/../..'),)
-sys.path[:0] = (abspath(os.path.dirname(__file__) + '/../../test/lib'),)
-sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/../../lib']
-
-from buptest import ex, exo, logcmd, test_tempdir
-from wvtest import wvfail, wvpass, wvpasseq, wvpassne, wvstart
-
-from bup.compat import environ
-from bup.helpers import unlink as unlink_if_exists
-import bup.path
-
-bup_cmd = bup.path.exe()
-
-def bup(*args, **kwargs):
- if 'stdout' not in kwargs:
- return exo((bup_cmd,) + args, **kwargs)
- return ex((bup_cmd,) + args, **kwargs)
-
-def jl(*lines):
- return b''.join(line + b'\n' for line in lines)
-
-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'
-
-with test_tempdir(b'ftp-') as 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')
+++ /dev/null
-#!/bin/sh
-"""": # -*-python-*-
-# https://sourceware.org/bugzilla/show_bug.cgi?id=26034
-export "BUP_ARGV_0"="$0"
-arg_i=1
-for arg in "$@"; do
- export "BUP_ARGV_${arg_i}"="$arg"
- shift
- arg_i=$((arg_i + 1))
-done
-bup_python="$(dirname "$0")/../../dev/bup-python" || exit $?
-exec "$bup_python" "$0"
-"""
-# end of bup preamble
-
-from __future__ import print_function
-from errno import ENOENT
-from os import chdir, mkdir, rename
-from os.path import abspath, dirname
-from shutil import rmtree
-from subprocess import PIPE
-import os, re, sys
-
-# For buptest, wvtest, ...
-sys.path[:0] = (abspath(os.path.dirname(__file__) + '/../..'),)
-sys.path[:0] = (abspath(os.path.dirname(__file__) + '/../../test/lib'),)
-sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/../../lib']
-
-from bup import compat, path
-from bup.compat import environ, getcwd, items
-from bup.helpers import bquote, merge_dict, unlink
-from bup.io import byte_stream
-from buptest import ex, exo, test_tempdir
-from wvtest import wvcheck, wvfail, wvmsg, wvpass, wvpasseq, wvpassne, wvstart
-import bup.path
-
-sys.stdout.flush()
-stdout = byte_stream(sys.stdout)
-
-# FIXME: per-test function
-environ[b'GIT_AUTHOR_NAME'] = b'bup test-get'
-environ[b'GIT_COMMITTER_NAME'] = b'bup test-get'
-environ[b'GIT_AUTHOR_EMAIL'] = b'bup@85430dcca2b611e4b2c3-8f5691723476'
-environ[b'GIT_COMMITTER_EMAIL'] = b'bup@85430dcca2b611e4b2c3-8f5691723476'
-
-# The clean-repo test can probably be applied more broadly. It was
-# initially just applied to test-pick to catch a bug.
-
-top = getcwd()
-bup_cmd = bup.path.exe()
-
-def rmrf(path):
- err = [] # because python's scoping mess...
- def onerror(function, path, excinfo):
- err.append((function, path, excinfo))
- rmtree(path, onerror=onerror)
- if err:
- function, path, excinfo = err[0]
- ex_type, ex, traceback = excinfo
- if (not isinstance(ex, OSError)) or ex.errno != ENOENT:
- raise ex
-
-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 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
-
-# FIXME: multline, or allow opts generally?
-
-def verify_rx(rx, string):
- wvcheck(re.search(rx, string), 'rx %r matches %r' % (rx, string))
-
-def verify_nrx(rx, string):
- wvcheck(not re.search(rx, string), "rx %r doesn't match %r" % (rx, string))
-
-def validate_clean_repo():
- out = verify_rcz((b'git', b'--git-dir', b'get-dest', b'fsck')).out
- verify_nrx(br'dangling|mismatch|missing|unreachable', out)
-
-def validate_blob(src_id, dest_id):
- global top
- rmrf(b'restore-src')
- rmrf(b'restore-dest')
- cat_tree = top + b'/dev/git-cat-tree'
- src_blob = verify_rcz((cat_tree, b'--git-dir', b'get-src', src_id)).out
- dest_blob = verify_rcz((cat_tree, b'--git-dir', b'get-src', src_id)).out
- wvpasseq(src_blob, dest_blob)
-
-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 validate_commit(src_id, dest_id):
- exr = verify_rcz((b'git', b'--git-dir', b'get-src', b'cat-file', b'commit', src_id))
- if exr.rc != 0: return False
- src_cat = exr.out
- exr = verify_rcz((b'git', b'--git-dir', b'get-dest', b'cat-file', b'commit', dest_id))
- if exr.rc != 0: return False
- dest_cat = exr.out
- wvpasseq(src_cat, dest_cat)
- if src_cat != dest_cat: return False
-
- rmrf(b'restore-src')
- rmrf(b'restore-dest')
- mkdir(b'restore-src')
- mkdir(b'restore-dest')
- qsrc = bquote(src_id)
- qdest = bquote(dest_id)
- exr = verify_rcz((b'git --git-dir get-src archive ' + qsrc
- + b' | tar xf - -C restore-src'),
- shell=True)
- if exr.rc != 0: return False
- exr = verify_rcz((b'git --git-dir get-dest archive ' + qdest +
- b' | tar xf - -C restore-dest'),
- shell=True)
- if exr.rc != 0: return False
-
- # git archive doesn't include an entry for ./.
- 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 _validate_save(orig_dir, save_path, commit_id, tree_id):
- global bup_cmd
- rmrf(b'restore')
- exr = verify_rcz((bup_cmd, b'-d', b'get-dest',
- b'restore', b'-C', b'restore', save_path + b'/.'))
- if exr.rc: return False
- verify_trees_match(orig_dir + b'/', b'restore/')
- if tree_id:
- # FIXME: double check that get-dest is correct
- exr = verify_rcz((b'git', b'--git-dir', b'get-dest', b'ls-tree', tree_id))
- if exr.rc: return False
- cat = verify_rcz((b'git', b'--git-dir', b'get-dest',
- b'cat-file', b'commit', commit_id))
- if cat.rc: return False
- wvpasseq(b'tree ' + tree_id, cat.out.splitlines()[0])
-
-# FIXME: re-merge save and new_save?
-
-def validate_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
- get_out):
- out = get_out.splitlines()
- print('blarg: out', repr(out), file=sys.stderr)
- wvpasseq(2, len(out))
- get_tree_id = out[0]
- get_commit_id = out[1]
- wvpasseq(tree_id, get_tree_id)
- wvpasseq(commit_id, get_commit_id)
- _validate_save(orig_value, dest_name + restore_subpath, commit_id, tree_id)
-
-def validate_new_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
- get_out):
- out = get_out.splitlines()
- wvpasseq(2, len(out))
- get_tree_id = out[0]
- get_commit_id = out[1]
- wvpasseq(tree_id, get_tree_id)
- wvpassne(commit_id, get_commit_id)
- _validate_save(orig_value, dest_name + restore_subpath, get_commit_id, tree_id)
-
-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 validate_new_tagged_commit(tag_name, commit_id, tree_id, get_out):
- out = get_out.splitlines()
- wvpasseq(1, len(out))
- get_tag_id = out[0]
- wvpassne(commit_id, get_tag_id)
- validate_tree(tree_id, tag_name + b':')
-
-
-get_cases_tested = 0
-
-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))
-
- global get_cases_tested
- 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)
- get_cases_tested += 1
- fsck = ex((bup_cmd, b'-d', b'get-dest', b'fsck'), check=False)
- wvpasseq(0, fsck.rc)
- return result
-
-def run_get(disposition, method, what=None, given=None):
- global bup_cmd
- rmrf(b'get-dest')
- ex((bup_cmd, b'-d', b'get-dest', b'init'))
-
- if given:
- # FIXME: replace bup-get with independent commands as is feasible
- exr = _run_get(disposition, b'--replace', given)
- assert not exr.rc
- return _run_get(disposition, method, what)
-
-def test_universal_behaviors(get_disposition):
- methods = (b'--ff', b'--append', b'--pick', b'--force-pick', b'--new-tag',
- b'--replace', b'--unnamed')
- for method in methods:
- mmsg = method.decode('ascii')
- wvstart(get_disposition + ' ' + mmsg + ', missing source, fails')
- exr = run_get(get_disposition, method, b'not-there')
- wvpassne(0, exr.rc)
- verify_rx(br'cannot find source', exr.err)
- for method in methods:
- mmsg = method.decode('ascii')
- wvstart(get_disposition + ' ' + mmsg + ' / fails')
- exr = run_get(get_disposition, method, b'/')
- wvpassne(0, exr.rc)
- verify_rx(b'cannot fetch entire repository', exr.err)
-
-def verify_only_refs(**kwargs):
- for kind, refs in items(kwargs):
- 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 test_replace(get_disposition, src_info):
- print('blarg:', repr(src_info), file=sys.stderr)
-
- wvstart(get_disposition + ' --replace to root fails')
- for item in (b'.tag/tinyfile',
- b'src/latest' + src_info['tinyfile-path'],
- b'.tag/subtree',
- b'src/latest' + src_info['subtree-vfs-path'],
- b'.tag/commit-1',
- b'src/latest',
- b'src'):
- exr = run_get(get_disposition, b'--replace', (item, b'/'))
- wvpassne(0, exr.rc)
- verify_rx(br'impossible; can only overwrite branch or tag', exr.err)
-
- tinyfile_id = src_info['tinyfile-id']
- tinyfile_path = src_info['tinyfile-path']
- subtree_vfs_path = src_info['subtree-vfs-path']
- subtree_id = src_info['subtree-id']
- commit_2_id = src_info['commit-2-id']
- tree_2_id = src_info['tree-2-id']
-
- # Anything to tag
- existing_items = {'nothing' : None,
- 'blob' : (b'.tag/tinyfile', b'.tag/obj'),
- 'tree' : (b'.tag/tree-1', b'.tag/obj'),
- 'commit': (b'.tag/commit-1', b'.tag/obj')}
- for ex_type, ex_ref in items(existing_items):
- wvstart(get_disposition + ' --replace ' + ex_type + ' with blob tag')
- for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
- exr = run_get(get_disposition, b'--replace', (item ,b'.tag/obj'),
- given=ex_ref)
- wvpasseq(0, exr.rc)
- validate_blob(tinyfile_id, tinyfile_id)
- verify_only_refs(heads=[], tags=(b'obj',))
- wvstart(get_disposition + ' --replace ' + ex_type + ' with tree tag')
- for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
- exr = run_get(get_disposition, b'--replace', (item, b'.tag/obj'),
- given=ex_ref)
- validate_tree(subtree_id, subtree_id)
- verify_only_refs(heads=[], tags=(b'obj',))
- wvstart(get_disposition + ' --replace ' + ex_type + ' with commitish tag')
- for item in (b'.tag/commit-2', b'src/latest', b'src'):
- exr = run_get(get_disposition, b'--replace', (item, b'.tag/obj'),
- given=ex_ref)
- validate_tagged_save(b'obj', getcwd() + b'/src',
- commit_2_id, tree_2_id, b'src-2', exr.out)
- verify_only_refs(heads=[], tags=(b'obj',))
-
- # Committish to branch.
- existing_items = (('nothing', None),
- ('branch', (b'.tag/commit-1', b'obj')))
- for ex_type, ex_ref in existing_items:
- for item_type, item in (('commit', b'.tag/commit-2'),
- ('save', b'src/latest'),
- ('branch', b'src')):
- wvstart(get_disposition + ' --replace '
- + ex_type + ' with ' + item_type)
- exr = run_get(get_disposition, b'--replace', (item, b'obj'),
- given=ex_ref)
- validate_save(b'obj/latest', getcwd() + b'/src',
- commit_2_id, tree_2_id, b'src-2', exr.out)
- verify_only_refs(heads=(b'obj',), tags=[])
-
- # Not committish to branch
- existing_items = (('nothing', None),
- ('branch', (b'.tag/commit-1', b'obj')))
- for ex_type, ex_ref in existing_items:
- for item_type, item in (('blob', b'.tag/tinyfile'),
- ('blob', b'src/latest' + tinyfile_path),
- ('tree', b'.tag/subtree'),
- ('tree', b'src/latest' + subtree_vfs_path)):
- wvstart(get_disposition + ' --replace branch with '
- + item_type + ' given ' + ex_type + ' fails')
-
- exr = run_get(get_disposition, b'--replace', (item, b'obj'),
- given=ex_ref)
- wvpassne(0, exr.rc)
- verify_rx(br'cannot overwrite branch with .+ for', exr.err)
-
- wvstart(get_disposition + ' --replace, implicit destinations')
-
- exr = run_get(get_disposition, b'--replace', b'src')
- validate_save(b'src/latest', getcwd() + b'/src',
- commit_2_id, tree_2_id, b'src-2', exr.out)
- verify_only_refs(heads=(b'src',), tags=[])
-
- exr = run_get(get_disposition, b'--replace', b'.tag/commit-2')
- validate_tagged_save(b'commit-2', getcwd() + b'/src',
- commit_2_id, tree_2_id, b'src-2', exr.out)
- verify_only_refs(heads=[], tags=(b'commit-2',))
-
-def test_ff(get_disposition, src_info):
-
- wvstart(get_disposition + ' --ff to root fails')
- tinyfile_path = src_info['tinyfile-path']
- for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
- exr = run_get(get_disposition, b'--ff', (item, b'/'))
- wvpassne(0, exr.rc)
- verify_rx(br'source for .+ must be a branch, save, or commit', exr.err)
- subtree_vfs_path = src_info['subtree-vfs-path']
- for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
- exr = run_get(get_disposition, b'--ff', (item, b'/'))
- wvpassne(0, exr.rc)
- verify_rx(br'is impossible; can only --append a tree to a branch',
- exr.err)
- for item in (b'.tag/commit-1', b'src/latest', b'src'):
- exr = run_get(get_disposition, b'--ff', (item, b'/'))
- wvpassne(0, exr.rc)
- verify_rx(br'destination for .+ is a root, not a branch', exr.err)
-
- wvstart(get_disposition + ' --ff of not-committish fails')
- for src in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
- # FIXME: use get_item elsewhere?
- for given, get_item in ((None, (src, b'obj')),
- (None, (src, b'.tag/obj')),
- ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
- ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
- ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
- ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
- exr = run_get(get_disposition, b'--ff', get_item, given=given)
- wvpassne(0, exr.rc)
- verify_rx(br'must be a branch, save, or commit', exr.err)
- for src in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
- for given, get_item in ((None, (src, b'obj')),
- (None, (src, b'.tag/obj')),
- ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
- ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
- ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
- ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
- exr = run_get(get_disposition, b'--ff', get_item, given=given)
- wvpassne(0, exr.rc)
- verify_rx(br'can only --append a tree to a branch', exr.err)
-
- wvstart(get_disposition + ' --ff committish, ff possible')
- save_2 = src_info['save-2']
- for src in (b'.tag/commit-2', b'src/' + save_2, b'src'):
- for given, get_item, complaint in \
- ((None, (src, b'.tag/obj'),
- br'destination .+ must be a valid branch name'),
- ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj'),
- br'destination .+ is a blob, not a branch'),
- ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj'),
- br'destination .+ is a tree, not a branch'),
- ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj'),
- br'destination .+ is a tagged commit, not a branch'),
- ((b'.tag/commit-2', b'.tag/obj'), (src, b'.tag/obj'),
- br'destination .+ is a tagged commit, not a branch')):
- exr = run_get(get_disposition, b'--ff', get_item, given=given)
- wvpassne(0, exr.rc)
- verify_rx(complaint, exr.err)
- # FIXME: use src or item and given or existing consistently in loops...
- commit_2_id = src_info['commit-2-id']
- tree_2_id = src_info['tree-2-id']
- for src in (b'.tag/commit-2', b'src/' + save_2, b'src'):
- for given in (None, (b'.tag/commit-1', b'obj'), (b'.tag/commit-2', b'obj')):
- exr = run_get(get_disposition, b'--ff', (src, b'obj'), given=given)
- wvpasseq(0, exr.rc)
- validate_save(b'obj/latest', getcwd() + b'/src',
- commit_2_id, tree_2_id, b'src-2', exr.out)
- verify_only_refs(heads=(b'obj',), tags=[])
-
- wvstart(get_disposition + ' --ff, implicit destinations')
- for item in (b'src', b'src/latest'):
- exr = run_get(get_disposition, b'--ff', item)
- wvpasseq(0, exr.rc)
-
- ex((b'find', b'get-dest/refs'))
- ex((bup_cmd, b'-d', b'get-dest', b'ls'))
-
- validate_save(b'src/latest', getcwd() + b'/src',
- commit_2_id, tree_2_id, b'src-2', exr.out)
- #verify_only_refs(heads=('src',), tags=[])
-
- wvstart(get_disposition + ' --ff, ff impossible')
- for given, get_item in (((b'unrelated-branch', b'src'), b'src'),
- ((b'.tag/commit-2', b'src'), (b'.tag/commit-1', b'src'))):
- exr = run_get(get_disposition, b'--ff', get_item, given=given)
- wvpassne(0, exr.rc)
- verify_rx(br'destination is not an ancestor of source', exr.err)
-
-def test_append(get_disposition, src_info):
- tinyfile_path = src_info['tinyfile-path']
- subtree_vfs_path = src_info['subtree-vfs-path']
-
- wvstart(get_disposition + ' --append to root fails')
- for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
- exr = run_get(get_disposition, b'--append', (item, b'/'))
- wvpassne(0, exr.rc)
- verify_rx(br'source for .+ must be a branch, save, commit, or tree',
- exr.err)
- for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path,
- b'.tag/commit-1', b'src/latest', b'src'):
- exr = run_get(get_disposition, b'--append', (item, b'/'))
- wvpassne(0, exr.rc)
- verify_rx(br'destination for .+ is a root, not a branch', exr.err)
-
- wvstart(get_disposition + ' --append of not-treeish fails')
- for src in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
- for given, item in ((None, (src, b'obj')),
- (None, (src, b'.tag/obj')),
- ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
- ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
- ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
- ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
- exr = run_get(get_disposition, b'--append', item, given=given)
- wvpassne(0, exr.rc)
- verify_rx(br'must be a branch, save, commit, or tree', exr.err)
-
- wvstart(get_disposition + ' --append committish failure cases')
- save_2 = src_info['save-2']
- for src in (b'.tag/subtree', b'src/latest' + subtree_vfs_path,
- b'.tag/commit-2', b'src/' + save_2, b'src'):
- for given, item, complaint in \
- ((None, (src, b'.tag/obj'),
- br'destination .+ must be a valid branch name'),
- ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj'),
- br'destination .+ is a blob, not a branch'),
- ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj'),
- br'destination .+ is a tree, not a branch'),
- ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj'),
- br'destination .+ is a tagged commit, not a branch'),
- ((b'.tag/commit-2', b'.tag/obj'), (src, b'.tag/obj'),
- br'destination .+ is a tagged commit, not a branch')):
- exr = run_get(get_disposition, b'--append', item, given=given)
- wvpassne(0, exr.rc)
- verify_rx(complaint, exr.err)
-
- wvstart(get_disposition + ' --append committish')
- commit_2_id = src_info['commit-2-id']
- tree_2_id = src_info['tree-2-id']
- for item in (b'.tag/commit-2', b'src/' + save_2, b'src'):
- for existing in (None, (b'.tag/commit-1', b'obj'),
- (b'.tag/commit-2', b'obj'),
- (b'unrelated-branch', b'obj')):
- exr = run_get(get_disposition, b'--append', (item, b'obj'),
- given=existing)
- wvpasseq(0, exr.rc)
- validate_new_save(b'obj/latest', getcwd() + b'/src',
- commit_2_id, tree_2_id, b'src-2', exr.out)
- verify_only_refs(heads=(b'obj',), tags=[])
- # Append ancestor
- save_1 = src_info['save-1']
- commit_1_id = src_info['commit-1-id']
- tree_1_id = src_info['tree-1-id']
- for item in (b'.tag/commit-1', b'src/' + save_1, b'src-1'):
- exr = run_get(get_disposition, b'--append', (item, b'obj'),
- given=(b'.tag/commit-2', b'obj'))
- wvpasseq(0, exr.rc)
- validate_new_save(b'obj/latest', getcwd() + b'/src',
- commit_1_id, tree_1_id, b'src-1', exr.out)
- verify_only_refs(heads=(b'obj',), tags=[])
-
- wvstart(get_disposition + ' --append tree')
- subtree_path = src_info['subtree-path']
- subtree_id = src_info['subtree-id']
- for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
- for existing in (None,
- (b'.tag/commit-1', b'obj'),
- (b'.tag/commit-2', b'obj')):
- exr = run_get(get_disposition, b'--append', (item, b'obj'),
- given=existing)
- wvpasseq(0, exr.rc)
- validate_new_save(b'obj/latest', b'/', None, subtree_id, subtree_path,
- exr.out)
- verify_only_refs(heads=(b'obj',), tags=[])
-
- wvstart(get_disposition + ' --append, implicit destinations')
-
- for item in (b'src', b'src/latest'):
- exr = run_get(get_disposition, b'--append', item)
- wvpasseq(0, exr.rc)
- validate_new_save(b'src/latest', getcwd() + b'/src', commit_2_id, tree_2_id,
- b'src-2', exr.out)
- verify_only_refs(heads=(b'src',), tags=[])
-
-def test_pick(get_disposition, src_info, force=False):
- flavor = b'--force-pick' if force else b'--pick'
- flavormsg = flavor.decode('ascii')
- tinyfile_path = src_info['tinyfile-path']
- subtree_vfs_path = src_info['subtree-vfs-path']
-
- wvstart(get_disposition + ' ' + flavormsg + ' to root fails')
- for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path, b'src'):
- exr = run_get(get_disposition, flavor, (item, b'/'))
- wvpassne(0, exr.rc)
- verify_rx(br'can only pick a commit or save', exr.err)
- for item in (b'.tag/commit-1', b'src/latest'):
- exr = run_get(get_disposition, flavor, (item, b'/'))
- wvpassne(0, exr.rc)
- verify_rx(br'destination is not a tag or branch', exr.err)
- for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
- exr = run_get(get_disposition, flavor, (item, b'/'))
- wvpassne(0, exr.rc)
- verify_rx(br'is impossible; can only --append a tree', exr.err)
-
- wvstart(get_disposition + ' ' + flavormsg + ' of blob or branch fails')
- for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path, b'src'):
- for given, get_item in ((None, (item, b'obj')),
- (None, (item, b'.tag/obj')),
- ((b'.tag/tinyfile', b'.tag/obj'), (item, b'.tag/obj')),
- ((b'.tag/tree-1', b'.tag/obj'), (item, b'.tag/obj')),
- ((b'.tag/commit-1', b'.tag/obj'), (item, b'.tag/obj')),
- ((b'.tag/commit-1', b'obj'), (item, b'obj'))):
- exr = run_get(get_disposition, flavor, get_item, given=given)
- wvpassne(0, exr.rc)
- verify_rx(br'impossible; can only pick a commit or save', exr.err)
-
- wvstart(get_disposition + ' ' + flavormsg + ' of tree fails')
- for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
- for given, get_item in ((None, (item, b'obj')),
- (None, (item, b'.tag/obj')),
- ((b'.tag/tinyfile', b'.tag/obj'), (item, b'.tag/obj')),
- ((b'.tag/tree-1', b'.tag/obj'), (item, b'.tag/obj')),
- ((b'.tag/commit-1', b'.tag/obj'), (item, b'.tag/obj')),
- ((b'.tag/commit-1', b'obj'), (item, b'obj'))):
- exr = run_get(get_disposition, flavor, get_item, given=given)
- wvpassne(0, exr.rc)
- verify_rx(br'impossible; can only --append a tree', exr.err)
-
- save_2 = src_info['save-2']
- commit_2_id = src_info['commit-2-id']
- tree_2_id = src_info['tree-2-id']
- # FIXME: these two wvstart texts?
- if force:
- wvstart(get_disposition + ' ' + flavormsg + ' commit/save to existing tag')
- for item in (b'.tag/commit-2', b'src/' + save_2):
- for given in ((b'.tag/tinyfile', b'.tag/obj'),
- (b'.tag/tree-1', b'.tag/obj'),
- (b'.tag/commit-1', b'.tag/obj')):
- exr = run_get(get_disposition, flavor, (item, b'.tag/obj'),
- given=given)
- wvpasseq(0, exr.rc)
- validate_new_tagged_commit(b'obj', commit_2_id, tree_2_id,
- exr.out)
- verify_only_refs(heads=[], tags=(b'obj',))
- else: # --pick
- wvstart(get_disposition + ' ' + flavormsg
- + ' commit/save to existing tag fails')
- for item in (b'.tag/commit-2', b'src/' + save_2):
- for given in ((b'.tag/tinyfile', b'.tag/obj'),
- (b'.tag/tree-1', b'.tag/obj'),
- (b'.tag/commit-1', b'.tag/obj')):
- exr = run_get(get_disposition, flavor, (item, b'.tag/obj'), given=given)
- wvpassne(0, exr.rc)
- verify_rx(br'cannot overwrite existing tag', exr.err)
-
- wvstart(get_disposition + ' ' + flavormsg + ' commit/save to tag')
- for item in (b'.tag/commit-2', b'src/' + save_2):
- exr = run_get(get_disposition, flavor, (item, b'.tag/obj'))
- wvpasseq(0, exr.rc)
- validate_clean_repo()
- validate_new_tagged_commit(b'obj', commit_2_id, tree_2_id, exr.out)
- verify_only_refs(heads=[], tags=(b'obj',))
-
- wvstart(get_disposition + ' ' + flavormsg + ' commit/save to branch')
- for item in (b'.tag/commit-2', b'src/' + save_2):
- for given in (None, (b'.tag/commit-1', b'obj'), (b'.tag/commit-2', b'obj')):
- exr = run_get(get_disposition, flavor, (item, b'obj'), given=given)
- wvpasseq(0, exr.rc)
- validate_clean_repo()
- validate_new_save(b'obj/latest', getcwd() + b'/src',
- commit_2_id, tree_2_id, b'src-2', exr.out)
- verify_only_refs(heads=(b'obj',), tags=[])
-
- wvstart(get_disposition + ' ' + flavormsg
- + ' commit/save unrelated commit to branch')
- for item in(b'.tag/commit-2', b'src/' + save_2):
- exr = run_get(get_disposition, flavor, (item, b'obj'),
- given=(b'unrelated-branch', b'obj'))
- wvpasseq(0, exr.rc)
- validate_clean_repo()
- validate_new_save(b'obj/latest', getcwd() + b'/src',
- commit_2_id, tree_2_id, b'src-2', exr.out)
- verify_only_refs(heads=(b'obj',), tags=[])
-
- wvstart(get_disposition + ' ' + flavormsg + ' commit/save ancestor to branch')
- save_1 = src_info['save-1']
- commit_1_id = src_info['commit-1-id']
- tree_1_id = src_info['tree-1-id']
- for item in (b'.tag/commit-1', b'src/' + save_1):
- exr = run_get(get_disposition, flavor, (item, b'obj'),
- given=(b'.tag/commit-2', b'obj'))
- wvpasseq(0, exr.rc)
- validate_clean_repo()
- validate_new_save(b'obj/latest', getcwd() + b'/src',
- commit_1_id, tree_1_id, b'src-1', exr.out)
- verify_only_refs(heads=(b'obj',), tags=[])
-
-
- wvstart(get_disposition + ' ' + flavormsg + ', implicit destinations')
- exr = run_get(get_disposition, flavor, b'.tag/commit-2')
- wvpasseq(0, exr.rc)
- validate_clean_repo()
- validate_new_tagged_commit(b'commit-2', commit_2_id, tree_2_id, exr.out)
- verify_only_refs(heads=[], tags=(b'commit-2',))
-
- exr = run_get(get_disposition, flavor, b'src/latest')
- wvpasseq(0, exr.rc)
- validate_clean_repo()
- validate_new_save(b'src/latest', getcwd() + b'/src',
- commit_2_id, tree_2_id, b'src-2', exr.out)
- verify_only_refs(heads=(b'src',), tags=[])
-
-def test_new_tag(get_disposition, src_info):
- tinyfile_id = src_info['tinyfile-id']
- tinyfile_path = src_info['tinyfile-path']
- commit_2_id = src_info['commit-2-id']
- tree_2_id = src_info['tree-2-id']
- subtree_id = src_info['subtree-id']
- subtree_vfs_path = src_info['subtree-vfs-path']
-
- wvstart(get_disposition + ' --new-tag to root fails')
- for item in (b'.tag/tinyfile',
- b'src/latest' + tinyfile_path,
- b'.tag/subtree',
- b'src/latest' + subtree_vfs_path,
- b'.tag/commit-1',
- b'src/latest',
- b'src'):
- exr = run_get(get_disposition, b'--new-tag', (item, b'/'))
- wvpassne(0, exr.rc)
- verify_rx(br'destination for .+ must be a VFS tag', exr.err)
-
- # Anything to new tag.
- wvstart(get_disposition + ' --new-tag, blob tag')
- for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
- exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
- wvpasseq(0, exr.rc)
- validate_blob(tinyfile_id, tinyfile_id)
- verify_only_refs(heads=[], tags=(b'obj',))
-
- wvstart(get_disposition + ' --new-tag, tree tag')
- for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
- exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
- wvpasseq(0, exr.rc)
- validate_tree(subtree_id, subtree_id)
- verify_only_refs(heads=[], tags=(b'obj',))
-
- wvstart(get_disposition + ' --new-tag, committish tag')
- for item in (b'.tag/commit-2', b'src/latest', b'src'):
- exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
- wvpasseq(0, exr.rc)
- validate_tagged_save(b'obj', getcwd() + b'/src/', commit_2_id, tree_2_id,
- b'src-2', exr.out)
- verify_only_refs(heads=[], tags=(b'obj',))
-
- # Anything to existing tag (fails).
- for ex_type, ex_tag in (('blob', (b'.tag/tinyfile', b'.tag/obj')),
- ('tree', (b'.tag/tree-1', b'.tag/obj')),
- ('commit', (b'.tag/commit-1', b'.tag/obj'))):
- for item_type, item in (('blob tag', b'.tag/tinyfile'),
- ('blob path', b'src/latest' + tinyfile_path),
- ('tree tag', b'.tag/subtree'),
- ('tree path', b'src/latest' + subtree_vfs_path),
- ('commit tag', b'.tag/commit-2'),
- ('save', b'src/latest'),
- ('branch', b'src')):
- wvstart(get_disposition + ' --new-tag of ' + item_type
- + ', given existing ' + ex_type + ' tag, fails')
- exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'),
- given=ex_tag)
- wvpassne(0, exr.rc)
- verify_rx(br'cannot overwrite existing tag .* \(requires --replace\)',
- exr.err)
-
- # Anything to branch (fails).
- for ex_type, ex_tag in (('nothing', None),
- ('blob', (b'.tag/tinyfile', b'.tag/obj')),
- ('tree', (b'.tag/tree-1', b'.tag/obj')),
- ('commit', (b'.tag/commit-1', b'.tag/obj'))):
- for item_type, item in (('blob tag', b'.tag/tinyfile'),
- ('blob path', b'src/latest' + tinyfile_path),
- ('tree tag', b'.tag/subtree'),
- ('tree path', b'src/latest' + subtree_vfs_path),
- ('commit tag', b'.tag/commit-2'),
- ('save', b'src/latest'),
- ('branch', b'src')):
- wvstart(get_disposition + ' --new-tag to branch of ' + item_type
- + ', given existing ' + ex_type + ' tag, fails')
- exr = run_get(get_disposition, b'--new-tag', (item, b'obj'),
- given=ex_tag)
- wvpassne(0, exr.rc)
- verify_rx(br'destination for .+ must be a VFS tag', exr.err)
-
- wvstart(get_disposition + ' --new-tag, implicit destinations')
- exr = run_get(get_disposition, b'--new-tag', b'.tag/commit-2')
- wvpasseq(0, exr.rc)
- validate_tagged_save(b'commit-2', getcwd() + b'/src/', commit_2_id, tree_2_id,
- b'src-2', exr.out)
- verify_only_refs(heads=[], tags=(b'commit-2',))
-
-def test_unnamed(get_disposition, src_info):
- tinyfile_id = src_info['tinyfile-id']
- tinyfile_path = src_info['tinyfile-path']
- subtree_vfs_path = src_info['subtree-vfs-path']
- wvstart(get_disposition + ' --unnamed to root fails')
- for item in (b'.tag/tinyfile',
- b'src/latest' + tinyfile_path,
- b'.tag/subtree',
- b'src/latest' + subtree_vfs_path,
- b'.tag/commit-1',
- b'src/latest',
- b'src'):
- for ex_ref in (None, (item, b'.tag/obj')):
- exr = run_get(get_disposition, b'--unnamed', (item, b'/'),
- given=ex_ref)
- wvpassne(0, exr.rc)
- verify_rx(br'usage: bup get ', exr.err)
-
- wvstart(get_disposition + ' --unnamed file')
- for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
- exr = run_get(get_disposition, b'--unnamed', item)
- wvpasseq(0, exr.rc)
- validate_blob(tinyfile_id, tinyfile_id)
- verify_only_refs(heads=[], tags=[])
-
- exr = run_get(get_disposition, b'--unnamed', item,
- given=(item, b'.tag/obj'))
- wvpasseq(0, exr.rc)
- validate_blob(tinyfile_id, tinyfile_id)
- verify_only_refs(heads=[], tags=(b'obj',))
-
- wvstart(get_disposition + ' --unnamed tree')
- subtree_id = src_info['subtree-id']
- for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
- exr = run_get(get_disposition, b'--unnamed', item)
- wvpasseq(0, exr.rc)
- validate_tree(subtree_id, subtree_id)
- verify_only_refs(heads=[], tags=[])
-
- exr = run_get(get_disposition, b'--unnamed', item,
- given=(item, b'.tag/obj'))
- wvpasseq(0, exr.rc)
- validate_tree(subtree_id, subtree_id)
- verify_only_refs(heads=[], tags=(b'obj',))
-
- wvstart(get_disposition + ' --unnamed committish')
- save_2 = src_info['save-2']
- commit_2_id = src_info['commit-2-id']
- for item in (b'.tag/commit-2', b'src/' + save_2, b'src'):
- exr = run_get(get_disposition, b'--unnamed', item)
- wvpasseq(0, exr.rc)
- validate_commit(commit_2_id, commit_2_id)
- verify_only_refs(heads=[], tags=[])
-
- exr = run_get(get_disposition, b'--unnamed', item,
- given=(item, b'.tag/obj'))
- wvpasseq(0, exr.rc)
- validate_commit(commit_2_id, commit_2_id)
- verify_only_refs(heads=[], tags=(b'obj',))
-
-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}
-
-# FIXME: this fails in a strange way:
-# WVPASS given nothing get --ff not-there
-
-dispositions_to_test = ('get',)
-
-if int(environ.get(b'BUP_TEST_LEVEL', b'0')) >= 11:
- dispositions_to_test += ('get-on', 'get-to')
-
-if len(compat.argv) == 1:
- categories = ('replace', 'universal', 'ff', 'append', 'pick', 'new-tag',
- 'unnamed')
-else:
- categories = compat.argv[1:]
-
-with test_tempdir(b'get-') as tmpdir:
- chdir(tmpdir)
- try:
- src_info = create_get_src()
- for category in categories:
- for disposition in dispositions_to_test:
- # given=FOO depends on --replace, so test it early
- if category == 'replace':
- test_replace(disposition, src_info)
- elif category == 'universal':
- test_universal_behaviors(disposition)
- elif category == 'ff':
- test_ff(disposition, src_info)
- elif category == 'append':
- test_append(disposition, src_info)
- elif category == 'pick':
- test_pick(disposition, src_info, force=False)
- test_pick(disposition, src_info, force=True)
- elif category == 'new-tag':
- test_new_tag(disposition, src_info)
- elif category == 'unnamed':
- test_unnamed(disposition, src_info)
- else:
- raise Exception('unrecognized get test category')
- except Exception as ex:
- chdir(top)
- raise
- chdir(top)
-
-wvmsg('checked %d cases' % get_cases_tested)
+++ /dev/null
-#!/bin/sh
-"""": # -*-python-*-
-bup_python="$(dirname "$0")/../../dev/bup-python" || exit $?
-exec "$bup_python" "$0" ${1+"$@"}
-"""
-# end of bup preamble
-
-from __future__ import absolute_import, print_function
-from collections import defaultdict
-from itertools import chain, dropwhile, groupby, takewhile
-from os import chdir
-from os.path import abspath, dirname
-from random import choice, randint
-from shutil import copytree, rmtree
-from subprocess import PIPE
-from sys import stderr
-from time import localtime, strftime, time
-import os, random, sys
-
-if sys.version_info[:2] >= (3, 5):
- from difflib import diff_bytes, unified_diff
-else:
- from difflib import unified_diff
-
-# For buptest, wvtest, ...
-sys.path[:0] = (abspath(os.path.dirname(__file__) + '/../..'),)
-sys.path[:0] = (abspath(os.path.dirname(__file__) + '/../../test/lib'),)
-sys.path[:0] = [os.path.dirname(os.path.realpath(__file__)) + '/../../lib']
-
-from buptest import ex, exo, test_tempdir
-from wvtest import wvfail, wvpass, wvpasseq, wvpassne, wvstart
-
-from bup import compat
-from bup.compat import environ
-from bup.helpers import partition, period_as_secs, readpipe
-from bup.io import byte_stream
-import bup.path
-
-if sys.version_info[:2] < (3, 5):
- def diff_bytes(_, *args):
- return unified_diff(*args)
-
-def create_older_random_saves(n, start_utc, end_utc):
- with open(b'foo', 'wb') as f:
- pass
- ex([b'git', b'add', b'foo'])
- utcs = set()
- while len(utcs) != n:
- utcs.add(randint(start_utc, end_utc))
- utcs = sorted(utcs)
- for utc in utcs:
- with open(b'foo', 'wb') as f:
- f.write(b'%d\n' % utc)
- ex([b'git', b'commit', b'--date', b'%d' % utc, b'-qam', b'%d' % utc])
- ex([b'git', b'gc', b'--aggressive'])
- return utcs
-
-# There is corresponding code in bup for some of this, but the
-# computation method is different here, in part so that the test can
-# provide a more effective cross-check.
-
-period_kinds = [b'all', b'dailies', b'monthlies', b'yearlies']
-period_scale = {b's': 1,
- b'min': 60,
- b'h': 60 * 60,
- b'd': 60 * 60 * 24,
- b'w': 60 * 60 * 24 * 7,
- b'm': 60 * 60 * 24 * 31,
- b'y': 60 * 60 * 24 * 366}
-period_scale_kinds = list(period_scale.keys())
-
-def expected_retentions(utcs, utc_start, spec):
- if not spec:
- return utcs
- utcs = sorted(utcs, reverse=True)
- period_start = dict(spec)
- for kind, duration in compat.items(period_start):
- period_start[kind] = utc_start - period_as_secs(duration)
- period_start = defaultdict(lambda: float('inf'), period_start)
-
- all = list(takewhile(lambda x: x >= period_start[b'all'], utcs))
- utcs = list(dropwhile(lambda x: x >= period_start[b'all'], utcs))
-
- matches = takewhile(lambda x: x >= period_start[b'dailies'], utcs)
- dailies = [max(day_utcs) for yday, day_utcs
- in groupby(matches, lambda x: localtime(x).tm_yday)]
- utcs = list(dropwhile(lambda x: x >= period_start[b'dailies'], utcs))
-
- matches = takewhile(lambda x: x >= period_start[b'monthlies'], utcs)
- monthlies = [max(month_utcs) for month, month_utcs
- in groupby(matches, lambda x: localtime(x).tm_mon)]
- utcs = dropwhile(lambda x: x >= period_start[b'monthlies'], utcs)
-
- matches = takewhile(lambda x: x >= period_start[b'yearlies'], utcs)
- yearlies = [max(year_utcs) for year, year_utcs
- in groupby(matches, lambda x: localtime(x).tm_year)]
-
- return chain(all, dailies, monthlies, yearlies)
-
-def period_spec(start_utc, end_utc):
- global period_kinds, period_scale, period_scale_kinds
- result = []
- desired_specs = randint(1, 2 * len(period_kinds))
- assert(desired_specs >= 1) # At least one --keep argument is required
- while len(result) < desired_specs:
- period = None
- if randint(1, 100) <= 5:
- period = b'forever'
- else:
- assert(end_utc > start_utc)
- period_secs = randint(1, end_utc - start_utc)
- scale = choice(period_scale_kinds)
- mag = int(float(period_secs) / period_scale[scale])
- if mag != 0:
- period = (b'%d' % mag) + scale
- if period:
- result += [(choice(period_kinds), period)]
- return tuple(result)
-
-def unique_period_specs(n, start_utc, end_utc):
- invocations = set()
- while len(invocations) < n:
- invocations.add(period_spec(start_utc, end_utc))
- return tuple(invocations)
-
-def period_spec_to_period_args(spec):
- return tuple(chain(*((b'--keep-' + kind + b'-for', period)
- for kind, period in spec)))
-
-def result_diffline(x):
- return (b'%d %s\n'
- % (x, strftime(' %Y-%m-%d-%H%M%S', localtime(x)).encode('ascii')))
-
-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)
-
-
-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()
-
-with test_tempdir(b'prune-older-') as tmpdir:
- 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)
--- /dev/null
+
+from __future__ import absolute_import, print_function
+
+from random import randint
+from subprocess import CalledProcessError, check_output
+from sys import stderr, stdout
+
+
+from test.lib.wvpytest import wvpasseq
+
+def rand_bytes(n):
+ return bytes([randint(1, 255) for x in range(n)])
+
+def test_argv():
+ for trial in range(100):
+ cmd = [b'dev/echo-argv-bytes', rand_bytes(randint(1, 32))]
+ out = check_output(cmd)
+ wvpasseq(b'\0\n'.join(cmd) + b'\0\n', out)
--- /dev/null
+
+from __future__ import absolute_import, print_function
+from os import chdir, mkdir, symlink, unlink
+from subprocess import PIPE
+from time import localtime, strftime, tzset
+
+from bup.compat import environ
+from bup.helpers import unlink as unlink_if_exists
+from buptest import ex, exo
+from wvpytest import wvfail, wvpass, wvpasseq, wvpassne, wvstart
+import bup.path
+
+bup_cmd = bup.path.exe()
+
+def bup(*args, **kwargs):
+ if 'stdout' not in kwargs:
+ return exo((bup_cmd,) + args, **kwargs)
+ return ex((bup_cmd,) + args, **kwargs)
+
+def jl(*lines):
+ return b''.join(line + b'\n' for line in lines)
+
+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'
+
+import subprocess
+
+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')
--- /dev/null
+
+from __future__ import print_function
+from errno import ENOENT
+from itertools import product
+from os import chdir, mkdir, rename
+from shutil import rmtree
+from subprocess import PIPE
+import pytest, re, sys
+
+from bup import compat, path
+from bup.compat import environ, getcwd, items
+from bup.helpers import bquote, merge_dict, unlink
+from bup.io import byte_stream
+from buptest import ex, exo
+from wvpytest import wvcheck, wvfail, wvmsg, wvpass, wvpasseq, wvpassne, wvstart
+import bup.path
+
+
+sys.stdout.flush()
+stdout = byte_stream(sys.stdout)
+
+# FIXME: per-test function
+environ[b'GIT_AUTHOR_NAME'] = b'bup test-get'
+environ[b'GIT_COMMITTER_NAME'] = b'bup test-get'
+environ[b'GIT_AUTHOR_EMAIL'] = b'bup@85430dcca2b611e4b2c3-8f5691723476'
+environ[b'GIT_COMMITTER_EMAIL'] = b'bup@85430dcca2b611e4b2c3-8f5691723476'
+
+# The clean-repo test can probably be applied more broadly. It was
+# initially just applied to test-pick to catch a bug.
+
+top = getcwd()
+bup_cmd = bup.path.exe()
+
+def rmrf(path):
+ err = [] # because python's scoping mess...
+ def onerror(function, path, excinfo):
+ err.append((function, path, excinfo))
+ rmtree(path, onerror=onerror)
+ if err:
+ function, path, excinfo = err[0]
+ ex_type, ex, traceback = excinfo
+ if (not isinstance(ex, OSError)) or ex.errno != ENOENT:
+ raise ex
+
+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 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
+
+# FIXME: multline, or allow opts generally?
+
+def verify_rx(rx, string):
+ wvcheck(re.search(rx, string), 'rx %r matches %r' % (rx, string))
+
+def verify_nrx(rx, string):
+ wvcheck(not re.search(rx, string), "rx %r doesn't match %r" % (rx, string))
+
+def validate_clean_repo():
+ out = verify_rcz((b'git', b'--git-dir', b'get-dest', b'fsck')).out
+ verify_nrx(br'dangling|mismatch|missing|unreachable', out)
+
+def validate_blob(src_id, dest_id):
+ global top
+ rmrf(b'restore-src')
+ rmrf(b'restore-dest')
+ cat_tree = top + b'/dev/git-cat-tree'
+ src_blob = verify_rcz((cat_tree, b'--git-dir', b'get-src', src_id)).out
+ dest_blob = verify_rcz((cat_tree, b'--git-dir', b'get-src', src_id)).out
+ wvpasseq(src_blob, dest_blob)
+
+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 validate_commit(src_id, dest_id):
+ exr = verify_rcz((b'git', b'--git-dir', b'get-src', b'cat-file', b'commit', src_id))
+ if exr.rc != 0: return False
+ src_cat = exr.out
+ exr = verify_rcz((b'git', b'--git-dir', b'get-dest', b'cat-file', b'commit', dest_id))
+ if exr.rc != 0: return False
+ dest_cat = exr.out
+ wvpasseq(src_cat, dest_cat)
+ if src_cat != dest_cat: return False
+
+ rmrf(b'restore-src')
+ rmrf(b'restore-dest')
+ mkdir(b'restore-src')
+ mkdir(b'restore-dest')
+ qsrc = bquote(src_id)
+ qdest = bquote(dest_id)
+ exr = verify_rcz((b'git --git-dir get-src archive ' + qsrc
+ + b' | tar xf - -C restore-src'),
+ shell=True)
+ if exr.rc != 0: return False
+ exr = verify_rcz((b'git --git-dir get-dest archive ' + qdest +
+ b' | tar xf - -C restore-dest'),
+ shell=True)
+ if exr.rc != 0: return False
+
+ # git archive doesn't include an entry for ./.
+ 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 _validate_save(orig_dir, save_path, commit_id, tree_id):
+ global bup_cmd
+ rmrf(b'restore')
+ exr = verify_rcz((bup_cmd, b'-d', b'get-dest',
+ b'restore', b'-C', b'restore', save_path + b'/.'))
+ if exr.rc: return False
+ verify_trees_match(orig_dir + b'/', b'restore/')
+ if tree_id:
+ # FIXME: double check that get-dest is correct
+ exr = verify_rcz((b'git', b'--git-dir', b'get-dest', b'ls-tree', tree_id))
+ if exr.rc: return False
+ cat = verify_rcz((b'git', b'--git-dir', b'get-dest',
+ b'cat-file', b'commit', commit_id))
+ if cat.rc: return False
+ wvpasseq(b'tree ' + tree_id, cat.out.splitlines()[0])
+
+# FIXME: re-merge save and new_save?
+
+def validate_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
+ get_out):
+ out = get_out.splitlines()
+ print('blarg: out', repr(out), file=sys.stderr)
+ wvpasseq(2, len(out))
+ get_tree_id = out[0]
+ get_commit_id = out[1]
+ wvpasseq(tree_id, get_tree_id)
+ wvpasseq(commit_id, get_commit_id)
+ _validate_save(orig_value, dest_name + restore_subpath, commit_id, tree_id)
+
+def validate_new_save(dest_name, restore_subpath, commit_id, tree_id, orig_value,
+ get_out):
+ out = get_out.splitlines()
+ wvpasseq(2, len(out))
+ get_tree_id = out[0]
+ get_commit_id = out[1]
+ wvpasseq(tree_id, get_tree_id)
+ wvpassne(commit_id, get_commit_id)
+ _validate_save(orig_value, dest_name + restore_subpath, get_commit_id, tree_id)
+
+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 validate_new_tagged_commit(tag_name, commit_id, tree_id, get_out):
+ out = get_out.splitlines()
+ wvpasseq(1, len(out))
+ get_tag_id = out[0]
+ wvpassne(commit_id, get_tag_id)
+ validate_tree(tree_id, tag_name + b':')
+
+
+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 run_get(disposition, method, what=None, given=None):
+ global bup_cmd
+ rmrf(b'get-dest')
+ ex((bup_cmd, b'-d', b'get-dest', b'init'))
+
+ if given:
+ # FIXME: replace bup-get with independent commands as is feasible
+ exr = _run_get(disposition, b'--replace', given)
+ assert not exr.rc
+ return _run_get(disposition, method, what)
+
+def _test_universal(get_disposition, src_info):
+ methods = (b'--ff', b'--append', b'--pick', b'--force-pick', b'--new-tag',
+ b'--replace', b'--unnamed')
+ for method in methods:
+ mmsg = method.decode('ascii')
+ wvstart(get_disposition + ' ' + mmsg + ', missing source, fails')
+ exr = run_get(get_disposition, method, b'not-there')
+ wvpassne(0, exr.rc)
+ verify_rx(br'cannot find source', exr.err)
+ for method in methods:
+ mmsg = method.decode('ascii')
+ wvstart(get_disposition + ' ' + mmsg + ' / fails')
+ exr = run_get(get_disposition, method, b'/')
+ wvpassne(0, exr.rc)
+ verify_rx(b'cannot fetch entire repository', exr.err)
+
+def verify_only_refs(**kwargs):
+ for kind, refs in items(kwargs):
+ 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 _test_replace(get_disposition, src_info):
+ print('blarg:', repr(src_info), file=sys.stderr)
+
+ wvstart(get_disposition + ' --replace to root fails')
+ for item in (b'.tag/tinyfile',
+ b'src/latest' + src_info['tinyfile-path'],
+ b'.tag/subtree',
+ b'src/latest' + src_info['subtree-vfs-path'],
+ b'.tag/commit-1',
+ b'src/latest',
+ b'src'):
+ exr = run_get(get_disposition, b'--replace', (item, b'/'))
+ wvpassne(0, exr.rc)
+ verify_rx(br'impossible; can only overwrite branch or tag', exr.err)
+
+ tinyfile_id = src_info['tinyfile-id']
+ tinyfile_path = src_info['tinyfile-path']
+ subtree_vfs_path = src_info['subtree-vfs-path']
+ subtree_id = src_info['subtree-id']
+ commit_2_id = src_info['commit-2-id']
+ tree_2_id = src_info['tree-2-id']
+
+ # Anything to tag
+ existing_items = {'nothing' : None,
+ 'blob' : (b'.tag/tinyfile', b'.tag/obj'),
+ 'tree' : (b'.tag/tree-1', b'.tag/obj'),
+ 'commit': (b'.tag/commit-1', b'.tag/obj')}
+ for ex_type, ex_ref in items(existing_items):
+ wvstart(get_disposition + ' --replace ' + ex_type + ' with blob tag')
+ for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
+ exr = run_get(get_disposition, b'--replace', (item ,b'.tag/obj'),
+ given=ex_ref)
+ wvpasseq(0, exr.rc)
+ validate_blob(tinyfile_id, tinyfile_id)
+ verify_only_refs(heads=[], tags=(b'obj',))
+ wvstart(get_disposition + ' --replace ' + ex_type + ' with tree tag')
+ for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
+ exr = run_get(get_disposition, b'--replace', (item, b'.tag/obj'),
+ given=ex_ref)
+ validate_tree(subtree_id, subtree_id)
+ verify_only_refs(heads=[], tags=(b'obj',))
+ wvstart(get_disposition + ' --replace ' + ex_type + ' with commitish tag')
+ for item in (b'.tag/commit-2', b'src/latest', b'src'):
+ exr = run_get(get_disposition, b'--replace', (item, b'.tag/obj'),
+ given=ex_ref)
+ validate_tagged_save(b'obj', getcwd() + b'/src',
+ commit_2_id, tree_2_id, b'src-2', exr.out)
+ verify_only_refs(heads=[], tags=(b'obj',))
+
+ # Committish to branch.
+ existing_items = (('nothing', None),
+ ('branch', (b'.tag/commit-1', b'obj')))
+ for ex_type, ex_ref in existing_items:
+ for item_type, item in (('commit', b'.tag/commit-2'),
+ ('save', b'src/latest'),
+ ('branch', b'src')):
+ wvstart(get_disposition + ' --replace '
+ + ex_type + ' with ' + item_type)
+ exr = run_get(get_disposition, b'--replace', (item, b'obj'),
+ given=ex_ref)
+ validate_save(b'obj/latest', getcwd() + b'/src',
+ commit_2_id, tree_2_id, b'src-2', exr.out)
+ verify_only_refs(heads=(b'obj',), tags=[])
+
+ # Not committish to branch
+ existing_items = (('nothing', None),
+ ('branch', (b'.tag/commit-1', b'obj')))
+ for ex_type, ex_ref in existing_items:
+ for item_type, item in (('blob', b'.tag/tinyfile'),
+ ('blob', b'src/latest' + tinyfile_path),
+ ('tree', b'.tag/subtree'),
+ ('tree', b'src/latest' + subtree_vfs_path)):
+ wvstart(get_disposition + ' --replace branch with '
+ + item_type + ' given ' + ex_type + ' fails')
+
+ exr = run_get(get_disposition, b'--replace', (item, b'obj'),
+ given=ex_ref)
+ wvpassne(0, exr.rc)
+ verify_rx(br'cannot overwrite branch with .+ for', exr.err)
+
+ wvstart(get_disposition + ' --replace, implicit destinations')
+
+ exr = run_get(get_disposition, b'--replace', b'src')
+ validate_save(b'src/latest', getcwd() + b'/src',
+ commit_2_id, tree_2_id, b'src-2', exr.out)
+ verify_only_refs(heads=(b'src',), tags=[])
+
+ exr = run_get(get_disposition, b'--replace', b'.tag/commit-2')
+ validate_tagged_save(b'commit-2', getcwd() + b'/src',
+ commit_2_id, tree_2_id, b'src-2', exr.out)
+ verify_only_refs(heads=[], tags=(b'commit-2',))
+
+def _test_ff(get_disposition, src_info):
+
+ wvstart(get_disposition + ' --ff to root fails')
+ tinyfile_path = src_info['tinyfile-path']
+ for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
+ exr = run_get(get_disposition, b'--ff', (item, b'/'))
+ wvpassne(0, exr.rc)
+ verify_rx(br'source for .+ must be a branch, save, or commit', exr.err)
+ subtree_vfs_path = src_info['subtree-vfs-path']
+ for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
+ exr = run_get(get_disposition, b'--ff', (item, b'/'))
+ wvpassne(0, exr.rc)
+ verify_rx(br'is impossible; can only --append a tree to a branch',
+ exr.err)
+ for item in (b'.tag/commit-1', b'src/latest', b'src'):
+ exr = run_get(get_disposition, b'--ff', (item, b'/'))
+ wvpassne(0, exr.rc)
+ verify_rx(br'destination for .+ is a root, not a branch', exr.err)
+
+ wvstart(get_disposition + ' --ff of not-committish fails')
+ for src in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
+ # FIXME: use get_item elsewhere?
+ for given, get_item in ((None, (src, b'obj')),
+ (None, (src, b'.tag/obj')),
+ ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
+ ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
+ ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
+ ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
+ exr = run_get(get_disposition, b'--ff', get_item, given=given)
+ wvpassne(0, exr.rc)
+ verify_rx(br'must be a branch, save, or commit', exr.err)
+ for src in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
+ for given, get_item in ((None, (src, b'obj')),
+ (None, (src, b'.tag/obj')),
+ ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
+ ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
+ ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
+ ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
+ exr = run_get(get_disposition, b'--ff', get_item, given=given)
+ wvpassne(0, exr.rc)
+ verify_rx(br'can only --append a tree to a branch', exr.err)
+
+ wvstart(get_disposition + ' --ff committish, ff possible')
+ save_2 = src_info['save-2']
+ for src in (b'.tag/commit-2', b'src/' + save_2, b'src'):
+ for given, get_item, complaint in \
+ ((None, (src, b'.tag/obj'),
+ br'destination .+ must be a valid branch name'),
+ ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj'),
+ br'destination .+ is a blob, not a branch'),
+ ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj'),
+ br'destination .+ is a tree, not a branch'),
+ ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj'),
+ br'destination .+ is a tagged commit, not a branch'),
+ ((b'.tag/commit-2', b'.tag/obj'), (src, b'.tag/obj'),
+ br'destination .+ is a tagged commit, not a branch')):
+ exr = run_get(get_disposition, b'--ff', get_item, given=given)
+ wvpassne(0, exr.rc)
+ verify_rx(complaint, exr.err)
+ # FIXME: use src or item and given or existing consistently in loops...
+ commit_2_id = src_info['commit-2-id']
+ tree_2_id = src_info['tree-2-id']
+ for src in (b'.tag/commit-2', b'src/' + save_2, b'src'):
+ for given in (None, (b'.tag/commit-1', b'obj'), (b'.tag/commit-2', b'obj')):
+ exr = run_get(get_disposition, b'--ff', (src, b'obj'), given=given)
+ wvpasseq(0, exr.rc)
+ validate_save(b'obj/latest', getcwd() + b'/src',
+ commit_2_id, tree_2_id, b'src-2', exr.out)
+ verify_only_refs(heads=(b'obj',), tags=[])
+
+ wvstart(get_disposition + ' --ff, implicit destinations')
+ for item in (b'src', b'src/latest'):
+ exr = run_get(get_disposition, b'--ff', item)
+ wvpasseq(0, exr.rc)
+
+ ex((b'find', b'get-dest/refs'))
+ ex((bup_cmd, b'-d', b'get-dest', b'ls'))
+
+ validate_save(b'src/latest', getcwd() + b'/src',
+ commit_2_id, tree_2_id, b'src-2', exr.out)
+ #verify_only_refs(heads=('src',), tags=[])
+
+ wvstart(get_disposition + ' --ff, ff impossible')
+ for given, get_item in (((b'unrelated-branch', b'src'), b'src'),
+ ((b'.tag/commit-2', b'src'), (b'.tag/commit-1', b'src'))):
+ exr = run_get(get_disposition, b'--ff', get_item, given=given)
+ wvpassne(0, exr.rc)
+ verify_rx(br'destination is not an ancestor of source', exr.err)
+
+def _test_append(get_disposition, src_info):
+ tinyfile_path = src_info['tinyfile-path']
+ subtree_vfs_path = src_info['subtree-vfs-path']
+
+ wvstart(get_disposition + ' --append to root fails')
+ for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
+ exr = run_get(get_disposition, b'--append', (item, b'/'))
+ wvpassne(0, exr.rc)
+ verify_rx(br'source for .+ must be a branch, save, commit, or tree',
+ exr.err)
+ for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path,
+ b'.tag/commit-1', b'src/latest', b'src'):
+ exr = run_get(get_disposition, b'--append', (item, b'/'))
+ wvpassne(0, exr.rc)
+ verify_rx(br'destination for .+ is a root, not a branch', exr.err)
+
+ wvstart(get_disposition + ' --append of not-treeish fails')
+ for src in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
+ for given, item in ((None, (src, b'obj')),
+ (None, (src, b'.tag/obj')),
+ ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj')),
+ ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj')),
+ ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj')),
+ ((b'.tag/commit-1', b'obj'), (src, b'obj'))):
+ exr = run_get(get_disposition, b'--append', item, given=given)
+ wvpassne(0, exr.rc)
+ verify_rx(br'must be a branch, save, commit, or tree', exr.err)
+
+ wvstart(get_disposition + ' --append committish failure cases')
+ save_2 = src_info['save-2']
+ for src in (b'.tag/subtree', b'src/latest' + subtree_vfs_path,
+ b'.tag/commit-2', b'src/' + save_2, b'src'):
+ for given, item, complaint in \
+ ((None, (src, b'.tag/obj'),
+ br'destination .+ must be a valid branch name'),
+ ((b'.tag/tinyfile', b'.tag/obj'), (src, b'.tag/obj'),
+ br'destination .+ is a blob, not a branch'),
+ ((b'.tag/tree-1', b'.tag/obj'), (src, b'.tag/obj'),
+ br'destination .+ is a tree, not a branch'),
+ ((b'.tag/commit-1', b'.tag/obj'), (src, b'.tag/obj'),
+ br'destination .+ is a tagged commit, not a branch'),
+ ((b'.tag/commit-2', b'.tag/obj'), (src, b'.tag/obj'),
+ br'destination .+ is a tagged commit, not a branch')):
+ exr = run_get(get_disposition, b'--append', item, given=given)
+ wvpassne(0, exr.rc)
+ verify_rx(complaint, exr.err)
+
+ wvstart(get_disposition + ' --append committish')
+ commit_2_id = src_info['commit-2-id']
+ tree_2_id = src_info['tree-2-id']
+ for item in (b'.tag/commit-2', b'src/' + save_2, b'src'):
+ for existing in (None, (b'.tag/commit-1', b'obj'),
+ (b'.tag/commit-2', b'obj'),
+ (b'unrelated-branch', b'obj')):
+ exr = run_get(get_disposition, b'--append', (item, b'obj'),
+ given=existing)
+ wvpasseq(0, exr.rc)
+ validate_new_save(b'obj/latest', getcwd() + b'/src',
+ commit_2_id, tree_2_id, b'src-2', exr.out)
+ verify_only_refs(heads=(b'obj',), tags=[])
+ # Append ancestor
+ save_1 = src_info['save-1']
+ commit_1_id = src_info['commit-1-id']
+ tree_1_id = src_info['tree-1-id']
+ for item in (b'.tag/commit-1', b'src/' + save_1, b'src-1'):
+ exr = run_get(get_disposition, b'--append', (item, b'obj'),
+ given=(b'.tag/commit-2', b'obj'))
+ wvpasseq(0, exr.rc)
+ validate_new_save(b'obj/latest', getcwd() + b'/src',
+ commit_1_id, tree_1_id, b'src-1', exr.out)
+ verify_only_refs(heads=(b'obj',), tags=[])
+
+ wvstart(get_disposition + ' --append tree')
+ subtree_path = src_info['subtree-path']
+ subtree_id = src_info['subtree-id']
+ for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
+ for existing in (None,
+ (b'.tag/commit-1', b'obj'),
+ (b'.tag/commit-2', b'obj')):
+ exr = run_get(get_disposition, b'--append', (item, b'obj'),
+ given=existing)
+ wvpasseq(0, exr.rc)
+ validate_new_save(b'obj/latest', b'/', None, subtree_id, subtree_path,
+ exr.out)
+ verify_only_refs(heads=(b'obj',), tags=[])
+
+ wvstart(get_disposition + ' --append, implicit destinations')
+
+ for item in (b'src', b'src/latest'):
+ exr = run_get(get_disposition, b'--append', item)
+ wvpasseq(0, exr.rc)
+ validate_new_save(b'src/latest', getcwd() + b'/src', commit_2_id, tree_2_id,
+ b'src-2', exr.out)
+ verify_only_refs(heads=(b'src',), tags=[])
+
+def _test_pick_common(get_disposition, src_info, force=False):
+ flavor = b'--force-pick' if force else b'--pick'
+ flavormsg = flavor.decode('ascii')
+ tinyfile_path = src_info['tinyfile-path']
+ subtree_vfs_path = src_info['subtree-vfs-path']
+
+ wvstart(get_disposition + ' ' + flavormsg + ' to root fails')
+ for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path, b'src'):
+ exr = run_get(get_disposition, flavor, (item, b'/'))
+ wvpassne(0, exr.rc)
+ verify_rx(br'can only pick a commit or save', exr.err)
+ for item in (b'.tag/commit-1', b'src/latest'):
+ exr = run_get(get_disposition, flavor, (item, b'/'))
+ wvpassne(0, exr.rc)
+ verify_rx(br'destination is not a tag or branch', exr.err)
+ for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
+ exr = run_get(get_disposition, flavor, (item, b'/'))
+ wvpassne(0, exr.rc)
+ verify_rx(br'is impossible; can only --append a tree', exr.err)
+
+ wvstart(get_disposition + ' ' + flavormsg + ' of blob or branch fails')
+ for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path, b'src'):
+ for given, get_item in ((None, (item, b'obj')),
+ (None, (item, b'.tag/obj')),
+ ((b'.tag/tinyfile', b'.tag/obj'), (item, b'.tag/obj')),
+ ((b'.tag/tree-1', b'.tag/obj'), (item, b'.tag/obj')),
+ ((b'.tag/commit-1', b'.tag/obj'), (item, b'.tag/obj')),
+ ((b'.tag/commit-1', b'obj'), (item, b'obj'))):
+ exr = run_get(get_disposition, flavor, get_item, given=given)
+ wvpassne(0, exr.rc)
+ verify_rx(br'impossible; can only pick a commit or save', exr.err)
+
+ wvstart(get_disposition + ' ' + flavormsg + ' of tree fails')
+ for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
+ for given, get_item in ((None, (item, b'obj')),
+ (None, (item, b'.tag/obj')),
+ ((b'.tag/tinyfile', b'.tag/obj'), (item, b'.tag/obj')),
+ ((b'.tag/tree-1', b'.tag/obj'), (item, b'.tag/obj')),
+ ((b'.tag/commit-1', b'.tag/obj'), (item, b'.tag/obj')),
+ ((b'.tag/commit-1', b'obj'), (item, b'obj'))):
+ exr = run_get(get_disposition, flavor, get_item, given=given)
+ wvpassne(0, exr.rc)
+ verify_rx(br'impossible; can only --append a tree', exr.err)
+
+ save_2 = src_info['save-2']
+ commit_2_id = src_info['commit-2-id']
+ tree_2_id = src_info['tree-2-id']
+ # FIXME: these two wvstart texts?
+ if force:
+ wvstart(get_disposition + ' ' + flavormsg + ' commit/save to existing tag')
+ for item in (b'.tag/commit-2', b'src/' + save_2):
+ for given in ((b'.tag/tinyfile', b'.tag/obj'),
+ (b'.tag/tree-1', b'.tag/obj'),
+ (b'.tag/commit-1', b'.tag/obj')):
+ exr = run_get(get_disposition, flavor, (item, b'.tag/obj'),
+ given=given)
+ wvpasseq(0, exr.rc)
+ validate_new_tagged_commit(b'obj', commit_2_id, tree_2_id,
+ exr.out)
+ verify_only_refs(heads=[], tags=(b'obj',))
+ else: # --pick
+ wvstart(get_disposition + ' ' + flavormsg
+ + ' commit/save to existing tag fails')
+ for item in (b'.tag/commit-2', b'src/' + save_2):
+ for given in ((b'.tag/tinyfile', b'.tag/obj'),
+ (b'.tag/tree-1', b'.tag/obj'),
+ (b'.tag/commit-1', b'.tag/obj')):
+ exr = run_get(get_disposition, flavor, (item, b'.tag/obj'), given=given)
+ wvpassne(0, exr.rc)
+ verify_rx(br'cannot overwrite existing tag', exr.err)
+
+ wvstart(get_disposition + ' ' + flavormsg + ' commit/save to tag')
+ for item in (b'.tag/commit-2', b'src/' + save_2):
+ exr = run_get(get_disposition, flavor, (item, b'.tag/obj'))
+ wvpasseq(0, exr.rc)
+ validate_clean_repo()
+ validate_new_tagged_commit(b'obj', commit_2_id, tree_2_id, exr.out)
+ verify_only_refs(heads=[], tags=(b'obj',))
+
+ wvstart(get_disposition + ' ' + flavormsg + ' commit/save to branch')
+ for item in (b'.tag/commit-2', b'src/' + save_2):
+ for given in (None, (b'.tag/commit-1', b'obj'), (b'.tag/commit-2', b'obj')):
+ exr = run_get(get_disposition, flavor, (item, b'obj'), given=given)
+ wvpasseq(0, exr.rc)
+ validate_clean_repo()
+ validate_new_save(b'obj/latest', getcwd() + b'/src',
+ commit_2_id, tree_2_id, b'src-2', exr.out)
+ verify_only_refs(heads=(b'obj',), tags=[])
+
+ wvstart(get_disposition + ' ' + flavormsg
+ + ' commit/save unrelated commit to branch')
+ for item in(b'.tag/commit-2', b'src/' + save_2):
+ exr = run_get(get_disposition, flavor, (item, b'obj'),
+ given=(b'unrelated-branch', b'obj'))
+ wvpasseq(0, exr.rc)
+ validate_clean_repo()
+ validate_new_save(b'obj/latest', getcwd() + b'/src',
+ commit_2_id, tree_2_id, b'src-2', exr.out)
+ verify_only_refs(heads=(b'obj',), tags=[])
+
+ wvstart(get_disposition + ' ' + flavormsg + ' commit/save ancestor to branch')
+ save_1 = src_info['save-1']
+ commit_1_id = src_info['commit-1-id']
+ tree_1_id = src_info['tree-1-id']
+ for item in (b'.tag/commit-1', b'src/' + save_1):
+ exr = run_get(get_disposition, flavor, (item, b'obj'),
+ given=(b'.tag/commit-2', b'obj'))
+ wvpasseq(0, exr.rc)
+ validate_clean_repo()
+ validate_new_save(b'obj/latest', getcwd() + b'/src',
+ commit_1_id, tree_1_id, b'src-1', exr.out)
+ verify_only_refs(heads=(b'obj',), tags=[])
+
+
+ wvstart(get_disposition + ' ' + flavormsg + ', implicit destinations')
+ exr = run_get(get_disposition, flavor, b'.tag/commit-2')
+ wvpasseq(0, exr.rc)
+ validate_clean_repo()
+ validate_new_tagged_commit(b'commit-2', commit_2_id, tree_2_id, exr.out)
+ verify_only_refs(heads=[], tags=(b'commit-2',))
+
+ exr = run_get(get_disposition, flavor, b'src/latest')
+ wvpasseq(0, exr.rc)
+ validate_clean_repo()
+ validate_new_save(b'src/latest', getcwd() + b'/src',
+ commit_2_id, tree_2_id, b'src-2', exr.out)
+ verify_only_refs(heads=(b'src',), tags=[])
+
+def _test_pick_force(get_disposition, src_info):
+ _test_pick_common(get_disposition, src_info, force=True)
+
+def _test_pick_noforce(get_disposition, src_info):
+ _test_pick_common(get_disposition, src_info, force=False)
+
+def _test_new_tag(get_disposition, src_info):
+ tinyfile_id = src_info['tinyfile-id']
+ tinyfile_path = src_info['tinyfile-path']
+ commit_2_id = src_info['commit-2-id']
+ tree_2_id = src_info['tree-2-id']
+ subtree_id = src_info['subtree-id']
+ subtree_vfs_path = src_info['subtree-vfs-path']
+
+ wvstart(get_disposition + ' --new-tag to root fails')
+ for item in (b'.tag/tinyfile',
+ b'src/latest' + tinyfile_path,
+ b'.tag/subtree',
+ b'src/latest' + subtree_vfs_path,
+ b'.tag/commit-1',
+ b'src/latest',
+ b'src'):
+ exr = run_get(get_disposition, b'--new-tag', (item, b'/'))
+ wvpassne(0, exr.rc)
+ verify_rx(br'destination for .+ must be a VFS tag', exr.err)
+
+ # Anything to new tag.
+ wvstart(get_disposition + ' --new-tag, blob tag')
+ for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
+ exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
+ wvpasseq(0, exr.rc)
+ validate_blob(tinyfile_id, tinyfile_id)
+ verify_only_refs(heads=[], tags=(b'obj',))
+
+ wvstart(get_disposition + ' --new-tag, tree tag')
+ for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
+ exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
+ wvpasseq(0, exr.rc)
+ validate_tree(subtree_id, subtree_id)
+ verify_only_refs(heads=[], tags=(b'obj',))
+
+ wvstart(get_disposition + ' --new-tag, committish tag')
+ for item in (b'.tag/commit-2', b'src/latest', b'src'):
+ exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'))
+ wvpasseq(0, exr.rc)
+ validate_tagged_save(b'obj', getcwd() + b'/src/', commit_2_id, tree_2_id,
+ b'src-2', exr.out)
+ verify_only_refs(heads=[], tags=(b'obj',))
+
+ # Anything to existing tag (fails).
+ for ex_type, ex_tag in (('blob', (b'.tag/tinyfile', b'.tag/obj')),
+ ('tree', (b'.tag/tree-1', b'.tag/obj')),
+ ('commit', (b'.tag/commit-1', b'.tag/obj'))):
+ for item_type, item in (('blob tag', b'.tag/tinyfile'),
+ ('blob path', b'src/latest' + tinyfile_path),
+ ('tree tag', b'.tag/subtree'),
+ ('tree path', b'src/latest' + subtree_vfs_path),
+ ('commit tag', b'.tag/commit-2'),
+ ('save', b'src/latest'),
+ ('branch', b'src')):
+ wvstart(get_disposition + ' --new-tag of ' + item_type
+ + ', given existing ' + ex_type + ' tag, fails')
+ exr = run_get(get_disposition, b'--new-tag', (item, b'.tag/obj'),
+ given=ex_tag)
+ wvpassne(0, exr.rc)
+ verify_rx(br'cannot overwrite existing tag .* \(requires --replace\)',
+ exr.err)
+
+ # Anything to branch (fails).
+ for ex_type, ex_tag in (('nothing', None),
+ ('blob', (b'.tag/tinyfile', b'.tag/obj')),
+ ('tree', (b'.tag/tree-1', b'.tag/obj')),
+ ('commit', (b'.tag/commit-1', b'.tag/obj'))):
+ for item_type, item in (('blob tag', b'.tag/tinyfile'),
+ ('blob path', b'src/latest' + tinyfile_path),
+ ('tree tag', b'.tag/subtree'),
+ ('tree path', b'src/latest' + subtree_vfs_path),
+ ('commit tag', b'.tag/commit-2'),
+ ('save', b'src/latest'),
+ ('branch', b'src')):
+ wvstart(get_disposition + ' --new-tag to branch of ' + item_type
+ + ', given existing ' + ex_type + ' tag, fails')
+ exr = run_get(get_disposition, b'--new-tag', (item, b'obj'),
+ given=ex_tag)
+ wvpassne(0, exr.rc)
+ verify_rx(br'destination for .+ must be a VFS tag', exr.err)
+
+ wvstart(get_disposition + ' --new-tag, implicit destinations')
+ exr = run_get(get_disposition, b'--new-tag', b'.tag/commit-2')
+ wvpasseq(0, exr.rc)
+ validate_tagged_save(b'commit-2', getcwd() + b'/src/', commit_2_id, tree_2_id,
+ b'src-2', exr.out)
+ verify_only_refs(heads=[], tags=(b'commit-2',))
+
+def _test_unnamed(get_disposition, src_info):
+ tinyfile_id = src_info['tinyfile-id']
+ tinyfile_path = src_info['tinyfile-path']
+ subtree_vfs_path = src_info['subtree-vfs-path']
+ wvstart(get_disposition + ' --unnamed to root fails')
+ for item in (b'.tag/tinyfile',
+ b'src/latest' + tinyfile_path,
+ b'.tag/subtree',
+ b'src/latest' + subtree_vfs_path,
+ b'.tag/commit-1',
+ b'src/latest',
+ b'src'):
+ for ex_ref in (None, (item, b'.tag/obj')):
+ exr = run_get(get_disposition, b'--unnamed', (item, b'/'),
+ given=ex_ref)
+ wvpassne(0, exr.rc)
+ verify_rx(br'usage: bup get ', exr.err)
+
+ wvstart(get_disposition + ' --unnamed file')
+ for item in (b'.tag/tinyfile', b'src/latest' + tinyfile_path):
+ exr = run_get(get_disposition, b'--unnamed', item)
+ wvpasseq(0, exr.rc)
+ validate_blob(tinyfile_id, tinyfile_id)
+ verify_only_refs(heads=[], tags=[])
+
+ exr = run_get(get_disposition, b'--unnamed', item,
+ given=(item, b'.tag/obj'))
+ wvpasseq(0, exr.rc)
+ validate_blob(tinyfile_id, tinyfile_id)
+ verify_only_refs(heads=[], tags=(b'obj',))
+
+ wvstart(get_disposition + ' --unnamed tree')
+ subtree_id = src_info['subtree-id']
+ for item in (b'.tag/subtree', b'src/latest' + subtree_vfs_path):
+ exr = run_get(get_disposition, b'--unnamed', item)
+ wvpasseq(0, exr.rc)
+ validate_tree(subtree_id, subtree_id)
+ verify_only_refs(heads=[], tags=[])
+
+ exr = run_get(get_disposition, b'--unnamed', item,
+ given=(item, b'.tag/obj'))
+ wvpasseq(0, exr.rc)
+ validate_tree(subtree_id, subtree_id)
+ verify_only_refs(heads=[], tags=(b'obj',))
+
+ wvstart(get_disposition + ' --unnamed committish')
+ save_2 = src_info['save-2']
+ commit_2_id = src_info['commit-2-id']
+ for item in (b'.tag/commit-2', b'src/' + save_2, b'src'):
+ exr = run_get(get_disposition, b'--unnamed', item)
+ wvpasseq(0, exr.rc)
+ validate_commit(commit_2_id, commit_2_id)
+ verify_only_refs(heads=[], tags=[])
+
+ exr = run_get(get_disposition, b'--unnamed', item,
+ given=(item, b'.tag/obj'))
+ wvpasseq(0, exr.rc)
+ validate_commit(commit_2_id, commit_2_id)
+ verify_only_refs(heads=[], tags=(b'obj',))
+
+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}
+
+# FIXME: this fails in a strange way:
+# WVPASS given nothing get --ff not-there
+
+dispositions_to_test = ('get',)
+
+if int(environ.get(b'BUP_TEST_LEVEL', b'0')) >= 11:
+ dispositions_to_test += ('get-on', 'get-to')
+
+categories = ('replace', 'universal', 'ff', 'append', 'pick_force', 'pick_noforce', 'new_tag', 'unnamed')
+
+@pytest.mark.parametrize("disposition,category", product(dispositions_to_test, categories))
+def test_get(tmpdir, disposition, category):
+ chdir(tmpdir)
+ try:
+ src_info = create_get_src()
+ globals().get('_test_' + category)(disposition, src_info)
+ finally:
+ chdir(top)
--- /dev/null
+
+from __future__ import absolute_import, print_function
+from collections import defaultdict
+from itertools import chain, dropwhile, groupby, takewhile
+from os import chdir
+from random import choice, randint
+from shutil import copytree, rmtree
+from subprocess import PIPE
+from sys import stderr
+from time import localtime, strftime, time, tzset
+import random, sys
+
+if sys.version_info[:2] >= (3, 5):
+ from difflib import diff_bytes, unified_diff
+else:
+ from difflib import unified_diff
+
+from bup import compat
+from bup.compat import environ
+from bup.helpers import partition, period_as_secs, readpipe
+from bup.io import byte_stream
+from buptest import ex, exo
+from wvpytest import wvfail, wvpass, wvpasseq, wvpassne, wvstart
+import bup.path
+
+if sys.version_info[:2] < (3, 5):
+ def diff_bytes(_, *args):
+ return unified_diff(*args)
+
+def create_older_random_saves(n, start_utc, end_utc):
+ with open(b'foo', 'wb') as f:
+ pass
+ ex([b'git', b'add', b'foo'])
+ utcs = set()
+ while len(utcs) != n:
+ utcs.add(randint(start_utc, end_utc))
+ utcs = sorted(utcs)
+ for utc in utcs:
+ with open(b'foo', 'wb') as f:
+ f.write(b'%d\n' % utc)
+ ex([b'git', b'commit', b'--date', b'%d' % utc, b'-qam', b'%d' % utc])
+ ex([b'git', b'gc', b'--aggressive'])
+ return utcs
+
+# There is corresponding code in bup for some of this, but the
+# computation method is different here, in part so that the test can
+# provide a more effective cross-check.
+
+period_kinds = [b'all', b'dailies', b'monthlies', b'yearlies']
+period_scale = {b's': 1,
+ b'min': 60,
+ b'h': 60 * 60,
+ b'd': 60 * 60 * 24,
+ b'w': 60 * 60 * 24 * 7,
+ b'm': 60 * 60 * 24 * 31,
+ b'y': 60 * 60 * 24 * 366}
+period_scale_kinds = list(period_scale.keys())
+
+def expected_retentions(utcs, utc_start, spec):
+ if not spec:
+ return utcs
+ utcs = sorted(utcs, reverse=True)
+ period_start = dict(spec)
+ for kind, duration in compat.items(period_start):
+ period_start[kind] = utc_start - period_as_secs(duration)
+ period_start = defaultdict(lambda: float('inf'), period_start)
+
+ all = list(takewhile(lambda x: x >= period_start[b'all'], utcs))
+ utcs = list(dropwhile(lambda x: x >= period_start[b'all'], utcs))
+
+ matches = takewhile(lambda x: x >= period_start[b'dailies'], utcs)
+ dailies = [max(day_utcs) for yday, day_utcs
+ in groupby(matches, lambda x: localtime(x).tm_yday)]
+ utcs = list(dropwhile(lambda x: x >= period_start[b'dailies'], utcs))
+
+ matches = takewhile(lambda x: x >= period_start[b'monthlies'], utcs)
+ monthlies = [max(month_utcs) for month, month_utcs
+ in groupby(matches, lambda x: localtime(x).tm_mon)]
+ utcs = dropwhile(lambda x: x >= period_start[b'monthlies'], utcs)
+
+ matches = takewhile(lambda x: x >= period_start[b'yearlies'], utcs)
+ yearlies = [max(year_utcs) for year, year_utcs
+ in groupby(matches, lambda x: localtime(x).tm_year)]
+
+ return chain(all, dailies, monthlies, yearlies)
+
+def period_spec(start_utc, end_utc):
+ global period_kinds, period_scale, period_scale_kinds
+ result = []
+ desired_specs = randint(1, 2 * len(period_kinds))
+ assert(desired_specs >= 1) # At least one --keep argument is required
+ while len(result) < desired_specs:
+ period = None
+ if randint(1, 100) <= 5:
+ period = b'forever'
+ else:
+ assert(end_utc > start_utc)
+ period_secs = randint(1, end_utc - start_utc)
+ scale = choice(period_scale_kinds)
+ mag = int(float(period_secs) / period_scale[scale])
+ if mag != 0:
+ period = (b'%d' % mag) + scale
+ if period:
+ result += [(choice(period_kinds), period)]
+ return tuple(result)
+
+def unique_period_specs(n, start_utc, end_utc):
+ invocations = set()
+ while len(invocations) < n:
+ invocations.add(period_spec(start_utc, end_utc))
+ return tuple(invocations)
+
+def period_spec_to_period_args(spec):
+ return tuple(chain(*((b'--keep-' + kind + b'-for', period)
+ for kind, period in spec)))
+
+def result_diffline(x):
+ return (b'%d %s\n'
+ % (x, strftime(' %Y-%m-%d-%H%M%S', localtime(x)).encode('ascii')))
+
+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 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)
from __future__ import absolute_import, print_function
-from wvtest import *
-
from bup.compat import pending_raise
+from wvpytest import wvpasseq
-@wvtest
def test_pending_raise():
outer = Exception('outer')
inner = Exception('inner')
with pending_raise(ex):
pass
except Exception as ex:
- WVPASSEQ(outer, ex)
- WVPASSEQ(None, getattr(outer, '__context__', None))
+ wvpasseq(outer, ex)
+ wvpasseq(None, getattr(outer, '__context__', None))
try:
try:
with pending_raise(ex):
raise inner
except Exception as ex:
- WVPASSEQ(inner, ex)
- WVPASSEQ(None, getattr(outer, '__context__', None))
- WVPASSEQ(outer, getattr(inner, '__context__', None))
+ wvpasseq(inner, ex)
+ wvpasseq(None, getattr(outer, '__context__', None))
+ wvpasseq(outer, getattr(inner, '__context__', None))
from traceback import extract_stack
import errno, os, subprocess, sys, tempfile
-from wvtest import WVPASSEQ, wvfailure_count
-
from bup import helpers
from bup.compat import fsencode, str_type
from bup.io import byte_stream
-# Assumes (of course) this file is at the top-level of the source tree
-_bup_tmp = realpath(dirname(fsencode(__file__))) + b'/test/tmp'
-try:
- os.makedirs(_bup_tmp)
-except OSError as e:
- if e.errno != errno.EEXIST:
- raise
-
-
-@contextmanager
-def test_tempdir(prefix):
- initial_failures = wvfailure_count()
- tmpdir = tempfile.mkdtemp(dir=_bup_tmp, prefix=prefix)
- yield tmpdir
- if wvfailure_count() == initial_failures:
- subprocess.call(['chmod', '-R', 'u+rwX', tmpdir])
- subprocess.call(['rm', '-rf', tmpdir])
-
-
ex_res = namedtuple('SubprocResult', ['out', 'err', 'proc', 'rc'])
def run(cmd, check=True, input=None, **kwargs):
+++ /dev/null
-#!/bin/sh
-"""": # -*-python-*-
-bup_python="$(dirname "$0")/dev/bup-python"
-exec "$bup_python" "$0" ${1+"$@"}
-"""
-# end of bup preamble
-
-#
-# WvTest:
-# Copyright (C)2007-2012 Versabanq Innovations Inc. and contributors.
-# Licensed under the GNU Library General Public License, version 2.
-# See the included file named LICENSE for license information.
-# You can get wvtest from: http://github.com/apenwarr/wvtest
-#
-
-from __future__ import absolute_import, print_function
-
-import os
-import random
-
-_wvtest_random_seed = os.environ.get('BUP_TEST_SEED')
-if _wvtest_random_seed:
- random.seed(int(_wvtest_random_seed))
-
-from os.path import relpath
-import atexit
-import inspect
-import re
-import sys
-import traceback
-
-sys.path[:0] = [os.path.realpath('test/lib')]
-
-_start_dir = os.getcwd()
-
-# NOTE
-# Why do we do we need the "!= main" check? Because if you run
-# wvtest.py as a main program and it imports your test files, then
-# those test files will try to import the wvtest module recursively.
-# That actually *works* fine, because we don't run this main program
-# when we're imported as a module. But you end up with two separate
-# wvtest modules, the one that gets imported, and the one that's the
-# main program. Each of them would have duplicated global variables
-# (most importantly, wvtest._registered), and so screwy things could
-# happen. Thus, we make the main program module *totally* different
-# from the imported module. Then we import wvtest (the module) into
-# wvtest (the main program) here and make sure to refer to the right
-# versions of global variables.
-#
-# All this is done just so that wvtest.py can be a single file that's
-# easy to import into your own applications.
-if __name__ != '__main__': # we're imported as a module
- _registered = []
- _tests = 0
- _fails = 0
-
- def wvtest(func):
- """ Use this decorator (@wvtest) in front of any function you want to
- run as part of the unit test suite. Then run:
- python wvtest.py path/to/yourtest.py [other test.py files...]
- to run all the @wvtest functions in the given file(s).
- """
- _registered.append(func)
- return func
-
-
- def _result(msg, tb, code):
- global _tests, _fails
- _tests += 1
- if code != 'ok':
- _fails += 1
- (filename, line, func, text) = tb
- filename = os.path.basename(filename)
- msg = re.sub(r'\s+', ' ', str(msg))
- sys.stderr.flush()
- print('! %-70s %s' % ('%s:%-4d %s' % (filename, line, msg),
- code))
- sys.stdout.flush()
-
-
- def _caller_stack(wv_call_depth):
- # Without the chdir, the source text lookup may fail
- orig = os.getcwd()
- os.chdir(_start_dir)
- try:
- return traceback.extract_stack()[-(wv_call_depth + 2)]
- finally:
- os.chdir(orig)
-
-
- def _check(cond, msg = 'unknown', tb = None):
- if tb == None: tb = _caller_stack(2)
- if cond:
- _result(msg, tb, 'ok')
- else:
- _result(msg, tb, 'FAILED')
- return cond
-
- def wvcheck(cond, msg, tb = None):
- if tb == None: tb = _caller_stack(2)
- if cond:
- _result(msg, tb, 'ok')
- else:
- _result(msg, tb, 'FAILED')
- return cond
-
- _code_rx = re.compile(r'^\w+\((.*)\)(\s*#.*)?$')
- def _code():
- text = _caller_stack(2)[3]
- return _code_rx.sub(r'\1', text)
-
- def WVSTART(message):
- filename = _caller_stack(1)[0]
- sys.stderr.write('Testing \"' + message + '\" in ' + filename + ':\n')
-
- def WVMSG(message):
- ''' Issues a notification. '''
- return _result(message, _caller_stack(1), 'ok')
-
- def WVPASS(cond = True):
- ''' Counts a test failure unless cond is true. '''
- return _check(cond, _code())
-
- def WVFAIL(cond = True):
- ''' Counts a test failure unless cond is false. '''
- return _check(not cond, 'NOT(%s)' % _code())
-
- def WVPASSEQ(a, b):
- ''' Counts a test failure unless a == b. '''
- return _check(a == b, '%s == %s' % (repr(a), repr(b)))
-
- def WVPASSNE(a, b):
- ''' Counts a test failure unless a != b. '''
- return _check(a != b, '%s != %s' % (repr(a), repr(b)))
-
- def WVPASSLT(a, b):
- ''' Counts a test failure unless a < b. '''
- return _check(a < b, '%s < %s' % (repr(a), repr(b)))
-
- def WVPASSLE(a, b):
- ''' Counts a test failure unless a <= b. '''
- return _check(a <= b, '%s <= %s' % (repr(a), repr(b)))
-
- def WVPASSGT(a, b):
- ''' Counts a test failure unless a > b. '''
- return _check(a > b, '%s > %s' % (repr(a), repr(b)))
-
- def WVPASSGE(a, b):
- ''' Counts a test failure unless a >= b. '''
- return _check(a >= b, '%s >= %s' % (repr(a), repr(b)))
-
- def WVEXCEPT(etype, func, *args, **kwargs):
- ''' Counts a test failure unless func throws an 'etype' exception.
- You have to spell out the function name and arguments, rather than
- calling the function yourself, so that WVEXCEPT can run before
- your test code throws an exception.
- '''
- try:
- func(*args, **kwargs)
- except etype as e:
- return _check(True, 'EXCEPT(%s)' % _code())
- except:
- _check(False, 'EXCEPT(%s)' % _code())
- raise
- else:
- return _check(False, 'EXCEPT(%s)' % _code())
-
- wvstart = WVSTART
- wvmsg = WVMSG
- wvpass = WVPASS
- wvfail = WVFAIL
- wvpasseq = WVPASSEQ
- wvpassne = WVPASSNE
- wvpaslt = WVPASSLT
- wvpassle = WVPASSLE
- wvpassgt = WVPASSGT
- wvpassge = WVPASSGE
- wvexcept = WVEXCEPT
-
- def wvfailure_count():
- return _fails
-
- def _check_unfinished():
- if _registered:
- for func in _registered:
- print('WARNING: not run: %r' % (func,))
- WVFAIL('wvtest_main() not called')
- if _fails:
- sys.exit(1)
-
- atexit.register(_check_unfinished)
-
-
-def _run_in_chdir(path, func, *args, **kwargs):
- oldwd = os.getcwd()
- oldpath = sys.path
- try:
- os.chdir(path)
- sys.path += [path, os.path.split(path)[0]]
- return func(*args, **kwargs)
- finally:
- os.chdir(oldwd)
- sys.path = oldpath
-
-
-def _runtest(fname, f):
- mod = inspect.getmodule(f)
- rpath = relpath(mod.__file__, os.getcwd()).replace('.pyc', '.py')
- print()
- print('Testing "%s" in %s:' % (fname, rpath))
- sys.stdout.flush()
- try:
- _run_in_chdir(os.path.split(mod.__file__)[0], f)
- except Exception as e:
- print()
- print(traceback.format_exc())
- tb = sys.exc_info()[2]
- wvtest._result(e, traceback.extract_tb(tb)[1], 'EXCEPTION')
-
-
-def _run_registered_tests():
- import wvtest as _wvtestmod
- while _wvtestmod._registered:
- t = _wvtestmod._registered.pop(0)
- _runtest(t.__name__, t)
- print()
-
-
-def wvtest_main(extra_testfiles=tuple()):
- import wvtest as _wvtestmod
- _run_registered_tests()
- for modname in extra_testfiles:
- if not os.path.exists(modname):
- print('Skipping: %s' % modname)
- continue
- if modname.endswith('.py'):
- modname = modname[:-3]
- print('Importing: %s' % modname)
- path, mod = os.path.split(os.path.abspath(modname))
- nicename = modname.replace(os.path.sep, '.')
- while nicename.startswith('.'):
- nicename = modname[1:]
- _run_in_chdir(path, __import__, nicename, None, None, [])
- _run_registered_tests()
- print()
- print('WvTest: %d tests, %d failures.' % (_wvtestmod._tests,
- _wvtestmod._fails))
-
-
-if __name__ == '__main__':
- import wvtest as _wvtestmod
- sys.modules['wvtest'] = _wvtestmod
- sys.modules['wvtest.wvtest'] = _wvtestmod
- wvtest = _wvtestmod
- wvtest_main(sys.argv[1:])