2019-10-01 13:12:18 +00:00
|
|
|
"""Test alt"""
|
|
|
|
import os
|
|
|
|
import string
|
|
|
|
import py
|
|
|
|
import pytest
|
|
|
|
import utils
|
|
|
|
|
|
|
|
TEST_PATHS = [utils.ALT_FILE1, utils.ALT_FILE2, utils.ALT_DIR]
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('ds1_copy')
|
2019-10-10 13:23:36 +00:00
|
|
|
@pytest.mark.parametrize('yadm_alt', [True, False], ids=['alt', 'worktree'])
|
2019-10-01 13:12:18 +00:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
'tracked,encrypt,exclude', [
|
|
|
|
(False, False, False),
|
|
|
|
(True, False, False),
|
|
|
|
(False, True, False),
|
|
|
|
(False, True, True),
|
|
|
|
], ids=['untracked', 'tracked', 'encrypted', 'excluded'])
|
|
|
|
def test_alt_source(
|
2019-10-10 13:23:36 +00:00
|
|
|
runner, paths,
|
|
|
|
tracked, encrypt, exclude,
|
|
|
|
yadm_alt):
|
2019-10-01 13:12:18 +00:00
|
|
|
"""Test yadm alt operates on all expected sources of alternates"""
|
2019-10-10 13:23:36 +00:00
|
|
|
yadm_dir = setup_standard_yadm_dir(paths)
|
2019-10-01 13:12:18 +00:00
|
|
|
|
|
|
|
utils.create_alt_files(
|
2019-10-10 13:23:36 +00:00
|
|
|
paths, '##default', tracked=tracked, encrypt=encrypt, exclude=exclude,
|
|
|
|
yadm_alt=yadm_alt, yadm_dir=yadm_dir)
|
|
|
|
run = runner([paths.pgm, '-Y', yadm_dir, 'alt'])
|
2019-10-01 13:12:18 +00:00
|
|
|
assert run.success
|
|
|
|
assert run.err == ''
|
|
|
|
linked = utils.parse_alt_output(run.out)
|
|
|
|
|
2019-10-10 13:23:36 +00:00
|
|
|
basepath = yadm_dir.join('alt') if yadm_alt else paths.work
|
|
|
|
|
2019-10-01 13:12:18 +00:00
|
|
|
for link_path in TEST_PATHS:
|
2019-10-10 13:23:36 +00:00
|
|
|
source_file_content = link_path + '##default'
|
|
|
|
source_file = basepath.join(source_file_content)
|
|
|
|
link_file = paths.work.join(link_path)
|
2019-10-01 13:12:18 +00:00
|
|
|
if tracked or (encrypt and not exclude):
|
2019-10-10 13:23:36 +00:00
|
|
|
assert link_file.islink()
|
|
|
|
target = py.path.local(link_file.readlink())
|
2019-10-01 13:12:18 +00:00
|
|
|
if target.isfile():
|
2019-10-10 13:23:36 +00:00
|
|
|
assert link_file.read() == source_file_content
|
|
|
|
assert str(source_file) in linked
|
2019-10-01 13:12:18 +00:00
|
|
|
else:
|
2019-10-10 13:23:36 +00:00
|
|
|
assert link_file.join(
|
|
|
|
utils.CONTAINED).read() == source_file_content
|
|
|
|
assert str(source_file) in linked
|
2019-10-01 13:12:18 +00:00
|
|
|
else:
|
2019-10-10 13:23:36 +00:00
|
|
|
assert not link_file.exists()
|
|
|
|
assert str(source_file) not in linked
|
2019-10-01 13:12:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('ds1_copy')
|
|
|
|
@pytest.mark.parametrize('suffix', [
|
|
|
|
'##default',
|
|
|
|
'##o.$tst_sys', '##os.$tst_sys',
|
2019-10-06 16:04:21 +00:00
|
|
|
'##d.$tst_distro', '##distro.$tst_distro',
|
2019-10-01 13:12:18 +00:00
|
|
|
'##c.$tst_class', '##class.$tst_class',
|
|
|
|
'##h.$tst_host', '##hostname.$tst_host',
|
|
|
|
'##u.$tst_user', '##user.$tst_user',
|
|
|
|
])
|
|
|
|
def test_alt_conditions(
|
2019-10-10 13:23:36 +00:00
|
|
|
runner, paths,
|
2019-10-06 16:04:21 +00:00
|
|
|
tst_sys, tst_distro, tst_host, tst_user, suffix):
|
2019-10-01 13:12:18 +00:00
|
|
|
"""Test conditions supported by yadm alt"""
|
2019-10-10 13:23:36 +00:00
|
|
|
yadm_dir = setup_standard_yadm_dir(paths)
|
2019-10-01 13:12:18 +00:00
|
|
|
|
|
|
|
# set the class
|
|
|
|
tst_class = 'testclass'
|
|
|
|
utils.set_local(paths, 'class', tst_class)
|
|
|
|
|
|
|
|
suffix = string.Template(suffix).substitute(
|
|
|
|
tst_sys=tst_sys,
|
2019-10-06 16:04:21 +00:00
|
|
|
tst_distro=tst_distro,
|
2019-10-01 13:12:18 +00:00
|
|
|
tst_class=tst_class,
|
|
|
|
tst_host=tst_host,
|
|
|
|
tst_user=tst_user,
|
|
|
|
)
|
|
|
|
|
|
|
|
utils.create_alt_files(paths, suffix)
|
2019-10-10 13:23:36 +00:00
|
|
|
run = runner([paths.pgm, '-Y', yadm_dir, 'alt'])
|
2019-10-01 13:12:18 +00:00
|
|
|
assert run.success
|
|
|
|
assert run.err == ''
|
|
|
|
linked = utils.parse_alt_output(run.out)
|
|
|
|
|
|
|
|
for link_path in TEST_PATHS:
|
|
|
|
source_file = link_path + suffix
|
|
|
|
assert paths.work.join(link_path).islink()
|
|
|
|
target = py.path.local(paths.work.join(link_path).readlink())
|
|
|
|
if target.isfile():
|
|
|
|
assert paths.work.join(link_path).read() == source_file
|
|
|
|
assert str(paths.work.join(source_file)) in linked
|
|
|
|
else:
|
|
|
|
assert paths.work.join(link_path).join(
|
|
|
|
utils.CONTAINED).read() == source_file
|
|
|
|
assert str(paths.work.join(source_file)) in linked
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('ds1_copy')
|
2019-10-12 14:14:45 +00:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
'kind', ['builtin', '', None, 'envtpl', 'j2cli', 'j2'])
|
2019-10-01 13:12:18 +00:00
|
|
|
@pytest.mark.parametrize('label', ['t', 'template', 'yadm', ])
|
|
|
|
def test_alt_templates(
|
2019-10-10 13:23:36 +00:00
|
|
|
runner, paths, kind, label):
|
2019-10-01 13:12:18 +00:00
|
|
|
"""Test templates supported by yadm alt"""
|
2019-10-10 13:23:36 +00:00
|
|
|
yadm_dir = setup_standard_yadm_dir(paths)
|
2019-10-01 13:12:18 +00:00
|
|
|
|
|
|
|
suffix = f'##{label}.{kind}'
|
2019-10-12 14:14:45 +00:00
|
|
|
if kind is None:
|
|
|
|
suffix = f'##{label}'
|
2019-10-01 13:12:18 +00:00
|
|
|
utils.create_alt_files(paths, suffix)
|
2019-10-10 13:23:36 +00:00
|
|
|
run = runner([paths.pgm, '-Y', yadm_dir, 'alt'])
|
2019-10-01 13:12:18 +00:00
|
|
|
assert run.success
|
|
|
|
assert run.err == ''
|
|
|
|
created = utils.parse_alt_output(run.out, linked=False)
|
|
|
|
|
|
|
|
for created_path in TEST_PATHS:
|
|
|
|
if created_path != utils.ALT_DIR:
|
|
|
|
source_file = created_path + suffix
|
|
|
|
assert paths.work.join(created_path).isfile()
|
|
|
|
assert paths.work.join(created_path).read().strip() == source_file
|
|
|
|
assert str(paths.work.join(source_file)) in created
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('ds1_copy')
|
|
|
|
@pytest.mark.parametrize('autoalt', [None, 'true', 'false'])
|
|
|
|
def test_auto_alt(runner, yadm_y, paths, autoalt):
|
|
|
|
"""Test auto alt"""
|
|
|
|
|
|
|
|
# set the value of auto-alt
|
|
|
|
if autoalt:
|
|
|
|
os.system(' '.join(yadm_y('config', 'yadm.auto-alt', autoalt)))
|
|
|
|
|
|
|
|
utils.create_alt_files(paths, '##default')
|
|
|
|
run = runner(yadm_y('status'))
|
|
|
|
assert run.success
|
|
|
|
assert run.err == ''
|
|
|
|
linked = utils.parse_alt_output(run.out)
|
|
|
|
|
|
|
|
for link_path in TEST_PATHS:
|
|
|
|
source_file = link_path + '##default'
|
|
|
|
if autoalt == 'false':
|
|
|
|
assert not paths.work.join(link_path).exists()
|
|
|
|
else:
|
|
|
|
assert paths.work.join(link_path).islink()
|
|
|
|
target = py.path.local(paths.work.join(link_path).readlink())
|
|
|
|
if target.isfile():
|
|
|
|
assert paths.work.join(link_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(link_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.usefixtures('ds1_copy')
|
|
|
|
def test_stale_link_removal(runner, yadm_y, paths):
|
|
|
|
"""Stale links to 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'##class.{tst_class}')
|
|
|
|
|
|
|
|
# run alt to trigger linking
|
|
|
|
run = runner(yadm_y('alt'))
|
|
|
|
assert run.success
|
|
|
|
assert run.err == ''
|
|
|
|
linked = utils.parse_alt_output(run.out)
|
|
|
|
|
|
|
|
# assert the proper linking has occurred
|
|
|
|
for stale_path in TEST_PATHS:
|
|
|
|
source_file = stale_path + '##class.' + tst_class
|
|
|
|
assert paths.work.join(stale_path).islink()
|
|
|
|
target = py.path.local(paths.work.join(stale_path).readlink())
|
|
|
|
if target.isfile():
|
|
|
|
assert paths.work.join(stale_path).read() == source_file
|
|
|
|
assert str(paths.work.join(source_file)) in linked
|
|
|
|
else:
|
|
|
|
assert paths.work.join(stale_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
|
|
|
|
run = runner(yadm_y('alt'))
|
|
|
|
assert run.success
|
|
|
|
assert run.err == ''
|
|
|
|
linked = utils.parse_alt_output(run.out)
|
|
|
|
|
|
|
|
# assert the linking is removed
|
|
|
|
for stale_path in TEST_PATHS:
|
|
|
|
source_file = stale_path + '##class.' + tst_class
|
|
|
|
assert not paths.work.join(stale_path).exists()
|
|
|
|
assert str(paths.work.join(source_file)) not in linked
|
2019-10-11 12:20:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.usefixtures('ds1_repo_copy')
|
|
|
|
def test_template_overwrite_symlink(runner, yadm_y, 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
|
|
|
|
symlink will get the template content. To prevent this, the symlink should
|
|
|
|
be removed just before processing a template.
|
|
|
|
"""
|
|
|
|
|
|
|
|
target = paths.work.join(f'test_link##os.{tst_sys}')
|
|
|
|
target.write('target')
|
|
|
|
|
|
|
|
link = paths.work.join('test_link')
|
|
|
|
link.mksymlinkto(target, absolute=1)
|
|
|
|
|
|
|
|
template = paths.work.join('test_link##template.builtin')
|
|
|
|
template.write('test-data')
|
|
|
|
|
|
|
|
run = runner(yadm_y('add', target, template))
|
|
|
|
assert run.success
|
|
|
|
assert run.err == ''
|
|
|
|
assert run.out == ''
|
|
|
|
assert not link.islink()
|
|
|
|
assert target.read().strip() == 'target'
|
|
|
|
assert link.read().strip() == 'test-data'
|
2019-10-10 13:23:36 +00:00
|
|
|
|
|
|
|
|
2019-10-12 23:22:02 +00:00
|
|
|
@pytest.mark.usefixtures('ds1_copy')
|
|
|
|
@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)
|
|
|
|
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])
|
|
|
|
assert run.success
|
|
|
|
assert run.err == ''
|
|
|
|
assert run.out == ''
|
|
|
|
assert paths.work.join(filename).read().strip() == 'test-data'
|
|
|
|
|
|
|
|
|
2019-10-10 13:23:36 +00:00
|
|
|
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_dir.join('encrypt').mksymlinkto(paths.encrypt, absolute=1)
|
|
|
|
return std_yadm_dir
|