blob: f4920eaaba90fc61a2b3c35aa897bc89fc3a0635 [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),
Jan Kundrát19d28912024-10-29 16:06:06 +0100252 "Couldn't send RPC: SR_ERR_OPERATION_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"
Jan Kundrát315838e2023-06-05 19:45:50 +0200256 " NETCONF: application: operation-failed: Already processing a different method",
257 sysrepo::ErrorWithCode);
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100258 }
259
260 SECTION("Firmware slot data are available")
261 {
262 // 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 +0100263 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware", sysrepo::Datastore::Operational) == std::map<std::string, std::string> {
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100264 {"/firmware-slot[name='A']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200265 {"/firmware-slot[name='A']/is-healthy", "false"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100266 {"/firmware-slot[name='A']/installed", "2021-01-13T17:15:50-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100267 {"/firmware-slot[name='A']/name", "A"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200268 {"/firmware-slot[name='A']/is-booted-now", "false"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100269 {"/firmware-slot[name='A']/version", "v4-104-ge80fcd4"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200270 {"/firmware-slot[name='A']/will-boot-next", "false"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100271 {"/firmware-slot[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200272 {"/firmware-slot[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100273 {"/firmware-slot[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100274 {"/firmware-slot[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200275 {"/firmware-slot[name='B']/is-booted-now", "true"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100276 {"/firmware-slot[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200277 {"/firmware-slot[name='B']/will-boot-next", "true"},
Tomáš Pecka92b14e42021-01-27 17:33:11 +0100278 {"/installation", ""},
279 {"/installation/message", ""},
280 {"/installation/status", "in-progress"},
281 });
282 }
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100283 }
284 }
Jan Kundrát3795cab2022-07-13 18:08:19 +0200285
286 SECTION("marking FW slots") {
287 auto rpcInput = client.getContext().newPath("/czechlight-system:firmware/firmware-slot[name='A']/set-active-after-reboot");
288 {
289 REQUIRE_CALL(raucServer, impl_Mark("active", "rootfs.0")).IN_SEQUENCE(seq1);
290 REQUIRE(client.sendRPC(rpcInput).child() == std::nullopt);
291 }
292
293 rpcInput = client.getContext().newPath("/czechlight-system:firmware/firmware-slot[name='B']/set-active-after-reboot");
294 {
295 REQUIRE_CALL(raucServer, impl_Mark("active", "rootfs.1")).IN_SEQUENCE(seq1);
296 REQUIRE(client.sendRPC(rpcInput).child() == std::nullopt);
297 }
298
299 rpcInput = client.getContext().newPath("/czechlight-system:firmware/firmware-slot[name='B']/set-unhealthy");
300 {
301 REQUIRE_CALL(raucServer, impl_Mark("bad", "rootfs.1")).IN_SEQUENCE(seq1);
302 REQUIRE(client.sendRPC(rpcInput).child() == std::nullopt);
303 }
304
305 waitForCompletionAndBitMore(seq1);
306 }
Tomáš Peckacb7a5f82021-01-20 15:12:00 +0100307}
Tomáš Pecka825542f2021-02-24 14:00:10 +0100308
309TEST_CASE("Firmware in czechlight-system, slot status")
310{
311 trompeloeil::sequence seq1;
312
313 TEST_SYSREPO_INIT_LOGS;
314 TEST_SYSREPO_INIT;
315 TEST_SYSREPO_INIT_CLIENT;
316
317 auto dbusServerConnection = sdbus::createSessionBusConnection("de.pengutronix.rauc");
318 auto dbusClientConnectionSignals = sdbus::createSessionBusConnection();
319 auto dbusClientConnectionMethods = sdbus::createSessionBusConnection();
320 dbusClientConnectionSignals->enterEventLoopAsync();
321 dbusClientConnectionMethods->enterEventLoopAsync();
322 dbusServerConnection->enterEventLoopAsync();
323
324 std::map<std::string, velia::system::RAUC::SlotProperties> dbusRaucStatus;
325 std::map<std::string, std::string> expected;
326
327 SECTION("Complete data")
328 {
329 dbusRaucStatus = {
330 {"rootfs.1", {
331 {"activated.count", uint32_t {39}},
332 {"activated.timestamp", "2021-01-13T17:20:18Z"},
333 {"bootname", "B"},
334 {"boot-status", "good"},
335 {"bundle.compatible", "czechlight-clearfog"},
336 {"bundle.version", "v4-103-g34d2f48"},
337 {"class", "rootfs"},
338 {"device", "/dev/mmcblk0p3"},
339 {"installed.count", uint32_t {39}},
340 {"installed.timestamp", "2021-01-13T17:20:15Z"},
341 {"mountpoint", "/"},
342 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
343 {"size", uint64_t {45601892}},
344 {"state", "booted"},
345 {"status", "ok"},
346 {"type", "ext4"},
347 }},
348 {"rootfs.0", {
349 {"activated.count", uint32_t {41}},
350 {"activated.timestamp", "2021-01-13T17:15:54Z"},
351 {"bootname", "A"},
352 {"boot-status", "bad"},
353 {"bundle.compatible", "czechlight-clearfog"},
354 {"bundle.version", "v4-104-ge80fcd4"},
355 {"class", "rootfs"},
356 {"device", "/dev/mmcblk0p1"},
357 {"installed.count", uint32_t {41}},
358 {"installed.timestamp", "2021-01-13T17:15:50Z"},
359 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
360 {"size", uint64_t {45647664}},
361 {"state", "inactive"},
362 {"status", "ok"},
363 {"type", "ext4"},
364 }},
365 {"cfg.1", {
366 {"bundle.compatible", "czechlight-clearfog"},
367 {"bundle.version", "v4-103-g34d2f48"},
368 {"class", "cfg"},
369 {"device", "/dev/mmcblk0p4"},
370 {"installed.count", uint32_t {39}},
371 {"installed.timestamp", "2021-01-13T17:20:18Z"},
372 {"mountpoint", "/cfg"},
373 {"parent", "rootfs.1"},
374 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
375 {"size", uint64_t {108}},
376 {"state", "active"},
377 {"status", "ok"},
378 {"type", "ext4"},
379 }},
380 {"cfg.0", {
381 {"bundle.compatible", "czechlight-clearfog"},
382 {"bundle.version", "v4-104-ge80fcd4"},
383 {"class", "cfg"},
384 {"device", "/dev/mmcblk0p2"},
385 {"installed.count", uint32_t {41}},
386 {"installed.timestamp", "2021-01-13T17:15:54Z"},
387 {"parent", "rootfs.0"},
388 {"sha256", "5ca1b6c461fc194055d52b181f57c63dc1d34c19d041f6395e6f6abc039692bb"},
389 {"size", uint64_t {108}},
390 {"state", "inactive"},
391 {"status", "ok"},
392 {"type", "ext4"},
393 }},
394 };
395
396 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100397 {"[name='A']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200398 {"[name='A']/is-healthy", "false"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100399 {"[name='A']/installed", "2021-01-13T17:15:50-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100400 {"[name='A']/name", "A"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200401 {"[name='A']/is-booted-now", "false"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100402 {"[name='A']/version", "v4-104-ge80fcd4"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200403 {"[name='A']/will-boot-next", "false"},
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100404 {"[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200405 {"[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100406 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100407 {"[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200408 {"[name='B']/is-booted-now", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100409 {"[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200410 {"[name='B']/will-boot-next", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100411 };
412 }
413
414 SECTION("Missing data in rootfs.0")
415 {
416 dbusRaucStatus = {
417 {"rootfs.1", {
418 {"activated.count", uint32_t {39}},
419 {"activated.timestamp", "2021-01-13T17:20:18Z"},
420 {"bootname", "B"},
421 {"boot-status", "good"},
422 {"bundle.compatible", "czechlight-clearfog"},
423 {"bundle.version", "v4-103-g34d2f48"},
424 {"class", "rootfs"},
425 {"device", "/dev/mmcblk0p3"},
426 {"installed.count", uint32_t {39}},
427 {"installed.timestamp", "2021-01-13T17:20:15Z"},
428 {"mountpoint", "/"},
429 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
430 {"size", uint64_t {45601892}},
431 {"state", "booted"},
432 {"status", "ok"},
433 {"type", "ext4"},
434 }},
435 {"rootfs.0", {
436 {"bootname", "A"},
437 {"boot-status", "bad"},
438 {"class", "rootfs"},
439 {"device", "/dev/mmcblk0p1"},
440 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
441 {"size", uint64_t {45647664}},
442 {"state", "inactive"},
443 {"status", "ok"},
444 {"type", "ext4"},
445 }},
446 };
447
448 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100449 {"[name='A']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200450 {"[name='A']/is-healthy", "false"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100451 {"[name='A']/name", "A"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200452 {"[name='A']/is-booted-now", "false"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200453 {"[name='A']/will-boot-next", "false"},
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100454 {"[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200455 {"[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100456 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100457 {"[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200458 {"[name='B']/is-booted-now", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100459 {"[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200460 {"[name='B']/will-boot-next", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100461 };
462 }
463
464 SECTION("Missing bootname in rootfs.0")
465 {
466 dbusRaucStatus = {
467 {"rootfs.1", {
468 {"activated.count", uint32_t {39}},
469 {"activated.timestamp", "2021-01-13T17:20:18Z"},
470 {"bootname", "B"},
471 {"boot-status", "good"},
472 {"bundle.compatible", "czechlight-clearfog"},
473 {"bundle.version", "v4-103-g34d2f48"},
474 {"class", "rootfs"},
475 {"device", "/dev/mmcblk0p3"},
476 {"installed.count", uint32_t {39}},
477 {"installed.timestamp", "2021-01-13T17:20:15Z"},
478 {"mountpoint", "/"},
479 {"sha256", "07b30d065c7aad64d2006ce99fd339c929d3ca97b666fca4584b9ef726469fc4"},
480 {"size", uint64_t {45601892}},
481 {"state", "booted"},
482 {"status", "ok"},
483 {"type", "ext4"},
484 }},
485 {"rootfs.0", {
486 {"boot-status", "bad"},
487 {"class", "rootfs"},
488 {"device", "/dev/mmcblk0p1"},
489 {"sha256", "6d81e8f341edd17c127811f7347c7e23d18c2fc25c0bdc29ac56999cc9c25629"},
490 {"size", uint64_t {45647664}},
491 {"state", "inactive"},
492 {"status", "ok"},
493 {"type", "ext4"},
494 }},
495 };
496
497 expected = {
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100498 {"[name='B']", ""},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200499 {"[name='B']/is-healthy", "true"},
Václav Kubernátb7f26352021-11-26 14:58:33 +0100500 {"[name='B']/installed", "2021-01-13T17:20:15-00:00"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100501 {"[name='B']/name", "B"},
Jan Kundrát58b39ae2022-07-08 18:54:10 +0200502 {"[name='B']/is-booted-now", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100503 {"[name='B']/version", "v4-103-g34d2f48"},
Jan Kundráte55b56b2022-07-13 12:51:44 +0200504 {"[name='B']/will-boot-next", "true"},
Tomáš Pecka825542f2021-02-24 14:00:10 +0100505 };
506 }
507
508 auto raucServer = DBusRAUCServer(*dbusServerConnection, "rootfs.1", dbusRaucStatus);
509 auto sysrepo = std::make_shared<velia::system::Firmware>(srConn, *dbusClientConnectionSignals, *dbusClientConnectionMethods);
510
Václav Kubernát7efd6d52021-11-09 01:31:11 +0100511 REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware/firmware-slot", sysrepo::Datastore::Operational) == expected);
Tomáš Pecka825542f2021-02-24 14:00:10 +0100512}