diff --git a/tests/regression/lp-1802581/mock-gpio.py b/tests/lib/fakegpio/fake-gpio.py similarity index 89% rename from tests/regression/lp-1802581/mock-gpio.py rename to tests/lib/fakegpio/fake-gpio.py index 89ab4448dfd..13e52819009 100755 --- a/tests/regression/lp-1802581/mock-gpio.py +++ b/tests/lib/fakegpio/fake-gpio.py @@ -6,6 +6,7 @@ import os import selectors import shutil +import socket import subprocess import sys import tempfile @@ -59,6 +60,15 @@ def dispatch(sel): return True +def maybe_sd_notify(s: str) -> None: + addr = os.getenv('NOTIFY_SOCKET') + if not addr: + return + soc = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) + soc.connect(addr) + soc.sendall(s.encode()) + + def main(): """the main method""" if os.getuid() != 0: @@ -83,6 +93,8 @@ def main(): ufd = os.open("unexport", os.O_RDWR | os.O_NONBLOCK) sel.register(efd, selectors.EVENT_READ, export_ready) sel.register(ufd, selectors.EVENT_READ, unexport_ready) + # notify + maybe_sd_notify("READY=1") while True: if not dispatch(sel): break diff --git a/tests/lib/systemd.sh b/tests/lib/systemd.sh index 6cef8e82226..52a9d3e7606 100644 --- a/tests/lib/systemd.sh +++ b/tests/lib/systemd.sh @@ -10,6 +10,31 @@ systemd_create_and_start_unit() { systemctl start "$1" } +# Create and start a persistent systemd unit that survives reboots. Use as: +# systemd_create_and_start_persistent_unit "name" "my-service --args" +# The third arg supports "overrides" which allow to customize the service +# as needed, e.g.: +# systemd_create_and_start_persistent_unit "name" "start" "[Unit]\nAfter=foo" +systemd_create_and_start_persistent_unit() { + printf '[Unit]\nDescription=For testing purposes\n[Service]\nType=simple\nExecStart=%s\n[Install]\nWantedBy=multi-user.target\n' "$2" > "/etc/systemd/system/$1.service" + if [ -n "${3:-}" ]; then + mkdir -p "/etc/systemd/system/$1.service.d" + # shellcheck disable=SC2059 + printf "$3" >> "/etc/systemd/system/$1.service.d/override.conf" + fi + systemctl daemon-reload + systemctl enable "$1" + systemctl start "$1" + wait_for_service "$1" +} + +system_stop_and_remove_persistent_unit() { + systemctl stop "$1" || true + systemctl disable "$1" || true + rm -f "/etc/systemd/system/$1.service" + rm -rf "/etc/systemd/system/$1.service.d" +} + # Use like systemd_stop_and_destroy_unit(fakestore) systemd_stop_and_destroy_unit() { if systemctl is-active "$1"; then diff --git a/tests/main/enable-disable-units-gpio/task.yaml b/tests/main/enable-disable-units-gpio/task.yaml index e19bd873c22..e308a6493e8 100644 --- a/tests/main/enable-disable-units-gpio/task.yaml +++ b/tests/main/enable-disable-units-gpio/task.yaml @@ -12,80 +12,41 @@ details: | systems: [ubuntu-core-16-64] -environment: - GPIO_MOCK_DIR: /home/test/gpio-mock - prepare: | - if [ "$TRUST_TEST_KEYS" = "false" ]; then - echo "This test needs test keys to be trusted" - exit - fi + # shellcheck source=tests/lib/systemd.sh + . "$TESTSLIB/systemd.sh" + echo "Create/enable fake gpio" + systemd_create_and_start_persistent_unit fake-gpio "$TESTSLIB/fakegpio/fake-gpio.py" "[Unit]\\nBefore=snap.core.interface.gpio-100.service\\n[Service]\\nType=notify" + echo "Given a snap declaring a plug on gpio is installed" #shellcheck source=tests/lib/snaps.sh . "$TESTSLIB"/snaps.sh install_local gpio-consumer - echo "And a mocked gpio device is in place" - cat > /home/test/gpio-mock.sh <<-EOF - #!/bin/sh - if [ ! -d "$GPIO_MOCK_DIR" ]; then - # the service has just been created - mkdir -p "$GPIO_MOCK_DIR" - touch "$GPIO_MOCK_DIR/gpio100" "$GPIO_MOCK_DIR/export" "$GPIO_MOCK_DIR/unexport" - else - # after reboot, remove device node to test export - rm "$GPIO_MOCK_DIR/gpio100" - truncate -s 0 "$GPIO_MOCK_DIR/export" - fi - mount --bind "$GPIO_MOCK_DIR" /sys/class/gpio - EOF - chmod a+x /home/test/gpio-mock.sh - - cat > /etc/systemd/system/gpio-mock.service <<-EOF - [Unit] - Description=Set up mock for gpio test - Before=snap.core.interface.gpio-100.service - - [Service] - Type=oneshot - RemainAfterExit=true - ExecStart=/home/test/gpio-mock.sh - ExecStop= - - [Install] - WantedBy=multi-user.target - EOF - systemctl enable --now gpio-mock.service - echo "And the gpio plug is connected" snap connect gpio-consumer:gpio :gpio-pin restore: | - if [ "$TRUST_TEST_KEYS" = "false" ]; then - echo "This test needs test keys to be trusted" - exit - fi + # shellcheck source=tests/lib/systemd.sh + . "$TESTSLIB/systemd.sh" + system_stop_and_remove_persistent_unit fake-gpio umount /sys/class/gpio || true - systemctl disable gpio-mock.service - rm -rf "$GPIO_MOCK_DIR" /etc/systemd/system/gpio-mock.service /home/test/gpio-mock.sh execute: | # shellcheck source=tests/lib/journalctl.sh . "$TESTSLIB/journalctl.sh" - if [ "$TRUST_TEST_KEYS" = "false" ]; then - echo "This test needs test keys to be trusted" - exit - fi - echo "Then the snap service units concerning the gpio device must be run before and after a reboot" expected="Unit snap.core.interface.gpio-100.service has finished starting up" - get_journalctl_log -xe --no-pager | MATCH "$expected" - - if [ "$SPREAD_REBOOT" = "1" ]; then - MATCH "^100$" < "$GPIO_MOCK_DIR/export" - fi + for i in $(seq 120); do + get_journalctl_log -xe --no-pager | MATCH "$expected" + sleep 0.5 + done if [ "$SPREAD_REBOOT" = "0" ]; then REBOOT fi + + if [ "$SPREAD_REBOOT" = "1" ]; then + test -e /sys/class/gpio/gpio100 + fi diff --git a/tests/regression/lp-1802581/task.yaml b/tests/regression/lp-1802581/task.yaml index 80a0b8516b0..4d37d906f7b 100644 --- a/tests/regression/lp-1802581/task.yaml +++ b/tests/regression/lp-1802581/task.yaml @@ -20,19 +20,20 @@ description: | systems: [ubuntu-core-16-64] prepare: | - echo "Run mock gpio daemon" - systemd-run --unit mock-gpio -- "$(pwd)/mock-gpio.py" # shellcheck source=tests/lib/systemd.sh . "$TESTSLIB/systemd.sh" - wait_for_service mock-gpio + echo "Create/enable fake gpio" + systemd_create_and_start_persistent_unit fake-gpio "$TESTSLIB/fakegpio/fake-gpio.py" "[Unit]\nBefore=snap.core.interface.gpio-100.service\n[Service]\nType=notify" restore: | - systemctl stop mock-gpio || true - # for good measure, mock-gpio.py does this umount already on exit + # shellcheck source=tests/lib/systemd.sh + . "$TESTSLIB/systemd.sh" + system_stop_and_remove_persistent_unit fake-gpio + # for good measure, fake-gpio.py does this umount already on exit umount /sys/class/gpio || true debug: | - journalctl -u mock-gpio.service + journalctl -u fake-gpio.service execute: | echo "Install a snap that uses the gpio consumer" @@ -53,4 +54,4 @@ execute: | snap interfaces | MATCH ":gpio-pin.*gpio-consumer:gpio" echo "Ensure that our mock service is full functional" - systemctl status mock-gpio.service | MATCH "Active: active" + systemctl status fake-gpio.service | MATCH "Active: active"