blob: a16eee345b543a96465763fc8c683ef3cac337c4 [file] [log] [blame]
Václav Kubernát7efd6d52021-11-09 01:31:11 +01001#include <sysrepo-cpp/utils/exception.hpp>
Tomáš Peckacb7a5f82021-01-20 15:12:00 +01002#include "trompeloeil_doctest.h"
3#include "dbus-helpers/dbus_rauc_server.h"
4#include "pretty_printers.h"
Tomáš Pecka594a6762021-01-29 11:06:08 +01005#include "system/Firmware.h"
Tomáš Peckacb7a5f82021-01-20 15:12:00 +01006#include "test_log_setup.h"
Tomáš Peckacb7a5f82021-01-20 15:12:00 +01007#include "tests/configure.cmake.h"
Tomáš Peckac164ca62024-01-24 13:38:03 +01008#include "tests/sysrepo-helpers/common.h"
Tomáš Pecka9f7b13e2024-01-24 13:47:04 +01009#include "tests/sysrepo-helpers/notifications.h"
Tomáš Peckacb7a5f82021-01-20 15:12:00 +010010
11using namespace std::literals;
12
Jan Kundrát7aa894e2022-03-30 19:32:40 +020013std::vector<std::unique_ptr<trompeloeil::expectation>> expectationFactory(const DBusRAUCServer::InstallBehaviour& installType, NotificationWatcher& eventMock, trompeloeil::sequence& seq1)
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +010014{
15 std::vector<std::unique_ptr<trompeloeil::expectation>> expectations;
16
Jan Kundrát7aa894e2022-03-30 19:32:40 +020017 auto progressData = [](int progress, std::string message) {
Tomáš Peckabaafdd92024-01-24 13:53:34 +010018 return Values{
Jan Kundrát7aa894e2022-03-30 19:32:40 +020019 {"progress", std::to_string(progress)},
20 {"message", message},
21 };
22 };
23
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +010024 if (installType == DBusRAUCServer::InstallBehaviour::OK) {
Jan Kundrát7aa894e2022-03-30 19:32:40 +020025 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(0, "Installing"))).IN_SEQUENCE(seq1));
26 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(0, "Determining slot states"))).IN_SEQUENCE(seq1));
27 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(20, "Determining slot states done."))).IN_SEQUENCE(seq1));
28 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(20, "Checking bundle"))).IN_SEQUENCE(seq1));
29 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(20, "Veryfing signature"))).IN_SEQUENCE(seq1));
30 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(40, "Veryfing signature done."))).IN_SEQUENCE(seq1));
31 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(40, "Checking bundle done."))).IN_SEQUENCE(seq1));
32 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(40, "Loading manifest file"))).IN_SEQUENCE(seq1));
33 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(60, "Loading manifest file done."))).IN_SEQUENCE(seq1));
34 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(60, "Determining target install group"))).IN_SEQUENCE(seq1));
35 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(80, "Determining target install group done."))).IN_SEQUENCE(seq1));
36 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(80, "Updating slots"))).IN_SEQUENCE(seq1));
37 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(80, "Checking slot rootfs.0"))).IN_SEQUENCE(seq1));
38 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(85, "Checking slot rootfs.0 done."))).IN_SEQUENCE(seq1));
39 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(85, "Copying image to rootfs.0"))).IN_SEQUENCE(seq1));
40 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(90, "Copying image to rootfs.0 done."))).IN_SEQUENCE(seq1));
41 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(90, "Checking slot cfg.0"))).IN_SEQUENCE(seq1));
42 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(95, "Checking slot cfg.0 done."))).IN_SEQUENCE(seq1));
43 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(95, "Copying image to cfg.0"))).IN_SEQUENCE(seq1));
44 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(100, "Copying image to cfg.0 done."))).IN_SEQUENCE(seq1));
45 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(100, "Updating slots done."))).IN_SEQUENCE(seq1));
46 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(100, "Installing done."))).IN_SEQUENCE(seq1));
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +010047 } else {
Jan Kundrát7aa894e2022-03-30 19:32:40 +020048 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(0, "Installing"))).IN_SEQUENCE(seq1));
49 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(0, "Determining slot states"))).IN_SEQUENCE(seq1));
50 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(20, "Determining slot states done."))).IN_SEQUENCE(seq1));
51 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(20, "Checking bundle"))).IN_SEQUENCE(seq1));
52 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(40, "Checking bundle failed."))).IN_SEQUENCE(seq1));
53 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, notified(progressData(100, "Installing failed."))).IN_SEQUENCE(seq1));
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +010054 }
55
56 return expectations;
57}
58
59
Tomáš Pecka825542f2021-02-24 14:00:10 +010060TEST_CASE("Firmware in czechlight-system, RPC")
Tomáš Peckacb7a5f82021-01-20 15:12:00 +010061{
62 trompeloeil::sequence seq1;
63
64 TEST_SYSREPO_INIT_LOGS;
65 TEST_SYSREPO_INIT;
66 TEST_SYSREPO_INIT_CLIENT;
67
68 auto dbusServerConnection = sdbus::createSessionBusConnection("de.pengutronix.rauc");
Tomáš Peckad51d4cb2021-02-03 14:15:49 +010069 auto dbusClientConnectionSignals = sdbus::createSessionBusConnection();
70 auto dbusClientConnectionMethods = sdbus::createSessionBusConnection();
71 dbusClientConnectionSignals->enterEventLoopAsync();
72 dbusClientConnectionMethods->enterEventLoopAsync();
Tomáš Peckacb7a5f82021-01-20 15:12:00 +010073 dbusServerConnection->enterEventLoopAsync();
74
75 std::map<std::string, velia::system::RAUC::SlotProperties> dbusRaucStatus = {
76 {"rootfs.1", {
77 {"activated.count", uint32_t {39}},
78 {"activated.timestamp", "2021-01-13T17:20:18Z"},
79 {"bootname", "B"},
80 {"boot-status", "good"},
81 {"bundle.compatible", "czechlight-clearfog"},
82 {"bundle.version", "v4-103-g34d2f48"},
83 {"class", "rootfs"},
84 {"device", "/dev/mmcblk0p3"},
85 {"installed.count", uint32_t {39}},
86 {"installed.timestamp", "2021-01-13T17:20:15Z"},
87 {"mountpoint", "/"},
88 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
89 {"size", uint64_t {45601892}},
90 {"state", "booted"},
91 {"status", "ok"},
92 {"type", "ext4"},
93 }},
94 {"rootfs.0", {
95 {"activated.count", uint32_t {41}},
96 {"activated.timestamp", "2021-01-13T17:15:54Z"},
97 {"bootname", "A"},
98 {"boot-status", "bad"},
99 {"bundle.compatible", "czechlight-clearfog"},
100 {"bundle.version", "v4-104-ge80fcd4"},
101 {"class", "rootfs"},
102 {"device", "/dev/mmcblk0p1"},
103 {"installed.count", uint32_t {41}},
104 {"installed.timestamp", "2021-01-13T17:15:50Z"},
105 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
106 {"size", uint64_t {45647664}},
107 {"state", "inactive"},
108 {"status", "ok"},
109 {"type", "ext4"},
110 }},
111 {"cfg.1", {
112 {"bundle.compatible", "czechlight-clearfog"},
113 {"bundle.version", "v4-103-g34d2f48"},
114 {"class", "cfg"},
115 {"device", "/dev/mmcblk0p4"},
116 {"installed.count", uint32_t {39}},
117 {"installed.timestamp", "2021-01-13T17:20:18Z"},
118 {"mountpoint", "/cfg"},
119 {"parent", "rootfs.1"},
120 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
121 {"size", uint64_t {108}},
122 {"state", "active"},
123 {"status", "ok"},
124 {"type", "ext4"},
125 }},
126 {"cfg.0", {
127 {"bundle.compatible", "czechlight-clearfog"},
128 {"bundle.version", "v4-104-ge80fcd4"},
129 {"class", "cfg"},
130 {"device", "/dev/mmcblk0p2"},
131 {"installed.count", uint32_t {41}},
132 {"installed.timestamp", "2021-01-13T17:15:54Z"},
133 {"parent", "rootfs.0"},
134 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
135 {"size", uint64_t {108}},
136 {"state", "inactive"},
137 {"status", "ok"},
138 {"type", "ext4"},
139 }},
140 };
141 auto raucServer = DBusRAUCServer(*dbusServerConnection, "rootfs.1", dbusRaucStatus);
Tomáš Peckad51d4cb2021-02-03 14:15:49 +0100142 auto sysrepo = std::make_shared<velia::system::Firmware>(srConn, *dbusClientConnectionSignals, *dbusClientConnectionMethods);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100143
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100144 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware", sysrepo::Datastore::Operational) == std::map<std::string, std::string> {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100145 {"/firmware-slot[name='A']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200146 {"/firmware-slot[name='A']/is-healthy", "false"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100147 {"/firmware-slot[name='A']/installed", "2021-01-13T17:15:50-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100148 {"/firmware-slot[name='A']/name", "A"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200149 {"/firmware-slot[name='A']/is-booted-now", "false"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100150 {"/firmware-slot[name='A']/version", "v4-104-ge80fcd4"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200151 {"/firmware-slot[name='A']/will-boot-next", "false"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100152 {"/firmware-slot[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200153 {"/firmware-slot[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100154 {"/firmware-slot[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100155 {"/firmware-slot[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200156 {"/firmware-slot[name='B']/is-booted-now", "true"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100157 {"/firmware-slot[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200158 {"/firmware-slot[name='B']/will-boot-next", "true"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100159 {"/installation", ""},
160 {"/installation/message", ""},
161 {"/installation/status", "none"},
162 });
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100163
164 SECTION("Firmware install RPC")
165 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100166 auto rpcInput = client.getContext().newPath("/czechlight-system:firmware/installation/install/url", "/path/to/bundle/update.raucb");
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100167
168 SECTION("Installation runs")
169 {
Jan Kundrát7aa894e2022-03-30 19:32:40 +0200170 NotificationWatcher installProgressMock{client, "/czechlight-system:firmware/installation/update"};
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100171 DBusRAUCServer::InstallBehaviour installType;
172 std::map<std::string, std::string> expectedFinished, expectedInProgress = {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100173 {"/message", ""},
174 {"/status", "in-progress"},
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100175 };
176
177 SECTION("Successfull install")
178 {
179 installType = DBusRAUCServer::InstallBehaviour::OK;
180 expectedFinished = {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100181 {"/message", ""},
182 {"/status", "succeeded"},
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100183 };
184 }
185
186 SECTION("Unsuccessfull install")
187 {
188 installType = DBusRAUCServer::InstallBehaviour::FAILURE;
189 expectedFinished = {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100190 {"/message", "Failed to download bundle https://10.88.3.11:8000/update.raucb: Transfer failed: error:1408F10B:SSL routines:ssl3_get_record:wrong version number"},
191 {"/status", "failed"},
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100192 };
193 }
194
195 raucServer.installBundleBehaviour(installType);
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100196 auto progressExpectations = expectationFactory(installType, installProgressMock, seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100197 auto res = client.sendRPC(rpcInput);
198 REQUIRE(res.child() == std::nullopt);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100199
200 std::this_thread::sleep_for(10ms); // lets wait a while, so the RAUC's callback for operation changed takes place
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100201 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", sysrepo::Datastore::Operational) == expectedInProgress);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100202
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100203 waitForCompletionAndBitMore(seq1); // wait for installation to complete
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100204 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", sysrepo::Datastore::Operational) == expectedFinished);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100205 }
206
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100207 SECTION("Unsuccessfull install followed by successfull install")
208 {
Jan Kundrát7aa894e2022-03-30 19:32:40 +0200209 NotificationWatcher installProgressMock{client, "/czechlight-system:firmware/installation/update"};
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100210 // invoke unsuccessfull install
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100211 {
212 raucServer.installBundleBehaviour(DBusRAUCServer::InstallBehaviour::FAILURE);
213 auto progressExpectations = expectationFactory(DBusRAUCServer::InstallBehaviour::FAILURE, installProgressMock, seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100214 client.sendRPC(rpcInput);
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100215
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100216 waitForCompletionAndBitMore(seq1); // wait for installation to complete
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100217 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", sysrepo::Datastore::Operational) == std::map<std::string, std::string> {
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100218 {"/message", "Failed to download bundle https://10.88.3.11:8000/update.raucb: Transfer failed: error:1408F10B:SSL routines:ssl3_get_record:wrong version number"},
219 {"/status", "failed"},
220 });
221 }
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100222
223 // invoke successfull install
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100224 {
225 raucServer.installBundleBehaviour(DBusRAUCServer::InstallBehaviour::OK);
226 auto progressExpectations = expectationFactory(DBusRAUCServer::InstallBehaviour::OK, installProgressMock, seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100227 client.sendRPC(rpcInput);
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100228
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100229 std::this_thread::sleep_for(10ms); // lets wait a while, so the RAUC's callback for operation changed takes place
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100230 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", sysrepo::Datastore::Operational) == std::map<std::string, std::string> {
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100231 {"/message", ""},
232 {"/status", "in-progress"},
233 });
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100234
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100235 waitForCompletionAndBitMore(seq1); // wait for installation to complete
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100236 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", sysrepo::Datastore::Operational) == std::map<std::string, std::string>{
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100237 {"/message", ""},
238 {"/status", "succeeded"},
239 });
240 }
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100241 }
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100242
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100243 SECTION("Installation in progress")
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100244 {
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100245 raucServer.installBundleBehaviour(DBusRAUCServer::InstallBehaviour::OK);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100246 client.sendRPC(rpcInput);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100247 std::this_thread::sleep_for(10ms);
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100248
249 SECTION("Invoking second installation throws")
250 {
Jan Kundrát315838e2023-06-05 19:45:50 +0200251 REQUIRE_THROWS_WITH_AS(client.sendRPC(rpcInput),
252 "Couldn't send RPC: SR_ERR_CALLBACK_FAILED\n"
Jan Kundrát4a10d0a2024-04-10 03:33:43 +0200253 // FIXME: why is this present twice? Looks like a libyang-v2.2/sysrepo change that I do not understand
254 " Already processing a different method (SR_ERR_OPERATION_FAILED)\n"
Jan Kundrát315838e2023-06-05 19:45:50 +0200255 " Already processing a different method (SR_ERR_OPERATION_FAILED)\n"
256 " User callback failed. (SR_ERR_CALLBACK_FAILED)\n"
257 " NETCONF: application: operation-failed: Already processing a different method",
258 sysrepo::ErrorWithCode);
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100259 }
260
261 SECTION("Firmware slot data are available")
262 {
263 // RAUC does not respond to GetSlotStatus when another operation in progress, so let's check we use the cached data
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100264 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware", sysrepo::Datastore::Operational) == std::map<std::string, std::string> {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100265 {"/firmware-slot[name='A']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200266 {"/firmware-slot[name='A']/is-healthy", "false"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100267 {"/firmware-slot[name='A']/installed", "2021-01-13T17:15:50-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100268 {"/firmware-slot[name='A']/name", "A"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200269 {"/firmware-slot[name='A']/is-booted-now", "false"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100270 {"/firmware-slot[name='A']/version", "v4-104-ge80fcd4"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200271 {"/firmware-slot[name='A']/will-boot-next", "false"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100272 {"/firmware-slot[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200273 {"/firmware-slot[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100274 {"/firmware-slot[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100275 {"/firmware-slot[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200276 {"/firmware-slot[name='B']/is-booted-now", "true"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100277 {"/firmware-slot[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200278 {"/firmware-slot[name='B']/will-boot-next", "true"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100279 {"/installation", ""},
280 {"/installation/message", ""},
281 {"/installation/status", "in-progress"},
282 });
283 }
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100284 }
285 }
Jan Kundrát3795cab2022-07-13 18:08:19 +0200286
287 SECTION("marking FW slots") {
288 auto rpcInput = client.getContext().newPath("/czechlight-system:firmware/firmware-slot[name='A']/set-active-after-reboot");
289 {
290 REQUIRE_CALL(raucServer, impl_Mark("active", "rootfs.0")).IN_SEQUENCE(seq1);
291 REQUIRE(client.sendRPC(rpcInput).child() == std::nullopt);
292 }
293
294 rpcInput = client.getContext().newPath("/czechlight-system:firmware/firmware-slot[name='B']/set-active-after-reboot");
295 {
296 REQUIRE_CALL(raucServer, impl_Mark("active", "rootfs.1")).IN_SEQUENCE(seq1);
297 REQUIRE(client.sendRPC(rpcInput).child() == std::nullopt);
298 }
299
300 rpcInput = client.getContext().newPath("/czechlight-system:firmware/firmware-slot[name='B']/set-unhealthy");
301 {
302 REQUIRE_CALL(raucServer, impl_Mark("bad", "rootfs.1")).IN_SEQUENCE(seq1);
303 REQUIRE(client.sendRPC(rpcInput).child() == std::nullopt);
304 }
305
306 waitForCompletionAndBitMore(seq1);
307 }
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100308}
Tomáš Pecka825542f2021-02-24 14:00:10 +0100309
310TEST_CASE("Firmware in czechlight-system, slot status")
311{
312 trompeloeil::sequence seq1;
313
314 TEST_SYSREPO_INIT_LOGS;
315 TEST_SYSREPO_INIT;
316 TEST_SYSREPO_INIT_CLIENT;
317
318 auto dbusServerConnection = sdbus::createSessionBusConnection("de.pengutronix.rauc");
319 auto dbusClientConnectionSignals = sdbus::createSessionBusConnection();
320 auto dbusClientConnectionMethods = sdbus::createSessionBusConnection();
321 dbusClientConnectionSignals->enterEventLoopAsync();
322 dbusClientConnectionMethods->enterEventLoopAsync();
323 dbusServerConnection->enterEventLoopAsync();
324
325 std::map<std::string, velia::system::RAUC::SlotProperties> dbusRaucStatus;
326 std::map<std::string, std::string> expected;
327
328 SECTION("Complete data")
329 {
330 dbusRaucStatus = {
331 {"rootfs.1", {
332 {"activated.count", uint32_t {39}},
333 {"activated.timestamp", "2021-01-13T17:20:18Z"},
334 {"bootname", "B"},
335 {"boot-status", "good"},
336 {"bundle.compatible", "czechlight-clearfog"},
337 {"bundle.version", "v4-103-g34d2f48"},
338 {"class", "rootfs"},
339 {"device", "/dev/mmcblk0p3"},
340 {"installed.count", uint32_t {39}},
341 {"installed.timestamp", "2021-01-13T17:20:15Z"},
342 {"mountpoint", "/"},
343 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
344 {"size", uint64_t {45601892}},
345 {"state", "booted"},
346 {"status", "ok"},
347 {"type", "ext4"},
348 }},
349 {"rootfs.0", {
350 {"activated.count", uint32_t {41}},
351 {"activated.timestamp", "2021-01-13T17:15:54Z"},
352 {"bootname", "A"},
353 {"boot-status", "bad"},
354 {"bundle.compatible", "czechlight-clearfog"},
355 {"bundle.version", "v4-104-ge80fcd4"},
356 {"class", "rootfs"},
357 {"device", "/dev/mmcblk0p1"},
358 {"installed.count", uint32_t {41}},
359 {"installed.timestamp", "2021-01-13T17:15:50Z"},
360 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
361 {"size", uint64_t {45647664}},
362 {"state", "inactive"},
363 {"status", "ok"},
364 {"type", "ext4"},
365 }},
366 {"cfg.1", {
367 {"bundle.compatible", "czechlight-clearfog"},
368 {"bundle.version", "v4-103-g34d2f48"},
369 {"class", "cfg"},
370 {"device", "/dev/mmcblk0p4"},
371 {"installed.count", uint32_t {39}},
372 {"installed.timestamp", "2021-01-13T17:20:18Z"},
373 {"mountpoint", "/cfg"},
374 {"parent", "rootfs.1"},
375 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
376 {"size", uint64_t {108}},
377 {"state", "active"},
378 {"status", "ok"},
379 {"type", "ext4"},
380 }},
381 {"cfg.0", {
382 {"bundle.compatible", "czechlight-clearfog"},
383 {"bundle.version", "v4-104-ge80fcd4"},
384 {"class", "cfg"},
385 {"device", "/dev/mmcblk0p2"},
386 {"installed.count", uint32_t {41}},
387 {"installed.timestamp", "2021-01-13T17:15:54Z"},
388 {"parent", "rootfs.0"},
389 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
390 {"size", uint64_t {108}},
391 {"state", "inactive"},
392 {"status", "ok"},
393 {"type", "ext4"},
394 }},
395 };
396
397 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100398 {"[name='A']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200399 {"[name='A']/is-healthy", "false"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100400 {"[name='A']/installed", "2021-01-13T17:15:50-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100401 {"[name='A']/name", "A"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200402 {"[name='A']/is-booted-now", "false"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100403 {"[name='A']/version", "v4-104-ge80fcd4"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200404 {"[name='A']/will-boot-next", "false"},
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100405 {"[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200406 {"[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100407 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100408 {"[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200409 {"[name='B']/is-booted-now", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100410 {"[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200411 {"[name='B']/will-boot-next", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100412 };
413 }
414
415 SECTION("Missing data in rootfs.0")
416 {
417 dbusRaucStatus = {
418 {"rootfs.1", {
419 {"activated.count", uint32_t {39}},
420 {"activated.timestamp", "2021-01-13T17:20:18Z"},
421 {"bootname", "B"},
422 {"boot-status", "good"},
423 {"bundle.compatible", "czechlight-clearfog"},
424 {"bundle.version", "v4-103-g34d2f48"},
425 {"class", "rootfs"},
426 {"device", "/dev/mmcblk0p3"},
427 {"installed.count", uint32_t {39}},
428 {"installed.timestamp", "2021-01-13T17:20:15Z"},
429 {"mountpoint", "/"},
430 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
431 {"size", uint64_t {45601892}},
432 {"state", "booted"},
433 {"status", "ok"},
434 {"type", "ext4"},
435 }},
436 {"rootfs.0", {
437 {"bootname", "A"},
438 {"boot-status", "bad"},
439 {"class", "rootfs"},
440 {"device", "/dev/mmcblk0p1"},
441 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
442 {"size", uint64_t {45647664}},
443 {"state", "inactive"},
444 {"status", "ok"},
445 {"type", "ext4"},
446 }},
447 };
448
449 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100450 {"[name='A']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200451 {"[name='A']/is-healthy", "false"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100452 {"[name='A']/name", "A"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200453 {"[name='A']/is-booted-now", "false"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200454 {"[name='A']/will-boot-next", "false"},
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100455 {"[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200456 {"[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100457 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100458 {"[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200459 {"[name='B']/is-booted-now", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100460 {"[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200461 {"[name='B']/will-boot-next", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100462 };
463 }
464
465 SECTION("Missing bootname in rootfs.0")
466 {
467 dbusRaucStatus = {
468 {"rootfs.1", {
469 {"activated.count", uint32_t {39}},
470 {"activated.timestamp", "2021-01-13T17:20:18Z"},
471 {"bootname", "B"},
472 {"boot-status", "good"},
473 {"bundle.compatible", "czechlight-clearfog"},
474 {"bundle.version", "v4-103-g34d2f48"},
475 {"class", "rootfs"},
476 {"device", "/dev/mmcblk0p3"},
477 {"installed.count", uint32_t {39}},
478 {"installed.timestamp", "2021-01-13T17:20:15Z"},
479 {"mountpoint", "/"},
480 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
481 {"size", uint64_t {45601892}},
482 {"state", "booted"},
483 {"status", "ok"},
484 {"type", "ext4"},
485 }},
486 {"rootfs.0", {
487 {"boot-status", "bad"},
488 {"class", "rootfs"},
489 {"device", "/dev/mmcblk0p1"},
490 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
491 {"size", uint64_t {45647664}},
492 {"state", "inactive"},
493 {"status", "ok"},
494 {"type", "ext4"},
495 }},
496 };
497
498 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100499 {"[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200500 {"[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100501 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100502 {"[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200503 {"[name='B']/is-booted-now", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100504 {"[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200505 {"[name='B']/will-boot-next", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100506 };
507 }
508
509 auto raucServer = DBusRAUCServer(*dbusServerConnection, "rootfs.1", dbusRaucStatus);
510 auto sysrepo = std::make_shared<velia::system::Firmware>(srConn, *dbusClientConnectionSignals, *dbusClientConnectionMethods);
511
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100512 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/firmware-slot", sysrepo::Datastore::Operational) == expected);
Tomáš Pecka825542f2021-02-24 14:00:10 +0100513}