blob: 001d44940d5f3fc7d1afdcaa617f562027585eea [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
39 server.createUnit(*serverConnection, "/cz/cesnet/systemd1/unit/unit1", "active", "running");
40 server.createUnit(*serverConnection, "/cz/cesnet/systemd1/unit/unit2", "activating", "auto-restart");
41 server.createUnit(*serverConnection, "/cz/cesnet/systemd1/unit/unit3", "failed", "failed");
42
43 REQUIRE_CALL(*mx, updateState(ANY(void*), velia::State::OK)).IN_SEQUENCE(seq1);
44 REQUIRE_CALL(*mx, updateState(ANY(void*), velia::State::ERROR)).IN_SEQUENCE(seq1);
45 REQUIRE_CALL(*mx, updateState(ANY(void*), velia::State::ERROR)).IN_SEQUENCE(seq1);
46 auto i1 = std::make_shared<velia::DbusSystemdInput>(mx, *clientConnection, "cz.cesnet.systemd1", "/cz/cesnet/systemd1", "cz.cesnet.systemd1.Manager", "cz.cesnet.systemd1.Unit");
47 // i1 now listens for dbus events, we can start the semaphore server
48
49 // FailedUnits: {unit3} -> ERROR
50 REQUIRE_CALL(*mx, updateState(i1.get(), velia::State::ERROR)).IN_SEQUENCE(seq1);
51 server.changeUnitState("/cz/cesnet/systemd1/unit/unit2", "active", "running");
52
53 // FailedUnits: {} -> OK
54 REQUIRE_CALL(*mx, updateState(i1.get(), velia::State::OK)).IN_SEQUENCE(seq1);
55 server.changeUnitState("/cz/cesnet/systemd1/unit/unit3", "active", "running");
56
57 // add new unit with failed/failed, DbusSystemdInput should receive UnitNew signal and monitor this unit too
58 // FailedUnits: {unit4} -> OK
59 REQUIRE_CALL(*mx, updateState(i1.get(), velia::State::ERROR)).IN_SEQUENCE(seq1);
60 server.createUnit(*serverConnection, "/cz/cesnet/systemd1/unit/unit4", "failed", "failed");
61
62 waitForCompletionAndBitMore(seq1);
63
64 // FailedUnits: {} -> OK
65 REQUIRE_CALL(*mx, updateState(i1.get(), velia::State::OK)).IN_SEQUENCE(seq1);
66 server.changeUnitState("/cz/cesnet/systemd1/unit/unit4", "active", "running");
67
68 waitForCompletionAndBitMore(seq1);
69
70 REQUIRE_CALL(*mx, unregisterInput(i1.get())).IN_SEQUENCE(seq1);
71 i1.reset();
72}
73
74#if 0
75// Runs a StateManager with DbusSystemdInput connected to the development machine's systemd. Might be useful for debugging.
76TEST_CASE("This machine's systemd monitor")
77{
78 TEST_INIT_LOGS;
79
80 auto clientConnection = sdbus::createSystemBusConnection();
81
82 auto mx = std::make_shared<velia::StateManager>();
83 auto i1 = std::make_shared<velia::DbusSystemdInput>(mx, *clientConnection);
84
85 clientConnection->enterEventLoop();
86}
87#endif