1 #include <gtest/gtest.h>
5 #include "boost/algorithm/string/trim.hpp"
6 #include "boost/process.hpp"
8 #include "logging/logging.h"
9 #include "test_utils.h"
11 #include "aktualizr_secondary.h"
12 #include "aktualizr_secondary_factory.h"
13 #include "update_agent_ostree.h"
14 #include "uptane_repo.h"
18 Treehub(
const std::string& server_path)
19 : _port(TestUtils::getFreePort()),
20 _url(
"http://127.0.0.1:" + _port),
21 _process(server_path,
"-p", _port,
"-d", _root_dir.PathString(),
"-s0.5",
"--create") {
22 TestUtils::waitForServer(url() +
"/");
23 auto rev_process =
Process(
"ostree").run({
"rev-parse",
"--repo", _root_dir.PathString(),
"master"});
24 EXPECT_EQ(std::get<0>(rev_process), 0) << std::get<2>(rev_process);
25 _cur_rev = std::get<1>(rev_process);
26 boost::trim_right_if(_cur_rev, boost::is_any_of(
" \t\r\n"));
28 LOG_INFO <<
"Treehub is running on: " << _port <<
" current revision: " << _cur_rev;
33 _process.wait_for(std::chrono::seconds(10));
34 if (_process.running()) {
35 LOG_ERROR <<
"Failed to stop Treehub server";
37 LOG_INFO <<
"Treehub server has been stopped";
42 const std::string& url()
const {
return _url; }
43 const std::string& curRev()
const {
return _cur_rev; }
47 const std::string _port;
48 const std::string _url;
49 boost::process::child _process;
56 auto sysroot_copy =
Process(
"cp").run({
"-r", rootfs_template, getPath().c_str()});
57 EXPECT_EQ(std::get<0>(sysroot_copy), 0) << std::get<1>(sysroot_copy);
59 auto deployment_rev =
Process(
"ostree").run(
60 {
"rev-parse", std::string(
"--repo"), getPath().string() +
"/ostree/repo",
"generate-remote/generated"});
62 EXPECT_EQ(std::get<0>(deployment_rev), 0) << std::get<2>(deployment_rev);
64 _rev = std::get<1>(deployment_rev);
65 boost::trim_right_if(_rev, boost::is_any_of(
" \t\r\n"));
67 _deployment.reset(ostree_deployment_new(0, getOSName(), getDeploymentRev(), getDeploymentSerial(),
68 getDeploymentRev(), getDeploymentSerial()));
71 const boost::filesystem::path& getPath()
const {
return _sysroot_dir; }
72 const char* getDeploymentRev()
const {
return _rev.c_str(); }
73 int getDeploymentSerial()
const {
return 0; }
74 const char* getOSName()
const {
return _os_name.c_str(); }
76 OstreeDeployment* getDeployment()
const {
return _deployment.get(); }
77 void setNewDeploymentRev(
const std::string& new_rev) { _rev = new_rev; }
80 struct OstreeDeploymentDeleter {
81 void operator()(OstreeDeployment* e)
const { g_object_unref(reinterpret_cast<gpointer>(e)); }
85 const std::string _os_name{
"dummy-os"};
87 boost::filesystem::path _sysroot_dir{_tmp_dir /
"ostree-rootfs"};
89 std::unique_ptr<OstreeDeployment, OstreeDeploymentDeleter> _deployment;
97 _config.pacman.type = PACKAGE_MANAGER_OSTREE;
98 _config.pacman.os = sysroot.getOSName();
99 _config.pacman.sysroot = sysroot.getPath();
100 _config.pacman.ostree_server = treehub.url();
102 _config.bootloader.reboot_sentinel_dir = _storage_dir.Path();
103 _config.bootloader.reboot_sentinel_name =
"need_reboot";
105 _config.storage.path = _storage_dir.Path();
106 _config.storage.type = StorageType::kSqlite;
108 _storage = INvStorage::newStorage(_config.storage);
109 _secondary = AktualizrSecondaryFactory::create(_config, _storage);
113 Uptane::SecondaryInterface::Ptr& operator->() {
return _secondary; }
115 Uptane::Target getPendingVersion()
const {
return getVersion().first; }
117 Uptane::Target getCurrentVersion()
const {
return getVersion().second; }
119 std::pair<Uptane::Target, Uptane::Target> getVersion()
const {
120 boost::optional<Uptane::Target> current_target;
121 boost::optional<Uptane::Target> pending_target;
123 _storage->loadInstalledVersions(_secondary->getSerial().ToString(), ¤t_target, &pending_target);
125 return std::make_pair(!pending_target ? Uptane::Target::Unknown() : *pending_target,
126 !current_target ? Uptane::Target::Unknown() : *current_target);
129 std::string hardwareID()
const {
return _secondary->getHwId().ToString(); }
131 std::string serial()
const {
return _secondary->getSerial().ToString(); }
134 boost::filesystem::remove(_storage_dir / _config.bootloader.reboot_sentinel_name);
135 _secondary = AktualizrSecondaryFactory::create(_config, _storage);
141 std::shared_ptr<INvStorage> _storage;
142 Uptane::SecondaryInterface::Ptr _secondary;
149 Metadata addOstreeRev(
const std::string& rev,
const std::string& hardware_id,
const std::string& serial) {
151 auto custom = Json::Value();
152 custom[
"targetFormat"] =
"OSTREE";
153 _uptane_repo.addCustomImage(rev,
Uptane::Hash(Uptane::Hash::Type::kSha256, rev), 0, hardware_id,
"",
Delegation(),
156 _uptane_repo.addTarget(rev, hardware_id, serial,
"");
157 _uptane_repo.signTargets();
159 return getCurrentMetadata();
165 boost::filesystem::load_string_file(_director_dir /
"root.json", metadata.director_root);
166 boost::filesystem::load_string_file(_director_dir /
"targets.json", metadata.director_targets);
168 boost::filesystem::load_string_file(_imagerepo_dir /
"root.json", metadata.image_root);
169 boost::filesystem::load_string_file(_imagerepo_dir /
"timestamp.json", metadata.image_timestamp);
170 boost::filesystem::load_string_file(_imagerepo_dir /
"snapshot.json", metadata.image_snapshot);
171 boost::filesystem::load_string_file(_imagerepo_dir /
"targets.json", metadata.image_targets);
176 std::shared_ptr<std::string> getImageData(
const std::string& targetname)
const {
177 auto image_data = std::make_shared<std::string>();
178 boost::filesystem::load_string_file(_root_dir / targetname, *image_data);
184 boost::filesystem::path _director_dir{_root_dir /
"repo/director"};
185 boost::filesystem::path _imagerepo_dir{_root_dir /
"repo/repo"};
186 UptaneRepo _uptane_repo{_root_dir.Path(),
"",
""};
191 static const char* curOstreeRootfsRev(OstreeDeployment* ostree_depl) {
193 return _sysroot->getDeploymentRev();
196 static OstreeDeployment* curOstreeDeployment(OstreeSysroot* ostree_sysroot) {
197 (void)ostree_sysroot;
198 return _sysroot->getDeployment();
201 static void setOstreeRootfsTemplate(
const std::string& ostree_rootfs_template) {
202 _ostree_rootfs_template = ostree_rootfs_template;
206 static void SetUpTestSuite() {
207 _treehub = std::make_shared<Treehub>(
"tests/sota_tools/treehub_server.py");
208 _sysroot = std::make_shared<OstreeRootfs>(_ostree_rootfs_template);
211 static void TearDownTestSuite() {
221 Uptane::RawMetaPack addTarget(
const std::string& rev =
"",
const std::string& hardware_id =
"",
222 const std::string& serial =
"") {
223 auto rev_to_apply = rev.empty() ? _treehub->curRev() : rev;
224 auto hw_id = hardware_id.empty() ? _secondary.hardwareID() : hardware_id;
225 auto serial_id = serial.empty() ? _secondary.serial() : serial;
227 _uptane_repo.addOstreeRev(rev, hw_id, serial_id);
229 return currentMetadata();
234 std::string getCredsToSend()
const {
235 std::map<std::string, std::string> creds_map = {
236 {
"ca.pem",
""}, {
"client.pem",
""}, {
"pkey.pem",
""}, {
"server.url", _treehub->url()}};
238 std::stringstream creads_strstream;
239 Utils::writeArchive(creds_map, creads_strstream);
241 return creads_strstream.str();
246 return Uptane::Hash(Uptane::Hash::Type::kSha256, _sysroot->getDeploymentRev());
248 const std::string& treehubCurRev()
const {
return _treehub->curRev(); }
251 static std::shared_ptr<Treehub> _treehub;
252 static std::string _ostree_rootfs_template;
253 static std::shared_ptr<OstreeRootfs> _sysroot;
259 std::shared_ptr<Treehub> SecondaryOstreeTest::_treehub{
nullptr};
260 std::string SecondaryOstreeTest::_ostree_rootfs_template{
"./build/ostree_repo"};
261 std::shared_ptr<OstreeRootfs> SecondaryOstreeTest::_sysroot{
nullptr};
264 EXPECT_TRUE(_secondary->putMetadata(addTarget(
"invalid-revision")));
265 EXPECT_FALSE(_secondary->sendFirmware(getCredsToSend()));
269 EXPECT_FALSE(_secondary->putMetadata(addTarget(
"",
"invalid-hardware-id",
"")));
273 EXPECT_FALSE(_secondary->putMetadata(addTarget(
"",
"",
"invalid-serial-id")));
279 EXPECT_TRUE(manifest.verifySignature(_secondary->getPublicKey()));
280 EXPECT_EQ(manifest.installedImageHash(), sysrootCurRevHash());
283 EXPECT_TRUE(_secondary->putMetadata(addDefaultTarget()));
289 EXPECT_TRUE(_secondary->sendFirmware(getCredsToSend()));
290 EXPECT_EQ(_secondary->install(treehubCurRev()), data::ResultCode::Numeric::kNeedCompletion);
293 EXPECT_TRUE(_secondary.getPendingVersion().MatchHash(treehubCurRevHash()));
295 manifest = _secondary->getManifest();
296 EXPECT_TRUE(manifest.verifySignature(_secondary->getPublicKey()));
297 EXPECT_EQ(manifest.installedImageHash(), sysrootCurRevHash());
300 _sysroot->setNewDeploymentRev(treehubCurRev());
304 EXPECT_FALSE(_secondary.getPendingVersion().IsValid());
305 EXPECT_TRUE(_secondary.getCurrentVersion().MatchHash(treehubCurRevHash()));
306 manifest = _secondary->getManifest();
307 EXPECT_TRUE(manifest.verifySignature(_secondary->getPublicKey()));
308 EXPECT_EQ(manifest.installedImageHash(), treehubCurRevHash());
313 EXPECT_FALSE(_secondary.getPendingVersion().IsValid());
314 EXPECT_TRUE(_secondary.getCurrentVersion().MatchHash(treehubCurRevHash()));
315 manifest = _secondary->getManifest();
316 EXPECT_TRUE(manifest.verifySignature(_secondary->getPublicKey()));
317 EXPECT_EQ(manifest.installedImageHash(), treehubCurRevHash());
320 int main(
int argc,
char** argv) {
321 ::testing::InitGoogleTest(&argc, argv);
324 std::cerr <<
"Error: " << argv[0] <<
" <ostree rootfs path>\n";
328 SecondaryOstreeTest::setOstreeRootfsTemplate(argv[1]);
331 logger_set_threshold(boost::log::trivial::info);
333 return RUN_ALL_TESTS();
336 extern "C" OstreeDeployment* ostree_sysroot_get_booted_deployment(OstreeSysroot* ostree_sysroot) {
337 return SecondaryOstreeTest::curOstreeDeployment(ostree_sysroot);
340 extern "C" const char* ostree_deployment_get_csum(OstreeDeployment* ostree_deployment) {
341 return SecondaryOstreeTest::curOstreeRootfsRev(ostree_deployment);