blob: 897e12e851bd7a7ee4bca628d447918fb713d61c [file] [log] [blame]
Tomáš Peckacb7a5f82021-01-20 15:12:00 +01001#include "trompeloeil_doctest.h"
2#include "dbus-helpers/dbus_rauc_server.h"
3#include "pretty_printers.h"
Tomáš Pecka594a6762021-01-29 11:06:08 +01004#include "system/Firmware.h"
Tomáš Peckacb7a5f82021-01-20 15:12:00 +01005#include "test_log_setup.h"
6#include "test_sysrepo_helpers.h"
7#include "tests/configure.cmake.h"
Tomáš Pecka9a6e15b2021-01-25 18:57:48 +01008#include "tests/mock/sysrepo/events.h"
Tomáš Peckacb7a5f82021-01-20 15:12:00 +01009
10using namespace std::literals;
11
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +010012struct InstallProgressMock {
13 MAKE_CONST_MOCK2(update, void(int32_t, const std::string&));
14};
15
16std::vector<std::unique_ptr<trompeloeil::expectation>> expectationFactory(const DBusRAUCServer::InstallBehaviour& installType, const InstallProgressMock& eventMock, trompeloeil::sequence& seq1)
17{
18 std::vector<std::unique_ptr<trompeloeil::expectation>> expectations;
19
20 if (installType == DBusRAUCServer::InstallBehaviour::OK) {
21 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(0, "Installing")).IN_SEQUENCE(seq1));
22 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(0, "Determining slot states")).IN_SEQUENCE(seq1));
23 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(20, "Determining slot states done.")).IN_SEQUENCE(seq1));
24 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(20, "Checking bundle")).IN_SEQUENCE(seq1));
25 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(20, "Veryfing signature")).IN_SEQUENCE(seq1));
26 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(40, "Veryfing signature done.")).IN_SEQUENCE(seq1));
27 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(40, "Checking bundle done.")).IN_SEQUENCE(seq1));
28 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(40, "Loading manifest file")).IN_SEQUENCE(seq1));
29 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(60, "Loading manifest file done.")).IN_SEQUENCE(seq1));
30 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(60, "Determining target install group")).IN_SEQUENCE(seq1));
31 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(80, "Determining target install group done.")).IN_SEQUENCE(seq1));
32 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(80, "Updating slots")).IN_SEQUENCE(seq1));
33 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(80, "Checking slot rootfs.0")).IN_SEQUENCE(seq1));
34 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(85, "Checking slot rootfs.0 done.")).IN_SEQUENCE(seq1));
35 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(85, "Copying image to rootfs.0")).IN_SEQUENCE(seq1));
36 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(90, "Copying image to rootfs.0 done.")).IN_SEQUENCE(seq1));
37 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(90, "Checking slot cfg.0")).IN_SEQUENCE(seq1));
38 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(95, "Checking slot cfg.0 done.")).IN_SEQUENCE(seq1));
39 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(95, "Copying image to cfg.0")).IN_SEQUENCE(seq1));
40 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(100, "Copying image to cfg.0 done.")).IN_SEQUENCE(seq1));
41 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(100, "Updating slots done.")).IN_SEQUENCE(seq1));
42 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(100, "Installing done.")).IN_SEQUENCE(seq1));
43 } else {
44 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(0, "Installing")).IN_SEQUENCE(seq1));
45 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(0, "Determining slot states")).IN_SEQUENCE(seq1));
46 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(20, "Determining slot states done.")).IN_SEQUENCE(seq1));
47 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(20, "Checking bundle")).IN_SEQUENCE(seq1));
48 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(40, "Checking bundle failed.")).IN_SEQUENCE(seq1));
49 expectations.push_back(NAMED_REQUIRE_CALL(eventMock, update(100, "Installing failed.")).IN_SEQUENCE(seq1));
50 }
51
52 return expectations;
53}
54
55
Tomáš Pecka825542f2021-02-24 14:00:10 +010056TEST_CASE("Firmware in czechlight-system, RPC")
Tomáš Peckacb7a5f82021-01-20 15:12:00 +010057{
58 trompeloeil::sequence seq1;
59
60 TEST_SYSREPO_INIT_LOGS;
61 TEST_SYSREPO_INIT;
62 TEST_SYSREPO_INIT_CLIENT;
63
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +010064 // process install notifications
65 InstallProgressMock installProgressMock;
66 EventWatcher events([&installProgressMock](const EventWatcher::Event& event) {
67 installProgressMock.update(std::stoi(event.data.at("/czechlight-system:firmware/installation/update/progress")), event.data.at("/czechlight-system:firmware/installation/update/message"));
68 });
69
Tomáš Peckacb7a5f82021-01-20 15:12:00 +010070 auto dbusServerConnection = sdbus::createSessionBusConnection("de.pengutronix.rauc");
Tomáš Peckad51d4cb2021-02-03 14:15:49 +010071 auto dbusClientConnectionSignals = sdbus::createSessionBusConnection();
72 auto dbusClientConnectionMethods = sdbus::createSessionBusConnection();
73 dbusClientConnectionSignals->enterEventLoopAsync();
74 dbusClientConnectionMethods->enterEventLoopAsync();
Tomáš Peckacb7a5f82021-01-20 15:12:00 +010075 dbusServerConnection->enterEventLoopAsync();
76
77 std::map<std::string, velia::system::RAUC::SlotProperties> dbusRaucStatus = {
78 {"rootfs.1", {
79 {"activated.count", uint32_t {39}},
80 {"activated.timestamp", "2021-01-13T17:20:18Z"},
81 {"bootname", "B"},
82 {"boot-status", "good"},
83 {"bundle.compatible", "czechlight-clearfog"},
84 {"bundle.version", "v4-103-g34d2f48"},
85 {"class", "rootfs"},
86 {"device", "/dev/mmcblk0p3"},
87 {"installed.count", uint32_t {39}},
88 {"installed.timestamp", "2021-01-13T17:20:15Z"},
89 {"mountpoint", "/"},
90 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
91 {"size", uint64_t {45601892}},
92 {"state", "booted"},
93 {"status", "ok"},
94 {"type", "ext4"},
95 }},
96 {"rootfs.0", {
97 {"activated.count", uint32_t {41}},
98 {"activated.timestamp", "2021-01-13T17:15:54Z"},
99 {"bootname", "A"},
100 {"boot-status", "bad"},
101 {"bundle.compatible", "czechlight-clearfog"},
102 {"bundle.version", "v4-104-ge80fcd4"},
103 {"class", "rootfs"},
104 {"device", "/dev/mmcblk0p1"},
105 {"installed.count", uint32_t {41}},
106 {"installed.timestamp", "2021-01-13T17:15:50Z"},
107 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
108 {"size", uint64_t {45647664}},
109 {"state", "inactive"},
110 {"status", "ok"},
111 {"type", "ext4"},
112 }},
113 {"cfg.1", {
114 {"bundle.compatible", "czechlight-clearfog"},
115 {"bundle.version", "v4-103-g34d2f48"},
116 {"class", "cfg"},
117 {"device", "/dev/mmcblk0p4"},
118 {"installed.count", uint32_t {39}},
119 {"installed.timestamp", "2021-01-13T17:20:18Z"},
120 {"mountpoint", "/cfg"},
121 {"parent", "rootfs.1"},
122 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
123 {"size", uint64_t {108}},
124 {"state", "active"},
125 {"status", "ok"},
126 {"type", "ext4"},
127 }},
128 {"cfg.0", {
129 {"bundle.compatible", "czechlight-clearfog"},
130 {"bundle.version", "v4-104-ge80fcd4"},
131 {"class", "cfg"},
132 {"device", "/dev/mmcblk0p2"},
133 {"installed.count", uint32_t {41}},
134 {"installed.timestamp", "2021-01-13T17:15:54Z"},
135 {"parent", "rootfs.0"},
136 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
137 {"size", uint64_t {108}},
138 {"state", "inactive"},
139 {"status", "ok"},
140 {"type", "ext4"},
141 }},
142 };
143 auto raucServer = DBusRAUCServer(*dbusServerConnection, "rootfs.1", dbusRaucStatus);
Tomáš Peckad51d4cb2021-02-03 14:15:49 +0100144 auto sysrepo = std::make_shared<velia::system::Firmware>(srConn, *dbusClientConnectionSignals, *dbusClientConnectionMethods);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100145
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100146 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware", SR_DS_OPERATIONAL) == std::map<std::string, std::string> {
147 {"/firmware-slot[name='A']", ""},
148 {"/firmware-slot[name='A']/boot-status", "bad"},
149 {"/firmware-slot[name='A']/installed", "2021-01-13T17:15:50Z"},
150 {"/firmware-slot[name='A']/name", "A"},
151 {"/firmware-slot[name='A']/state", "inactive"},
152 {"/firmware-slot[name='A']/version", "v4-104-ge80fcd4"},
153 {"/firmware-slot[name='B']", ""},
154 {"/firmware-slot[name='B']/boot-status", "good"},
155 {"/firmware-slot[name='B']/installed", "2021-01-13T17:20:15Z"},
156 {"/firmware-slot[name='B']/name", "B"},
157 {"/firmware-slot[name='B']/state", "booted"},
158 {"/firmware-slot[name='B']/version", "v4-103-g34d2f48"},
159 {"/installation", ""},
160 {"/installation/message", ""},
161 {"/installation/status", "none"},
162 });
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100163
164 SECTION("Firmware install RPC")
165 {
166 auto rpcInput = std::make_shared<sysrepo::Vals>(1);
167 rpcInput->val(0)->set("/czechlight-system:firmware/installation/install/url", "/path/to/bundle/update.raucb");
168
169 SECTION("Installation runs")
170 {
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100171 subscription->event_notif_subscribe("czechlight-system", events, "/czechlight-system:firmware/installation/update");
172
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100173 DBusRAUCServer::InstallBehaviour installType;
174 std::map<std::string, std::string> expectedFinished, expectedInProgress = {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100175 {"/message", ""},
176 {"/status", "in-progress"},
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100177 };
178
179 SECTION("Successfull install")
180 {
181 installType = DBusRAUCServer::InstallBehaviour::OK;
182 expectedFinished = {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100183 {"/message", ""},
184 {"/status", "succeeded"},
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100185 };
186 }
187
188 SECTION("Unsuccessfull install")
189 {
190 installType = DBusRAUCServer::InstallBehaviour::FAILURE;
191 expectedFinished = {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100192 {"/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"},
193 {"/status", "failed"},
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100194 };
195 }
196
197 raucServer.installBundleBehaviour(installType);
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100198 auto progressExpectations = expectationFactory(installType, installProgressMock, seq1);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100199 auto res = client->rpc_send("/czechlight-system:firmware/installation/install", rpcInput);
200 REQUIRE(res->val_cnt() == 0);
201
202 std::this_thread::sleep_for(10ms); // lets wait a while, so the RAUC's callback for operation changed takes place
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100203 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", SR_DS_OPERATIONAL) == expectedInProgress);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100204
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100205 waitForCompletionAndBitMore(seq1); // wait for installation to complete
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100206 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", SR_DS_OPERATIONAL) == expectedFinished);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100207 }
208
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100209 SECTION("Unsuccessfull install followed by successfull install")
210 {
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100211 subscription->event_notif_subscribe("czechlight-system", events, "/czechlight-system:firmware/installation/update");
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100212
213 // invoke unsuccessfull install
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100214 {
215 raucServer.installBundleBehaviour(DBusRAUCServer::InstallBehaviour::FAILURE);
216 auto progressExpectations = expectationFactory(DBusRAUCServer::InstallBehaviour::FAILURE, installProgressMock, seq1);
217 client->rpc_send("/czechlight-system:firmware/installation/install", rpcInput);
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100218
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100219 waitForCompletionAndBitMore(seq1); // wait for installation to complete
220 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", SR_DS_OPERATIONAL) == std::map<std::string, std::string> {
221 {"/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"},
222 {"/status", "failed"},
223 });
224 }
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100225
226 // invoke successfull install
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100227 {
228 raucServer.installBundleBehaviour(DBusRAUCServer::InstallBehaviour::OK);
229 auto progressExpectations = expectationFactory(DBusRAUCServer::InstallBehaviour::OK, installProgressMock, seq1);
230 client->rpc_send("/czechlight-system:firmware/installation/install", rpcInput);
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100231
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100232 std::this_thread::sleep_for(10ms); // lets wait a while, so the RAUC's callback for operation changed takes place
233 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", SR_DS_OPERATIONAL) == std::map<std::string, std::string> {
234 {"/message", ""},
235 {"/status", "in-progress"},
236 });
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100237
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100238 waitForCompletionAndBitMore(seq1); // wait for installation to complete
239 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", SR_DS_OPERATIONAL) == std::map<std::string, std::string>{
240 {"/message", ""},
241 {"/status", "succeeded"},
242 });
243 }
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100244 }
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100245
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100246 SECTION("Installation in progress")
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100247 {
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100248 raucServer.installBundleBehaviour(DBusRAUCServer::InstallBehaviour::OK);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100249 client->rpc_send("/czechlight-system:firmware/installation/install", rpcInput);
250 std::this_thread::sleep_for(10ms);
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100251
252 SECTION("Invoking second installation throws")
253 {
254 REQUIRE_THROWS_WITH_AS(client->rpc_send("/czechlight-system:firmware/installation/install", rpcInput), "User callback failed", sysrepo::sysrepo_exception);
255 }
256
257 SECTION("Firmware slot data are available")
258 {
259 // RAUC does not respond to GetSlotStatus when another operation in progress, so let's check we use the cached data
260 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware", SR_DS_OPERATIONAL) == std::map<std::string, std::string> {
261 {"/firmware-slot[name='A']", ""},
262 {"/firmware-slot[name='A']/boot-status", "bad"},
263 {"/firmware-slot[name='A']/installed", "2021-01-13T17:15:50Z"},
264 {"/firmware-slot[name='A']/name", "A"},
265 {"/firmware-slot[name='A']/state", "inactive"},
266 {"/firmware-slot[name='A']/version", "v4-104-ge80fcd4"},
267 {"/firmware-slot[name='B']", ""},
268 {"/firmware-slot[name='B']/boot-status", "good"},
269 {"/firmware-slot[name='B']/installed", "2021-01-13T17:20:15Z"},
270 {"/firmware-slot[name='B']/name", "B"},
271 {"/firmware-slot[name='B']/state", "booted"},
272 {"/firmware-slot[name='B']/version", "v4-103-g34d2f48"},
273 {"/installation", ""},
274 {"/installation/message", ""},
275 {"/installation/status", "in-progress"},
276 });
277 }
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100278 }
279 }
280}
Tomáš Pecka825542f2021-02-24 14:00:10 +0100281
282TEST_CASE("Firmware in czechlight-system, slot status")
283{
284 trompeloeil::sequence seq1;
285
286 TEST_SYSREPO_INIT_LOGS;
287 TEST_SYSREPO_INIT;
288 TEST_SYSREPO_INIT_CLIENT;
289
290 auto dbusServerConnection = sdbus::createSessionBusConnection("de.pengutronix.rauc");
291 auto dbusClientConnectionSignals = sdbus::createSessionBusConnection();
292 auto dbusClientConnectionMethods = sdbus::createSessionBusConnection();
293 dbusClientConnectionSignals->enterEventLoopAsync();
294 dbusClientConnectionMethods->enterEventLoopAsync();
295 dbusServerConnection->enterEventLoopAsync();
296
297 std::map<std::string, velia::system::RAUC::SlotProperties> dbusRaucStatus;
298 std::map<std::string, std::string> expected;
299
300 SECTION("Complete data")
301 {
302 dbusRaucStatus = {
303 {"rootfs.1", {
304 {"activated.count", uint32_t {39}},
305 {"activated.timestamp", "2021-01-13T17:20:18Z"},
306 {"bootname", "B"},
307 {"boot-status", "good"},
308 {"bundle.compatible", "czechlight-clearfog"},
309 {"bundle.version", "v4-103-g34d2f48"},
310 {"class", "rootfs"},
311 {"device", "/dev/mmcblk0p3"},
312 {"installed.count", uint32_t {39}},
313 {"installed.timestamp", "2021-01-13T17:20:15Z"},
314 {"mountpoint", "/"},
315 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
316 {"size", uint64_t {45601892}},
317 {"state", "booted"},
318 {"status", "ok"},
319 {"type", "ext4"},
320 }},
321 {"rootfs.0", {
322 {"activated.count", uint32_t {41}},
323 {"activated.timestamp", "2021-01-13T17:15:54Z"},
324 {"bootname", "A"},
325 {"boot-status", "bad"},
326 {"bundle.compatible", "czechlight-clearfog"},
327 {"bundle.version", "v4-104-ge80fcd4"},
328 {"class", "rootfs"},
329 {"device", "/dev/mmcblk0p1"},
330 {"installed.count", uint32_t {41}},
331 {"installed.timestamp", "2021-01-13T17:15:50Z"},
332 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
333 {"size", uint64_t {45647664}},
334 {"state", "inactive"},
335 {"status", "ok"},
336 {"type", "ext4"},
337 }},
338 {"cfg.1", {
339 {"bundle.compatible", "czechlight-clearfog"},
340 {"bundle.version", "v4-103-g34d2f48"},
341 {"class", "cfg"},
342 {"device", "/dev/mmcblk0p4"},
343 {"installed.count", uint32_t {39}},
344 {"installed.timestamp", "2021-01-13T17:20:18Z"},
345 {"mountpoint", "/cfg"},
346 {"parent", "rootfs.1"},
347 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
348 {"size", uint64_t {108}},
349 {"state", "active"},
350 {"status", "ok"},
351 {"type", "ext4"},
352 }},
353 {"cfg.0", {
354 {"bundle.compatible", "czechlight-clearfog"},
355 {"bundle.version", "v4-104-ge80fcd4"},
356 {"class", "cfg"},
357 {"device", "/dev/mmcblk0p2"},
358 {"installed.count", uint32_t {41}},
359 {"installed.timestamp", "2021-01-13T17:15:54Z"},
360 {"parent", "rootfs.0"},
361 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
362 {"size", uint64_t {108}},
363 {"state", "inactive"},
364 {"status", "ok"},
365 {"type", "ext4"},
366 }},
367 };
368
369 expected = {
370 {"[name='A']/boot-status", "bad"},
371 {"[name='A']/installed", "2021-01-13T17:15:50Z"},
372 {"[name='A']/name", "A"},
373 {"[name='A']/state", "inactive"},
374 {"[name='A']/version", "v4-104-ge80fcd4"},
375 {"[name='B']/boot-status", "good"},
376 {"[name='B']/installed", "2021-01-13T17:20:15Z"},
377 {"[name='B']/name", "B"},
378 {"[name='B']/state", "booted"},
379 {"[name='B']/version", "v4-103-g34d2f48"},
380 };
381 }
382
383 SECTION("Missing data in rootfs.0")
384 {
385 dbusRaucStatus = {
386 {"rootfs.1", {
387 {"activated.count", uint32_t {39}},
388 {"activated.timestamp", "2021-01-13T17:20:18Z"},
389 {"bootname", "B"},
390 {"boot-status", "good"},
391 {"bundle.compatible", "czechlight-clearfog"},
392 {"bundle.version", "v4-103-g34d2f48"},
393 {"class", "rootfs"},
394 {"device", "/dev/mmcblk0p3"},
395 {"installed.count", uint32_t {39}},
396 {"installed.timestamp", "2021-01-13T17:20:15Z"},
397 {"mountpoint", "/"},
398 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
399 {"size", uint64_t {45601892}},
400 {"state", "booted"},
401 {"status", "ok"},
402 {"type", "ext4"},
403 }},
404 {"rootfs.0", {
405 {"bootname", "A"},
406 {"boot-status", "bad"},
407 {"class", "rootfs"},
408 {"device", "/dev/mmcblk0p1"},
409 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
410 {"size", uint64_t {45647664}},
411 {"state", "inactive"},
412 {"status", "ok"},
413 {"type", "ext4"},
414 }},
415 };
416
417 expected = {
418 {"[name='A']/boot-status", "bad"},
419 {"[name='A']/name", "A"},
420 {"[name='A']/state", "inactive"},
421 {"[name='B']/boot-status", "good"},
422 {"[name='B']/installed", "2021-01-13T17:20:15Z"},
423 {"[name='B']/name", "B"},
424 {"[name='B']/state", "booted"},
425 {"[name='B']/version", "v4-103-g34d2f48"},
426 };
427 }
428
429 SECTION("Missing bootname in rootfs.0")
430 {
431 dbusRaucStatus = {
432 {"rootfs.1", {
433 {"activated.count", uint32_t {39}},
434 {"activated.timestamp", "2021-01-13T17:20:18Z"},
435 {"bootname", "B"},
436 {"boot-status", "good"},
437 {"bundle.compatible", "czechlight-clearfog"},
438 {"bundle.version", "v4-103-g34d2f48"},
439 {"class", "rootfs"},
440 {"device", "/dev/mmcblk0p3"},
441 {"installed.count", uint32_t {39}},
442 {"installed.timestamp", "2021-01-13T17:20:15Z"},
443 {"mountpoint", "/"},
444 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
445 {"size", uint64_t {45601892}},
446 {"state", "booted"},
447 {"status", "ok"},
448 {"type", "ext4"},
449 }},
450 {"rootfs.0", {
451 {"boot-status", "bad"},
452 {"class", "rootfs"},
453 {"device", "/dev/mmcblk0p1"},
454 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
455 {"size", uint64_t {45647664}},
456 {"state", "inactive"},
457 {"status", "ok"},
458 {"type", "ext4"},
459 }},
460 };
461
462 expected = {
463 {"[name='B']/boot-status", "good"},
464 {"[name='B']/installed", "2021-01-13T17:20:15Z"},
465 {"[name='B']/name", "B"},
466 {"[name='B']/state", "booted"},
467 {"[name='B']/version", "v4-103-g34d2f48"},
468 };
469 }
470
471 auto raucServer = DBusRAUCServer(*dbusServerConnection, "rootfs.1", dbusRaucStatus);
472 auto sysrepo = std::make_shared<velia::system::Firmware>(srConn, *dbusClientConnectionSignals, *dbusClientConnectionMethods);
473
474 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/firmware-slot", SR_DS_OPERATIONAL) == expected);
475}