aboutsummaryrefslogtreecommitdiff
path: root/scripts/testing/tests/test_services.py
blob: 0ca3970c715a18f932e3d22e933cbd98631f3a6e (plain)
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
# SPDX-License-Identifier: GPL-3.0-or-later
"""Post-install checks: services, timers, and their functional health.

Parity port of validate_firewall, validate_dns_config, validate_avahi,
validate_fail2ban, validate_networkmanager, and validate_all_services /
validate_service_functions.

Mapping of the shell sweep's three outcomes:
  - validation_fail (hard)  -> assert
  - validation_warn (soft)  -> pytest.skip with the reason (visible, never red)
  - validation_skip (precond)-> pytest.skip gated on a fixture
"""

import pytest


# Required services: (name, must_be_active). ufw can't activate in the VM (no
# iptables kernel modules), so it's enabled-only; cronie/atd are enabled-only too.
REQUIRED_ENABLED_ACTIVE = ["sshd", "systemd-resolved", "fail2ban", "NetworkManager", "rngd"]
REQUIRED_ENABLED_ONLY = ["ufw", "cronie", "atd"]
REQUIRED_TIMERS = ["reflector.timer", "paccache.timer"]
OPTIONAL_SERVICES = ["avahi-daemon", "bluetooth", "cups", "docker", "tailscaled"]


@pytest.mark.attribution("archsetup")
@pytest.mark.parametrize("svc", REQUIRED_ENABLED_ACTIVE)
def test_required_service_enabled_and_active(host, svc):
    s = host.service(svc)
    assert s.is_enabled, "%s should be enabled" % svc
    assert s.is_running, "%s should be active" % svc


@pytest.mark.smoke
@pytest.mark.attribution("archsetup")
@pytest.mark.parametrize("svc", REQUIRED_ENABLED_ONLY)
def test_required_service_enabled(host, svc):
    assert host.service(svc).is_enabled, "%s should be enabled" % svc


@pytest.mark.attribution("archsetup")
@pytest.mark.parametrize("timer", REQUIRED_TIMERS)
def test_required_timer_enabled(host, timer):
    assert host.service(timer).is_enabled, "%s should be enabled" % timer


@pytest.mark.parametrize("svc", OPTIONAL_SERVICES)
def test_optional_service(host, svc):
    # Optional: warn-if-missing in the shell sweep -> skip here so it never reds.
    if not host.service(svc).is_enabled:
        pytest.skip("%s not enabled (optional)" % svc)


@pytest.mark.attribution("archsetup")
def test_dns_over_tls_dropin_present(host):
    # archsetup ships /etc/systemd/resolved.conf.d/dns-over-tls.conf.
    assert host.file("/etc/systemd/resolved.conf.d/dns-over-tls.conf").exists


@pytest.mark.attribution("archsetup")
def test_fail2ban_responds(host):
    assert host.run("fail2ban-client status").rc == 0


@pytest.mark.attribution("archsetup")
def test_networkmanager_responds(host):
    assert host.run("nmcli general status").rc == 0


@pytest.mark.attribution("archsetup")
def test_log_cleanup_cron_installed(host, target_user):
    out = host.run("sudo -u %s crontab -l" % target_user).stdout
    assert "log-cleanup" in out, "log-cleanup entry missing from user crontab"


@pytest.mark.attribution("archsetup")
def test_syncthing_user_lingering_enabled(host, target_user):
    # syncthing runs as a user service; lingering must be on for autostart.
    assert host.file("/var/lib/systemd/linger/%s" % target_user).exists


def test_dns_resolution(host):
    # Network-dependent; advisory in the shell sweep. Skip on failure.
    if host.run("resolvectl query archlinux.org").rc != 0:
        pytest.skip("DNS resolution query failed (network-dependent)")


def test_mdns_resolves(host, on_slirp):
    # mDNS needs multicast, which QEMU slirp doesn't pass.
    if on_slirp:
        pytest.skip("mDNS not possible on slirp networking (no multicast)")
    if not host.service("avahi-daemon").is_enabled:
        pytest.skip("avahi-daemon not enabled")
    hostname = host.run("hostname").stdout.strip()
    assert host.run("ping -c 1 -W 2 %s.local" % hostname).rc == 0


def test_docker_functional(host):
    if not host.service("docker").is_enabled:
        pytest.skip("docker not enabled")
    if not host.service("docker").is_running:
        # archsetup enables docker for next boot, not --now; pre-reboot this is correct.
        pytest.skip("docker enabled but not started (starts on boot by design)")
    assert host.run("docker info").rc == 0