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 AktualizrSecondary::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 AktualizrSecondary::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,
Hash(Hash::Type::kSha256, rev), 0, hardware_id,
"",
Delegation(), custom);
155 uptane_repo_.addTarget(rev, hardware_id, serial,
"");
156 uptane_repo_.signTargets();
158 return getCurrentMetadata();
164 boost::filesystem::load_string_file(director_dir_ /
"root.json", metadata.director_root);
165 boost::filesystem::load_string_file(director_dir_ /
"targets.json", metadata.director_targets);
167 boost::filesystem::load_string_file(imagerepo_dir_ /
"root.json", metadata.image_root);
168 boost::filesystem::load_string_file(imagerepo_dir_ /
"timestamp.json", metadata.image_timestamp);
169 boost::filesystem::load_string_file(imagerepo_dir_ /
"snapshot.json", metadata.image_snapshot);
170 boost::filesystem::load_string_file(imagerepo_dir_ /
"targets.json", metadata.image_targets);
175 std::shared_ptr<std::string> getImageData(
const std::string& targetname)
const {
176 auto image_data = std::make_shared<std::string>();
177 boost::filesystem::load_string_file(root_dir_ / targetname, *image_data);
183 boost::filesystem::path director_dir_{root_dir_ /
"repo/director"};
184 boost::filesystem::path imagerepo_dir_{root_dir_ /
"repo/repo"};
185 UptaneRepo uptane_repo_{root_dir_.Path(),
"",
""};
190 static const char* curOstreeRootfsRev(OstreeDeployment* ostree_depl) {
192 return sysroot_->getDeploymentRev();
195 static OstreeDeployment* curOstreeDeployment(OstreeSysroot* ostree_sysroot) {
196 (void)ostree_sysroot;
197 return sysroot_->getDeployment();
200 static void setOstreeRootfsTemplate(
const std::string& ostree_rootfs_template) {
201 ostree_rootfs_template_ = ostree_rootfs_template;
205 static void SetUpTestSuite() {
206 treehub_ = std::make_shared<Treehub>(
"tests/sota_tools/treehub_server.py");
207 sysroot_ = std::make_shared<OstreeRootfs>(ostree_rootfs_template_);
210 static void TearDownTestSuite() {
220 Uptane::RawMetaPack addTarget(
const std::string& rev =
"",
const std::string& hardware_id =
"",
221 const std::string& serial =
"") {
222 auto rev_to_apply = rev.empty() ? treehub_->curRev() : rev;
223 auto hw_id = hardware_id.empty() ? secondary_.hardwareID() : hardware_id;
224 auto serial_id = serial.empty() ? secondary_.serial() : serial;
226 uptane_repo_.addOstreeRev(rev, hw_id, serial_id);
228 return currentMetadata();
233 std::string getCredsToSend()
const {
234 std::map<std::string, std::string> creds_map = {
235 {
"ca.pem",
""}, {
"client.pem",
""}, {
"pkey.pem",
""}, {
"server.url", treehub_->url()}};
237 std::stringstream creads_strstream;
238 Utils::writeArchive(creds_map, creads_strstream);
240 return creads_strstream.str();
243 Hash treehubCurRevHash()
const {
return Hash(Hash::Type::kSha256, treehub_->curRev()); }
244 Hash sysrootCurRevHash()
const {
return Hash(Hash::Type::kSha256, sysroot_->getDeploymentRev()); }
245 const std::string& treehubCurRev()
const {
return treehub_->curRev(); }
248 static std::shared_ptr<Treehub> treehub_;
249 static std::string ostree_rootfs_template_;
250 static std::shared_ptr<OstreeRootfs> sysroot_;
256 std::shared_ptr<Treehub> SecondaryOstreeTest::treehub_{
nullptr};
257 std::string SecondaryOstreeTest::ostree_rootfs_template_{
"./build/ostree_repo"};
258 std::shared_ptr<OstreeRootfs> SecondaryOstreeTest::sysroot_{
nullptr};
261 EXPECT_TRUE(secondary_->putMetadata(addTarget(
"invalid-revision")));
262 EXPECT_FALSE(secondary_->sendFirmware(getCredsToSend()));
266 EXPECT_FALSE(secondary_->putMetadata(addTarget(
"",
"invalid-hardware-id",
"")));
270 EXPECT_FALSE(secondary_->putMetadata(addTarget(
"",
"",
"invalid-serial-id")));
276 EXPECT_TRUE(manifest.verifySignature(secondary_->getPublicKey()));
277 EXPECT_EQ(manifest.installedImageHash(), sysrootCurRevHash());
280 EXPECT_TRUE(secondary_->putMetadata(addDefaultTarget()));
286 EXPECT_TRUE(secondary_->sendFirmware(getCredsToSend()));
287 EXPECT_EQ(secondary_->install(treehubCurRev()), data::ResultCode::Numeric::kNeedCompletion);
290 EXPECT_TRUE(secondary_.getPendingVersion().MatchHash(treehubCurRevHash()));
292 manifest = secondary_->getManifest();
293 EXPECT_TRUE(manifest.verifySignature(secondary_->getPublicKey()));
294 EXPECT_EQ(manifest.installedImageHash(), sysrootCurRevHash());
297 sysroot_->setNewDeploymentRev(treehubCurRev());
301 EXPECT_FALSE(secondary_.getPendingVersion().IsValid());
302 EXPECT_TRUE(secondary_.getCurrentVersion().MatchHash(treehubCurRevHash()));
303 manifest = secondary_->getManifest();
304 EXPECT_TRUE(manifest.verifySignature(secondary_->getPublicKey()));
305 EXPECT_EQ(manifest.installedImageHash(), treehubCurRevHash());
310 EXPECT_FALSE(secondary_.getPendingVersion().IsValid());
311 EXPECT_TRUE(secondary_.getCurrentVersion().MatchHash(treehubCurRevHash()));
312 manifest = secondary_->getManifest();
313 EXPECT_TRUE(manifest.verifySignature(secondary_->getPublicKey()));
314 EXPECT_EQ(manifest.installedImageHash(), treehubCurRevHash());
317 int main(
int argc,
char** argv) {
318 ::testing::InitGoogleTest(&argc, argv);
321 std::cerr <<
"Error: " << argv[0] <<
" <ostree rootfs path>\n";
325 SecondaryOstreeTest::setOstreeRootfsTemplate(argv[1]);
328 logger_set_threshold(boost::log::trivial::info);
330 return RUN_ALL_TESTS();
333 extern "C" OstreeDeployment* ostree_sysroot_get_booted_deployment(OstreeSysroot* ostree_sysroot) {
334 return SecondaryOstreeTest::curOstreeDeployment(ostree_sysroot);
337 extern "C" const char* ostree_deployment_get_csum(OstreeDeployment* ostree_deployment) {
338 return SecondaryOstreeTest::curOstreeRootfsRev(ostree_deployment);