1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
import os
import pytest
from yarsync import YARsync
from yarsync.yarsync import _Sync
from .settings import (
TEST_DIR, TEST_DIR_EMPTY, TEST_DIR_CONFIG_DIR, TEST_DIR_WORK_DIR, TEST_DIR_FILTER,
TEST_DIR_YS_BAD_PERMISSIONS,
)
def test_status_error(mocker, test_dir_read_only):
## test directory without .ys configuration
os.chdir(test_dir_read_only)
mocker_stdout = mocker.patch("sys.stdout")
mocker_stderr = mocker.patch("sys.stderr")
call = mocker.call
args = ["yarsync", "status"]
# issues a mocker warning
# with mocker.patch("sys.stderr") as mocker_stderr:
with pytest.raises(OSError) as err:
ys = YARsync(args)
assert ".ys not found" in repr(err.value)
# adapted from https://stackoverflow.com/a/59398826/952234
write_calls = mocker_stderr.write.call_args_list
# [0] is call args, [1] is kwargs
written_strs = "".join(call[0][0] for call in write_calls)
# error message is correct
assert written_strs.startswith(
"! fatal: no yarsync configuration directory .ys found\n"
)
# no stdout output
assert mocker_stdout.mock_calls == []
# don't test for exact messages,
# because we might improve them in the future.
# assert mocker_print.mock_calls == [
# call.write('!'),
# call.write(' '),
# call.write("fatal: no yarsync configuration "
# ".ys found"),
# call.write('\n')
# ]
def test_status_error_bad_permissions(capfd):
os.chdir(TEST_DIR_YS_BAD_PERMISSIONS)
ys = YARsync(["yarsync", "status"])
returncode = ys()
# rsync returns 23 in case of permission errors
assert returncode == 23
# mock will not work with non-Python stderr,
# https://github.com/pytest-dev/pytest-mock/issues/295#issuecomment-1155105804
# so we use capfd
# https://docs.pytest.org/en/stable/how-to/capture-stdout-stderr.html#accessing-captured-output-from-a-test-function
# https://docs.pytest.org/en/stable/reference/reference.html#capfd
captured = capfd.readouterr()
assert 'test_dir_ys_bad_permissions/forbidden" failed: Permission denied '\
in captured.err
assert "No synchronization information found." in captured.out
def test_status_no_commits(mocker):
os.chdir(TEST_DIR_EMPTY)
# io.StringIO uses only utf-8
mocker_print = mocker.patch("sys.stdout") #, new_callable=StringIO)
args = ["yarsync", "status"]
ys = YARsync(args)
res = ys()
call = mocker.call
assert res == 0
assert mocker_print.mock_calls == [
call.write('In repository myhost'), call.write('\n'),
call.write('No commits found'), call.write('\n')
]
@pytest.mark.parametrize(
"command,test_dir",
[
(["yarsync"], TEST_DIR_FILTER),
(["yarsync", "--config-dir="+TEST_DIR_CONFIG_DIR], TEST_DIR_WORK_DIR),
]
)
def test_status_existing_commits(capfd, command, test_dir):
"""Status works same for a normal and a detached configuration."""
os.chdir(test_dir)
# mocker_print = mocker.patch("sys.stdout")
command.append("status")
ys = YARsync(command)
res = ys()
# we don't check for the exact rsync message here, only for results.
# # filter is needed, because not only .ys can be excluded
assert res == 0
## stdout is correct
# we don't test for exact lines, because they can change
# when we e.g. add and remove a file to a subdirectory
# (thus changing its timestamps)
captured = capfd.readouterr()
assert not captured.err
assert captured.out.endswith(
'Nothing to commit, working directory clean.\n'
'No synchronization directory found.\n'
'No synchronization information found.\n'
)
# assert mocker_print.mock_calls == [
# # this is written only with -v
# # call.write('# '),
# # call.write(''),
# # call.write(
# # "rsync -aun --delete -i --exclude=/.ys {} --outbuf=L {}/ {}/commits/2"\
# # .format(filter_str, ys.root_dir, ys.config_dir)
# # ),
# # call.write('\n'),
# call.write('Nothing to commit, working directory clean.'),
# call.write('\n'),
# call.write('No synchronization information found.'),
# call.write('\n'),
# ]
@pytest.mark.parametrize(
"local_sync",
[
(["1_other_repo.txt"]),
(["2_other_repo.txt", "1_other_repo.txt"]),
]
)
def test_status_existing_sync(mocker, capfd, local_sync):
n_commits_ahead = 1
other_repo = "other_repo"
os.chdir(TEST_DIR)
ys = YARsync(["yarsync", "status"])
sync = _Sync(local_sync)
mock = mocker.Mock()
mock.return_value = sync
ys._get_local_sync = mock
res = ys()
captured = capfd.readouterr()
assert not captured.err
if len(local_sync) == 1:
sync_str = "Local repository is {} commits ahead of {}\n"\
.format(n_commits_ahead, other_repo)
assert sync_str in captured.out
else:
sync_str = "Commits are up to date with {}.\n".format(other_repo)
assert sync_str in captured.out
|