summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/Dockerfile73
-rw-r--r--test/conftest.py52
-rw-r--r--test/requirements.txt6
-rw-r--r--test/test_alt.py45
-rw-r--r--test/test_alt_copy.py15
-rw-r--r--test/test_assert_private_dirs.py16
-rw-r--r--test/test_bootstrap.py12
-rw-r--r--test/test_clean.py8
-rw-r--r--test/test_clone.py74
-rw-r--r--test/test_compat_alt.py453
-rw-r--r--test/test_compat_jinja.py198
-rw-r--r--test/test_config.py52
-rw-r--r--test/test_default_remote_branch.py27
-rw-r--r--test/test_encryption.py52
-rw-r--r--test/test_enter.py22
-rw-r--r--test/test_ext_crypt.py (renamed from test/test_git_crypt.py)26
-rw-r--r--test/test_git.py14
-rw-r--r--test/test_help.py10
-rw-r--r--test/test_hooks.py48
-rw-r--r--test/test_init.py8
-rw-r--r--test/test_introspect.py6
-rw-r--r--test/test_list.py6
-rw-r--r--test/test_perms.py15
-rw-r--r--test/test_unit_configure_paths.py28
-rw-r--r--test/test_unit_copy_perms.py53
-rw-r--r--test/test_unit_encryption.py135
-rw-r--r--test/test_unit_issue_legacy_path_warning.py26
-rw-r--r--test/test_unit_record_score.py27
-rw-r--r--test/test_unit_report_invalid_alts.py35
-rw-r--r--test/test_unit_score_file.py38
-rw-r--r--test/test_unit_set_local_alt_values.py7
-rw-r--r--test/test_unit_set_yadm_dir.py41
-rw-r--r--test/test_unit_template_default.py71
-rw-r--r--test/test_unit_template_esh.py121
-rw-r--r--test/test_unit_template_j2.py7
-rw-r--r--test/test_unit_upgrade.py108
-rw-r--r--test/test_unit_x_program.py12
-rw-r--r--test/test_upgrade.py129
-rw-r--r--test/test_version.py5
39 files changed, 1115 insertions, 966 deletions
diff --git a/test/Dockerfile b/test/Dockerfile
new file mode 100644
index 0000000..3e5a299
--- /dev/null
+++ b/test/Dockerfile
@@ -0,0 +1,73 @@
+FROM ubuntu:18.04
+MAINTAINER Tim Byrne <sultan@locehilios.com>
+
+# Shellcheck and esh versions
+ARG SC_VER=0.7.1
+ARG ESH_VER=0.3.0
+
+# Install prerequisites and configure UTF-8 locale
+RUN \
+ echo "en_US.UTF-8 UTF-8" > /etc/locale.gen \
+ && apt-get update \
+ && DEBIAN_FRONTEND=noninteractive \
+ apt-get install -y --no-install-recommends \
+ expect \
+ git \
+ gnupg \
+ locales \
+ lsb-release \
+ make \
+ man \
+ python3-pip \
+ vim-tiny \
+ xz-utils \
+ && rm -rf /var/lib/apt/lists/* \
+ && update-locale LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
+
+ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
+
+# Convenience settings for the testbed's root account
+RUN echo 'set -o vi' >> /root/.bashrc
+
+# Create a flag to identify when running inside the yadm testbed
+RUN touch /.yadmtestbed
+
+# Install shellcheck
+ADD https://github.com/koalaman/shellcheck/releases/download/v$SC_VER/shellcheck-v$SC_VER.linux.x86_64.tar.xz /opt
+RUN cd /opt \
+ && tar xf shellcheck-v$SC_VER.linux.x86_64.tar.xz \
+ && rm -f shellcheck-v$SC_VER.linux.x86_64.tar.xz \
+ && ln -s /opt/shellcheck-v$SC_VER/shellcheck /usr/local/bin
+
+# Upgrade pip3 and install requirements
+COPY test/requirements.txt /tmp/requirements.txt
+RUN python3 -m pip install --upgrade pip setuptools \
+ && python3 -m pip install --upgrade -r /tmp/requirements.txt \
+ && rm -f /tmp/requirements
+
+# Install esh
+ADD https://raw.githubusercontent.com/jirutka/esh/v$ESH_VER/esh /usr/local/bin
+RUN chmod +x /usr/local/bin/esh
+
+# Create workdir and dummy Makefile to be used if no /yadm volume is mounted
+RUN mkdir /yadm \
+ && echo "test:" > /yadm/Makefile \
+ && echo "\t@echo 'The yadm project must be mounted at /yadm'" >> /yadm/Makefile \
+ && echo "\t@echo 'Try using a docker parameter like -v \"\$\$PWD:/yadm:ro\"'" >> /yadm/Makefile \
+ && echo "\t@false" >> /yadm/Makefile
+
+# Include released versions of yadm to test upgrades
+ADD https://raw.githubusercontent.com/TheLocehiliosan/yadm/1.12.0/yadm /usr/local/bin/yadm-1.12.0
+ADD https://raw.githubusercontent.com/TheLocehiliosan/yadm/2.5.0/yadm /usr/local/bin/yadm-2.5.0
+RUN chmod +x /usr/local/bin/yadm-*
+
+# Configure git to make it easier to test yadm manually
+RUN git config --system user.email "test@yadm.io" \
+ && git config --system user.name "Yadm Test"
+
+# /yadm will be the work directory for all tests
+# docker commands should mount the local yadm project as /yadm
+WORKDIR /yadm
+
+# By default, run all tests defined
+CMD make test
diff --git a/test/conftest.py b/test/conftest.py
index 31d872b..38228a1 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -25,25 +25,25 @@ def pytest_addoption(parser):
@pytest.fixture(scope='session')
def shellcheck_version():
"""Version of shellcheck supported"""
- return '0.4.6'
+ return '0.7.1'
@pytest.fixture(scope='session')
def pylint_version():
"""Version of pylint supported"""
- return '2.4.1'
+ return '2.6.0'
@pytest.fixture(scope='session')
def flake8_version():
"""Version of flake8 supported"""
- return '3.7.8'
+ return '3.8.4'
@pytest.fixture(scope='session')
def yamllint_version():
"""Version of yamllint supported"""
- return '1.17.0'
+ return '1.25.0'
@pytest.fixture(scope='session')
@@ -96,6 +96,7 @@ def supported_commands():
'introspect',
'list',
'perms',
+ 'transcrypt',
'upgrade',
'version',
]
@@ -117,10 +118,14 @@ def supported_configs():
'yadm.auto-exclude',
'yadm.auto-perms',
'yadm.auto-private-dirs',
+ 'yadm.cipher',
'yadm.git-program',
'yadm.gpg-perms',
'yadm.gpg-program',
'yadm.gpg-recipient',
+ 'yadm.openssl-ciphername',
+ 'yadm.openssl-old',
+ 'yadm.openssl-program',
'yadm.ssh-perms',
]
@@ -135,6 +140,7 @@ def supported_switches():
'--yadm-archive',
'--yadm-bootstrap',
'--yadm-config',
+ '--yadm-data',
'--yadm-dir',
'--yadm-encrypt',
'--yadm-repo',
@@ -174,6 +180,10 @@ class Runner():
self.command = ' '.join([str(cmd) for cmd in command])
else:
self.command = command
+ if env is None:
+ env = {}
+ merged_env = os.environ.copy()
+ merged_env.update(env)
self.inp = inp
self.wrap(expect)
process = Popen(
@@ -183,7 +193,7 @@ class Runner():
stderr=PIPE,
shell=shell,
cwd=cwd,
- env=env,
+ env=merged_env,
)
input_bytes = self.inp
if self.inp:
@@ -274,13 +284,17 @@ def yadm():
@pytest.fixture()
def paths(tmpdir, yadm):
"""Function scoped test paths"""
+
dir_root = tmpdir.mkdir('root')
+ dir_remote = dir_root.mkdir('remote')
dir_work = dir_root.mkdir('work')
- dir_yadm = dir_root.mkdir('yadm')
- dir_repo = dir_yadm.mkdir('repo.git')
+ dir_xdg_data = dir_root.mkdir('xdg_data')
+ dir_xdg_home = dir_root.mkdir('xdg_home')
+ dir_data = dir_xdg_data.mkdir('yadm')
+ dir_yadm = dir_xdg_home.mkdir('yadm')
dir_hooks = dir_yadm.mkdir('hooks')
- dir_remote = dir_root.mkdir('remote')
- file_archive = dir_yadm.join('files.gpg')
+ dir_repo = dir_data.mkdir('repo.git')
+ file_archive = dir_data.join('archive')
file_bootstrap = dir_yadm.join('bootstrap')
file_config = dir_yadm.join('config')
file_encrypt = dir_yadm.join('encrypt')
@@ -288,24 +302,32 @@ def paths(tmpdir, yadm):
'Paths', [
'pgm',
'root',
+ 'remote',
'work',
+ 'xdg_data',
+ 'xdg_home',
+ 'data',
'yadm',
- 'repo',
'hooks',
- 'remote',
+ 'repo',
'archive',
'bootstrap',
'config',
'encrypt',
])
+ os.environ['XDG_CONFIG_HOME'] = str(dir_xdg_home)
+ os.environ['XDG_DATA_HOME'] = str(dir_xdg_data)
return paths(
yadm,
dir_root,
+ dir_remote,
dir_work,
+ dir_xdg_data,
+ dir_xdg_home,
+ dir_data,
dir_yadm,
- dir_repo,
dir_hooks,
- dir_remote,
+ dir_repo,
file_archive,
file_bootstrap,
file_config,
@@ -314,11 +336,11 @@ def paths(tmpdir, yadm):
@pytest.fixture()
-def yadm_y(paths):
+def yadm_cmd(paths):
"""Generate custom command_list function"""
def command_list(*args):
"""Produce params for running yadm with -Y"""
- return [paths.pgm, '-Y', str(paths.yadm)] + list(args)
+ return [paths.pgm] + list(args)
return command_list
diff --git a/test/requirements.txt b/test/requirements.txt
new file mode 100644
index 0000000..30da6ae
--- /dev/null
+++ b/test/requirements.txt
@@ -0,0 +1,6 @@
+envtpl
+flake8==3.8.4
+j2cli
+pylint==2.6.0
+pytest==6.2.1
+yamllint==1.25.0
diff --git a/test/test_alt.py b/test/test_alt.py
index 359f32d..b18e6cb 100644
--- a/test/test_alt.py
+++ b/test/test_alt.py
@@ -22,12 +22,12 @@ def test_alt_source(
tracked, encrypt, exclude,
yadm_alt):
"""Test yadm alt operates on all expected sources of alternates"""
- yadm_dir = setup_standard_yadm_dir(paths)
+ yadm_dir, yadm_data = setup_standard_yadm_dir(paths)
utils.create_alt_files(
paths, '##default', tracked=tracked, encrypt=encrypt, exclude=exclude,
yadm_alt=yadm_alt, yadm_dir=yadm_dir)
- run = runner([paths.pgm, '-Y', yadm_dir, 'alt'])
+ run = runner([paths.pgm, '-Y', yadm_dir, '--yadm-data', yadm_data, 'alt'])
assert run.success
assert run.err == ''
linked = utils.parse_alt_output(run.out)
@@ -57,12 +57,12 @@ def test_alt_source(
@pytest.mark.parametrize('yadm_alt', [True, False], ids=['alt', 'worktree'])
def test_relative_link(runner, paths, yadm_alt):
"""Confirm links created are relative"""
- yadm_dir = setup_standard_yadm_dir(paths)
+ yadm_dir, yadm_data = setup_standard_yadm_dir(paths)
utils.create_alt_files(
paths, '##default', tracked=True, encrypt=False, exclude=False,
yadm_alt=yadm_alt, yadm_dir=yadm_dir)
- run = runner([paths.pgm, '-Y', yadm_dir, 'alt'])
+ run = runner([paths.pgm, '-Y', yadm_dir, '--yadm-data', yadm_data, 'alt'])
assert run.success
assert run.err == ''
@@ -81,6 +81,7 @@ def test_relative_link(runner, paths, yadm_alt):
@pytest.mark.usefixtures('ds1_copy')
@pytest.mark.parametrize('suffix', [
'##default',
+ '##default,e.txt', '##default,extension.txt',
'##o.$tst_sys', '##os.$tst_sys',
'##d.$tst_distro', '##distro.$tst_distro',
'##c.$tst_class', '##class.$tst_class',
@@ -91,7 +92,7 @@ def test_alt_conditions(
runner, paths,
tst_sys, tst_distro, tst_host, tst_user, suffix):
"""Test conditions supported by yadm alt"""
- yadm_dir = setup_standard_yadm_dir(paths)
+ yadm_dir, yadm_data = setup_standard_yadm_dir(paths)
# set the class
tst_class = 'testclass'
@@ -106,7 +107,7 @@ def test_alt_conditions(
)
utils.create_alt_files(paths, suffix)
- run = runner([paths.pgm, '-Y', yadm_dir, 'alt'])
+ run = runner([paths.pgm, '-Y', yadm_dir, '--yadm-data', yadm_data, 'alt'])
assert run.success
assert run.err == ''
linked = utils.parse_alt_output(run.out)
@@ -126,18 +127,18 @@ def test_alt_conditions(
@pytest.mark.usefixtures('ds1_copy')
@pytest.mark.parametrize(
- 'kind', ['default', '', None, 'envtpl', 'j2cli', 'j2'])
+ 'kind', ['default', '', None, 'envtpl', 'j2cli', 'j2', 'esh'])
@pytest.mark.parametrize('label', ['t', 'template', 'yadm', ])
def test_alt_templates(
runner, paths, kind, label):
"""Test templates supported by yadm alt"""
- yadm_dir = setup_standard_yadm_dir(paths)
+ yadm_dir, yadm_data = setup_standard_yadm_dir(paths)
suffix = f'##{label}.{kind}'
if kind is None:
suffix = f'##{label}'
utils.create_alt_files(paths, suffix)
- run = runner([paths.pgm, '-Y', yadm_dir, 'alt'])
+ run = runner([paths.pgm, '-Y', yadm_dir, '--yadm-data', yadm_data, 'alt'])
assert run.success
assert run.err == ''
created = utils.parse_alt_output(run.out, linked=False)
@@ -152,15 +153,15 @@ def test_alt_templates(
@pytest.mark.usefixtures('ds1_copy')
@pytest.mark.parametrize('autoalt', [None, 'true', 'false'])
-def test_auto_alt(runner, yadm_y, paths, autoalt):
+def test_auto_alt(runner, yadm_cmd, paths, autoalt):
"""Test auto alt"""
# set the value of auto-alt
if autoalt:
- os.system(' '.join(yadm_y('config', 'yadm.auto-alt', autoalt)))
+ os.system(' '.join(yadm_cmd('config', 'yadm.auto-alt', autoalt)))
utils.create_alt_files(paths, '##default')
- run = runner(yadm_y('status'))
+ run = runner(yadm_cmd('status'))
assert run.success
assert run.err == ''
linked = utils.parse_alt_output(run.out)
@@ -185,7 +186,7 @@ def test_auto_alt(runner, yadm_y, paths, autoalt):
@pytest.mark.usefixtures('ds1_copy')
-def test_stale_link_removal(runner, yadm_y, paths):
+def test_stale_link_removal(runner, yadm_cmd, paths):
"""Stale links to alternative files are removed
This test ensures that when an already linked alternative becomes invalid
@@ -200,7 +201,7 @@ def test_stale_link_removal(runner, yadm_y, paths):
utils.create_alt_files(paths, f'##class.{tst_class}')
# run alt to trigger linking
- run = runner(yadm_y('alt'))
+ run = runner(yadm_cmd('alt'))
assert run.success
assert run.err == ''
linked = utils.parse_alt_output(run.out)
@@ -222,7 +223,7 @@ def test_stale_link_removal(runner, yadm_y, paths):
utils.set_local(paths, 'class', 'changedclass')
# run alt to trigger linking
- run = runner(yadm_y('alt'))
+ run = runner(yadm_cmd('alt'))
assert run.success
assert run.err == ''
linked = utils.parse_alt_output(run.out)
@@ -235,7 +236,7 @@ def test_stale_link_removal(runner, yadm_y, paths):
@pytest.mark.usefixtures('ds1_repo_copy')
-def test_template_overwrite_symlink(runner, yadm_y, paths, tst_sys):
+def test_template_overwrite_symlink(runner, yadm_cmd, paths, tst_sys):
"""Remove symlinks before processing a template
If a symlink is in the way of the output of a template, the target of the
@@ -252,7 +253,7 @@ def test_template_overwrite_symlink(runner, yadm_y, paths, tst_sys):
template = paths.work.join('test_link##template.default')
template.write('test-data')
- run = runner(yadm_y('add', target, template))
+ run = runner(yadm_cmd('add', target, template))
assert run.success
assert run.err == ''
assert run.out == ''
@@ -265,12 +266,13 @@ def test_template_overwrite_symlink(runner, yadm_y, paths, tst_sys):
@pytest.mark.parametrize('style', ['symlink', 'template'])
def test_ensure_alt_path(runner, paths, style):
"""Test that directories are created before making alternates"""
- yadm_dir = setup_standard_yadm_dir(paths)
+ yadm_dir, yadm_data = setup_standard_yadm_dir(paths)
suffix = 'default' if style == 'symlink' else 'template'
filename = 'a/b/c/file'
source = yadm_dir.join(f'alt/{filename}##{suffix}')
source.write('test-data', ensure=True)
- run = runner([paths.pgm, '-Y', yadm_dir, 'add', source])
+ run = runner([
+ paths.pgm, '-Y', yadm_dir, '--yadm-data', yadm_data, 'add', source])
assert run.success
assert run.err == ''
assert run.out == ''
@@ -280,6 +282,7 @@ def test_ensure_alt_path(runner, paths, style):
def setup_standard_yadm_dir(paths):
"""Configure a yadm home within the work tree"""
std_yadm_dir = paths.work.mkdir('.config').mkdir('yadm')
- std_yadm_dir.join('repo.git').mksymlinkto(paths.repo, absolute=1)
+ std_yadm_data = paths.work.mkdir('.local').mkdir('share').mkdir('yadm')
+ std_yadm_data.join('repo.git').mksymlinkto(paths.repo, absolute=1)
std_yadm_dir.join('encrypt').mksymlinkto(paths.encrypt, absolute=1)
- return std_yadm_dir
+ return std_yadm_dir, std_yadm_data
diff --git a/test/test_alt_copy.py b/test/test_alt_copy.py
index c808348..fa8e09c 100644
--- a/test/test_alt_copy.py
+++ b/test/test_alt_copy.py
@@ -5,10 +5,6 @@ import pytest
@pytest.mark.parametrize(
- 'cygwin',
- [pytest.param(True, marks=pytest.mark.deprecated), False],
- ids=['cygwin', 'no-cygwin'])
-@pytest.mark.parametrize(
'setting, expect_link, pre_existing', [
(None, True, None),
(True, False, None),
@@ -25,15 +21,12 @@ import pytest
])
@pytest.mark.usefixtures('ds1_copy')
def test_alt_copy(
- runner, yadm_y, paths, tst_sys,
- setting, expect_link, pre_existing,
- cygwin):
+ runner, yadm_cmd, paths, tst_sys,
+ setting, expect_link, pre_existing):
"""Test yadm.alt-copy"""
- option = 'yadm.cygwin-copy' if cygwin else 'yadm.alt-copy'
-
if setting is not None:
- os.system(' '.join(yadm_y('config', option, str(setting))))
+ os.system(' '.join(yadm_cmd('config', 'yadm.alt-copy', str(setting))))
expected_content = f'test_alt_copy##os.{tst_sys}'
@@ -43,7 +36,7 @@ def test_alt_copy(
elif pre_existing == 'file':
alt_path.write('wrong content')
- run = runner(yadm_y('alt'))
+ run = runner(yadm_cmd('alt'))
assert run.success
assert run.err == ''
assert 'Linking' in run.out
diff --git a/test/test_assert_private_dirs.py b/test/test_assert_private_dirs.py
index 606012f..bfd55ac 100644
--- a/test/test_assert_private_dirs.py
+++ b/test/test_assert_private_dirs.py
@@ -9,7 +9,7 @@ PRIVATE_DIRS = ['.gnupg', '.ssh']
@pytest.mark.parametrize('home', [True, False], ids=['home', 'not-home'])
-def test_pdirs_missing(runner, yadm_y, paths, home):
+def test_pdirs_missing(runner, yadm_cmd, paths, home):
"""Private dirs (private dirs missing)
When a git command is run
@@ -29,7 +29,7 @@ def test_pdirs_missing(runner, yadm_y, paths, home):
env['HOME'] = paths.work
# run status
- run = runner(command=yadm_y('status'), env=env)
+ run = runner(command=yadm_cmd('status'), env=env)
assert run.success
assert run.err == ''
assert 'On branch master' in run.out
@@ -53,7 +53,7 @@ def test_pdirs_missing(runner, yadm_y, paths, home):
run.out, re.DOTALL), 'directories created before command is run'
-def test_pdirs_missing_apd_false(runner, yadm_y, paths):
+def test_pdirs_missing_apd_false(runner, yadm_cmd, paths):
"""Private dirs (private dirs missing / yadm.auto-private-dirs=false)
When a git command is run
@@ -70,11 +70,11 @@ def test_pdirs_missing_apd_false(runner, yadm_y, paths):
assert not path.exists()
# set configuration
- os.system(' '.join(yadm_y(
+ os.system(' '.join(yadm_cmd(
'config', '--bool', 'yadm.auto-private-dirs', 'false')))
# run status
- run = runner(command=yadm_y('status'))
+ run = runner(command=yadm_cmd('status'))
assert run.success
assert run.err == ''
assert 'On branch master' in run.out
@@ -84,7 +84,7 @@ def test_pdirs_missing_apd_false(runner, yadm_y, paths):
assert not paths.work.join(pdir).exists()
-def test_pdirs_exist_apd_false(runner, yadm_y, paths):
+def test_pdirs_exist_apd_false(runner, yadm_cmd, paths):
"""Private dirs (private dirs exist / yadm.auto-perms=false)
When a git command is run
@@ -102,11 +102,11 @@ def test_pdirs_exist_apd_false(runner, yadm_y, paths):
assert oct(path.stat().mode).endswith('77'), 'Directory is secure.'
# set configuration
- os.system(' '.join(yadm_y(
+ os.system(' '.join(yadm_cmd(
'config', '--bool', 'yadm.auto-perms', 'false')))
# run status
- run = runner(command=yadm_y('status'))
+ run = runner(command=yadm_cmd('status'))
assert run.success
assert run.err == ''
assert 'On branch master' in run.out
diff --git a/test/test_bootstrap.py b/test/test_bootstrap.py
index 2adbe33..4865ece 100644
--- a/test/test_bootstrap.py
+++ b/test/test_bootstrap.py
@@ -14,7 +14,7 @@ import pytest
'executable',
])
def test_bootstrap(
- runner, yadm_y, paths, exists, executable, code, expect):
+ runner, yadm_cmd, paths, exists, executable, code, expect):
"""Test bootstrap command"""
if exists:
paths.bootstrap.write('')
@@ -25,7 +25,11 @@ def test_bootstrap(
f'exit {code}\n'
)
paths.bootstrap.chmod(0o775)
- run = runner(command=yadm_y('bootstrap'))
+ run = runner(command=yadm_cmd('bootstrap'))
assert run.code == code
- assert run.err == ''
- assert expect in run.out
+ if exists and executable:
+ assert run.err == ''
+ assert expect in run.out
+ else:
+ assert expect in run.err
+ assert run.out == ''
diff --git a/test/test_clean.py b/test/test_clean.py
index 9a2221a..39e7e54 100644
--- a/test/test_clean.py
+++ b/test/test_clean.py
@@ -1,11 +1,11 @@
"""Test clean"""
-def test_clean_command(runner, yadm_y):
+def test_clean_command(runner, yadm_cmd):
"""Run with clean command"""
- run = runner(command=yadm_y('clean'))
+ run = runner(command=yadm_cmd('clean'))
# do nothing, this is a dangerous Git command when managing dot files
# report the command as disabled and exit as a failure
assert run.failure
- assert run.err == ''
- assert 'disabled' in run.out
+ assert run.out == ''
+ assert 'disabled' in run.err
diff --git a/test/test_clone.py b/test/test_clone.py
index a6df6d0..b024e9c 100644
--- a/test/test_clone.py
+++ b/test/test_clone.py
@@ -24,7 +24,7 @@ BOOTSTRAP_MSG = 'Bootstrap successful'
'conflicts',
])
def test_clone(
- runner, paths, yadm_y, repo_config, ds1,
+ runner, paths, yadm_cmd, repo_config, ds1,
good_remote, repo_exists, force, conflicts):
"""Test basic clone operation"""
@@ -53,23 +53,26 @@ def test_clone(
if force:
args += ['-f']
args += [remote_url]
- run = runner(command=yadm_y(*args))
+ run = runner(command=yadm_cmd(*args))
if not good_remote:
# clone should fail
assert run.failure
- assert run.err != ''
- assert 'Unable to fetch origin' in run.out
+ assert run.out != ''
+ assert 'Unable to fetch origin' in run.err
assert not paths.repo.exists()
elif repo_exists and not force:
# can't overwrite data
assert run.failure
- assert run.err == ''
- assert 'Git repo already exists' in run.out
+ assert run.out == ''
+ assert 'Git repo already exists' in run.err
else:
# clone should succeed, and repo should be configured properly
assert successful_clone(run, paths, repo_config)
+ # these clones should have master as HEAD
+ verify_head(paths, 'master')
+
# ensure conflicts are handled properly
if conflicts:
assert 'NOTE' in run.out
@@ -88,20 +91,21 @@ def test_clone(
if conflicts:
# test to see if the work tree is actually "clean"
run = runner(
- command=yadm_y('status', '-uno', '--porcelain'),
+ command=yadm_cmd('status', '-uno', '--porcelain'),
cwd=paths.work)
assert run.success
assert run.err == ''
assert run.out == '', 'worktree has unexpected changes'
# test to see if the conflicts are stashed
- run = runner(command=yadm_y('stash', 'list'), cwd=paths.work)
+ run = runner(command=yadm_cmd('stash', 'list'), cwd=paths.work)
assert run.success
assert run.err == ''
assert 'Conflicts preserved' in run.out, 'conflicts not stashed'
# verify content of the stashed conflicts
- run = runner(command=yadm_y('stash', 'show', '-p'), cwd=paths.work)
+ run = runner(
+ command=yadm_cmd('stash', 'show', '-p'), cwd=paths.work)
assert run.success
assert run.err == ''
assert '\n+conflict' in run.out, 'conflicts not stashed'
@@ -130,7 +134,7 @@ def test_clone(
'existing, answer y',
])
def test_clone_bootstrap(
- runner, paths, yadm_y, repo_config, bs_exists, bs_param, answer):
+ runner, paths, yadm_cmd, repo_config, bs_exists, bs_param, answer):
"""Test bootstrap clone features"""
# establish a bootstrap
@@ -144,7 +148,7 @@ def test_clone_bootstrap(
expect = []
if answer:
expect.append(('Would you like to execute it now', answer))
- run = runner(command=yadm_y(*args), expect=expect)
+ run = runner(command=yadm_cmd(*args), expect=expect)
if answer:
assert 'Would you like to execute it now' in run.out
@@ -161,6 +165,7 @@ def test_clone_bootstrap(
assert BOOTSTRAP_MSG not in run.out
assert successful_clone(run, paths, repo_config, expected_code)
+ verify_head(paths, 'master')
if not bs_exists:
assert BOOTSTRAP_MSG not in run.out
@@ -197,7 +202,7 @@ def create_bootstrap(paths, exists):
'missing gnupg, tracked',
])
def test_clone_perms(
- runner, yadm_y, paths, repo_config,
+ runner, yadm_cmd, paths, repo_config,
private_type, in_repo, in_work):
"""Test clone permission-related functions"""
@@ -224,11 +229,12 @@ def test_clone_perms(
env = {'HOME': paths.work}
run = runner(
- yadm_y('clone', '-d', '-w', paths.work, f'file://{paths.remote}'),
+ yadm_cmd('clone', '-d', '-w', paths.work, f'file://{paths.remote}'),
env=env
)
assert successful_clone(run, paths, repo_config)
+ verify_head(paths, 'master')
if in_work:
# private directories which already exist, should be left as they are,
# which in this test is "insecure".
@@ -259,8 +265,9 @@ def test_clone_perms(
@pytest.mark.usefixtures('remote')
-@pytest.mark.parametrize('branch', ['master', 'valid', 'invalid'])
-def test_alternate_branch(runner, paths, yadm_y, repo_config, branch):
+@pytest.mark.parametrize(
+ 'branch', ['master', 'default', 'valid', 'invalid'])
+def test_alternate_branch(runner, paths, yadm_cmd, repo_config, branch):
"""Test cloning a branch other than master"""
# add a "valid" branch to the remote
@@ -268,6 +275,12 @@ def test_alternate_branch(runner, paths, yadm_y, repo_config, branch):
os.system(
f'GIT_DIR="{paths.remote}" git commit '
f'--allow-empty -m "This branch is valid"')
+ if branch != 'default':
+ # When branch == 'default', the "default" branch of the remote repo
+ # will remain "valid" to validate identification the correct default
+ # branch by inspecting the repo. Otherwise it will be set back to
+ # "master"
+ os.system(f'GIT_DIR="{paths.remote}" git checkout master')
# clear out the work path
paths.work.remove()
@@ -277,15 +290,15 @@ def test_alternate_branch(runner, paths, yadm_y, repo_config, branch):
# run the clone command
args = ['clone', '-w', paths.work]
- if branch != 'master':
+ if branch not in ['master', 'default']:
args += ['-b', branch]
args += [remote_url]
- run = runner(command=yadm_y(*args))
+ run = runner(command=yadm_cmd(*args))
if branch == 'invalid':
assert run.failure
- assert 'ERROR: Clone failed' in run.out
- assert f"'origin/{branch}' does not exist in {remote_url}" in run.out
+ assert 'ERROR: Clone failed' in run.err
+ assert f"'origin/{branch}' does not exist in {remote_url}" in run.err
else:
assert successful_clone(run, paths, repo_config)
@@ -296,11 +309,13 @@ def test_alternate_branch(runner, paths, yadm_y, repo_config, branch):
assert run.success
assert run.err == ''
assert f'origin\t{remote_url}' in run.out
- run = runner(command=yadm_y('show'))
- if branch == 'valid':
- assert 'This branch is valid' in run.out
- else:
+ run = runner(command=yadm_cmd('show'))
+ if branch == 'master':
assert 'Initial commit' in run.out
+ verify_head(paths, 'master')
+ else:
+ assert 'This branch is valid' in run.out
+ verify_head(paths, 'valid')
def successful_clone(run, paths, repo_config, expected_code=0):
@@ -323,3 +338,16 @@ def remote(paths, ds1_repo_copy):
# cannot be applied to another fixture.
paths.remote.remove()
paths.repo.move(paths.remote)
+
+
+def test_no_repo(runner, yadm_cmd, ):
+ """Test cloning without specifying a repo"""
+ run = runner(command=yadm_cmd('clone'))
+ assert run.failure
+ assert run.out == ''
+ assert 'ERROR: No repository provided' in run.err
+
+
+def verify_head(paths, branch):
+ """Assert the local repo has the correct head branch"""
+ assert paths.repo.join('HEAD').read() == f'ref: refs/heads/{branch}\n'
diff --git a/test/test_compat_alt.py b/test/test_compat_alt.py
deleted file mode 100644
index da7a8cf..0000000
--- a/test/test_compat_alt.py
+++ /dev/null
@@ -1,453 +0,0 @@
-"""Test alt"""
-
-import os
-import string
-import py
-import pytest
-import utils
-
-# These tests are for the alternate processing in YADM_COMPATIBILITY=1 mode
-pytestmark = pytest.mark.deprecated
-
-# These test IDs are broken. During the writing of these tests, problems have
-# been discovered in the way yadm orders matching files.
-BROKEN_TEST_IDS = [
- 'test_wild[tracked-##C.S.H.U-C-S%-H%-U]',
- 'test_wild[tracked-##C.S.H.U-C-S-H%-U]',
- 'test_wild[encrypted-##C.S.H.U-C-S%-H%-U]',
- 'test_wild[encrypted-##C.S.H.U-C-S-H%-U]',
- ]
-
-PRECEDENCE = [
- '##',
- '##$tst_sys',
- '##$tst_sys.$tst_host',
- '##$tst_sys.$tst_host.$tst_user',
- '##$tst_class',
- '##$tst_class.$tst_sys',
- '##$tst_class.$tst_sys.$tst_host',
- '##$tst_class.$tst_sys.$tst_host.$tst_user',
- ]
-
-WILD_TEMPLATES = [
- '##$tst_class',
- '##$tst_class.$tst_sys',
- '##$tst_class.$tst_sys.$tst_host',
- '##$tst_class.$tst_sys.$tst_host.$tst_user',
- ]
-
-TEST_PATHS = [utils.ALT_FILE1, utils.ALT_FILE2, utils.ALT_DIR]
-
-WILD_TESTED = set()
-
-
-@pytest.mark.parametrize('precedence_index', range(len(PRECEDENCE)))
-@pytest.mark.parametrize(
- 'tracked, encrypt, exclude', [
- (False, False, False),
- (True, False, False),
- (False, True, False),
- (False, True, True),
- ], ids=[
- 'untracked',
- 'tracked',
- 'encrypted',
- 'excluded',
- ])
-@pytest.mark.usefixtures('ds1_copy')
-def test_alt(runner, yadm_y, paths,
- tst_sys, tst_host, tst_user,
- tracked, encrypt, exclude,
- precedence_index):
- """Test alternate linking
-
- This test is done by iterating for the number of templates in PRECEDENCE.
- With each iteration, another file is left off the list. So with each
- iteration, the template with the "highest precedence" is left out. The file
- using the highest precedence should be the one linked.
- """
-
- # set the class
- tst_class = 'testclass'
- utils.set_local(paths, 'class', tst_class)
-
- # process the templates in PRECEDENCE
- precedence = list()
- for template in PRECEDENCE:
- precedence.append(
- string.Template(template).substitute(
- tst_class=tst_class,
- tst_host=tst_host,
- tst_sys=tst_sys,
- tst_user=tst_user,
- )
- )
-
- # create files using a subset of files
- for suffix in precedence[0:precedence_index+1]:
- utils.create_alt_files(paths, suffix, tracked=tracked,
- encrypt=encrypt, exclude=exclude)
-
- # run alt to trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('alt'), env=env)
- assert run.success
- assert run.err == ''
- linked = utils.parse_alt_output(run.out)
-
- # assert the proper linking has occurred
- for file_path in TEST_PATHS:
- source_file = file_path + precedence[precedence_index]
- if tracked or (encrypt and not exclude):
- assert paths.work.join(file_path).islink()
- target = py.path.local(
- os.path.realpath(paths.work.join(file_path)))
- if target.isfile():
- assert paths.work.join(file_path).read() == source_file
- assert str(paths.work.join(source_file)) in linked
- else:
- assert paths.work.join(file_path).join(
- utils.CONTAINED).read() == source_file
- assert str(paths.work.join(source_file)) in linked
- else:
- assert not paths.work.join(file_path).exists()
- assert str(paths.work.join(source_file)) not in linked
-
-
-def short_template(template):
- """Translate template into something short for test IDs"""
- return string.Template(template).substitute(
- tst_class='C',
- tst_host='H',
- tst_sys='S',
- tst_user='U',
- )
-
-
-@pytest.mark.parametrize('wild_user', [True, False], ids=['U%', 'U'])
-@pytest.mark.parametrize('wild_host', [True, False], ids=['H%', 'H'])
-@pytest.mark.parametrize('wild_sys', [True, False], ids=['S%', 'S'])
-@pytest.mark.parametrize('wild_class', [True, False], ids=['C%', 'C'])
-@pytest.mark.parametrize('template', WILD_TEMPLATES, ids=short_template)
-@pytest.mark.parametrize(
- 'tracked, encrypt', [
- (True, False),
- (False, True),
- ], ids=[
- 'tracked',
- 'encrypted',
- ])
-@pytest.mark.usefixtures('ds1_copy')
-def test_wild(request, runner, yadm_y, paths,
- tst_sys, tst_host, tst_user,
- tracked, encrypt,
- wild_class, wild_host, wild_sys, wild_user,
- template):
- """Test wild linking
-
- These tests are done by creating permutations of the possible files using
- WILD_TEMPLATES. Each case is then tested (while skipping the already tested
- permutations for efficiency).
- """
-
- if request.node.name in BROKEN_TEST_IDS:
- pytest.xfail(
- 'This test is known to be broken. '
- 'This bug only affects deprecated features.')
-
- tst_class = 'testclass'
-
- # determine the "wild" version of the suffix
- str_class = '%' if wild_class else tst_class
- str_host = '%' if wild_host else tst_host
- str_sys = '%' if wild_sys else tst_sys
- str_user = '%' if wild_user else tst_user
- wild_suffix = string.Template(template).substitute(
- tst_class=str_class,
- tst_host=str_host,
- tst_sys=str_sys,
- tst_user=str_user,
- )
-
- # determine the "standard" version of the suffix
- std_suffix = string.Template(template).substitute(
- tst_class=tst_class,
- tst_host=tst_host,
- tst_sys=tst_sys,
- tst_user=tst_user,
- )
-
- # skip over duplicate tests (this seems to be the simplest way to cover the
- # permutations of tests, while skipping duplicates.)
- test_key = f'{tracked}{encrypt}{wild_suffix}{std_suffix}'
- if test_key in WILD_TESTED:
- return
- WILD_TESTED.add(test_key)
-
- # set the class
- utils.set_local(paths, 'class', tst_class)
-
- # create files using the wild suffix
- utils.create_alt_files(paths, wild_suffix, tracked=tracked,
- encrypt=encrypt, exclude=False)
-
- # run alt to trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('alt'), env=env)
- assert run.success
- assert run.err == ''
- linked = utils.parse_alt_output(run.out)
-
- # assert the proper linking has occurred
- for file_path in TEST_PATHS:
- source_file = file_path + wild_suffix
- assert paths.work.join(file_path).islink()
- target = py.path.local(os.path.realpath(paths.work.join(file_path)))
- if target.isfile():
- assert paths.work.join(file_path).read() == source_file
- assert str(paths.work.join(source_file)) in linked
- else:
- assert paths.work.join(file_path).join(
- utils.CONTAINED).read() == source_file
- assert str(paths.work.join(source_file)) in linked
-
- # create files using the standard suffix
- utils.create_alt_files(paths, std_suffix, tracked=tracked,
- encrypt=encrypt, exclude=False)
-
- # run alt to trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('alt'), env=env)
- assert run.success
- assert run.err == ''
- linked = utils.parse_alt_output(run.out)
-
- # assert the proper linking has occurred
- for file_path in TEST_PATHS:
- source_file = file_path + std_suffix
- assert paths.work.join(file_path).islink()
- target = py.path.local(os.path.realpath(paths.work.join(file_path)))
- if target.isfile():
- assert paths.work.join(file_path).read() == source_file
- assert str(paths.work.join(source_file)) in linked
- else:
- assert paths.work.join(file_path).join(
- utils.CONTAINED).read() == source_file
- assert str(paths.work.join(source_file)) in linked
-
-
-@pytest.mark.usefixtures('ds1_copy')
-def test_local_override(runner, yadm_y, paths,
- tst_sys, tst_host, tst_user):
- """Test local overrides"""
-
- # define local overrides
- utils.set_local(paths, 'class', 'or-class')
- utils.set_local(paths, 'hostname', 'or-hostname')
- utils.set_local(paths, 'os', 'or-os')
- utils.set_local(paths, 'user', 'or-user')
-
- # create files, the first would normally be the most specific version
- # however, the second is the overridden version which should be preferred.
- utils.create_alt_files(
- paths, f'##or-class.{tst_sys}.{tst_host}.{tst_user}')
- utils.create_alt_files(
- paths, '##or-class.or-os.or-hostname.or-user')
-
- # run alt to trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('alt'), env=env)
- assert run.success
- assert run.err == ''
- linked = utils.parse_alt_output(run.out)
-
- # assert the proper linking has occurred
- for file_path in TEST_PATHS:
- source_file = file_path + '##or-class.or-os.or-hostname.or-user'
- assert paths.work.join(file_path).islink()
- target = py.path.local(os.path.realpath(paths.work.join(file_path)))
- if target.isfile():
- assert paths.work.join(file_path).read() == source_file
- assert str(paths.work.join(source_file)) in linked
- else:
- assert paths.work.join(file_path).join(
- utils.CONTAINED).read() == source_file
- assert str(paths.work.join(source_file)) in linked
-
-
-@pytest.mark.parametrize('suffix', ['AAA', 'ZZZ', 'aaa', 'zzz'])
-@pytest.mark.usefixtures('ds1_copy')
-def test_class_case(runner, yadm_y, paths, tst_sys, suffix):
- """Test range of class cases"""
-
- # set the class
- utils.set_local(paths, 'class', suffix)
-
- # create files
- endings = [suffix]
- if tst_sys == 'Linux':
- # Only create all of these side-by-side on Linux, which is
- # unquestionably case-sensitive. This would break tests on
- # case-insensitive systems.
- endings = ['AAA', 'ZZZ', 'aaa', 'zzz']
- for ending in endings:
- utils.create_alt_files(paths, f'##{ending}')
-
- # run alt to trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('alt'), env=env)
- assert run.success
- assert run.err == ''
- linked = utils.parse_alt_output(run.out)
-
- # assert the proper linking has occurred
- for file_path in TEST_PATHS:
- source_file = file_path + f'##{suffix}'
- assert paths.work.join(file_path).islink()
- target = py.path.local(os.path.realpath(paths.work.join(file_path)))
- if target.isfile():
- assert paths.work.join(file_path).read() == source_file
- assert str(paths.work.join(source_file)) in linked
- else:
- assert paths.work.join(file_path).join(
- utils.CONTAINED).read() == source_file
- assert str(paths.work.join(source_file)) in linked
-
-
-@pytest.mark.parametrize('autoalt', [None, 'true', 'false'])
-@pytest.mark.usefixtures('ds1_copy')
-def test_auto_alt(runner, yadm_y, paths, autoalt):
- """Test setting auto-alt"""
-
- # set the value of auto-alt
- if autoalt:
- os.system(' '.join(yadm_y('config', 'yadm.auto-alt', autoalt)))
-
- # create file
- suffix = '##'
- utils.create_alt_files(paths, suffix)
-
- # run status to possibly trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('status'), env=env)
- assert run.success
- assert run.err == ''
- linked = utils.parse_alt_output(run.out)
-
- # assert the proper linking has occurred
- for file_path in TEST_PATHS:
- source_file = file_path + suffix
- if autoalt == 'false':
- assert not paths.work.join(file_path).exists()
- else:
- assert paths.work.join(file_path).islink()
- target = py.path.local(
- os.path.realpath(paths.work.join(file_path)))
- if target.isfile():
- assert paths.work.join(file_path).read() == source_file
- # no linking output when run via auto-alt
- assert str(paths.work.join(source_file)) not in linked
- else:
- assert paths.work.join(file_path).join(
- utils.CONTAINED).read() == source_file
- # no linking output when run via auto-alt
- assert str(paths.work.join(source_file)) not in linked
-
-
-@pytest.mark.parametrize('delimiter', ['.', '_'])
-@pytest.mark.usefixtures('ds1_copy')
-def test_delimiter(runner, yadm_y, paths,
- tst_sys, tst_host, tst_user, delimiter):
- """Test delimiters used"""
-
- suffix = '##' + delimiter.join([tst_sys, tst_host, tst_user])
-
- # create file
- utils.create_alt_files(paths, suffix)
-
- # run alt to trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('alt'), env=env)
- assert run.success
- assert run.err == ''
- linked = utils.parse_alt_output(run.out)
-
- # assert the proper linking has occurred
- # only a delimiter of '.' is valid
- for file_path in TEST_PATHS:
- source_file = file_path + suffix
- if delimiter == '.':
- assert paths.work.join(file_path).islink()
- target = py.path.local(
- os.path.realpath(paths.work.join(file_path)))
- if target.isfile():
- assert paths.work.join(file_path).read() == source_file
- assert str(paths.work.join(source_file)) in linked
- else:
- assert paths.work.join(file_path).join(
- utils.CONTAINED).read() == source_file
- assert str(paths.work.join(source_file)) in linked
- else:
- assert not paths.work.join(file_path).exists()
- assert str(paths.work.join(source_file)) not in linked
-
-
-@pytest.mark.usefixtures('ds1_copy')
-def test_invalid_links_removed(runner, yadm_y, paths):
- """Links to invalid alternative files are removed
-
- This test ensures that when an already linked alternative becomes invalid
- due to a change in class, the alternate link is removed.
- """
-
- # set the class
- tst_class = 'testclass'
- utils.set_local(paths, 'class', tst_class)
-
- # create files which match the test class
- utils.create_alt_files(paths, f'##{tst_class}')
-
- # run alt to trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('alt'), env=env)
- assert run.success
- assert run.err == ''
- linked = utils.parse_alt_output(run.out)
-
- # assert the proper linking has occurred
- for file_path in TEST_PATHS:
- source_file = file_path + '##' + tst_class
- assert paths.work.join(file_path).islink()
- target = py.path.local(os.path.realpath(paths.work.join(file_path)))
- if target.isfile():
- assert paths.work.join(file_path).read() == source_file
- assert str(paths.work.join(source_file)) in linked
- else:
- assert paths.work.join(file_path).join(
- utils.CONTAINED).read() == source_file
- assert str(paths.work.join(source_file)) in linked
-
- # change the class so there are no valid alternates
- utils.set_local(paths, 'class', 'changedclass')
-
- # run alt to trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('alt'), env=env)
- assert run.success
- assert run.err == ''
- linked = utils.parse_alt_output(run.out)
-
- # assert the linking is removed
- for file_path in TEST_PATHS:
- source_file = file_path + '##' + tst_class
- assert not paths.work.join(file_path).exists()
- assert str(paths.work.join(source_file)) not in linked
diff --git a/test/test_compat_jinja.py b/test/test_compat_jinja.py
deleted file mode 100644
index 7e2b766..0000000
--- a/test/test_compat_jinja.py
+++ /dev/null
@@ -1,198 +0,0 @@
-"""Test jinja"""
-
-import os
-import pytest
-import utils
-
-# These tests are for the template processing in YADM_COMPATIBILITY=1 mode
-pytestmark = pytest.mark.deprecated
-
-
-@pytest.fixture(scope='module')
-def envtpl_present(runner):
- """Is envtpl present and working?"""
- try:
- run = runner(command=['envtpl', '-h'])
- if run.success:
- return True
- except OSError:
- pass
- return False
-
-
-@pytest.mark.usefixtures('ds1_copy')
-def test_local_override(runner, yadm_y, paths,
- tst_distro, envtpl_present):
- """Test local overrides"""
- if not envtpl_present:
- pytest.skip('Unable to test without envtpl.')
-
- # define local overrides
- utils.set_local(paths, 'class', 'or-class')
- utils.set_local(paths, 'hostname', 'or-hostname')
- utils.set_local(paths, 'os', 'or-os')
- utils.set_local(paths, 'user', 'or-user')
-
- template = (
- 'j2-{{ YADM_CLASS }}-'
- '{{ YADM_OS }}-{{ YADM_HOSTNAME }}-'
- '{{ YADM_USER }}-{{ YADM_DISTRO }}'
- '-{%- '
- f"include '{utils.INCLUDE_FILE}'"
- ' -%}'
- )
- expected = (
- f'j2-or-class-or-os-or-hostname-or-user-{tst_distro}'
- f'-{utils.INCLUDE_CONTENT}'
- )
-
- utils.create_alt_files(paths, '##yadm.j2', content=template,
- includefile=True)
-
- # os.system(f'find {paths.work}' + ' -name *j2 -ls -exec cat \'{}\' ";"')
- # os.system(f'find {paths.work}')
- # run alt to trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('alt'), env=env)
- assert run.success
- assert run.err == ''
- created = utils.parse_alt_output(run.out, linked=False)
-
- # assert the proper creation has occurred
- for file_path in (utils.ALT_FILE1, utils.ALT_FILE2):
- source_file = file_path + '##yadm.j2'
- assert paths.work.join(file_path).isfile()
- lines = paths.work.join(file_path).readlines(cr=False)
- assert lines[0] == source_file
- assert lines[1] == expected
- assert str(paths.work.join(source_file)) in created
-
-
-@pytest.mark.parametrize('autoalt', [None, 'true', 'false'])
-@pytest.mark.usefixtures('ds1_copy')
-def test_auto_alt(runner, yadm_y, paths, autoalt, tst_sys,
- envtpl_present):
- """Test setting auto-alt"""
-
- if not envtpl_present:
- pytest.skip('Unable to test without envtpl.')
-
- # set the value of auto-alt
- if autoalt:
- os.system(' '.join(yadm_y('config', 'yadm.auto-alt', autoalt)))
-
- # create file
- jinja_suffix = '##yadm.j2'
- utils.create_alt_files(paths, jinja_suffix, content='{{ YADM_OS }}')
-
- # run status to possibly trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('status'), env=env)
- assert run.success
- assert run.err == ''
- created = utils.parse_alt_output(run.out, linked=False)
-
- # assert the proper creation has occurred
- for file_path in (utils.ALT_FILE1, utils.ALT_FILE2):
- source_file = file_path + jinja_suffix
- if autoalt == 'false':
- assert not paths.work.join(file_path).exists()
- else:
- assert paths.work.join(file_path).isfile()
- lines = paths.work.join(file_path).readlines(cr=False)
- assert lines[0] == source_file
- assert lines[1] == tst_sys
- # no created output when run via auto-alt
- assert str(paths.work.join(source_file)) not in created
-
-
-@pytest.mark.usefixtures('ds1_copy')
-def test_jinja_envtpl_missing(runner, paths):
- """Test operation when envtpl is missing"""
-
- script = f"""
- YADM_TEST=1 source {paths.pgm}
- process_global_args -Y "{paths.yadm}"
- set_operating_system
- configure_paths
- YADM_COMPATIBILITY=1
- ENVTPL_PROGRAM='envtpl_missing' main alt
- """
-
- utils.create_alt_files(paths, '##yadm.j2')
-
- run = runner(command=['bash'], inp=script)
- assert run.success
- assert run.err == ''
- assert f'envtpl not available, not creating' in run.out
-
-
-@pytest.mark.parametrize(
- 'tracked, encrypt, exclude', [
- (False, False, False),
- (True, False, False),
- (False, True, False),
- (False, True, True),
- ], ids=[
- 'untracked',
- 'tracked',
- 'encrypted',
- 'excluded',
- ])
-@pytest.mark.usefixtures('ds1_copy')
-def test_jinja(runner, yadm_y, paths,
- tst_sys, tst_host, tst_user, tst_distro,
- tracked, encrypt, exclude,
- envtpl_present):
- """Test jinja processing"""
-
- if not envtpl_present:
- pytest.skip('Unable to test without envtpl.')
-
- jinja_suffix = '##yadm.j2'
-
- # set the class
- tst_class = 'testclass'
- utils.set_local(paths, 'class', tst_class)
-
- template = (
- 'j2-{{ YADM_CLASS }}-'
- '{{ YADM_OS }}-{{ YADM_HOSTNAME }}-'
- '{{ YADM_USER }}-{{ YADM_DISTRO }}'
- '-{%- '
- f"include '{utils.INCLUDE_FILE}'"
- ' -%}'
- )
- expected = (
- f'j2-{tst_class}-'
- f'{tst_sys}-{tst_host}-'
- f'{tst_user}-{tst_distro}'
- f'-{utils.INCLUDE_CONTENT}'
- )
-
- utils.create_alt_files(paths, jinja_suffix, content=template,
- tracked=tracked, encrypt=encrypt, exclude=exclude,
- includefile=True)
-
- # run alt to trigger linking
- env = os.environ.copy()
- env['YADM_COMPATIBILITY'] = '1'
- run = runner(yadm_y('alt'), env=env)
- assert run.success
- assert run.err == ''
- created = utils.parse_alt_output(run.out, linked=False)
-
- # assert the proper creation has occurred
- for file_path in (utils.ALT_FILE1, utils.ALT_FILE2):
- source_file = file_path + jinja_suffix
- if tracked or (encrypt and not exclude):
- assert paths.work.join(file_path).isfile()
- lines = paths.work.join(file_path).readlines(cr=False)
- assert lines[0] == source_file
- assert lines[1] == expected
- assert str(paths.work.join(source_file)) in created
- else:
- assert not paths.work.join(file_path).exists()
- assert str(paths.work.join(source_file)) not in created
diff --git a/test/test_config.py b/test/test_config.py
index 4e44b1c..d364128 100644
--- a/test/test_config.py
+++ b/test/test_config.py
@@ -10,7 +10,7 @@ TEST_VALUE = 'testvalue'
TEST_FILE = f'[{TEST_SECTION}]\n\t{TEST_ATTRIBUTE} = {TEST_VALUE}'
-def test_config_no_params(runner, yadm_y, supported_configs):
+def test_config_no_params(runner, yadm_cmd, supported_configs):
"""No parameters
Display instructions
@@ -18,7 +18,7 @@ def test_config_no_params(runner, yadm_y, supported_configs):
Exit with 0
"""
- run = runner(yadm_y('config'))
+ run = runner(yadm_cmd('config'))
assert run.success
assert run.err == ''
@@ -27,21 +27,21 @@ def test_config_no_params(runner, yadm_y, supported_configs):
assert config in run.out
-def test_config_read_missing(runner, yadm_y):
+def test_config_read_missing(runner, yadm_cmd):
"""Read missing attribute
Display an empty value
Exit with 0
"""
- run = runner(yadm_y('config', TEST_KEY))
+ run = runner(yadm_cmd('config', TEST_KEY))
assert run.success
assert run.err == ''
assert run.out == ''
-def test_config_write(runner, yadm_y, paths):
+def test_config_write(runner, yadm_cmd, paths):
"""Write attribute
Display no output
@@ -49,7 +49,7 @@ def test_config_write(runner, yadm_y, paths):
Exit with 0
"""
- run = runner(yadm_y('config', TEST_KEY, TEST_VALUE))
+ run = runner(yadm_cmd('config', TEST_KEY, TEST_VALUE))
assert run.success
assert run.err == ''
@@ -57,7 +57,7 @@ def test_config_write(runner, yadm_y, paths):
assert paths.config.read().strip() == TEST_FILE
-def test_config_read(runner, yadm_y, paths):
+def test_config_read(runner, yadm_cmd, paths):
"""Read attribute
Display value
@@ -65,14 +65,14 @@ def test_config_read(runner, yadm_y, paths):
"""
paths.config.write(TEST_FILE)
- run = runner(yadm_y('config', TEST_KEY))
+ run = runner(yadm_cmd('config', TEST_KEY))
assert run.success
assert run.err == ''
assert run.out.strip() == TEST_VALUE
-def test_config_update(runner, yadm_y, paths):
+def test_config_update(runner, yadm_cmd, paths):
"""Update attribute
Display no output
@@ -82,7 +82,7 @@ def test_config_update(runner, yadm_y, paths):
paths.config.write(TEST_FILE)
- run = runner(yadm_y('config', TEST_KEY, TEST_VALUE + 'extra'))
+ run = runner(yadm_cmd('config', TEST_KEY, TEST_VALUE + 'extra'))
assert run.success
assert run.err == ''
@@ -92,7 +92,7 @@ def test_config_update(runner, yadm_y, paths):
@pytest.mark.usefixtures('ds1_repo_copy')
-def test_config_local_read(runner, yadm_y, paths, supported_local_configs):
+def test_config_local_read(runner, yadm_cmd, paths, supported_local_configs):
"""Read local attribute
Display value from the repo config
@@ -107,14 +107,14 @@ def test_config_local_read(runner, yadm_y, paths, supported_local_configs):
# run yadm config
for config in supported_local_configs:
- run = runner(yadm_y('config', config))
+ run = runner(yadm_cmd('config', config))
assert run.success
assert run.err == ''
assert run.out.strip() == f'value_of_{config}'
@pytest.mark.usefixtures('ds1_repo_copy')
-def test_config_local_write(runner, yadm_y, paths, supported_local_configs):
+def test_config_local_write(runner, yadm_cmd, paths, supported_local_configs):
"""Write local attribute
Display no output
@@ -124,7 +124,7 @@ def test_config_local_write(runner, yadm_y, paths, supported_local_configs):
# run yadm config
for config in supported_local_configs:
- run = runner(yadm_y('config', config, f'value_of_{config}'))
+ run = runner(yadm_cmd('config', config, f'value_of_{config}'))
assert run.success
assert run.err == ''
assert run.out == ''
@@ -137,3 +137,27 @@ def test_config_local_write(runner, yadm_y, paths, supported_local_configs):
assert run.success
assert run.err == ''
assert run.out.strip() == f'value_of_{config}'
+
+
+def test_config_without_parent_directory(runner, yadm_cmd, paths):
+ """Write and read attribute to/from config file with non-existent parent dir
+
+ Update configuration file
+ Display value
+ Exit with 0
+ """
+
+ config_file = paths.root + '/folder/does/not/exist/config'
+
+ run = runner(
+ yadm_cmd('--yadm-config', config_file, 'config', TEST_KEY, TEST_VALUE))
+
+ assert run.success
+ assert run.err == ''
+ assert run.out == ''
+
+ run = runner(yadm_cmd('--yadm-config', config_file, 'config', TEST_KEY))
+
+ assert run.success
+ assert run.err == ''
+ assert run.out.strip() == TEST_VALUE
diff --git a/test/test_default_remote_branch.py b/test/test_default_remote_branch.py
new file mode 100644
index 0000000..6405417
--- /dev/null
+++ b/test/test_default_remote_branch.py
@@ -0,0 +1,27 @@
+"""Unit tests: _default_remote_branch()"""
+import pytest
+
+
+@pytest.mark.parametrize('condition', ['found', 'missing'])
+def test(runner, paths, condition):
+ """Test _default_remote_branch()"""
+ test_branch = 'test/branch'
+ output = f'ref: refs/heads/{test_branch}\\tHEAD\\n'
+ if condition == 'missing':
+ output = 'output that is missing ref'
+ script = f"""
+ YADM_TEST=1 source {paths.pgm}
+ function git() {{
+ printf '{output}';
+ printf 'mock stderr\\n' 1>&2
+ }}
+ _default_remote_branch URL
+ """
+ print(condition)
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ if condition == 'found':
+ assert run.out.strip() == test_branch
+ else:
+ assert run.out.strip() == 'master'
diff --git a/test/test_encryption.py b/test/test_encryption.py
index b0d00de..fea2ff0 100644
--- a/test/test_encryption.py
+++ b/test/test_encryption.py
@@ -61,7 +61,7 @@ def asymmetric_key(runner, gnupg):
@pytest.fixture
-def encrypt_targets(yadm_y, paths):
+def encrypt_targets(yadm_cmd, paths):
"""Fixture for setting up data to encrypt
This fixture:
@@ -78,7 +78,7 @@ def encrypt_targets(yadm_y, paths):
"""
# init empty yadm repo
- os.system(' '.join(yadm_y('init', '-w', str(paths.work), '-f')))
+ os.system(' '.join(yadm_cmd('init', '-w', str(paths.work), '-f')))
expected = []
@@ -186,7 +186,7 @@ def decrypt_targets(tmpdir_factory, runner, gnupg):
'overwrite', [False, True],
ids=['clean', 'overwrite'])
def test_symmetric_encrypt(
- runner, yadm_y, paths, encrypt_targets,
+ runner, yadm_cmd, paths, encrypt_targets,
gnupg, bad_phrase, overwrite, missing_encrypt):
"""Test symmetric encryption"""
@@ -203,7 +203,7 @@ def test_symmetric_encrypt(
env = os.environ.copy()
env['GNUPGHOME'] = gnupg.home
- run = runner(yadm_y('encrypt'), env=env)
+ run = runner(yadm_cmd('encrypt'), env=env)
if missing_encrypt or bad_phrase:
assert run.failure
@@ -212,7 +212,7 @@ def test_symmetric_encrypt(
assert run.err == ''
if missing_encrypt:
- assert 'does not exist' in run.out
+ assert 'does not exist' in run.err
elif bad_phrase:
assert 'Invalid passphrase' in run.err
else:
@@ -230,12 +230,12 @@ def test_symmetric_encrypt(
'dolist', [False, True],
ids=['decrypt', 'list'])
def test_symmetric_decrypt(
- runner, yadm_y, paths, decrypt_targets, gnupg,
+ runner, yadm_cmd, paths, decrypt_targets, gnupg,
dolist, archive_exists, bad_phrase):
"""Test decryption"""
# init empty yadm repo
- os.system(' '.join(yadm_y('init', '-w', str(paths.work), '-f')))
+ os.system(' '.join(yadm_cmd('init', '-w', str(paths.work), '-f')))
if bad_phrase:
gnupg.pw('')
@@ -256,7 +256,7 @@ def test_symmetric_decrypt(
if dolist:
args.append('-l')
- run = runner(yadm_y('decrypt') + args, env=env)
+ run = runner(yadm_cmd('decrypt') + args, env=env)
if archive_exists and not bad_phrase:
assert run.success
@@ -284,16 +284,16 @@ def test_symmetric_decrypt(
'overwrite', [False, True],
ids=['clean', 'overwrite'])
def test_asymmetric_encrypt(
- runner, yadm_y, paths, encrypt_targets, gnupg,
+ runner, yadm_cmd, paths, encrypt_targets, gnupg,
overwrite, key_exists, ask):
"""Test asymmetric encryption"""
# specify encryption recipient
if ask:
- os.system(' '.join(yadm_y('config', 'yadm.gpg-recipient', 'ASK')))
+ os.system(' '.join(yadm_cmd('config', 'yadm.gpg-recipient', 'ASK')))
expect = [('Enter the user ID', KEY_NAME), ('Enter the user ID', '')]
else:
- os.system(' '.join(yadm_y('config', 'yadm.gpg-recipient', KEY_NAME)))
+ os.system(' '.join(yadm_cmd('config', 'yadm.gpg-recipient', KEY_NAME)))
expect = []
if overwrite:
@@ -305,7 +305,7 @@ def test_asymmetric_encrypt(
env = os.environ.copy()
env['GNUPGHOME'] = gnupg.home
- run = runner(yadm_y('encrypt'), env=env, expect=expect)
+ run = runner(yadm_cmd('encrypt'), env=env, expect=expect)
if key_exists:
assert run.success
@@ -313,7 +313,7 @@ def test_asymmetric_encrypt(
runner, gnupg, paths.archive, encrypt_targets)
else:
assert run.failure
- assert 'Unable to write' in run.out
+ assert 'Unable to write' in run.out if expect else run.err
if ask:
assert 'Enter the user ID' in run.out
@@ -321,17 +321,17 @@ def test_asymmetric_encrypt(
@pytest.mark.usefixtures('asymmetric_key')
@pytest.mark.usefixtures('encrypt_targets')
-def test_multi_key(runner, yadm_y, gnupg):
+def test_multi_key(runner, yadm_cmd, gnupg):
"""Test multiple recipients"""
# specify two encryption recipient
- os.system(' '.join(yadm_y(
+ os.system(' '.join(yadm_cmd(
'config', 'yadm.gpg-recipient', f'"{KEY_NAME} second-key"')))
env = os.environ.copy()
env['GNUPGHOME'] = gnupg.home
- run = runner(yadm_y('encrypt'), env=env)
+ run = runner(yadm_cmd('encrypt'), env=env)
assert run.failure
assert 'second-key: skipped: No public key' in run.err
@@ -345,12 +345,12 @@ def test_multi_key(runner, yadm_y, gnupg):
'dolist', [False, True],
ids=['decrypt', 'list'])
def test_asymmetric_decrypt(
- runner, yadm_y, paths, decrypt_targets, gnupg,
+ runner, yadm_cmd, paths, decrypt_targets, gnupg,
dolist, key_exists):
"""Test decryption"""
# init empty yadm repo
- os.system(' '.join(yadm_y('init', '-w', str(paths.work), '-f')))
+ os.system(' '.join(yadm_cmd('init', '-w', str(paths.work), '-f')))
decrypt_targets['asymmetric'].copy(paths.archive)
@@ -366,7 +366,7 @@ def test_asymmetric_decrypt(
args.append('-l')
env = os.environ.copy()
env['GNUPGHOME'] = gnupg.home
- run = runner(yadm_y('decrypt') + args, env=env)
+ run = runner(yadm_cmd('decrypt') + args, env=env)
if key_exists:
assert run.success
@@ -380,7 +380,7 @@ def test_asymmetric_decrypt(
assert paths.work.join(filename).read() == filename
else:
assert run.failure
- assert 'Unable to extract encrypted files' in run.out
+ assert 'Unable to extract encrypted files' in run.err
@pytest.mark.parametrize(
@@ -388,7 +388,7 @@ def test_asymmetric_decrypt(
[False, 'y', 'n'],
ids=['tracked', 'untracked_answer_y', 'untracked_answer_n'])
def test_offer_to_add(
- runner, yadm_y, paths, encrypt_targets, gnupg, untracked):
+ runner, yadm_cmd, paths, encrypt_targets, gnupg, untracked):
"""Test offer to add encrypted archive
All the other encryption tests use an archive outside of the work tree.
@@ -408,10 +408,10 @@ def test_offer_to_add(
expect.append(('add it now', untracked))
else:
worktree_archive.write('exists')
- os.system(' '.join(yadm_y('add', str(worktree_archive))))
+ os.system(' '.join(yadm_cmd('add', str(worktree_archive))))
run = runner(
- yadm_y('encrypt', '--yadm-archive', str(worktree_archive)),
+ yadm_cmd('encrypt', '--yadm-archive', str(worktree_archive)),
env=env,
expect=expect
)
@@ -422,7 +422,7 @@ def test_offer_to_add(
runner, gnupg, worktree_archive, encrypt_targets)
run = runner(
- yadm_y('status', '--porcelain', '-uall', str(worktree_archive)))
+ yadm_cmd('status', '--porcelain', '-uall', str(worktree_archive)))
assert run.success
assert run.err == ''
@@ -438,7 +438,7 @@ def test_offer_to_add(
@pytest.mark.usefixtures('ds1_copy')
-def test_encrypt_added_to_exclude(runner, yadm_y, paths, gnupg):
+def test_encrypt_added_to_exclude(runner, yadm_cmd, paths, gnupg):
"""Confirm that .config/yadm/encrypt is added to exclude"""
gnupg.pw(PASSPHRASE)
@@ -450,7 +450,7 @@ def test_encrypt_added_to_exclude(runner, yadm_y, paths, gnupg):
paths.work.join('test-encrypt-data').write('')
exclude_file.write('original-data', ensure=True)
- run = runner(yadm_y('encrypt'), env=env)
+ run = runner(yadm_cmd('encrypt'), env=env)
assert 'test-encrypt-data' in paths.repo.join('info/exclude').read()
assert 'original-data' in paths.repo.join('info/exclude').read()
diff --git a/test/test_enter.py b/test/test_enter.py
index d1f65d0..f5ea2d8 100644
--- a/test/test_enter.py
+++ b/test/test_enter.py
@@ -17,7 +17,7 @@ import pytest
'shell-noexec',
])
@pytest.mark.usefixtures('ds1_copy')
-def test_enter(runner, yadm_y, paths, shell, success):
+def test_enter(runner, yadm_cmd, paths, shell, success):
"""Enter tests"""
env = os.environ.copy()
if shell == 'delete':
@@ -33,15 +33,15 @@ def test_enter(runner, yadm_y, paths, shell, success):
else:
env['SHELL'] = shell
- run = runner(command=yadm_y('enter'), env=env)
+ run = runner(command=yadm_cmd('enter'), env=env)
assert run.success == success
- assert run.err == ''
prompt = f'yadm shell ({paths.repo})'
if success:
assert run.out.startswith('Entering yadm repo')
assert run.out.rstrip().endswith('Leaving yadm repo')
- if not success:
- assert 'does not refer to an executable' in run.out
+ assert run.err == ''
+ else:
+ assert 'does not refer to an executable' in run.err
if 'env' in shell:
assert f'GIT_DIR={paths.repo}' in run.out
assert f'GIT_WORK_TREE={paths.work}' in run.out
@@ -63,8 +63,12 @@ def test_enter(runner, yadm_y, paths, shell, success):
'cmd',
[False, 'cmd', 'cmd-bad-exit'],
ids=['no-cmd', 'cmd', 'cmd-bad-exit'])
+@pytest.mark.parametrize(
+ 'term', ['', 'dumb'],
+ ids=['term-empty', 'term-dumb'])
@pytest.mark.usefixtures('ds1_copy')
-def test_enter_shell_ops(runner, yadm_y, paths, shell, opts, path, cmd):
+def test_enter_shell_ops(runner, yadm_cmd, paths, shell,
+ opts, path, cmd, term):
"""Enter tests for specific shell options"""
change_exit = '\nfalse' if cmd == 'cmd-bad-exit' else ''
@@ -83,9 +87,13 @@ def test_enter_shell_ops(runner, yadm_y, paths, shell, opts, path, cmd):
enter_cmd += test_cmd
env = os.environ.copy()
+ env['TERM'] = term
env['SHELL'] = custom_shell
- run = runner(command=yadm_y(*enter_cmd), env=env)
+ if shell == 'zsh' and term == 'dumb':
+ opts += ' --no-zle'
+
+ run = runner(command=yadm_cmd(*enter_cmd), env=env)
if cmd == 'cmd-bad-exit':
assert run.failure
else:
diff --git a/test/test_git_crypt.py b/test/test_ext_crypt.py
index 6b92de9..cb74afc 100644
--- a/test/test_git_crypt.py
+++ b/test/test_ext_crypt.py
@@ -1,4 +1,4 @@
-"""Test git-crypt"""
+"""Test external encryption commands"""
import pytest
@@ -8,15 +8,21 @@ import pytest
[False, 'installed', 'installed-but-failed'],
ids=['not-installed', 'installed', 'installed-but-failed']
)
-def test_git_crypt(runner, yadm, paths, tmpdir, crypt):
- """git-crypt tests"""
+@pytest.mark.parametrize(
+ 'cmd,var', [
+ ['git_crypt', 'GIT_CRYPT_PROGRAM'],
+ ['transcrypt', 'TRANSCRYPT_PROGRAM'],
+ ],
+ ids=['git-crypt', 'transcrypt'])
+def test_ext_encryption(runner, yadm, paths, tmpdir, crypt, cmd, var):
+ """External encryption tests"""
paths.repo.ensure(dir=True)
bindir = tmpdir.mkdir('bin')
- pgm = bindir.join('test-git-crypt')
+ pgm = bindir.join('test-ext-crypt')
if crypt:
- pgm.write(f'#!/bin/sh\necho git-crypt ran\n')
+ pgm.write('#!/bin/sh\necho ext-crypt ran\n')
pgm.chmod(0o775)
if crypt == 'installed-but-failed':
pgm.write('false\n', mode='a')
@@ -24,8 +30,8 @@ def test_git_crypt(runner, yadm, paths, tmpdir, crypt):
script = f"""
YADM_TEST=1 source {yadm}
YADM_REPO={paths.repo}
- GIT_CRYPT_PROGRAM="{pgm}"
- git_crypt "param1"
+ {var}="{pgm}"
+ {cmd} "param1"
"""
run = runner(command=['bash'], inp=script)
@@ -35,8 +41,8 @@ def test_git_crypt(runner, yadm, paths, tmpdir, crypt):
assert run.failure
else:
assert run.success
- assert run.out.strip() == 'git-crypt ran'
+ assert run.out.strip() == 'ext-crypt ran'
+ assert run.err == ''
else:
assert run.failure
- assert f"command '{pgm}' cannot be located" in run.out
- assert run.err == ''
+ assert f"command '{pgm}' cannot be located" in run.err
diff --git a/test/test_git.py b/test/test_git.py
index 427c54a..76eccab 100644
--- a/test/test_git.py
+++ b/test/test_git.py
@@ -5,7 +5,7 @@ import pytest
@pytest.mark.usefixtures('ds1_copy')
-def test_git(runner, yadm_y, paths):
+def test_git(runner, yadm_cmd, paths):
"""Test series of passthrough git commands
Passthru unknown commands to Git
@@ -17,14 +17,14 @@ def test_git(runner, yadm_y, paths):
"""
# passthru unknown commands to Git
- run = runner(command=yadm_y('bogus'))
+ run = runner(command=yadm_cmd('bogus'))
assert run.failure
assert "git: 'bogus' is not a git command." in run.err
assert "See 'git --help'" in run.err
assert run.out == ''
# git command 'add' - badfile
- run = runner(command=yadm_y('add', '-v', 'does_not_exist'))
+ run = runner(command=yadm_cmd('add', '-v', 'does_not_exist'))
assert run.code == 128
assert "pathspec 'does_not_exist' did not match any files" in run.err
assert run.out == ''
@@ -32,19 +32,19 @@ def test_git(runner, yadm_y, paths):
# git command 'add'
newfile = paths.work.join('test_git')
newfile.write('test_git')
- run = runner(command=yadm_y('add', '-v', str(newfile)))
+ run = runner(command=yadm_cmd('add', '-v', str(newfile)))
assert run.success
assert run.err == ''
assert "add 'test_git'" in run.out
# git command 'status'
- run = runner(command=yadm_y('status'))
+ run = runner(command=yadm_cmd('status'))
assert run.success
assert run.err == ''
assert re.search(r'new file:\s+test_git', run.out)
# git command 'commit'
- run = runner(command=yadm_y('commit', '-m', 'Add test_git'))
+ run = runner(command=yadm_cmd('commit', '-m', 'Add test_git'))
assert run.success
assert run.err == ''
assert '1 file changed' in run.out
@@ -52,7 +52,7 @@ def test_git(runner, yadm_y, paths):
assert re.search(r'create mode .+ test_git', run.out)
# git command 'log'
- run = runner(command=yadm_y('log', '--oneline'))
+ run = runner(command=yadm_cmd('log', '--oneline'))
assert run.success
assert run.err == ''
assert 'Add test_git' in run.out
diff --git a/test/test_help.py b/test/test_help.py
index 79a7652..0d8f2c3 100644
--- a/test/test_help.py
+++ b/test/test_help.py
@@ -1,17 +1,19 @@
"""Test help"""
+import pytest
-def test_missing_command(runner, yadm_y):
+def test_missing_command(runner, yadm_cmd):
"""Run without any command"""
- run = runner(command=yadm_y())
+ run = runner(command=yadm_cmd())
assert run.failure
assert run.err == ''
assert run.out.startswith('Usage: yadm')
-def test_help_command(runner, yadm_y):
+@pytest.mark.parametrize('cmd', ['--help', 'help'])
+def test_help_command(runner, yadm_cmd, cmd):
"""Run with help command"""
- run = runner(command=yadm_y('help'))
+ run = runner(command=yadm_cmd(cmd))
assert run.failure
assert run.err == ''
assert run.out.startswith('Usage: yadm')
diff --git a/test/test_hooks.py b/test/test_hooks.py
index 36f3d98..704636a 100644
--- a/test/test_hooks.py
+++ b/test/test_hooks.py
@@ -21,8 +21,9 @@ import pytest
'pre-post-success',
'pre-post-fail',
])
+@pytest.mark.parametrize('cmd', ['--version', 'version'])
def test_hooks(
- runner, yadm_y, paths,
+ runner, yadm_cmd, paths, cmd,
pre, pre_code, post, post_code):
"""Test pre/post hook"""
@@ -33,7 +34,7 @@ def test_hooks(
create_hook(paths, 'post_version', post_code)
# run yadm
- run = runner(yadm_y('version'))
+ run = runner(yadm_cmd(cmd))
# when a pre hook fails, yadm should exit with the hook's code
assert run.code == pre_code
assert run.err == ''
@@ -53,7 +54,7 @@ def test_hooks(
# repo fixture is needed to test the population of YADM_HOOK_WORK
@pytest.mark.usefixtures('ds1_repo_copy')
-def test_hook_env(runner, yadm_y, paths):
+def test_hook_env(runner, yadm_cmd, paths):
"""Test hook environment"""
# test will be done with a non existent "git" passthru command
@@ -65,7 +66,7 @@ def test_hook_env(runner, yadm_y, paths):
hook.write('#!/bin/bash\nenv\ndeclare\n')
hook.chmod(0o755)
- run = runner(yadm_y(cmd, 'extra_args'))
+ run = runner(yadm_cmd(cmd, 'extra_args'))
# expect passthru to fail
assert run.failure
@@ -78,7 +79,7 @@ def test_hook_env(runner, yadm_y, paths):
assert f'YADM_HOOK_FULL_COMMAND={cmd} extra_args\n' in run.out
assert f'YADM_HOOK_REPO={paths.repo}\n' in run.out
assert f'YADM_HOOK_WORK={paths.work}\n' in run.out
- assert f'YADM_ENCRYPT_INCLUDE_FILES=\n' in run.out
+ assert 'YADM_ENCRYPT_INCLUDE_FILES=\n' in run.out
# verify the hook environment contains certain exported functions
for func in [
@@ -103,7 +104,7 @@ def test_hook_env(runner, yadm_y, paths):
assert 'YADM_ENCRYPT_INCLUDE_FILES=a\nb\nc\n' in run.out
-def test_escaped(runner, yadm_y, paths):
+def test_escaped(runner, yadm_cmd, paths):
"""Test escaped values in YADM_HOOK_FULL_COMMAND"""
# test will be done with a non existent "git" passthru command
@@ -115,7 +116,7 @@ def test_escaped(runner, yadm_y, paths):
hook.write('#!/bin/bash\nenv\n')
hook.chmod(0o755)
- run = runner(yadm_y(cmd, 'a b', 'c\td', 'e\\f'))
+ run = runner(yadm_cmd(cmd, 'a b', 'c\td', 'e\\f'))
# expect passthru to fail
assert run.failure
@@ -126,6 +127,39 @@ def test_escaped(runner, yadm_y, paths):
'a\\ b c\\\td e\\\\f\n') in run.out
+@pytest.mark.parametrize('condition', ['exec', 'no-exec', 'mingw'])
+def test_executable(runner, paths, condition):
+ """Verify hook must be exectuable"""
+ cmd = 'version'
+ hook = paths.hooks.join(f'pre_{cmd}')
+ hook.write('#!/bin/sh\necho HOOK\n')
+ hook.chmod(0o644)
+ if condition == 'exec':
+ hook.chmod(0o755)
+
+ mingw = 'OPERATING_SYSTEM="MINGWx"' if condition == 'mingw' else ''
+ script = f"""
+ YADM_TEST=1 source {paths.pgm}
+ YADM_HOOKS="{paths.hooks}"
+ HOOK_COMMAND="{cmd}"
+ {mingw}
+ invoke_hook "pre"
+ """
+ run = runner(command=['bash'], inp=script)
+
+ if condition != 'mingw':
+ assert run.success
+ assert run.err == ''
+ else:
+ assert run.failure
+ assert 'Permission denied' in run.err
+
+ if condition == 'exec':
+ assert 'HOOK' in run.out
+ elif condition == 'no-exec':
+ assert 'HOOK' not in run.out
+
+
def create_hook(paths, name, code):
"""Create hook"""
hook = paths.hooks.join(name)
diff --git a/test/test_init.py b/test/test_init.py
index 1519b38..c738a02 100644
--- a/test/test_init.py
+++ b/test/test_init.py
@@ -19,7 +19,7 @@ import pytest
])
@pytest.mark.usefixtures('ds1_work_copy')
def test_init(
- runner, yadm_y, paths, repo_config, alt_work, repo_present, force):
+ runner, yadm_cmd, paths, repo_config, alt_work, repo_present, force):
"""Test init
Repos should have attribs:
@@ -51,16 +51,16 @@ def test_init(
args.append('-f')
# run init
- run = runner(yadm_y(*args), env={'HOME': home})
- assert run.err == ''
+ run = runner(yadm_cmd(*args), env={'HOME': home})
if repo_present and not force:
assert run.failure
- assert 'repo already exists' in run.out
+ assert 'repo already exists' in run.err
assert old_repo.isfile(), 'Missing original repo'
else:
assert run.success
assert 'Initialized empty shared Git repository' in run.out
+ assert run.err == ''
if repo_present:
assert not old_repo.isfile(), 'Original repo still exists'
diff --git a/test/test_introspect.py b/test/test_introspect.py
index fcadf14..b292bd4 100644
--- a/test/test_introspect.py
+++ b/test/test_introspect.py
@@ -13,13 +13,13 @@ import pytest
'switches',
])
def test_introspect_category(
- runner, yadm_y, paths, name,
+ runner, yadm_cmd, paths, name,
supported_commands, supported_configs, supported_switches):
"""Validate introspection category"""
if name:
- run = runner(command=yadm_y('introspect', name))
+ run = runner(command=yadm_cmd('introspect', name))
else:
- run = runner(command=yadm_y('introspect'))
+ run = runner(command=yadm_cmd('introspect'))
assert run.success
assert run.err == ''
diff --git a/test/test_list.py b/test/test_list.py
index c2d8631..dcfe500 100644
--- a/test/test_list.py
+++ b/test/test_list.py
@@ -11,7 +11,7 @@ import pytest
'subdir',
])
@pytest.mark.usefixtures('ds1_copy')
-def test_list(runner, yadm_y, paths, ds1, location):
+def test_list(runner, yadm_cmd, paths, ds1, location):
"""List tests"""
if location == 'work':
run_dir = paths.work
@@ -23,7 +23,7 @@ def test_list(runner, yadm_y, paths, ds1, location):
with run_dir.as_cwd():
# test with '-a'
# should get all tracked files, relative to the work path
- run = runner(command=yadm_y('list', '-a'))
+ run = runner(command=yadm_cmd('list', '-a'))
assert run.success
assert run.err == ''
returned_files = set(run.out.splitlines())
@@ -33,7 +33,7 @@ def test_list(runner, yadm_y, paths, ds1, location):
# should get all tracked files, relative to the work path unless in a
# subdir, then those should be a limited set of files, relative to the
# subdir
- run = runner(command=yadm_y('list'))
+ run = runner(command=yadm_cmd('list'))
assert run.success
assert run.err == ''
returned_files = set(run.out.splitlines())
diff --git a/test/test_perms.py b/test/test_perms.py
index 0eb8add..4f052bd 100644
--- a/test/test_perms.py
+++ b/test/test_perms.py
@@ -6,12 +6,13 @@ import pytest
@pytest.mark.parametrize('autoperms', ['notest', 'unset', 'true', 'false'])
@pytest.mark.usefixtures('ds1_copy')
-def test_perms(runner, yadm_y, paths, ds1, autoperms):
+def test_perms(runner, yadm_cmd, paths, ds1, autoperms):
"""Test perms"""
# set the value of auto-perms
if autoperms != 'notest':
if autoperms != 'unset':
- os.system(' '.join(yadm_y('config', 'yadm.auto-perms', autoperms)))
+ os.system(' '.join(
+ yadm_cmd('config', 'yadm.auto-perms', autoperms)))
# privatepaths will hold all paths that should become secured
privatepaths = [paths.work.join('.ssh'), paths.work.join('.gnupg')]
@@ -38,7 +39,7 @@ def test_perms(runner, yadm_y, paths, ds1, autoperms):
cmd = 'perms'
if autoperms != 'notest':
cmd = 'status'
- run = runner(yadm_y(cmd), env={'HOME': paths.work})
+ run = runner(yadm_cmd(cmd), env={'HOME': paths.work})
assert run.success
assert run.err == ''
if cmd == 'perms':
@@ -62,15 +63,15 @@ def test_perms(runner, yadm_y, paths, ds1, autoperms):
@pytest.mark.parametrize('sshperms', [None, 'true', 'false'])
@pytest.mark.parametrize('gpgperms', [None, 'true', 'false'])
@pytest.mark.usefixtures('ds1_copy')
-def test_perms_control(runner, yadm_y, paths, ds1, sshperms, gpgperms):
+def test_perms_control(runner, yadm_cmd, paths, ds1, sshperms, gpgperms):
"""Test fine control of perms"""
# set the value of ssh-perms
if sshperms:
- os.system(' '.join(yadm_y('config', 'yadm.ssh-perms', sshperms)))
+ os.system(' '.join(yadm_cmd('config', 'yadm.ssh-perms', sshperms)))
# set the value of gpg-perms
if gpgperms:
- os.system(' '.join(yadm_y('config', 'yadm.gpg-perms', gpgperms)))
+ os.system(' '.join(yadm_cmd('config', 'yadm.gpg-perms', gpgperms)))
# privatepaths will hold all paths that should become secured
privatepaths = [paths.work.join('.ssh'), paths.work.join('.gnupg')]
@@ -81,7 +82,7 @@ def test_perms_control(runner, yadm_y, paths, ds1, sshperms, gpgperms):
assert not oct(private.stat().mode).endswith('00'), (
'Path started secured')
- run = runner(yadm_y('perms'), env={'HOME': paths.work})
+ run = runner(yadm_cmd('perms'), env={'HOME': paths.work})
assert run.success
assert run.err == ''
assert run.out == ''
diff --git a/test/test_unit_configure_paths.py b/test/test_unit_configure_paths.py
index 332277d..1a6fea9 100644
--- a/test/test_unit_configure_paths.py
+++ b/test/test_unit_configure_paths.py
@@ -2,19 +2,21 @@
import pytest
-ARCHIVE = 'files.gpg'
+ARCHIVE = 'archive'
BOOTSTRAP = 'bootstrap'
CONFIG = 'config'
ENCRYPT = 'encrypt'
HOME = '/testhome'
REPO = 'repo.git'
YDIR = '.config/yadm'
+YDATA = '.local/share/yadm'
@pytest.mark.parametrize(
'override, expect', [
(None, {}),
- ('-Y', {}),
+ ('-Y', {'yadm': 'YADM_DIR'}),
+ ('--yadm-data', {'data': 'YADM_DATA'}),
('--yadm-repo', {'repo': 'YADM_REPO', 'git': 'GIT_DIR'}),
('--yadm-config', {'config': 'YADM_CONFIG'}),
('--yadm-encrypt', {'encrypt': 'YADM_ENCRYPT'}),
@@ -23,6 +25,7 @@ YDIR = '.config/yadm'
], ids=[
'default',
'override yadm dir',
+ 'override yadm data',
'override repo',
'override config',
'override encrypt',
@@ -36,6 +39,8 @@ def test_config(runner, paths, override, expect):
args = []
if override == '-Y':
matches = match_map('/' + opath)
+ if override == '--yadm-data':
+ matches = match_map(None, '/' + opath)
if override:
args = [override, '/' + opath]
@@ -49,18 +54,20 @@ def test_config(runner, paths, override, expect):
run_test(runner, paths, args, matches.values(), 0)
-def match_map(yadm_dir=None):
+def match_map(yadm_dir=None, yadm_data=None):
"""Create a dictionary of matches, relative to yadm_dir"""
if not yadm_dir:
yadm_dir = '/'.join([HOME, YDIR])
+ if not yadm_data:
+ yadm_data = '/'.join([HOME, YDATA])
return {
'yadm': f'YADM_DIR="{yadm_dir}"',
- 'repo': f'YADM_REPO="{yadm_dir}/{REPO}"',
+ 'repo': f'YADM_REPO="{yadm_data}/{REPO}"',
'config': f'YADM_CONFIG="{yadm_dir}/{CONFIG}"',
'encrypt': f'YADM_ENCRYPT="{yadm_dir}/{ENCRYPT}"',
- 'archive': f'YADM_ARCHIVE="{yadm_dir}/{ARCHIVE}"',
+ 'archive': f'YADM_ARCHIVE="{yadm_data}/{ARCHIVE}"',
'bootstrap': f'YADM_BOOTSTRAP="{yadm_dir}/{BOOTSTRAP}"',
- 'git': f'GIT_DIR="{yadm_dir}/{REPO}"',
+ 'git': f'GIT_DIR="{yadm_data}/{REPO}"',
}
@@ -70,12 +77,15 @@ def run_test(runner, paths, args, expected_matches, expected_code=0):
script = f"""
YADM_TEST=1 HOME="{HOME}" source {paths.pgm}
process_global_args {argstring}
- HOME="{HOME}" set_yadm_dir
+ XDG_CONFIG_HOME=
+ XDG_DATA_HOME=
+ HOME="{HOME}" set_yadm_dirs
configure_paths
declare -p | grep -E '(YADM|GIT)_'
"""
run = runner(command=['bash'], inp=script)
assert run.code == expected_code
- assert run.err == ''
+ assert run.success == (run.code == 0)
+ assert (run.err if run.success else run.out) == ''
for match in expected_matches:
- assert match in run.out
+ assert match in run.out if run.success else run.err
diff --git a/test/test_unit_copy_perms.py b/test/test_unit_copy_perms.py
new file mode 100644
index 0000000..3c79768
--- /dev/null
+++ b/test/test_unit_copy_perms.py
@@ -0,0 +1,53 @@
+"""Unit tests: copy_perms"""
+import os
+import pytest
+
+OCTAL = '7654'
+NON_OCTAL = '9876'
+
+
+@pytest.mark.parametrize(
+ 'stat_broken', [True, False], ids=['normal', 'stat broken'])
+def test_copy_perms(runner, yadm, tmpdir, stat_broken):
+ """Test function copy_perms"""
+ src_mode = 0o754
+ dst_mode = 0o644
+ source = tmpdir.join('source')
+ source.write('test', ensure=True)
+ source.chmod(src_mode)
+
+ dest = tmpdir.join('dest')
+ dest.write('test', ensure=True)
+ dest.chmod(dst_mode)
+
+ override_stat = ''
+ if stat_broken:
+ override_stat = 'function stat() { echo broken; }'
+ script = f"""
+ YADM_TEST=1 source {yadm}
+ {override_stat}
+ copy_perms "{source}" "{dest}"
+ """
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ assert run.out == ''
+ expected = dst_mode if stat_broken else src_mode
+ assert oct(os.stat(dest).st_mode)[-3:] == oct(expected)[-3:]
+
+
+@pytest.mark.parametrize(
+ 'stat_output', [OCTAL, NON_OCTAL], ids=['octal', 'non-octal'])
+def test_get_mode(runner, yadm, stat_output):
+ """Test function get_mode"""
+ script = f"""
+ YADM_TEST=1 source {yadm}
+ function stat() {{ echo {stat_output}; }}
+ mode=$(get_mode abc)
+ echo "MODE:$mode"
+ """
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ expected = OCTAL if stat_output == OCTAL else ""
+ assert f'MODE:{expected}\n' in run.out
diff --git a/test/test_unit_encryption.py b/test/test_unit_encryption.py
new file mode 100644
index 0000000..ab03c62
--- /dev/null
+++ b/test/test_unit_encryption.py
@@ -0,0 +1,135 @@
+"""Unit tests: encryption functions"""
+
+import pytest
+
+
+@pytest.mark.parametrize('condition', ['default', 'override'])
+def test_get_cipher(runner, paths, condition):
+ """Test _get_cipher()"""
+
+ if condition == 'override':
+ paths.config.write('[yadm]\n\tcipher = override-cipher')
+
+ script = f"""
+ YADM_TEST=1 source {paths.pgm}
+ YADM_DIR="{paths.yadm}"
+ set_yadm_dirs
+ configure_paths
+ _get_cipher test-archive
+ echo "output_archive:$output_archive"
+ echo "yadm_cipher:$yadm_cipher"
+ """
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ assert 'output_archive:test-archive' in run.out
+ if condition == 'override':
+ assert 'yadm_cipher:override-cipher' in run.out
+ else:
+ assert 'yadm_cipher:gpg' in run.out
+
+
+@pytest.mark.parametrize('cipher', ['gpg', 'openssl', 'bad'])
+@pytest.mark.parametrize('mode', ['_encrypt_to', '_decrypt_from'])
+def test_encrypt_decrypt(runner, paths, cipher, mode):
+ """Test _encrypt_to() & _decrypt_from"""
+
+ script = f"""
+ YADM_TEST=1 source {paths.pgm}
+ YADM_DIR="{paths.yadm}"
+ set_yadm_dirs
+ configure_paths
+ function mock_openssl() {{ echo openssl $*; }}
+ function mock_gpg() {{ echo gpg $*; }}
+ function _get_cipher() {{
+ output_archive="$1"
+ yadm_cipher="{cipher}"
+ }}
+ OPENSSL_PROGRAM=mock_openssl
+ GPG_PROGRAM=mock_gpg
+ {mode} {paths.archive}
+ """
+ run = runner(command=['bash'], inp=script)
+
+ if cipher != 'bad':
+ assert run.success
+ assert run.out.startswith(cipher)
+ assert str(paths.archive) in run.out
+ assert run.err == ''
+ else:
+ assert run.failure
+ assert 'Unknown cipher' in run.err
+
+
+@pytest.mark.parametrize('condition', ['default', 'override'])
+def test_get_openssl_ciphername(runner, paths, condition):
+ """Test _get_openssl_ciphername()"""
+
+ if condition == 'override':
+ paths.config.write('[yadm]\n\topenssl-ciphername = override-cipher')
+
+ script = f"""
+ YADM_TEST=1 source {paths.pgm}
+ YADM_DIR="{paths.yadm}"
+ set_yadm_dirs
+ configure_paths
+ result=$(_get_openssl_ciphername)
+ echo "result:$result"
+ """
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ if condition == 'override':
+ assert run.out.strip() == 'result:override-cipher'
+ else:
+ assert run.out.strip() == 'result:aes-256-cbc'
+
+
+@pytest.mark.parametrize('condition', ['old', 'not-old'])
+def test_set_openssl_options(runner, paths, condition):
+ """Test _set_openssl_options()"""
+
+ if condition == 'old':
+ paths.config.write('[yadm]\n\topenssl-old = true')
+
+ script = f"""
+ YADM_TEST=1 source {paths.pgm}
+ YADM_DIR="{paths.yadm}"
+ set_yadm_dirs
+ configure_paths
+ function _get_openssl_ciphername() {{ echo "testcipher"; }}
+ _set_openssl_options
+ echo "result:${{OPENSSL_OPTS[@]}}"
+ """
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ if condition == 'old':
+ assert '-testcipher -salt -md md5' in run.out
+ else:
+ assert '-testcipher -salt -pbkdf2 -iter 100000 -md sha512' in run.out
+
+
+@pytest.mark.parametrize('recipient', ['ASK', 'present', ''])
+def test_set_gpg_options(runner, paths, recipient):
+ """Test _set_gpg_options()"""
+
+ paths.config.write(f'[yadm]\n\tgpg-recipient = {recipient}')
+
+ script = f"""
+ YADM_TEST=1 source {paths.pgm}
+ YADM_DIR="{paths.yadm}"
+ set_yadm_dirs
+ configure_paths
+ _set_gpg_options
+ echo "result:${{GPG_OPTS[@]}}"
+ """
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ if recipient == 'ASK':
+ assert run.out.strip() == 'result:--no-default-recipient -e'
+ elif recipient != '':
+ assert run.out.strip() == f'result:-e -r {recipient}'
+ else:
+ assert run.out.strip() == 'result:-c'
diff --git a/test/test_unit_issue_legacy_path_warning.py b/test/test_unit_issue_legacy_path_warning.py
index 3f5cd6f..e43228b 100644
--- a/test/test_unit_issue_legacy_path_warning.py
+++ b/test/test_unit_issue_legacy_path_warning.py
@@ -6,36 +6,36 @@ import pytest
'legacy_path', [
None,
'repo.git',
- 'config',
- 'encrypt',
'files.gpg',
- 'bootstrap',
- 'hooks/pre_command',
- 'hooks/post_command',
],
)
@pytest.mark.parametrize(
+ 'override', [True, False], ids=['override', 'no-override'])
+@pytest.mark.parametrize(
'upgrade', [True, False], ids=['upgrade', 'no-upgrade'])
-def test_legacy_warning(tmpdir, runner, yadm, upgrade, legacy_path):
+def test_legacy_warning(tmpdir, runner, yadm, upgrade, override, legacy_path):
"""Use issue_legacy_path_warning"""
home = tmpdir.mkdir('home')
if legacy_path:
- home.mkdir(f'.yadm').ensure(legacy_path)
+ home.ensure(f'.config/yadm/{str(legacy_path)}')
+ override = 'YADM_OVERRIDE_REPO=override' if override else ''
main_args = 'MAIN_ARGS=("upgrade")' if upgrade else ''
script = f"""
+ XDG_CONFIG_HOME=
+ XDG_DATA_HOME=
HOME={home}
YADM_TEST=1 source {yadm}
{main_args}
+ {override}
+ set_yadm_dirs
issue_legacy_path_warning
- echo "LWI:$LEGACY_WARNING_ISSUED"
"""
run = runner(command=['bash'], inp=script)
assert run.success
- assert run.err == ''
- if legacy_path and not upgrade:
- assert 'Legacy configuration paths have been detected' in run.out
- assert 'LWI:1' in run.out
+ assert run.out == ''
+ if legacy_path and (not upgrade) and (not override):
+ assert 'Legacy paths have been detected' in run.err
else:
- assert run.out.rstrip() == 'LWI:0'
+ assert 'Legacy paths have been detected' not in run.err
diff --git a/test/test_unit_record_score.py b/test/test_unit_record_score.py
index 525c967..78596e1 100644
--- a/test/test_unit_record_score.py
+++ b/test/test_unit_record_score.py
@@ -112,3 +112,30 @@ def test_existing_template(runner, yadm):
assert 'SCORES:1\n' in run.out
assert 'TARGETS:testtgt\n' in run.out
assert 'SOURCES:\n' in run.out
+
+
+def test_config_first(runner, yadm):
+ """Verify YADM_CONFIG is always processed first"""
+
+ config = 'yadm_config_file'
+ script = f"""
+ YADM_TEST=1 source {yadm}
+ {INIT_VARS}
+ YADM_CONFIG={config}
+ record_score "1" "tgt_before" "src_before"
+ record_template "tgt_tmp" "cmd_tmp" "src_tmp"
+ record_score "2" "{config}" "src_config"
+ record_score "3" "tgt_after" "src_after"
+ {REPORT_RESULTS}
+ echo "CMD_VALUE:${{alt_template_cmds[@]}}"
+ echo "CMD_INDEX:${{!alt_template_cmds[@]}}"
+ """
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ assert 'SIZE:3\n' in run.out
+ assert 'SCORES:2 1 3\n' in run.out
+ assert f'TARGETS:{config} tgt_before tgt_tmp tgt_after\n' in run.out
+ assert 'SOURCES:src_config src_before src_tmp src_after\n' in run.out
+ assert 'CMD_VALUE:cmd_tmp\n' in run.out
+ assert 'CMD_INDEX:2\n' in run.out
diff --git a/test/test_unit_report_invalid_alts.py b/test/test_unit_report_invalid_alts.py
index 7aa93bb..8730d61 100644
--- a/test/test_unit_report_invalid_alts.py
+++ b/test/test_unit_report_invalid_alts.py
@@ -2,38 +2,29 @@
import pytest
-@pytest.mark.parametrize(
- 'condition', [
- 'compat',
- 'previous-message',
- 'invalid-alts',
- 'no-invalid-alts',
- ])
-def test_report_invalid_alts(runner, yadm, condition):
+@pytest.mark.parametrize('valid', [True, False], ids=['valid', 'no_valid'])
+@pytest.mark.parametrize('previous', [True, False], ids=['prev', 'no_prev'])
+def test_report_invalid_alts(runner, yadm, valid, previous):
"""Use report_invalid_alts"""
- compat = ''
- previous = ''
+ lwi = ''
alts = 'INVALID_ALT=()'
- if condition == 'compat':
- compat = 'YADM_COMPATIBILITY=1'
- if condition == 'previous-message':
- previous = 'LEGACY_WARNING_ISSUED=1'
- if condition == 'invalid-alts':
+ if previous:
+ lwi = 'LEGACY_WARNING_ISSUED=1'
+ if not valid:
alts = 'INVALID_ALT=("file##invalid")'
script = f"""
YADM_TEST=1 source {yadm}
- {compat}
- {previous}
+ {lwi}
{alts}
report_invalid_alts
"""
run = runner(command=['bash'], inp=script)
assert run.success
- assert run.err == ''
- if condition == 'invalid-alts':
- assert 'WARNING' in run.out
- assert 'file##invalid' in run.out
+ assert run.out == ''
+ if not valid and not previous:
+ assert 'WARNING' in run.err
+ assert 'file##invalid' in run.err
else:
- assert run.out == ''
+ assert run.err == ''
diff --git a/test/test_unit_score_file.py b/test/test_unit_score_file.py
index 679229f..450c154 100644
--- a/test/test_unit_score_file.py
+++ b/test/test_unit_score_file.py
@@ -196,6 +196,28 @@ def test_score_values(
assert run.out == expected
+@pytest.mark.parametrize('ext', [None, 'e', 'extension'])
+def test_extensions(runner, yadm, ext):
+ """Verify extensions do not effect scores"""
+ local_user = 'testuser'
+ filename = f'filename##u.{local_user}'
+ if ext:
+ filename += f',{ext}.xyz'
+ expected = ''
+ script = f"""
+ YADM_TEST=1 source {yadm}
+ score=0
+ local_user={local_user}
+ score_file "{filename}"
+ echo "$score"
+ """
+ expected = f'{1000 + CONDITION["user"]["modifier"]}\n'
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ assert run.out == expected
+
+
def test_score_values_templates(runner, yadm):
"""Test score results"""
local_class = 'testclass'
@@ -260,19 +282,3 @@ def test_template_recording(runner, yadm, cmd_generated):
assert run.success
assert run.err == ''
assert run.out.rstrip() == expected
-
-
-def test_invalid(runner, yadm):
- """Verify invalid alternates are noted in INVALID_ALT"""
-
- invalid_file = "file##invalid"
-
- script = f"""
- YADM_TEST=1 source {yadm}
- score_file "{invalid_file}"
- echo "INVALID:${{INVALID_ALT[@]}}"
- """
- run = runner(command=['bash'], inp=script)
- assert run.success
- assert run.err == ''
- assert run.out.rstrip() == f'INVALID:{invalid_file}'
diff --git a/test/test_unit_set_local_alt_values.py b/test/test_unit_set_local_alt_values.py
index d3d2447..e49d055 100644
--- a/test/test_unit_set_local_alt_values.py
+++ b/test/test_unit_set_local_alt_values.py
@@ -26,7 +26,7 @@ def test_set_local_alt_values(
script = f"""
YADM_TEST=1 source {yadm} &&
set_operating_system &&
- YADM_DIR={paths.yadm} configure_paths &&
+ YADM_DIR={paths.yadm} YADM_DATA={paths.data} configure_paths &&
set_local_alt_values
echo "class='$local_class'"
echo "os='$local_system'"
@@ -52,12 +52,12 @@ def test_set_local_alt_values(
assert f"os='{tst_sys}'" in run.out
if override == 'hostname':
- assert f"host='override'" in run.out
+ assert "host='override'" in run.out
else:
assert f"host='{tst_host}'" in run.out
if override == 'user':
- assert f"user='override'" in run.out
+ assert "user='override'" in run.out
else:
assert f"user='{tst_user}'" in run.out
@@ -67,6 +67,7 @@ def test_distro(runner, yadm):
script = f"""
YADM_TEST=1 source {yadm}
+ function config() {{ echo "$1"; }}
function query_distro() {{ echo "testdistro"; }}
set_local_alt_values
echo "distro='$local_distro'"
diff --git a/test/test_unit_set_yadm_dir.py b/test/test_unit_set_yadm_dir.py
index 65459f8..32af8bf 100644
--- a/test/test_unit_set_yadm_dir.py
+++ b/test/test_unit_set_yadm_dir.py
@@ -1,35 +1,48 @@
-"""Unit tests: set_yadm_dir"""
+"""Unit tests: set_yadm_dirs"""
import pytest
@pytest.mark.parametrize(
- 'condition',
- ['basic', 'override', 'xdg_config_home', 'legacy'],
+ 'condition', [
+ 'basic',
+ 'override',
+ 'override_data',
+ 'xdg_config_home',
+ 'xdg_data_home'
+ ],
)
-def test_set_yadm_dir(runner, yadm, condition):
- """Test set_yadm_dir"""
+def test_set_yadm_dirs(runner, yadm, condition):
+ """Test set_yadm_dirs"""
setup = ''
if condition == 'override':
setup = 'YADM_DIR=/override'
+ elif condition == 'override_data':
+ setup = 'YADM_DATA=/override'
elif condition == 'xdg_config_home':
setup = 'XDG_CONFIG_HOME=/xdg'
- elif condition == 'legacy':
- setup = 'YADM_COMPATIBILITY=1'
+ elif condition == 'xdg_data_home':
+ setup = 'XDG_DATA_HOME=/xdg'
script = f"""
HOME=/testhome
YADM_TEST=1 source {yadm}
+ XDG_CONFIG_HOME=
+ XDG_DATA_HOME=
{setup}
- set_yadm_dir
- echo "$YADM_DIR"
+ set_yadm_dirs
+ echo "YADM_DIR=$YADM_DIR"
+ echo "YADM_DATA=$YADM_DATA"
"""
run = runner(command=['bash'], inp=script)
assert run.success
assert run.err == ''
if condition == 'basic':
- assert run.out.rstrip() == '/testhome/.config/yadm'
+ assert 'YADM_DIR=/testhome/.config/yadm' in run.out
+ assert 'YADM_DATA=/testhome/.local/share/yadm' in run.out
elif condition == 'override':
- assert run.out.rstrip() == '/override'
+ assert 'YADM_DIR=/override' in run.out
+ elif condition == 'override_data':
+ assert 'YADM_DATA=/override' in run.out
elif condition == 'xdg_config_home':
- assert run.out.rstrip() == '/xdg/yadm'
- elif condition == 'legacy':
- assert run.out.rstrip() == '/testhome/.yadm'
+ assert 'YADM_DIR=/xdg/yadm' in run.out
+ elif condition == 'xdg_data_home':
+ assert 'YADM_DATA=/xdg/yadm' in run.out
diff --git a/test/test_unit_template_default.py b/test/test_unit_template_default.py
index 42464b8..639cb29 100644
--- a/test/test_unit_template_default.py
+++ b/test/test_unit_template_default.py
@@ -1,4 +1,7 @@
"""Unit tests: template_default"""
+import os
+
+FILE_MODE = 0o754
# these values are also testing the handling of bizarre characters
LOCAL_CLASS = "default_Test+@-!^Class"
@@ -85,12 +88,43 @@ Included section for distro = {LOCAL_DISTRO} ({LOCAL_DISTRO} again)
end of template
'''
+INCLUDE_BASIC = 'basic\n'
+INCLUDE_VARIABLES = '''\
+included <{{ yadm.class }}> file
+
+empty line above
+'''
+INCLUDE_NESTED = 'no newline at the end'
+
+TEMPLATE_INCLUDE = '''\
+The first line
+{% include empty %}
+An empty file removes the line above
+{%include basic%}
+{% include "./variables.{{ yadm.os }}" %}
+{% include dir/nested %}
+Include basic again:
+{% include basic %}
+'''
+EXPECTED_INCLUDE = f'''\
+The first line
+An empty file removes the line above
+basic
+included <{LOCAL_CLASS}> file
+
+empty line above
+no newline at the end
+Include basic again:
+basic
+'''
+
def test_template_default(runner, yadm, tmpdir):
"""Test template_default"""
input_file = tmpdir.join('input')
input_file.write(TEMPLATE, ensure=True)
+ input_file.chmod(FILE_MODE)
output_file = tmpdir.join('output')
script = f"""
@@ -107,6 +141,7 @@ def test_template_default(runner, yadm, tmpdir):
assert run.success
assert run.err == ''
assert output_file.read() == EXPECTED
+ assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
def test_source(runner, yadm, tmpdir):
@@ -114,6 +149,7 @@ def test_source(runner, yadm, tmpdir):
input_file = tmpdir.join('input')
input_file.write('{{yadm.source}}', ensure=True)
+ input_file.chmod(FILE_MODE)
output_file = tmpdir.join('output')
script = f"""
@@ -125,3 +161,38 @@ def test_source(runner, yadm, tmpdir):
assert run.success
assert run.err == ''
assert output_file.read().strip() == str(input_file)
+ assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
+
+
+def test_include(runner, yadm, tmpdir):
+ """Test include"""
+
+ empty_file = tmpdir.join('empty')
+ empty_file.write('', ensure=True)
+
+ basic_file = tmpdir.join('basic')
+ basic_file.write(INCLUDE_BASIC)
+
+ variables_file = tmpdir.join(f'variables.{LOCAL_SYSTEM}')
+ variables_file.write(INCLUDE_VARIABLES)
+
+ nested_file = tmpdir.join('dir').join('nested')
+ nested_file.write(INCLUDE_NESTED, ensure=True)
+
+ input_file = tmpdir.join('input')
+ input_file.write(TEMPLATE_INCLUDE)
+ input_file.chmod(FILE_MODE)
+ output_file = tmpdir.join('output')
+
+ script = f"""
+ YADM_TEST=1 source {yadm}
+ set_awk
+ local_class="{LOCAL_CLASS}"
+ local_system="{LOCAL_SYSTEM}"
+ template_default "{input_file}" "{output_file}"
+ """
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ assert output_file.read() == EXPECTED_INCLUDE
+ assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
diff --git a/test/test_unit_template_esh.py b/test/test_unit_template_esh.py
new file mode 100644
index 0000000..e975152
--- /dev/null
+++ b/test/test_unit_template_esh.py
@@ -0,0 +1,121 @@
+"""Unit tests: template_esh"""
+import os
+
+FILE_MODE = 0o754
+
+LOCAL_CLASS = "esh_Test+@-!^Class"
+LOCAL_SYSTEM = "esh_Test+@-!^System"
+LOCAL_HOST = "esh_Test+@-!^Host"
+LOCAL_USER = "esh_Test+@-!^User"
+LOCAL_DISTRO = "esh_Test+@-!^Distro"
+TEMPLATE = f'''
+start of template
+esh class = ><%=$YADM_CLASS%><
+esh os = ><%=$YADM_OS%><
+esh host = ><%=$YADM_HOSTNAME%><
+esh user = ><%=$YADM_USER%><
+esh distro = ><%=$YADM_DISTRO%><
+<% if [ "$YADM_CLASS" = "wrongclass1" ]; then -%>
+wrong class 1
+<% fi -%>
+<% if [ "$YADM_CLASS" = "{LOCAL_CLASS}" ]; then -%>
+Included section for class = <%=$YADM_CLASS%> (<%=$YADM_CLASS%> repeated)
+<% fi -%>
+<% if [ "$YADM_CLASS" = "wrongclass2" ]; then -%>
+wrong class 2
+<% fi -%>
+<% if [ "$YADM_OS" = "wrongos1" ]; then -%>
+wrong os 1
+<% fi -%>
+<% if [ "$YADM_OS" = "{LOCAL_SYSTEM}" ]; then -%>
+Included section for os = <%=$YADM_OS%> (<%=$YADM_OS%> repeated)
+<% fi -%>
+<% if [ "$YADM_OS" = "wrongos2" ]; then -%>
+wrong os 2
+<% fi -%>
+<% if [ "$YADM_HOSTNAME" = "wronghost1" ]; then -%>
+wrong host 1
+<% fi -%>
+<% if [ "$YADM_HOSTNAME" = "{LOCAL_HOST}" ]; then -%>
+Included section for host = <%=$YADM_HOSTNAME%> (<%=$YADM_HOSTNAME%> again)
+<% fi -%>
+<% if [ "$YADM_HOSTNAME" = "wronghost2" ]; then -%>
+wrong host 2
+<% fi -%>
+<% if [ "$YADM_USER" = "wronguser1" ]; then -%>
+wrong user 1
+<% fi -%>
+<% if [ "$YADM_USER" = "{LOCAL_USER}" ]; then -%>
+Included section for user = <%=$YADM_USER%> (<%=$YADM_USER%> repeated)
+<% fi -%>
+<% if [ "$YADM_USER" = "wronguser2" ]; then -%>
+wrong user 2
+<% fi -%>
+<% if [ "$YADM_DISTRO" = "wrongdistro1" ]; then -%>
+wrong distro 1
+<% fi -%>
+<% if [ "$YADM_DISTRO" = "{LOCAL_DISTRO}" ]; then -%>
+Included section for distro = <%=$YADM_DISTRO%> (<%=$YADM_DISTRO%> again)
+<% fi -%>
+<% if [ "$YADM_DISTRO" = "wrongdistro2" ]; then -%>
+wrong distro 2
+<% fi -%>
+end of template
+'''
+EXPECTED = f'''
+start of template
+esh class = >{LOCAL_CLASS}<
+esh os = >{LOCAL_SYSTEM}<
+esh host = >{LOCAL_HOST}<
+esh user = >{LOCAL_USER}<
+esh distro = >{LOCAL_DISTRO}<
+Included section for class = {LOCAL_CLASS} ({LOCAL_CLASS} repeated)
+Included section for os = {LOCAL_SYSTEM} ({LOCAL_SYSTEM} repeated)
+Included section for host = {LOCAL_HOST} ({LOCAL_HOST} again)
+Included section for user = {LOCAL_USER} ({LOCAL_USER} repeated)
+Included section for distro = {LOCAL_DISTRO} ({LOCAL_DISTRO} again)
+end of template
+'''
+
+
+def test_template_esh(runner, yadm, tmpdir):
+ """Test processing by esh"""
+
+ input_file = tmpdir.join('input')
+ input_file.write(TEMPLATE, ensure=True)
+ input_file.chmod(FILE_MODE)
+ output_file = tmpdir.join('output')
+
+ script = f"""
+ YADM_TEST=1 source {yadm}
+ local_class="{LOCAL_CLASS}"
+ local_system="{LOCAL_SYSTEM}"
+ local_host="{LOCAL_HOST}"
+ local_user="{LOCAL_USER}"
+ local_distro="{LOCAL_DISTRO}"
+ template_esh "{input_file}" "{output_file}"
+ """
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ assert output_file.read().strip() == str(EXPECTED).strip()
+ assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
+
+
+def test_source(runner, yadm, tmpdir):
+ """Test YADM_SOURCE"""
+
+ input_file = tmpdir.join('input')
+ input_file.write('<%= $YADM_SOURCE %>', ensure=True)
+ input_file.chmod(FILE_MODE)
+ output_file = tmpdir.join('output')
+
+ script = f"""
+ YADM_TEST=1 source {yadm}
+ template_esh "{input_file}" "{output_file}"
+ """
+ run = runner(command=['bash'], inp=script)
+ assert run.success
+ assert run.err == ''
+ assert output_file.read().strip() == str(input_file)
+ assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
diff --git a/test/test_unit_template_j2.py b/test/test_unit_template_j2.py
index 85c6822..f81f4c6 100644
--- a/test/test_unit_template_j2.py
+++ b/test/test_unit_template_j2.py
@@ -1,6 +1,9 @@
"""Unit tests: template_j2cli & template_envtpl"""
+import os
import pytest
+FILE_MODE = 0o754
+
LOCAL_CLASS = "j2_Test+@-!^Class"
LOCAL_SYSTEM = "j2_Test+@-!^System"
LOCAL_HOST = "j2_Test+@-!^Host"
@@ -82,6 +85,7 @@ def test_template_j2(runner, yadm, tmpdir, processor):
input_file = tmpdir.join('input')
input_file.write(TEMPLATE, ensure=True)
+ input_file.chmod(FILE_MODE)
output_file = tmpdir.join('output')
script = f"""
@@ -97,6 +101,7 @@ def test_template_j2(runner, yadm, tmpdir, processor):
assert run.success
assert run.err == ''
assert output_file.read() == EXPECTED
+ assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
@pytest.mark.parametrize('processor', ('j2cli', 'envtpl'))
@@ -105,6 +110,7 @@ def test_source(runner, yadm, tmpdir, processor):
input_file = tmpdir.join('input')
input_file.write('{{YADM_SOURCE}}', ensure=True)
+ input_file.chmod(FILE_MODE)
output_file = tmpdir.join('output')
script = f"""
@@ -115,3 +121,4 @@ def test_source(runner, yadm, tmpdir, processor):
assert run.success
assert run.err == ''
assert output_file.read().strip() == str(input_file)
+ assert os.stat(output_file).st_mode == os.stat(input_file).st_mode
diff --git a/test/test_unit_upgrade.py b/test/test_unit_upgrade.py
index 73f4cac..3463740 100644
--- a/test/test_unit_upgrade.py
+++ b/test/test_unit_upgrade.py
@@ -1,53 +1,39 @@
"""Unit tests: upgrade"""
import pytest
-LEGACY_PATHS = [
- 'config',
- 'encrypt',
- 'files.gpg',
- 'bootstrap',
- 'hooks/pre_command',
- 'hooks/post_command',
-]
-# used:
-# YADM_COMPATIBILITY
-# YADM_DIR
-# YADM_LEGACY_DIR
-# GIT_PROGRAM
-@pytest.mark.parametrize('condition', ['compat', 'equal', 'existing_repo'])
+@pytest.mark.parametrize('condition', ['override', 'equal', 'existing_repo'])
def test_upgrade_errors(tmpdir, runner, yadm, condition):
"""Test upgrade() error conditions"""
- compatibility = 'YADM_COMPATIBILITY=1' if condition == 'compat' else ''
-
home = tmpdir.mkdir('home')
yadm_dir = home.join('.config/yadm')
- legacy_dir = home.join('.yadm')
+ yadm_data = home.join('.local/share/yadm')
+ override = ''
+ if condition == 'override':
+ override = 'override'
if condition == 'equal':
- legacy_dir = yadm_dir
+ yadm_data = yadm_dir
if condition == 'existing_repo':
yadm_dir.ensure_dir('repo.git')
- legacy_dir.ensure_dir('repo.git')
+ yadm_data.ensure_dir('repo.git')
script = f"""
YADM_TEST=1 source {yadm}
- {compatibility}
YADM_DIR="{yadm_dir}"
- YADM_REPO="{yadm_dir}/repo.git"
- YADM_LEGACY_DIR="{legacy_dir}"
+ YADM_DATA="{yadm_data}"
+ YADM_REPO="{yadm_data}/repo.git"
+ YADM_LEGACY_ARCHIVE="files.gpg"
+ YADM_OVERRIDE_REPO="{override}"
upgrade
"""
run = runner(command=['bash'], inp=script)
assert run.failure
- assert run.err == ''
- assert 'Unable to upgrade' in run.out
- if condition == 'compat':
- assert 'YADM_COMPATIBILITY' in run.out
- if condition == 'equal':
- assert 'has been resolved as' in run.out
- if condition == 'existing_repo':
- assert 'already exists' in run.out
+ assert 'Unable to upgrade' in run.err
+ if condition in ['override', 'equal']:
+ assert 'Paths have been overridden' in run.err
+ elif condition == 'existing_repo':
+ assert 'already exists' in run.err
@pytest.mark.parametrize(
@@ -59,22 +45,29 @@ def test_upgrade(tmpdir, runner, yadm, condition):
mock for git. echo will return true, simulating a positive result from "git
ls-files". Also echo will report the parameters for "git mv".
"""
+ legacy_paths = ('config', 'encrypt', 'bootstrap', 'hooks/pre_cmd')
home = tmpdir.mkdir('home')
yadm_dir = home.join('.config/yadm')
- legacy_dir = home.join('.yadm')
+ yadm_data = home.join('.local/share/yadm')
+ yadm_legacy = home.join('.yadm')
if condition != 'no-paths':
- legacy_dir.join('repo.git/config').write('test-repo', ensure=True)
- for lpath in LEGACY_PATHS:
- legacy_dir.join(lpath).write(lpath, ensure=True)
+ yadm_dir.join('repo.git/config').write('test-repo', ensure=True)
+ yadm_dir.join('files.gpg').write('files.gpg', ensure=True)
+ for path in legacy_paths:
+ yadm_legacy.join(path).write(path, ensure=True)
mock_git = ""
- if condition in ['tracked', 'submodules']:
+ if condition != 'no-paths':
mock_git = f'''
function git() {{
echo "$@"
- if [[ "$*" == *.gitmodules* ]]; then
- return { '0' if condition == 'submodules' else '1' }
+ if [[ "$*" = *"submodule status" ]]; then
+ { 'echo " 1234567 mymodule (1.0)"'
+ if condition == 'submodules' else ':' }
+ fi
+ if [[ "$*" = *ls-files* ]]; then
+ return { 1 if condition == 'untracked' else 0 }
fi
return 0
}}
@@ -82,9 +75,11 @@ def test_upgrade(tmpdir, runner, yadm, condition):
script = f"""
YADM_TEST=1 source {yadm}
+ YADM_LEGACY_DIR="{yadm_legacy}"
YADM_DIR="{yadm_dir}"
- YADM_REPO="{yadm_dir}/repo.git"
- YADM_LEGACY_DIR="{legacy_dir}"
+ YADM_DATA="{yadm_data}"
+ YADM_REPO="{yadm_data}/repo.git"
+ YADM_ARCHIVE="{yadm_data}/archive"
GIT_PROGRAM="git"
{mock_git}
function cd {{ echo "$@";}}
@@ -96,25 +91,32 @@ def test_upgrade(tmpdir, runner, yadm, condition):
if condition == 'no-paths':
assert 'Upgrade is not necessary' in run.out
else:
- for lpath in LEGACY_PATHS + ['repo.git']:
+ for (lpath, npath) in [
+ ('repo.git', 'repo.git'), ('files.gpg', 'archive')]:
+ expected = (
+ f'Moving {yadm_dir.join(lpath)} '
+ f'to {yadm_data.join(npath)}')
+ assert expected in run.out
+ for path in legacy_paths:
expected = (
- f'Moving {legacy_dir.join(lpath)} '
- f'to {yadm_dir.join(lpath)}')
+ f'Moving {yadm_legacy.join(path)} '
+ f'to {yadm_dir.join(path)}')
assert expected in run.out
if condition == 'untracked':
- assert 'test-repo' in yadm_dir.join('repo.git/config').read()
- for lpath in LEGACY_PATHS:
- assert lpath in yadm_dir.join(lpath).read()
+ assert 'test-repo' in yadm_data.join('repo.git/config').read()
+ assert 'files.gpg' in yadm_data.join('archive').read()
+ for path in legacy_paths:
+ assert path in yadm_dir.join(path).read()
elif condition in ['tracked', 'submodules']:
- for lpath in LEGACY_PATHS:
- expected = (
- f'mv {legacy_dir.join(lpath)} '
- f'{yadm_dir.join(lpath)}')
- assert expected in run.out
+ expected = (
+ f'mv {yadm_dir.join("files.gpg")} '
+ f'{yadm_data.join("archive")}')
+ assert expected in run.out
assert 'files tracked by yadm have been renamed' in run.out
if condition == 'submodules':
- assert 'submodule deinit -f .' in run.out
- assert 'submodule update --init --recursive' in run.out
+ assert 'submodule deinit -- mymodule' in run.out
+ assert 'submodule update --init --recursive -- mymodule' \
+ in run.out
else:
- assert 'submodule deinit -f .' not in run.out
+ assert 'submodule deinit' not in run.out
assert 'submodule update --init --recursive' not in run.out
diff --git a/test/test_unit_x_program.py b/test/test_unit_x_program.py
index 3233a3d..8302f3c 100644
--- a/test/test_unit_x_program.py
+++ b/test/test_unit_x_program.py
@@ -16,24 +16,24 @@ import pytest
])
@pytest.mark.parametrize('program', ['git', 'gpg'])
def test_x_program(
- runner, yadm_y, paths, program, executable, success, value, match):
+ runner, yadm_cmd, paths, program, executable, success, value, match):
"""Set yadm.X-program, and test result of require_X"""
# set configuration
if executable:
- os.system(' '.join(yadm_y(
+ os.system(' '.join(yadm_cmd(
'config', f'yadm.{program}-program', executable)))
# test require_[git,gpg]
script = f"""
YADM_TEST=1 source {paths.pgm}
- YADM_CONFIG="{paths.config}"
+ YADM_OVERRIDE_CONFIG="{paths.config}"
+ configure_paths
require_{program}
echo ${program.upper()}_PROGRAM
"""
run = runner(command=['bash'], inp=script)
assert run.success == success
- assert run.err == ''
# [GIT,GPG]_PROGRAM set correctly
if value == 'program':
@@ -43,4 +43,6 @@ def test_x_program(
# error reported about bad config
if match:
- assert match in run.out
+ assert match in run.err
+ else:
+ assert run.err == ''
diff --git a/test/test_upgrade.py b/test/test_upgrade.py
new file mode 100644
index 0000000..1ccf075
--- /dev/null
+++ b/test/test_upgrade.py
@@ -0,0 +1,129 @@
+"""Test upgrade"""
+
+import os
+import pytest
+
+
+@pytest.mark.parametrize(
+ 'versions', [
+ ('1.12.0', '2.5.0'),
+ ('1.12.0',),
+ ('2.5.0',),
+ ], ids=[
+ '1.12.0 -> 2.5.0 -> latest',
+ '1.12.0 -> latest',
+ '2.5.0 -> latest',
+ ])
+@pytest.mark.parametrize(
+ 'submodule', [False, True],
+ ids=['no submodule', 'with submodules'])
+def test_upgrade(tmpdir, runner, versions, submodule):
+ """Upgrade tests"""
+ # pylint: disable=too-many-statements
+ home = tmpdir.mkdir('HOME')
+ env = {'HOME': str(home)}
+
+ if submodule:
+ ext_repo = tmpdir.mkdir('ext_repo')
+ ext_repo.join('afile').write('some data')
+
+ for cmd in (('init',), ('add', 'afile'), ('commit', '-m', 'test')):
+ run = runner(['git', '-C', str(ext_repo), *cmd])
+ assert run.success
+
+ os.environ.pop('XDG_CONFIG_HOME', None)
+ os.environ.pop('XDG_DATA_HOME', None)
+
+ def run_version(version, *args, check_stderr=True):
+ yadm = 'yadm-%s' % version if version else '/yadm/yadm'
+ run = runner([yadm, *args], shell=True, cwd=str(home), env=env)
+ assert run.success
+ if check_stderr:
+ assert run.err == ''
+ return run
+
+ # Initialize the repo with the first version
+ first = versions[0]
+ run_version(first, 'init')
+
+ home.join('file').write('some data')
+ run_version(first, 'add', 'file')
+ run_version(first, 'commit', '-m', '"First commit"')
+
+ if submodule:
+ # When upgrading via 2.5.0 we can't have a submodule that's been added
+ # after being cloned as 2.5.0 fails the upgrade in that case.
+ can_upgraded_cloned_submodule = '2.5.0' not in versions[1:]
+ if can_upgraded_cloned_submodule:
+ # Check out a repo and then add it as a submodule
+ run = runner(['git', '-C', str(home), 'clone', str(ext_repo), 'b'])
+ assert run.success
+ run_version(first, 'submodule', 'add', str(ext_repo), 'b')
+
+ # Add submodule without first checking it out
+ run_version(first, 'submodule', 'add', str(ext_repo), 'a',
+ check_stderr=False)
+ run_version(first, 'submodule', 'add', str(ext_repo), 'c',
+ check_stderr=False)
+
+ run_version(first, 'commit', '-m', '"Add submodules"')
+
+ for path in ('.yadm', '.config/yadm'):
+ yadm_dir = home.join(path)
+ if yadm_dir.exists():
+ break
+
+ yadm_dir.join('bootstrap').write('init stuff')
+ run_version(first, 'add', yadm_dir.join('bootstrap'))
+ run_version(first, 'commit', '-m', 'bootstrap')
+
+ yadm_dir.join('encrypt').write('secret')
+
+ hooks_dir = yadm_dir.mkdir('hooks')
+ hooks_dir.join('pre_status').write('status')
+ hooks_dir.join('post_commit').write('commit')
+
+ run_version(first, 'config', 'local.class', 'test')
+ run_version(first, 'config', 'foo.bar', 'true')
+
+ # Run upgrade with intermediate versions and latest
+ latest = None
+ for version in versions[1:] + (latest,):
+ run = run_version(version, 'upgrade', check_stderr=not submodule)
+ if submodule:
+ lines = run.err.splitlines()
+ if can_upgraded_cloned_submodule:
+ assert 'Migrating git directory of' in lines[0]
+ assert str(home.join('b/.git')) in lines[1]
+ assert str(yadm_dir.join('repo.git/modules/b')) in lines[2]
+ del lines[:3]
+ for line in lines:
+ assert line.startswith('Submodule')
+ assert 'registered for path' in line
+
+ # Verify result for the final upgrade
+ run_version(latest, 'status')
+
+ run = run_version(latest, 'show', 'HEAD:file')
+ assert run.out == 'some data'
+
+ if submodule:
+ if can_upgraded_cloned_submodule:
+ assert home.join('b/afile').read() == 'some data'
+ assert home.join('a/afile').read() == 'some data'
+ assert home.join('c/afile').read() == 'some data'
+
+ yadm_dir = home.join('.config/yadm')
+
+ assert yadm_dir.join('bootstrap').read() == 'init stuff'
+ assert yadm_dir.join('encrypt').read() == 'secret'
+
+ hooks_dir = yadm_dir.join('hooks')
+ assert hooks_dir.join('pre_status').read() == 'status'
+ assert hooks_dir.join('post_commit').read() == 'commit'
+
+ run = run_version(latest, 'config', 'local.class')
+ assert run.out.rstrip() == 'test'
+
+ run = run_version(latest, 'config', 'foo.bar')
+ assert run.out.rstrip() == 'true'
diff --git a/test/test_version.py b/test/test_version.py
index 023eb82..08bebe1 100644
--- a/test/test_version.py
+++ b/test/test_version.py
@@ -26,10 +26,11 @@ def test_semantic_version(expected_version):
'does not conform to MAJOR.MINOR.PATCH')
+@pytest.mark.parametrize('cmd', ['--version', 'version'])
def test_reported_version(
- runner, yadm_y, expected_version):
+ runner, yadm_cmd, cmd, expected_version):
"""Report correct version"""
- run = runner(command=yadm_y('version'))
+ run = runner(command=yadm_cmd(cmd))
assert run.success
assert run.err == ''
assert run.out == f'yadm {expected_version}\n'