2016-10-11 06:14:39 +02:00
|
|
|
import pytest
|
|
|
|
import testinfra
|
2018-07-06 02:10:43 +02:00
|
|
|
from textwrap import dedent
|
2016-10-11 06:14:39 +02:00
|
|
|
|
|
|
|
check_output = testinfra.get_backend(
|
|
|
|
"local://"
|
|
|
|
).get_module("Command").check_output
|
|
|
|
|
2018-07-06 02:10:43 +02:00
|
|
|
SETUPVARS = {
|
|
|
|
'PIHOLE_INTERFACE': 'eth99',
|
|
|
|
'PIHOLE_DNS_1': '4.2.2.1',
|
|
|
|
'PIHOLE_DNS_2': '4.2.2.2'
|
|
|
|
}
|
|
|
|
|
2020-03-03 08:30:44 +01:00
|
|
|
tick_box = "[\x1b[1;32m\u2713\x1b[0m]"
|
|
|
|
cross_box = "[\x1b[1;31m\u2717\x1b[0m]"
|
|
|
|
info_box = "[i]"
|
2018-07-06 02:10:43 +02:00
|
|
|
|
2018-07-02 22:54:19 +02:00
|
|
|
|
2016-10-11 06:14:39 +02:00
|
|
|
@pytest.fixture
|
|
|
|
def Pihole(Docker):
|
2018-07-03 08:05:24 +02:00
|
|
|
'''
|
|
|
|
used to contain some script stubbing, now pretty much an alias.
|
|
|
|
Also provides bash as the default run function shell
|
|
|
|
'''
|
2016-11-03 05:58:54 +01:00
|
|
|
def run_bash(self, command, *args, **kwargs):
|
|
|
|
cmd = self.get_command(command, *args)
|
|
|
|
if self.user is not None:
|
|
|
|
out = self.run_local(
|
|
|
|
"docker exec -u %s %s /bin/bash -c %s",
|
|
|
|
self.user, self.name, cmd)
|
|
|
|
else:
|
|
|
|
out = self.run_local(
|
|
|
|
"docker exec %s /bin/bash -c %s", self.name, cmd)
|
|
|
|
out.command = self.encode(cmd)
|
|
|
|
return out
|
|
|
|
|
|
|
|
funcType = type(Docker.run)
|
2020-03-03 08:30:44 +01:00
|
|
|
Docker.run = funcType(run_bash, Docker)
|
2016-10-11 06:14:39 +02:00
|
|
|
return Docker
|
|
|
|
|
2018-07-02 22:54:19 +02:00
|
|
|
|
2016-10-11 06:14:39 +02:00
|
|
|
@pytest.fixture
|
|
|
|
def Docker(request, args, image, cmd):
|
2018-07-03 08:05:24 +02:00
|
|
|
'''
|
|
|
|
combine our fixtures into a docker run command and setup finalizer to
|
|
|
|
cleanup
|
|
|
|
'''
|
2016-10-11 06:14:39 +02:00
|
|
|
assert 'docker' in check_output('id'), "Are you in the docker group?"
|
|
|
|
docker_run = "docker run {} {} {}".format(args, image, cmd)
|
|
|
|
docker_id = check_output(docker_run)
|
|
|
|
|
|
|
|
def teardown():
|
|
|
|
check_output("docker rm -f %s", docker_id)
|
|
|
|
request.addfinalizer(teardown)
|
|
|
|
|
|
|
|
docker_container = testinfra.get_backend("docker://" + docker_id)
|
|
|
|
docker_container.id = docker_id
|
|
|
|
return docker_container
|
|
|
|
|
2018-07-02 22:54:19 +02:00
|
|
|
|
2016-10-11 06:14:39 +02:00
|
|
|
@pytest.fixture
|
|
|
|
def args(request):
|
2018-07-03 08:05:24 +02:00
|
|
|
'''
|
|
|
|
-t became required when tput began being used
|
|
|
|
'''
|
2021-11-11 17:44:57 +01:00
|
|
|
return '-t -d --cap-add=ALL'
|
2016-10-11 06:14:39 +02:00
|
|
|
|
2018-07-02 22:54:19 +02:00
|
|
|
|
2020-10-27 12:32:23 +01:00
|
|
|
@pytest.fixture(params=[
|
2020-12-01 11:02:31 +01:00
|
|
|
'test_container'
|
2020-10-27 12:32:23 +01:00
|
|
|
])
|
2016-10-11 06:14:39 +02:00
|
|
|
def tag(request):
|
2018-07-03 08:05:24 +02:00
|
|
|
'''
|
|
|
|
consumed by image to make the test matrix
|
|
|
|
'''
|
2016-10-11 06:14:39 +02:00
|
|
|
return request.param
|
|
|
|
|
2018-07-02 22:54:19 +02:00
|
|
|
|
2016-10-11 06:14:39 +02:00
|
|
|
@pytest.fixture()
|
|
|
|
def image(request, tag):
|
2018-07-03 08:05:24 +02:00
|
|
|
'''
|
|
|
|
built by test_000_build_containers.py
|
|
|
|
'''
|
2016-10-11 06:14:39 +02:00
|
|
|
return 'pytest_pihole:{}'.format(tag)
|
|
|
|
|
2018-07-02 22:54:19 +02:00
|
|
|
|
2016-10-11 06:14:39 +02:00
|
|
|
@pytest.fixture()
|
|
|
|
def cmd(request):
|
2018-07-03 08:05:24 +02:00
|
|
|
'''
|
|
|
|
default to doing nothing by tailing null, but don't exit
|
|
|
|
'''
|
2016-10-11 06:14:39 +02:00
|
|
|
return 'tail -f /dev/null'
|
2018-07-06 02:10:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
# Helper functions
|
|
|
|
def mock_command(script, args, container):
|
|
|
|
'''
|
|
|
|
Allows for setup of commands we don't really want to have to run for real
|
|
|
|
in unit tests
|
|
|
|
'''
|
|
|
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
2021-11-11 17:44:57 +01:00
|
|
|
mock_script = dedent(r'''\
|
2018-07-06 02:10:43 +02:00
|
|
|
#!/bin/bash -e
|
|
|
|
echo "\$0 \$@" >> /var/log/{script}
|
|
|
|
case "\$1" in'''.format(script=script))
|
2020-03-03 08:30:44 +01:00
|
|
|
for k, v in args.items():
|
2018-07-06 02:10:43 +02:00
|
|
|
case = dedent('''
|
|
|
|
{arg})
|
|
|
|
echo {res}
|
|
|
|
exit {retcode}
|
|
|
|
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
|
|
|
mock_script += case
|
|
|
|
mock_script += dedent('''
|
|
|
|
esac''')
|
|
|
|
container.run('''
|
|
|
|
cat <<EOF> {script}\n{content}\nEOF
|
|
|
|
chmod +x {script}
|
|
|
|
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
|
|
|
content=mock_script,
|
|
|
|
scriptlog=script))
|
|
|
|
|
|
|
|
|
2021-11-11 17:44:57 +01:00
|
|
|
def mock_command_passthrough(script, args, container):
|
|
|
|
'''
|
|
|
|
Per other mock_command* functions, allows intercepting of commands we don't want to run for real
|
|
|
|
in unit tests, however also allows only specific arguments to be mocked. Anything not defined will
|
|
|
|
be passed through to the actual command.
|
|
|
|
|
|
|
|
Example use-case: mocking `git pull` but still allowing `git clone` to work as intended
|
|
|
|
'''
|
|
|
|
orig_script_path = check_output('which {}'.format(script))
|
|
|
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
|
|
|
mock_script = dedent(r'''\
|
|
|
|
#!/bin/bash -e
|
|
|
|
echo "\$0 \$@" >> /var/log/{script}
|
|
|
|
case "\$1" in'''.format(script=script))
|
|
|
|
for k, v in args.items():
|
|
|
|
case = dedent('''
|
|
|
|
{arg})
|
|
|
|
echo {res}
|
|
|
|
exit {retcode}
|
|
|
|
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
|
|
|
mock_script += case
|
|
|
|
mock_script += dedent(r'''
|
|
|
|
*)
|
|
|
|
{orig_script_path} "\$@"
|
|
|
|
;;'''.format(orig_script_path=orig_script_path))
|
|
|
|
mock_script += dedent('''
|
|
|
|
esac''')
|
|
|
|
container.run('''
|
|
|
|
cat <<EOF> {script}\n{content}\nEOF
|
|
|
|
chmod +x {script}
|
|
|
|
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
|
|
|
content=mock_script,
|
|
|
|
scriptlog=script))
|
|
|
|
|
|
|
|
|
|
|
|
def mock_command_run(script, args, container):
|
|
|
|
'''
|
|
|
|
Allows for setup of commands we don't really want to have to run for real
|
|
|
|
in unit tests
|
|
|
|
'''
|
|
|
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
|
|
|
mock_script = dedent(r'''\
|
|
|
|
#!/bin/bash -e
|
|
|
|
echo "\$0 \$@" >> /var/log/{script}
|
|
|
|
case "\$1 \$2" in'''.format(script=script))
|
|
|
|
for k, v in args.items():
|
|
|
|
case = dedent('''
|
|
|
|
\"{arg}\")
|
|
|
|
echo {res}
|
|
|
|
exit {retcode}
|
|
|
|
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
|
|
|
mock_script += case
|
|
|
|
mock_script += dedent('''
|
|
|
|
esac''')
|
|
|
|
container.run('''
|
|
|
|
cat <<EOF> {script}\n{content}\nEOF
|
|
|
|
chmod +x {script}
|
|
|
|
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
|
|
|
content=mock_script,
|
|
|
|
scriptlog=script))
|
|
|
|
|
|
|
|
|
2018-07-06 02:10:43 +02:00
|
|
|
def mock_command_2(script, args, container):
|
|
|
|
'''
|
|
|
|
Allows for setup of commands we don't really want to have to run for real
|
|
|
|
in unit tests
|
|
|
|
'''
|
|
|
|
full_script_path = '/usr/local/bin/{}'.format(script)
|
2021-11-11 17:44:57 +01:00
|
|
|
mock_script = dedent(r'''\
|
2018-07-06 02:10:43 +02:00
|
|
|
#!/bin/bash -e
|
|
|
|
echo "\$0 \$@" >> /var/log/{script}
|
|
|
|
case "\$1 \$2" in'''.format(script=script))
|
2020-03-03 08:30:44 +01:00
|
|
|
for k, v in args.items():
|
2018-07-06 02:10:43 +02:00
|
|
|
case = dedent('''
|
|
|
|
\"{arg}\")
|
|
|
|
echo \"{res}\"
|
|
|
|
exit {retcode}
|
|
|
|
;;'''.format(arg=k, res=v[0], retcode=v[1]))
|
|
|
|
mock_script += case
|
|
|
|
mock_script += dedent('''
|
|
|
|
esac''')
|
|
|
|
container.run('''
|
|
|
|
cat <<EOF> {script}\n{content}\nEOF
|
|
|
|
chmod +x {script}
|
|
|
|
rm -f /var/log/{scriptlog}'''.format(script=full_script_path,
|
|
|
|
content=mock_script,
|
|
|
|
scriptlog=script))
|
|
|
|
|
|
|
|
def run_script(Pihole, script):
|
|
|
|
result = Pihole.run(script)
|
|
|
|
assert result.rc == 0
|
2020-12-01 11:13:36 +01:00
|
|
|
return result
|