blob: c6a428bf6daaf6ab8a72b46f3ed50a10dcd46775 [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']", ""},
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"
253 " Already processing a different method (SR_ERR_OPERATION_FAILED)\n"
254 " User callback failed. (SR_ERR_CALLBACK_FAILED)\n"
255 " NETCONF: application: operation-failed: Already processing a different method",
256 sysrepo::ErrorWithCode);
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100257 }
258
259 SECTION("Firmware slot data are available")
260 {
261 // 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 +0100262 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware", sysrepo::Datastore::Operational) == std::map<std::string, std::string> {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100263 {"/firmware-slot[name='A']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200264 {"/firmware-slot[name='A']/is-healthy", "false"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100265 {"/firmware-slot[name='A']/installed", "2021-01-13T17:15:50-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100266 {"/firmware-slot[name='A']/name", "A"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200267 {"/firmware-slot[name='A']/is-booted-now", "false"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100268 {"/firmware-slot[name='A']/version", "v4-104-ge80fcd4"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200269 {"/firmware-slot[name='A']/will-boot-next", "false"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100270 {"/firmware-slot[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200271 {"/firmware-slot[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100272 {"/firmware-slot[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100273 {"/firmware-slot[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200274 {"/firmware-slot[name='B']/is-booted-now", "true"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100275 {"/firmware-slot[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200276 {"/firmware-slot[name='B']/will-boot-next", "true"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100277 {"/installation", ""},
278 {"/installation/message", ""},
279 {"/installation/status", "in-progress"},
280 });
281 }
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100282 }
283 }
Jan Kundrát3795cab2022-07-13 18:08:19 +0200284
285 SECTION("marking FW slots") {
286 auto rpcInput = client.getContext().newPath("/czechlight-system:firmware/firmware-slot[name='A']/set-active-after-reboot");
287 {
288 REQUIRE_CALL(raucServer, impl_Mark("active", "rootfs.0")).IN_SEQUENCE(seq1);
289 REQUIRE(client.sendRPC(rpcInput).child() == std::nullopt);
290 }
291
292 rpcInput = client.getContext().newPath("/czechlight-system:firmware/firmware-slot[name='B']/set-active-after-reboot");
293 {
294 REQUIRE_CALL(raucServer, impl_Mark("active", "rootfs.1")).IN_SEQUENCE(seq1);
295 REQUIRE(client.sendRPC(rpcInput).child() == std::nullopt);
296 }
297
298 rpcInput = client.getContext().newPath("/czechlight-system:firmware/firmware-slot[name='B']/set-unhealthy");
299 {
300 REQUIRE_CALL(raucServer, impl_Mark("bad", "rootfs.1")).IN_SEQUENCE(seq1);
301 REQUIRE(client.sendRPC(rpcInput).child() == std::nullopt);
302 }
303
304 waitForCompletionAndBitMore(seq1);
305 }
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100306}
Tomáš Pecka825542f2021-02-24 14:00:10 +0100307
308TEST_CASE("Firmware in czechlight-system, slot status")
309{
310 trompeloeil::sequence seq1;
311
312 TEST_SYSREPO_INIT_LOGS;
313 TEST_SYSREPO_INIT;
314 TEST_SYSREPO_INIT_CLIENT;
315
316 auto dbusServerConnection = sdbus::createSessionBusConnection("de.pengutronix.rauc");
317 auto dbusClientConnectionSignals = sdbus::createSessionBusConnection();
318 auto dbusClientConnectionMethods = sdbus::createSessionBusConnection();
319 dbusClientConnectionSignals->enterEventLoopAsync();
320 dbusClientConnectionMethods->enterEventLoopAsync();
321 dbusServerConnection->enterEventLoopAsync();
322
323 std::map<std::string, velia::system::RAUC::SlotProperties> dbusRaucStatus;
324 std::map<std::string, std::string> expected;
325
326 SECTION("Complete data")
327 {
328 dbusRaucStatus = {
329 {"rootfs.1", {
330 {"activated.count", uint32_t {39}},
331 {"activated.timestamp", "2021-01-13T17:20:18Z"},
332 {"bootname", "B"},
333 {"boot-status", "good"},
334 {"bundle.compatible", "czechlight-clearfog"},
335 {"bundle.version", "v4-103-g34d2f48"},
336 {"class", "rootfs"},
337 {"device", "/dev/mmcblk0p3"},
338 {"installed.count", uint32_t {39}},
339 {"installed.timestamp", "2021-01-13T17:20:15Z"},
340 {"mountpoint", "/"},
341 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
342 {"size", uint64_t {45601892}},
343 {"state", "booted"},
344 {"status", "ok"},
345 {"type", "ext4"},
346 }},
347 {"rootfs.0", {
348 {"activated.count", uint32_t {41}},
349 {"activated.timestamp", "2021-01-13T17:15:54Z"},
350 {"bootname", "A"},
351 {"boot-status", "bad"},
352 {"bundle.compatible", "czechlight-clearfog"},
353 {"bundle.version", "v4-104-ge80fcd4"},
354 {"class", "rootfs"},
355 {"device", "/dev/mmcblk0p1"},
356 {"installed.count", uint32_t {41}},
357 {"installed.timestamp", "2021-01-13T17:15:50Z"},
358 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
359 {"size", uint64_t {45647664}},
360 {"state", "inactive"},
361 {"status", "ok"},
362 {"type", "ext4"},
363 }},
364 {"cfg.1", {
365 {"bundle.compatible", "czechlight-clearfog"},
366 {"bundle.version", "v4-103-g34d2f48"},
367 {"class", "cfg"},
368 {"device", "/dev/mmcblk0p4"},
369 {"installed.count", uint32_t {39}},
370 {"installed.timestamp", "2021-01-13T17:20:18Z"},
371 {"mountpoint", "/cfg"},
372 {"parent", "rootfs.1"},
373 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
374 {"size", uint64_t {108}},
375 {"state", "active"},
376 {"status", "ok"},
377 {"type", "ext4"},
378 }},
379 {"cfg.0", {
380 {"bundle.compatible", "czechlight-clearfog"},
381 {"bundle.version", "v4-104-ge80fcd4"},
382 {"class", "cfg"},
383 {"device", "/dev/mmcblk0p2"},
384 {"installed.count", uint32_t {41}},
385 {"installed.timestamp", "2021-01-13T17:15:54Z"},
386 {"parent", "rootfs.0"},
387 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
388 {"size", uint64_t {108}},
389 {"state", "inactive"},
390 {"status", "ok"},
391 {"type", "ext4"},
392 }},
393 };
394
395 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100396 {"[name='A']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200397 {"[name='A']/is-healthy", "false"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100398 {"[name='A']/installed", "2021-01-13T17:15:50-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100399 {"[name='A']/name", "A"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200400 {"[name='A']/is-booted-now", "false"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100401 {"[name='A']/version", "v4-104-ge80fcd4"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200402 {"[name='A']/will-boot-next", "false"},
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100403 {"[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200404 {"[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100405 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100406 {"[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200407 {"[name='B']/is-booted-now", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100408 {"[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200409 {"[name='B']/will-boot-next", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100410 };
411 }
412
413 SECTION("Missing data in rootfs.0")
414 {
415 dbusRaucStatus = {
416 {"rootfs.1", {
417 {"activated.count", uint32_t {39}},
418 {"activated.timestamp", "2021-01-13T17:20:18Z"},
419 {"bootname", "B"},
420 {"boot-status", "good"},
421 {"bundle.compatible", "czechlight-clearfog"},
422 {"bundle.version", "v4-103-g34d2f48"},
423 {"class", "rootfs"},
424 {"device", "/dev/mmcblk0p3"},
425 {"installed.count", uint32_t {39}},
426 {"installed.timestamp", "2021-01-13T17:20:15Z"},
427 {"mountpoint", "/"},
428 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
429 {"size", uint64_t {45601892}},
430 {"state", "booted"},
431 {"status", "ok"},
432 {"type", "ext4"},
433 }},
434 {"rootfs.0", {
435 {"bootname", "A"},
436 {"boot-status", "bad"},
437 {"class", "rootfs"},
438 {"device", "/dev/mmcblk0p1"},
439 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
440 {"size", uint64_t {45647664}},
441 {"state", "inactive"},
442 {"status", "ok"},
443 {"type", "ext4"},
444 }},
445 };
446
447 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100448 {"[name='A']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200449 {"[name='A']/is-healthy", "false"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100450 {"[name='A']/name", "A"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200451 {"[name='A']/is-booted-now", "false"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200452 {"[name='A']/will-boot-next", "false"},
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100453 {"[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200454 {"[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100455 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100456 {"[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200457 {"[name='B']/is-booted-now", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100458 {"[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200459 {"[name='B']/will-boot-next", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100460 };
461 }
462
463 SECTION("Missing bootname in rootfs.0")
464 {
465 dbusRaucStatus = {
466 {"rootfs.1", {
467 {"activated.count", uint32_t {39}},
468 {"activated.timestamp", "2021-01-13T17:20:18Z"},
469 {"bootname", "B"},
470 {"boot-status", "good"},
471 {"bundle.compatible", "czechlight-clearfog"},
472 {"bundle.version", "v4-103-g34d2f48"},
473 {"class", "rootfs"},
474 {"device", "/dev/mmcblk0p3"},
475 {"installed.count", uint32_t {39}},
476 {"installed.timestamp", "2021-01-13T17:20:15Z"},
477 {"mountpoint", "/"},
478 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
479 {"size", uint64_t {45601892}},
480 {"state", "booted"},
481 {"status", "ok"},
482 {"type", "ext4"},
483 }},
484 {"rootfs.0", {
485 {"boot-status", "bad"},
486 {"class", "rootfs"},
487 {"device", "/dev/mmcblk0p1"},
488 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
489 {"size", uint64_t {45647664}},
490 {"state", "inactive"},
491 {"status", "ok"},
492 {"type", "ext4"},
493 }},
494 };
495
496 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100497 {"[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200498 {"[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100499 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100500 {"[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200501 {"[name='B']/is-booted-now", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100502 {"[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200503 {"[name='B']/will-boot-next", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100504 };
505 }
506
507 auto raucServer = DBusRAUCServer(*dbusServerConnection, "rootfs.1", dbusRaucStatus);
508 auto sysrepo = std::make_shared<velia::system::Firmware>(srConn, *dbusClientConnectionSignals, *dbusClientConnectionMethods);
509
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100510 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/firmware-slot", sysrepo::Datastore::Operational) == expected);
Tomáš Pecka825542f2021-02-24 14:00:10 +0100511}