Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
aktualizr_secondary_test.cc
1 #include <gtest/gtest.h>
2 
3 #include <boost/process.hpp>
4 
5 #include "aktualizr_secondary.h"
6 #include "aktualizr_secondary_factory.h"
7 #include "test_utils.h"
8 #include "uptane_repo.h"
9 
11  public:
14  config.pacman.type = PackageManager::kNone;
15 
16  config.storage.path = _storage_dir.Path();
17  config.storage.type = StorageType::kSqlite;
18 
19  _storage = INvStorage::newStorage(config.storage);
20  _secondary = AktualizrSecondaryFactory::create(config, _storage);
21  }
22 
23  public:
24  std::shared_ptr<AktualizrSecondary>& operator->() { return _secondary; }
25 
26  Uptane::Target getPendingVersion() const {
27  boost::optional<Uptane::Target> pending_target;
28 
29  _storage->loadInstalledVersions(_secondary->getSerial().ToString(), nullptr, &pending_target);
30  return *pending_target;
31  }
32 
33  std::string hardwareID() const { return _secondary->getHwId().ToString(); }
34 
35  std::string serial() const { return _secondary->getSerial().ToString(); }
36 
37  private:
38  TemporaryDirectory _storage_dir;
39  AktualizrSecondary::Ptr _secondary;
40  std::shared_ptr<INvStorage> _storage;
41 };
42 
43 class UptaneRepoWrapper {
44  public:
45  UptaneRepoWrapper() { _uptane_repo.generateRepo(KeyType::kED25519); }
46 
47  Metadata addImageFile(const std::string& targetname, const std::string& hardware_id, const std::string& serial,
48  bool add_and_sign_target = true) {
49  const auto image_file_path = _root_dir / targetname;
50  boost::filesystem::ofstream(image_file_path) << "some data";
51 
52  _uptane_repo.addImage(image_file_path, targetname, hardware_id, "", Delegation());
53  if (add_and_sign_target) {
54  _uptane_repo.addTarget(targetname, hardware_id, serial, "");
55  _uptane_repo.signTargets();
56  }
57 
58  return getCurrentMetadata();
59  }
60 
61  Uptane::RawMetaPack getCurrentMetadata() const {
62  Uptane::RawMetaPack metadata;
63 
64  boost::filesystem::load_string_file(_director_dir / "root.json", metadata.director_root);
65  boost::filesystem::load_string_file(_director_dir / "targets.json", metadata.director_targets);
66 
67  boost::filesystem::load_string_file(_imagerepo_dir / "root.json", metadata.image_root);
68  boost::filesystem::load_string_file(_imagerepo_dir / "timestamp.json", metadata.image_timestamp);
69  boost::filesystem::load_string_file(_imagerepo_dir / "snapshot.json", metadata.image_snapshot);
70  boost::filesystem::load_string_file(_imagerepo_dir / "targets.json", metadata.image_targets);
71 
72  return metadata;
73  }
74 
75  std::string getImageData(const std::string& targetname) const {
76  std::string image_data;
77  boost::filesystem::load_string_file(_root_dir / targetname, image_data);
78  return image_data;
79  }
80 
81  void refreshRoot(Uptane::RepositoryType repo) { _uptane_repo.refresh(repo, Uptane::Role::Root()); }
82 
83  private:
84  TemporaryDirectory _root_dir;
85  boost::filesystem::path _director_dir{_root_dir / "repo/director"};
86  boost::filesystem::path _imagerepo_dir{_root_dir / "repo/repo"};
87  UptaneRepo _uptane_repo{_root_dir.Path(), "", ""};
88 };
89 
90 class SecondaryTest : public ::testing::Test {
91  protected:
92  SecondaryTest() {
93  _uptane_repo.addImageFile(_default_target, _secondary->getHwId().ToString(), _secondary->getSerial().ToString());
94  }
95 
96  std::string getImageData(const std::string& targetname = _default_target) const {
97  return _uptane_repo.getImageData(targetname);
98  }
99 
100  protected:
101  static constexpr const char* const _default_target{"defaulttarget"};
102  AktualizrSecondaryWrapper _secondary;
103  UptaneRepoWrapper _uptane_repo;
104 };
105 
107  public ::testing::WithParamInterface<std::pair<Uptane::RepositoryType, Uptane::Role>> {
108  protected:
109  class MetadataInvalidator : public Metadata {
110  public:
111  MetadataInvalidator(const Uptane::RawMetaPack& valid_metadata, const Uptane::RepositoryType& repo,
112  const Uptane::Role& role)
113  : Metadata(valid_metadata), _repo_type(repo), _role(role) {}
114 
115  bool getRoleMetadata(std::string* result, const Uptane::RepositoryType& repo, const Uptane::Role& role,
116  Uptane::Version version) const override {
117  auto return_val = Metadata::getRoleMetadata(result, repo, role, version);
118  if (!(_repo_type == repo && _role == role)) {
119  return return_val;
120  }
121  (*result)[10] = 'f';
122  return true;
123  }
124 
125  private:
126  Uptane::RepositoryType _repo_type;
127  Uptane::Role _role;
128  };
129 
130  protected:
131  MetadataInvalidator currentMetadata() const {
132  return MetadataInvalidator(_uptane_repo.getCurrentMetadata(), GetParam().first, GetParam().second);
133  }
134 };
135 
136 /**
137  * Parameterized test,
138  * The parameter is std::pair<Uptane::RepositoryType, Uptane::Role> to indicate which metadata to malform
139  *
140  * see INSTANTIATE_TEST_SUITE_P for the test instantiations with concrete parameter values
141  */
142 TEST_P(SecondaryTestNegative, MalformedMetadaJson) { EXPECT_FALSE(_secondary->putMetadata(currentMetadata())); }
143 
144 /**
145  * Instantiates the parameterized test for each specified value of std::pair<Uptane::RepositoryType, Uptane::Role>
146  * the parameter value indicates which metadata to malform
147  */
148 INSTANTIATE_TEST_SUITE_P(SecondaryTestMalformedMetadata, SecondaryTestNegative,
149  ::testing::Values(std::make_pair(Uptane::RepositoryType::Director(), Uptane::Role::Root()),
150  std::make_pair(Uptane::RepositoryType::Director(), Uptane::Role::Targets()),
151  std::make_pair(Uptane::RepositoryType::Image(), Uptane::Role::Root()),
152  std::make_pair(Uptane::RepositoryType::Image(), Uptane::Role::Timestamp()),
153  std::make_pair(Uptane::RepositoryType::Image(), Uptane::Role::Snapshot()),
154  std::make_pair(Uptane::RepositoryType::Image(), Uptane::Role::Targets())));
155 
156 TEST_F(SecondaryTest, fullUptaneVerificationPositive) {
157  EXPECT_TRUE(_secondary->putMetadata(_uptane_repo.getCurrentMetadata()));
158  EXPECT_TRUE(_secondary->sendFirmware(getImageData()));
159  EXPECT_EQ(_secondary->install(_default_target), data::ResultCode::Numeric::kOk);
160 }
161 
162 TEST_F(SecondaryTest, TwoImagesAndOneTarget) {
163  // two images for the same ECU, just one of them is added as a target and signed
164  // default image and corresponding target has been already added, just add another image
165  _uptane_repo.addImageFile("second_image_00", _secondary->getHwId().ToString(), _secondary->getSerial().ToString(),
166  false);
167  EXPECT_TRUE(_secondary->putMetadata(_uptane_repo.getCurrentMetadata()));
168 }
169 
170 TEST_F(SecondaryTest, IncorrectTargetQuantity) {
171  {
172  // two targets for the same ECU
173  _uptane_repo.addImageFile("second_target", _secondary->getHwId().ToString(), _secondary->getSerial().ToString());
174 
175  EXPECT_FALSE(_secondary->putMetadata(_uptane_repo.getCurrentMetadata()));
176  }
177 
178  {
179  // zero targets for the ECU being tested
180  auto metadata =
181  UptaneRepoWrapper().addImageFile("mytarget", _secondary->getHwId().ToString(), "non-existing-serial");
182 
183  EXPECT_FALSE(_secondary->putMetadata(metadata));
184  }
185 
186  {
187  // zero targets for the ECU being tested
188  auto metadata =
189  UptaneRepoWrapper().addImageFile("mytarget", "non-existig-hwid", _secondary->getSerial().ToString());
190 
191  EXPECT_FALSE(_secondary->putMetadata(metadata));
192  }
193 }
194 
195 TEST_F(SecondaryTest, DirectorRootVersionIncremented) {
196  _uptane_repo.refreshRoot(Uptane::RepositoryType::Director());
197  EXPECT_TRUE(_secondary->putMetadata(_uptane_repo.getCurrentMetadata()));
198 }
199 
200 TEST_F(SecondaryTest, ImageRootVersionIncremented) {
201  _uptane_repo.refreshRoot(Uptane::RepositoryType::Image());
202  EXPECT_TRUE(_secondary->putMetadata(_uptane_repo.getCurrentMetadata()));
203 }
204 
205 TEST_F(SecondaryTest, InvalidImageFileSize) {
206  EXPECT_TRUE(_secondary->putMetadata(_uptane_repo.getCurrentMetadata()));
207  auto image_data = getImageData();
208  image_data.append("\n");
209  EXPECT_FALSE(_secondary->sendFirmware(image_data));
210 }
211 
212 TEST_F(SecondaryTest, InvalidImageData) {
213  EXPECT_TRUE(_secondary->putMetadata(_uptane_repo.getCurrentMetadata()));
214  auto image_data = getImageData();
215  image_data.operator[](3) = '0';
216  EXPECT_FALSE(_secondary->sendFirmware(image_data));
217 }
218 
219 // TODO: add more tests in case of file/binary based updates
220 
221 int main(int argc, char** argv) {
222  ::testing::InitGoogleTest(&argc, argv);
223 
224  logger_init();
225  logger_set_threshold(boost::log::trivial::info);
226 
227  return RUN_ALL_TESTS();
228 }
UptaneRepoWrapper
Definition: aktualizr_secondary_ostree_test.cc:145
Uptane::Version
Metadata version numbers.
Definition: tuf.h:116
AktualizrSecondaryConfig
Definition: aktualizr_secondary_config.h:39
Uptane::RawMetaPack
Definition: tuf.h:532
Uptane::RepositoryType
Definition: tuf.h:20
SecondaryTest
Definition: aktualizr_secondary_test.cc:90
SecondaryTestNegative::MetadataInvalidator
Definition: aktualizr_secondary_test.cc:109
SecondaryTestNegative
Definition: aktualizr_secondary_test.cc:106
TemporaryDirectory
Definition: utils.h:82
result
Results of libaktualizr API calls.
Definition: results.h:13
Uptane::Role
TUF Roles.
Definition: tuf.h:57
Uptane::Target
Definition: tuf.h:238
Metadata
Definition: aktualizr_secondary_metadata.h:8
UptaneRepo
Definition: uptane_repo.h:7
AktualizrSecondaryWrapper
Definition: aktualizr_secondary_ostree_test.cc:92
Delegation
Definition: repo.h:19