Commit 618a4e50 authored by Georges Racinet's avatar Georges Racinet 🦑
Browse files

Declarative system for network connections from Heptapod

We'll need to have Heptapod initiate connections to the
system running the tests, in order to test outbound operations
such as web hooks.

We introduce a marker for tests that rely on this, so that they
can be skipped, together with the new `--heptapod-reverse-call-host`
option, for that to be possible, with reasonable defaults.
parent 9c189e0c99fb
......@@ -36,6 +36,13 @@ and does not match the expected one.
In the Docker case, the expected container name is by default `heptapod`.
By default, the tests expect to be running on the Docker host, and that the
container can initiate TCP connections to the host, identified as the main
IPv4 gateway of the container. Don't forget to *allow incoming TCP connections
from the container in your firewall*, if you have one. You can also pass a
reachable address explicitely with `--heptapod-reverse-call-host` or disable
such tests by passing an empty string as address.
The container HTTP and SSH ports must be forwarded by default to `heptapod:81`
and `heptapod:2022`. This is usually done by making the `heptapod` host name
resolve to a loopback IP address, such as, and forwarding the
......@@ -82,6 +89,9 @@ These are available in all cases
resolves to the loopback interface, it is advised to tie it to a dedicated
address, such as ``, to minimize risks with your SSH
`known_hosts` file.
- `--heptapod-reverse-call-host`: address that the Heptapod server can use
to reach the system running theses tests (necessary to test outbound
connections, such as web hooks).
- `--heptapod-root-password` (default `5iveL!fe`). The password to use and maybe
set for the `root` user. The default value is the same as with the GitLab
Development Kit (GDK).
......@@ -35,21 +35,34 @@ def pytest_addoption(parser):
parser.addoption('--heptapod-ssh-user', default='git')
parser.addoption('--heptapod-docker-container', default='heptapod')
parser.addoption('--heptapod-root-password', default='5iveL!fe')
help="Network address that the Heptapod server "
"can use to initiate network connections to "
"the system running these tests.")
def pytest_configure(config):
"fs_access: mark test as needing file system "
"access to Heptapod server (Docker or local).")
"reverse_call: mark test as involving network "
"calls from the Heptapod server to the host "
"running these tests")
def pytest_collection_modifyitems(config, items):
if not config.getoption('heptapod_remote'):
remote = config.getoption('heptapod_remote')
skip_fs_needed = pytest.mark.skip(reason="needs filesystem access")
skip_reverse_call = pytest.mark.skip(
reason="needs to be able to initiate network connections to the host "
"running these tests")
no_reverse_call = not(config.getoption('heptapod_reverse_call_host'))
for item in items:
if "fs_access" in item.keywords:
if remote and "fs_access" in item.keywords:
if "reverse_call" in item.keywords and no_reverse_call:
......@@ -59,6 +72,8 @@ def heptapod(pytestconfig):
if pytestconfig.getoption('heptapod_source_install'):
repos_root = pytestconfig.getoption('heptapod_repositories_root')
......@@ -57,3 +57,16 @@ def heptapod_get_archive(ct, path, tarf):
for chunk in bits:
return stats
def host_address(ct):
"""Return a suitable address for the host, as seen from the container.
For now this is just the IPv4 gateway, assumed to be the host, i.e. where
these tests run.
It will probably fail for more complicated network settings, but that's
good enough for the time being.
container = _client.containers.get(ct)
return container.attrs['NetworkSettings']['Gateway']
......@@ -46,12 +46,18 @@ class Heptapod:
see :class:`DockerHeptapod` for an example.
def __init__(self, url, ssh_user, ssh_port):
reverse_call_host = None
"""Network address for the system running these tests, seen from Heptapod.
def __init__(self, url, ssh_user, ssh_port, reverse_call_host=None):
self.parsed_url = urlparse(url)
self.url = url
self.ssh_port = ssh_port
self.ssh_user = ssh_user
self.users = {}
if reverse_call_host is not None:
self.reverse_call_host = reverse_call_host
self.dead = None
......@@ -123,6 +129,11 @@ class Heptapod:
# guaranteeing driver to be available for teardown as soon as created
root['webdriver'] = driver
session.login_as_root(driver, self, root_password)
# necessary if we want to listen to web hooks from these tests
# in GitLab v12.2.0, this is deprecated for ...from_web_hooks...
basic, driver = session.ensure_user(self, 'test_basic',
fullname='Bäsîc Test',
......@@ -193,6 +204,8 @@ class DockerHeptapod(Heptapod):
def __init__(self, docker_container, **kw):
super(DockerHeptapod, self).__init__(**kw)
self.docker_container = docker_container
if self.reverse_call_host is None:
self.reverse_call_host = docker.host_address(docker_container)
def execute(self, command, user='root'):
return docker.heptapod_exec(self.docker_container, command, user=user)
......@@ -261,6 +274,8 @@ class SourceHeptapod(Heptapod):
shell_access = True
reverse_call_host = 'localhost'
def ssh_url(self):
return 'ssh://{host}:{port}'.format(
import pytest
fs_access = pytest.mark.fs_access
reverse_call = pytest.mark.reverse_call
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment