blob: 02a6ae39c0d06526f6a99ea1ceb1bc03fd210155 [file] [log] [blame]
Tomáš Peckaccd80c32020-06-22 14:44:32 +02001/*
2 * Copyright (C) 2020 CESNET, https://photonics.cesnet.cz/
3 *
4 * Written by Tomáš Pecka <tomas.pecka@fit.cvut.cz>
5 *
6*/
7
8#include "trompeloeil_doctest.h"
9#include "dbus-helpers/dbus_systemd_server.h"
10#include "fake.h"
11#include "inputs/DbusSystemdInput.h"
12#include "test_log_setup.h"
13#include "utils/log-init.h"
14#include "utils/log.h"
15
16TEST_CASE("Systemd monitor")
17{
18 TEST_INIT_LOGS;
19 trompeloeil::sequence seq1;
20
21 // Create and setuo separate connections for both client and server. Could be done using a single connection but this way it is more generic
22 auto clientConnection = sdbus::createSessionBusConnection();
23 auto serverConnection = sdbus::createSessionBusConnection("cz.cesnet.systemd1");
24 clientConnection->enterEventLoopAsync();
25 serverConnection->enterEventLoopAsync();
26
27 auto mx = std::make_shared<FakeManager>();
28 auto server = DbusSystemdServer(*serverConnection);
29
30 // i1 gets constructed which means:
31 // - a registration is performed, along with an updateState call (State::OK)
32 // - i1's constructor queries the current state and performs updateState
33 REQUIRE_CALL(*mx, registerInput(ANY(void*), velia::State::OK)).LR_SIDE_EFFECT(mx->updateState(_1, _2)).IN_SEQUENCE(seq1);
34 REQUIRE_CALL(*mx, updateState(ANY(void*), velia::State::OK)).IN_SEQUENCE(seq1);
35
36 // create units. Unit2 and Unit3 are in states that we consider failed
37 // therefore the DbusSystemdInput will report ERROR after loading the second unit
38 // FailedUnits: {unit2, unit3} -> ERROR
Tomáš Peckaf2391d62020-11-06 14:02:00 +010039 server.createUnit(*serverConnection, "unit1.service", "/cz/cesnet/systemd1/unit/unit1", "active", "running");
40 server.createUnit(*serverConnection, "unit2.service", "/cz/cesnet/systemd1/unit/unit2", "activating", "auto-restart");
41 server.createUnit(*serverConnection, "unit3.service", "/cz/cesnet/systemd1/unit/unit3", "failed", "failed");
42 server.createUnit(*serverConnection, "unitIgnored.service", "/cz/cesnet/systemd1/unit/unitIgnored", "failed", "failed");
Tomáš Peckaccd80c32020-06-22 14:44:32 +020043
44 REQUIRE_CALL(*mx, updateState(ANY(void*), velia::State::OK)).IN_SEQUENCE(seq1);
45 REQUIRE_CALL(*mx, updateState(ANY(void*), velia::State::ERROR)).IN_SEQUENCE(seq1);
46 REQUIRE_CALL(*mx, updateState(ANY(void*), velia::State::ERROR)).IN_SEQUENCE(seq1);
Tomáš Peckaf2391d62020-11-06 14:02:00 +010047 auto i1 = std::make_shared<velia::DbusSystemdInput>(mx, std::set<std::string> {"unitIgnored.service"}, *clientConnection, "cz.cesnet.systemd1", "/cz/cesnet/systemd1", "cz.cesnet.systemd1.Manager", "cz.cesnet.systemd1.Unit");
Tomáš Peckaccd80c32020-06-22 14:44:32 +020048 // i1 now listens for dbus events, we can start the semaphore server
49
50 // FailedUnits: {unit3} -> ERROR
51 REQUIRE_CALL(*mx, updateState(i1.get(), velia::State::ERROR)).IN_SEQUENCE(seq1);
52 server.changeUnitState("/cz/cesnet/systemd1/unit/unit2", "active", "running");
53
54 // FailedUnits: {} -> OK
55 REQUIRE_CALL(*mx, updateState(i1.get(), velia::State::OK)).IN_SEQUENCE(seq1);
56 server.changeUnitState("/cz/cesnet/systemd1/unit/unit3", "active", "running");
57
58 // add new unit with failed/failed, DbusSystemdInput should receive UnitNew signal and monitor this unit too
59 // FailedUnits: {unit4} -> OK
60 REQUIRE_CALL(*mx, updateState(i1.get(), velia::State::ERROR)).IN_SEQUENCE(seq1);
Tomáš Peckaf2391d62020-11-06 14:02:00 +010061 server.createUnit(*serverConnection, "unit4.service", "/cz/cesnet/systemd1/unit/unit4", "failed", "failed");
62
63 // unitIgnored is ignored by us, so it can change in any way but since we don't obtain the notifications, nothing will happen
64 server.changeUnitState("/cz/cesnet/systemd1/unit/unitIgnored", "failed", "failed");
65 server.changeUnitState("/cz/cesnet/systemd1/unit/unitIgnored", "active", "auto-restarting");
66 server.changeUnitState("/cz/cesnet/systemd1/unit/unitIgnored", "active", "running");
Tomáš Peckaccd80c32020-06-22 14:44:32 +020067
68 waitForCompletionAndBitMore(seq1);
69
70 // FailedUnits: {} -> OK
71 REQUIRE_CALL(*mx, updateState(i1.get(), velia::State::OK)).IN_SEQUENCE(seq1);
72 server.changeUnitState("/cz/cesnet/systemd1/unit/unit4", "active", "running");
73
74 waitForCompletionAndBitMore(seq1);
75
76 REQUIRE_CALL(*mx, unregisterInput(i1.get())).IN_SEQUENCE(seq1);
77 i1.reset();
78}
79
80#if 0
81// Runs a StateManager with DbusSystemdInput connected to the development machine's systemd. Might be useful for debugging.
82TEST_CASE("This machine's systemd monitor")
83{
84 TEST_INIT_LOGS;
85
86 auto clientConnection = sdbus::createSystemBusConnection();
87
88 auto mx = std::make_shared<velia::StateManager>();
89 auto i1 = std::make_shared<velia::DbusSystemdInput>(mx, *clientConnection);
90
91 clientConnection->enterEventLoop();
92}
93#endif