blob: bcd9237846669ab9572592f4de3fe9f63becf74f [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"
7#include "test_sysrepo_helpers.h"
8#include "tests/configure.cmake.h"
Tomáš Pecka9a6e15b2021-01-25 18:57:48 +01009#include "tests/mock/sysrepo/events.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) {
18 return NotificationWatcher::data_t{
19 {"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']", ""},
146 {"/firmware-slot[name='A']/boot-status", "bad"},
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"},
149 {"/firmware-slot[name='A']/state", "inactive"},
150 {"/firmware-slot[name='A']/version", "v4-104-ge80fcd4"},
151 {"/firmware-slot[name='B']", ""},
152 {"/firmware-slot[name='B']/boot-status", "good"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100153 {"/firmware-slot[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100154 {"/firmware-slot[name='B']/name", "B"},
155 {"/firmware-slot[name='B']/state", "booted"},
156 {"/firmware-slot[name='B']/version", "v4-103-g34d2f48"},
157 {"/installation", ""},
158 {"/installation/message", ""},
159 {"/installation/status", "none"},
160 });
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100161
162 SECTION("Firmware install RPC")
163 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100164 auto rpcInput = client.getContext().newPath("/czechlight-system:firmware/installation/install/url", "/path/to/bundle/update.raucb");
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100165
166 SECTION("Installation runs")
167 {
Jan Kundrát7aa894e2022-03-30 19:32:40 +0200168 NotificationWatcher installProgressMock{client, "/czechlight-system:firmware/installation/update"};
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100169 DBusRAUCServer::InstallBehaviour installType;
170 std::map<std::string, std::string> expectedFinished, expectedInProgress = {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100171 {"/message", ""},
172 {"/status", "in-progress"},
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100173 };
174
175 SECTION("Successfull install")
176 {
177 installType = DBusRAUCServer::InstallBehaviour::OK;
178 expectedFinished = {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100179 {"/message", ""},
180 {"/status", "succeeded"},
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100181 };
182 }
183
184 SECTION("Unsuccessfull install")
185 {
186 installType = DBusRAUCServer::InstallBehaviour::FAILURE;
187 expectedFinished = {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100188 {"/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"},
189 {"/status", "failed"},
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100190 };
191 }
192
193 raucServer.installBundleBehaviour(installType);
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100194 auto progressExpectations = expectationFactory(installType, installProgressMock, seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100195 auto res = client.sendRPC(rpcInput);
196 REQUIRE(res.child() == std::nullopt);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100197
198 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 +0100199 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", sysrepo::Datastore::Operational) == expectedInProgress);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100200
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100201 waitForCompletionAndBitMore(seq1); // wait for installation to complete
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100202 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", sysrepo::Datastore::Operational) == expectedFinished);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100203 }
204
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100205 SECTION("Unsuccessfull install followed by successfull install")
206 {
Jan Kundrát7aa894e2022-03-30 19:32:40 +0200207 NotificationWatcher installProgressMock{client, "/czechlight-system:firmware/installation/update"};
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100208 // invoke unsuccessfull install
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100209 {
210 raucServer.installBundleBehaviour(DBusRAUCServer::InstallBehaviour::FAILURE);
211 auto progressExpectations = expectationFactory(DBusRAUCServer::InstallBehaviour::FAILURE, installProgressMock, seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100212 client.sendRPC(rpcInput);
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100213
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100214 waitForCompletionAndBitMore(seq1); // wait for installation to complete
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100215 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", sysrepo::Datastore::Operational) == std::map<std::string, std::string> {
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100216 {"/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"},
217 {"/status", "failed"},
218 });
219 }
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100220
221 // invoke successfull install
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100222 {
223 raucServer.installBundleBehaviour(DBusRAUCServer::InstallBehaviour::OK);
224 auto progressExpectations = expectationFactory(DBusRAUCServer::InstallBehaviour::OK, installProgressMock, seq1);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100225 client.sendRPC(rpcInput);
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100226
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100227 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 +0100228 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", sysrepo::Datastore::Operational) == std::map<std::string, std::string> {
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100229 {"/message", ""},
230 {"/status", "in-progress"},
231 });
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100232
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100233 waitForCompletionAndBitMore(seq1); // wait for installation to complete
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100234 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/installation", sysrepo::Datastore::Operational) == std::map<std::string, std::string>{
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100235 {"/message", ""},
236 {"/status", "succeeded"},
237 });
238 }
Tomáš Pecka0eefdf12021-02-17 19:28:13 +0100239 }
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100240
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100241 SECTION("Installation in progress")
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100242 {
Tomáš Pecka76fa2ff2021-03-15 16:28:06 +0100243 raucServer.installBundleBehaviour(DBusRAUCServer::InstallBehaviour::OK);
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100244 client.sendRPC(rpcInput);
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100245 std::this_thread::sleep_for(10ms);
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100246
247 SECTION("Invoking second installation throws")
248 {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100249 REQUIRE_THROWS_WITH_AS(client.sendRPC(rpcInput), "Couldn't send RPC: SR_ERR_CALLBACK_FAILED", sysrepo::ErrorWithCode);
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100250 }
251
252 SECTION("Firmware slot data are available")
253 {
254 // 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 +0100255 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware", sysrepo::Datastore::Operational) == std::map<std::string, std::string> {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100256 {"/firmware-slot[name='A']", ""},
257 {"/firmware-slot[name='A']/boot-status", "bad"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100258 {"/firmware-slot[name='A']/installed", "2021-01-13T17:15:50-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100259 {"/firmware-slot[name='A']/name", "A"},
260 {"/firmware-slot[name='A']/state", "inactive"},
261 {"/firmware-slot[name='A']/version", "v4-104-ge80fcd4"},
262 {"/firmware-slot[name='B']", ""},
263 {"/firmware-slot[name='B']/boot-status", "good"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100264 {"/firmware-slot[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100265 {"/firmware-slot[name='B']/name", "B"},
266 {"/firmware-slot[name='B']/state", "booted"},
267 {"/firmware-slot[name='B']/version", "v4-103-g34d2f48"},
268 {"/installation", ""},
269 {"/installation/message", ""},
270 {"/installation/status", "in-progress"},
271 });
272 }
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100273 }
274 }
275}
Tomáš Pecka825542f2021-02-24 14:00:10 +0100276
277TEST_CASE("Firmware in czechlight-system, slot status")
278{
279 trompeloeil::sequence seq1;
280
281 TEST_SYSREPO_INIT_LOGS;
282 TEST_SYSREPO_INIT;
283 TEST_SYSREPO_INIT_CLIENT;
284
285 auto dbusServerConnection = sdbus::createSessionBusConnection("de.pengutronix.rauc");
286 auto dbusClientConnectionSignals = sdbus::createSessionBusConnection();
287 auto dbusClientConnectionMethods = sdbus::createSessionBusConnection();
288 dbusClientConnectionSignals->enterEventLoopAsync();
289 dbusClientConnectionMethods->enterEventLoopAsync();
290 dbusServerConnection->enterEventLoopAsync();
291
292 std::map<std::string, velia::system::RAUC::SlotProperties> dbusRaucStatus;
293 std::map<std::string, std::string> expected;
294
295 SECTION("Complete data")
296 {
297 dbusRaucStatus = {
298 {"rootfs.1", {
299 {"activated.count", uint32_t {39}},
300 {"activated.timestamp", "2021-01-13T17:20:18Z"},
301 {"bootname", "B"},
302 {"boot-status", "good"},
303 {"bundle.compatible", "czechlight-clearfog"},
304 {"bundle.version", "v4-103-g34d2f48"},
305 {"class", "rootfs"},
306 {"device", "/dev/mmcblk0p3"},
307 {"installed.count", uint32_t {39}},
308 {"installed.timestamp", "2021-01-13T17:20:15Z"},
309 {"mountpoint", "/"},
310 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
311 {"size", uint64_t {45601892}},
312 {"state", "booted"},
313 {"status", "ok"},
314 {"type", "ext4"},
315 }},
316 {"rootfs.0", {
317 {"activated.count", uint32_t {41}},
318 {"activated.timestamp", "2021-01-13T17:15:54Z"},
319 {"bootname", "A"},
320 {"boot-status", "bad"},
321 {"bundle.compatible", "czechlight-clearfog"},
322 {"bundle.version", "v4-104-ge80fcd4"},
323 {"class", "rootfs"},
324 {"device", "/dev/mmcblk0p1"},
325 {"installed.count", uint32_t {41}},
326 {"installed.timestamp", "2021-01-13T17:15:50Z"},
327 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
328 {"size", uint64_t {45647664}},
329 {"state", "inactive"},
330 {"status", "ok"},
331 {"type", "ext4"},
332 }},
333 {"cfg.1", {
334 {"bundle.compatible", "czechlight-clearfog"},
335 {"bundle.version", "v4-103-g34d2f48"},
336 {"class", "cfg"},
337 {"device", "/dev/mmcblk0p4"},
338 {"installed.count", uint32_t {39}},
339 {"installed.timestamp", "2021-01-13T17:20:18Z"},
340 {"mountpoint", "/cfg"},
341 {"parent", "rootfs.1"},
342 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
343 {"size", uint64_t {108}},
344 {"state", "active"},
345 {"status", "ok"},
346 {"type", "ext4"},
347 }},
348 {"cfg.0", {
349 {"bundle.compatible", "czechlight-clearfog"},
350 {"bundle.version", "v4-104-ge80fcd4"},
351 {"class", "cfg"},
352 {"device", "/dev/mmcblk0p2"},
353 {"installed.count", uint32_t {41}},
354 {"installed.timestamp", "2021-01-13T17:15:54Z"},
355 {"parent", "rootfs.0"},
356 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
357 {"size", uint64_t {108}},
358 {"state", "inactive"},
359 {"status", "ok"},
360 {"type", "ext4"},
361 }},
362 };
363
364 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100365 {"[name='A']", ""},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100366 {"[name='A']/boot-status", "bad"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100367 {"[name='A']/installed", "2021-01-13T17:15:50-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100368 {"[name='A']/name", "A"},
369 {"[name='A']/state", "inactive"},
370 {"[name='A']/version", "v4-104-ge80fcd4"},
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100371 {"[name='B']", ""},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100372 {"[name='B']/boot-status", "good"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100373 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100374 {"[name='B']/name", "B"},
375 {"[name='B']/state", "booted"},
376 {"[name='B']/version", "v4-103-g34d2f48"},
377 };
378 }
379
380 SECTION("Missing data in rootfs.0")
381 {
382 dbusRaucStatus = {
383 {"rootfs.1", {
384 {"activated.count", uint32_t {39}},
385 {"activated.timestamp", "2021-01-13T17:20:18Z"},
386 {"bootname", "B"},
387 {"boot-status", "good"},
388 {"bundle.compatible", "czechlight-clearfog"},
389 {"bundle.version", "v4-103-g34d2f48"},
390 {"class", "rootfs"},
391 {"device", "/dev/mmcblk0p3"},
392 {"installed.count", uint32_t {39}},
393 {"installed.timestamp", "2021-01-13T17:20:15Z"},
394 {"mountpoint", "/"},
395 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
396 {"size", uint64_t {45601892}},
397 {"state", "booted"},
398 {"status", "ok"},
399 {"type", "ext4"},
400 }},
401 {"rootfs.0", {
402 {"bootname", "A"},
403 {"boot-status", "bad"},
404 {"class", "rootfs"},
405 {"device", "/dev/mmcblk0p1"},
406 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
407 {"size", uint64_t {45647664}},
408 {"state", "inactive"},
409 {"status", "ok"},
410 {"type", "ext4"},
411 }},
412 };
413
414 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100415 {"[name='A']", ""},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100416 {"[name='A']/boot-status", "bad"},
417 {"[name='A']/name", "A"},
418 {"[name='A']/state", "inactive"},
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100419 {"[name='B']", ""},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100420 {"[name='B']/boot-status", "good"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100421 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100422 {"[name='B']/name", "B"},
423 {"[name='B']/state", "booted"},
424 {"[name='B']/version", "v4-103-g34d2f48"},
425 };
426 }
427
428 SECTION("Missing bootname in rootfs.0")
429 {
430 dbusRaucStatus = {
431 {"rootfs.1", {
432 {"activated.count", uint32_t {39}},
433 {"activated.timestamp", "2021-01-13T17:20:18Z"},
434 {"bootname", "B"},
435 {"boot-status", "good"},
436 {"bundle.compatible", "czechlight-clearfog"},
437 {"bundle.version", "v4-103-g34d2f48"},
438 {"class", "rootfs"},
439 {"device", "/dev/mmcblk0p3"},
440 {"installed.count", uint32_t {39}},
441 {"installed.timestamp", "2021-01-13T17:20:15Z"},
442 {"mountpoint", "/"},
443 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
444 {"size", uint64_t {45601892}},
445 {"state", "booted"},
446 {"status", "ok"},
447 {"type", "ext4"},
448 }},
449 {"rootfs.0", {
450 {"boot-status", "bad"},
451 {"class", "rootfs"},
452 {"device", "/dev/mmcblk0p1"},
453 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
454 {"size", uint64_t {45647664}},
455 {"state", "inactive"},
456 {"status", "ok"},
457 {"type", "ext4"},
458 }},
459 };
460
461 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100462 {"[name='B']", ""},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100463 {"[name='B']/boot-status", "good"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100464 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100465 {"[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
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100474 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/firmware-slot", sysrepo::Datastore::Operational) == expected);
Tomáš Pecka825542f2021-02-24 14:00:10 +0100475}