Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions tests/common_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,56 @@ def standard_setup_one_client(request):
return env


@pytest.fixture(scope="function")
def standard_setup_one_docker_client(request):
env = container_factory.get_docker_client_setup()
request.addfinalizer(env.teardown)

env.setup()

env.device = MenderDevice(env.get_mender_clients()[0])
env.device.ssh_is_opened()

reset_mender_api(env)

env.auth = auth
return env


@pytest.fixture(scope="function")
def standard_setup_two_docker_clients_bootstrapped(request):
env = container_factory.get_docker_client_setup(num_clients=2)
request.addfinalizer(env.teardown)

env.setup()

env.device_group = MenderDeviceGroup(env.get_mender_clients())
env.device_group.ssh_is_opened()

reset_mender_api(env)
devauth.accept_devices(2)

env.auth = auth
return env


@pytest.fixture(scope="function")
def qemu_setup_one_client(request):
"""Explicit QEMU client setup for tests that require A/B rootfs updates."""
env = container_factory.get_qemu_client_setup(num_clients=1)
env.setup()

env.device = MenderDevice(env.get_mender_clients()[0])
env.device.ssh_is_opened()

reset_mender_api(env)

request.addfinalizer(env.teardown)

env.auth = auth
return env


@pytest.fixture(scope="function")
def standard_setup_extended(request):
env = container_factory.get_extended_setup(num_clients=1)
Expand Down Expand Up @@ -376,6 +426,42 @@ def enterprise_one_docker_client_bootstrapped(request):
return env


@pytest.fixture(scope="function")
def enterprise_one_docker_client(request):
env = container_factory.get_enterprise_docker_client_setup(num_clients=0)
request.addfinalizer(env.teardown)

env.setup()
reset_mender_api(env)

tenant = create_tenant(env)
new_tenant_client(env, "mender-client", tenant["tenant_token"], docker=True)
env.device_group.ssh_is_opened()

return env


@pytest.fixture(scope="function")
def enterprise_two_docker_clients_bootstrapped(request):
env = container_factory.get_enterprise_docker_client_setup(num_clients=0)
request.addfinalizer(env.teardown)

env.setup()
reset_mender_api(env)

tenant = create_tenant(env)
new_tenant_client(env, "mender-client-1", tenant["tenant_token"], docker=True)
new_tenant_client(env, "mender-client-2", tenant["tenant_token"], docker=True)
env.device_group.ssh_is_opened()

devauth_tenant = DeviceAuthV2(env.auth)
devauth_tenant.accept_devices(2)
devices = devauth_tenant.get_devices_status("accepted", expected_devices=2)
assert 2 == len(devices)

return env


@pytest.fixture(scope="function")
def enterprise_one_rofs_client_bootstrapped(request):
env = container_factory.get_enterprise_rofs_client_setup(num_clients=0)
Expand Down
27 changes: 27 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,33 @@ def ip_to_device_id_map(device_group, devauth=devauth):

@staticmethod
def _check_log_for_message(device, message, since=None):
# Docker client has no systemd — check auth state via D-Bus instead.
has_systemd = (
device.run("which systemctl 2>/dev/null", warn=True, hide=True) != ""
)
if not has_systemd:
if "Successfully received new authorization data" in message:
sleepsec = 0
timeout = 600
while sleepsec < timeout:
out = device.run(
"dbus-send --system --print-reply "
"--dest=io.mender.AuthenticationManager "
"/io/mender/AuthenticationManager "
"io.mender.Authentication1.GetJwtToken 2>/dev/null",
warn=True,
hide=True,
)
if out and "string" in out:
return
time.sleep(10)
sleepsec += 10
logger.info(
f"waiting for device to authenticate via D-Bus, waited {sleepsec}s"
)
assert False, "timeout waiting for device to authenticate via D-Bus"
return

if since:
cmd = f"journalctl --unit mender-authd --full --since '{since}'"
else:
Expand Down
10 changes: 6 additions & 4 deletions tests/tests/test_bootstrapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
from ..common_setup import (
standard_setup_one_client,
standard_setup_one_client_bootstrapped,
standard_setup_one_docker_client,
enterprise_one_client,
enterprise_one_client_bootstrapped,
enterprise_one_docker_client,
)
from .common_update import common_update_procedure
from ..MenderAPI import DeviceAuthV2, Deployments, logger
Expand Down Expand Up @@ -102,8 +104,8 @@ def do_test_reject_bootstrap(self, env, valid_image):

class TestBootstrappingOpenSource(BaseTestBootstrapping):
@MenderTesting.fast
def test_bootstrap(self, standard_setup_one_client):
self.do_test_bootstrap(standard_setup_one_client)
def test_bootstrap(self, standard_setup_one_docker_client):
self.do_test_bootstrap(standard_setup_one_docker_client)

@MenderTesting.slow
def test_reject_bootstrap(
Expand All @@ -116,8 +118,8 @@ def test_reject_bootstrap(

class TestBootstrappingEnterprise(BaseTestBootstrapping):
@MenderTesting.fast
def test_bootstrap(self, enterprise_one_client):
self.do_test_bootstrap(enterprise_one_client)
def test_bootstrap(self, enterprise_one_docker_client):
self.do_test_bootstrap(enterprise_one_docker_client)

@MenderTesting.slow
def test_reject_bootstrap(self, enterprise_one_client_bootstrapped, valid_image):
Expand Down
10 changes: 6 additions & 4 deletions tests/tests/test_grouping.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

from ..common_setup import (
standard_setup_two_clients_bootstrapped,
standard_setup_two_docker_clients_bootstrapped,
enterprise_two_clients_bootstrapped,
enterprise_two_docker_clients_bootstrapped,
)
from .common_update import common_update_procedure
from ..MenderAPI import DeviceAuthV2, Deployments, Inventory, image, logger
Expand Down Expand Up @@ -171,8 +173,8 @@ def do_test_update_device_group(self, env, valid_image_with_mender_conf):

@MenderTesting.fast
class TestGroupingOpenSource(BaseTestGrouping):
def test_basic_groups(self, standard_setup_two_clients_bootstrapped):
self.do_test_basic_groups(standard_setup_two_clients_bootstrapped)
def test_basic_groups(self, standard_setup_two_docker_clients_bootstrapped):
self.do_test_basic_groups(standard_setup_two_docker_clients_bootstrapped)

def test_update_device_group(
self, standard_setup_two_clients_bootstrapped, valid_image_with_mender_conf
Expand All @@ -185,8 +187,8 @@ def test_update_device_group(

@MenderTesting.fast
class TestGroupingEnterprise(BaseTestGrouping):
def test_basic_groups(self, enterprise_two_clients_bootstrapped):
self.do_test_basic_groups(enterprise_two_clients_bootstrapped)
def test_basic_groups(self, enterprise_two_docker_clients_bootstrapped):
self.do_test_basic_groups(enterprise_two_docker_clients_bootstrapped)

def test_update_device_group(
self, enterprise_two_clients_bootstrapped, valid_image_with_mender_conf
Expand Down
41 changes: 24 additions & 17 deletions tests/tests/test_preauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization

from ..common_setup import standard_setup_one_client, enterprise_no_client
from ..common_setup import standard_setup_one_docker_client, enterprise_no_client
from .mendertesting import MenderTesting
from ..MenderAPI import auth, devauth, inv, logger
from ..helpers import Helpers
Expand Down Expand Up @@ -154,13 +154,13 @@ def do_test_fail_preauth_existing(self):


class TestPreauth(TestPreauthBase):
def test_ok_preauth_and_bootstrap(self, standard_setup_one_client):
self.do_test_ok_preauth_and_bootstrap(standard_setup_one_client)
def test_ok_preauth_and_bootstrap(self, standard_setup_one_docker_client):
self.do_test_ok_preauth_and_bootstrap(standard_setup_one_docker_client)

def test_ok_preauth_and_remove(self, standard_setup_one_client):
def test_ok_preauth_and_remove(self, standard_setup_one_docker_client):
self.do_test_ok_preauth_and_remove()

def test_fail_preauth_existing(self, standard_setup_one_client):
def test_fail_preauth_existing(self, standard_setup_one_docker_client):
self.do_test_fail_preauth_existing()


Expand Down Expand Up @@ -196,7 +196,11 @@ class Client:
"""Wraps various actions on the client, performed via SSH (inside fabric.execute())."""

ID_HELPER = "/usr/share/mender/identity/mender-device-identity"
PRIV_KEY = "/data/mender/mender-agent.pem"
# QEMU (Yocto) stores the key under /data/mender; Docker client uses /var/lib/mender.
_PRIV_KEY_CANDIDATES = [
"/data/mender/mender-agent.pem",
"/var/lib/mender/mender-agent.pem",
]

KEYGEN_TIMEOUT = 300

Expand All @@ -209,8 +213,8 @@ def get_logs(device):
def get_pub_key(device):
"""Extract the device's public key from its private key."""

Client.__wait_for_keygen(device)
keystr = device.run("cat {}".format(Client.PRIV_KEY))
priv_key_path = Client.__wait_for_keygen(device)
keystr = device.run("cat {}".format(priv_key_path))
private_key = serialization.load_pem_private_key(
data=keystr.encode() if isinstance(keystr, str) else keystr,
password=None,
Expand All @@ -234,16 +238,19 @@ def substitute_id_data(device, id_data_dict):

@staticmethod
def __wait_for_keygen(device):
"""Wait for the mender private key to appear and return its path."""
sleepsec = 0
while sleepsec < Client.KEYGEN_TIMEOUT:
try:
device.run("stat {}".format(Client.PRIV_KEY))
except:
time.sleep(10)
sleepsec += 10
logger.info("waiting for key gen, sleepsec: {}".format(sleepsec))
else:
time.sleep(5)
break
for path in Client._PRIV_KEY_CANDIDATES:
try:
device.run(f"stat {path}")
time.sleep(5)
return path
except Exception:
pass
time.sleep(10)
sleepsec += 10
logger.info("waiting for key gen, sleepsec: {}".format(sleepsec))

assert sleepsec <= Client.KEYGEN_TIMEOUT, "timeout for key generation exceeded"
return Client._PRIV_KEY_CANDIDATES[0]
22 changes: 17 additions & 5 deletions testutils/infra/container_manager/docker_compose_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,15 @@ def setup(self):
self._docker_compose_up(f"--scale mender-client={self.num_clients}")


class DockerComposeQemuClientSetup(DockerComposeNamespace):
def __init__(self, name, num_clients=1):
self.num_clients = num_clients
super().__init__(name, self.QEMU_CLIENT_FILES)

def setup(self):
self._docker_compose_up(f"--scale mender-client={self.num_clients}")


class DockerComposeExtendedSetup(DockerComposeNamespace):
def __init__(self, name, num_clients=1):
self.num_clients = num_clients
Expand Down Expand Up @@ -184,12 +193,13 @@ def new_tenant_docker_client(self, name, tenant):


class DockerComposeDockerClientSetup(DockerComposeNamespace):
def __init__(
self,
name,
):
def __init__(self, name, num_clients=1):
self.num_clients = num_clients
DockerComposeNamespace.__init__(self, name, self.DOCKER_CLIENT_FILES)

def setup(self):
self._docker_compose_up(f"--scale mender-client={self.num_clients}")


class DockerComposeRofsClientSetup(DockerComposeNamespace):
def __init__(
Expand Down Expand Up @@ -393,6 +403,7 @@ def __init__(self, name, num_clients=0):
class DockerComposeEnterpriseDockerClientSetup(DockerComposeEnterpriseSetup):
def __init__(self, name, num_clients=0):
self.num_clients = num_clients
self._docker_client_count = 0
if self.num_clients > 0:
raise NotImplementedError(
"Clients not implemented on setup time, use new_tenant_client"
Expand All @@ -406,9 +417,10 @@ def setup(self):
self._docker_compose_up("--scale mender-client=0")

def new_tenant_docker_client(self, name, tenant):
self._docker_client_count += 1
logger.info("creating docker client connected to tenant: " + tenant)
self._docker_compose_up(
"--scale mender-client=1",
f"--scale mender-client={self._docker_client_count}",
{"TENANT_TOKEN": "%s" % tenant},
)

Expand Down
Loading