Aktualizr
C++ SOTA Client
uptane_vector_tests.cc
1 #include <gtest/gtest.h>
2 
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <cstdlib>
6 #include <iostream>
7 #include <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "http/httpclient.h"
12 #include "libaktualizr/config.h"
13 #include "logging/logging.h"
14 #include "primary/sotauptaneclient.h"
15 #include "storage/invstorage.h"
16 #include "utilities/utils.h"
17 
18 std::string address;
19 
21  public:
22  VectorWrapper(Json::Value vector) : vector_(std::move(vector)) {}
23 
24  bool matchError(const Uptane::Exception& e) {
25  auto me = [this, &e](const std::string r) {
26  if (vector_[r]["update"]["err_msg"].asString() == e.what()) {
27  return true;
28  }
29  const Json::Value& targets = vector_[r]["targets"];
30  for (Json::Value::const_iterator it = targets.begin(); it != targets.end(); it++) {
31  if ((*it)["err_msg"].asString() == e.what()) {
32  return true;
33  }
34  }
35  return false;
36  };
37  if (me("director") || me("image_repo")) {
38  return true;
39  }
40  std::cout << "aktualizr failed with unmatched exception " << typeid(e).name() << ": " << e.what() << "\n";
41  std::cout << "Expected error: " << vector_ << "\n";
42  return false;
43  }
44 
45  bool shouldFail() {
46  bool should_fail = false;
47  if (!vector_["director"]["update"]["is_success"].asBool() ||
48  !vector_["image_repo"]["update"]["is_success"].asBool()) {
49  should_fail = true;
50  } else {
51  for (const auto& t : vector_["director"]["targets"]) {
52  if (!t["is_success"].asBool()) {
53  should_fail = true;
54  break;
55  }
56  }
57  for (const auto& t : vector_["image_repo"]["targets"]) {
58  if (!t["is_success"].asBool()) {
59  should_fail = true;
60  break;
61  }
62  }
63  }
64  return should_fail;
65  }
66 
67  void printExpectedFailure() {
68  std::cout << "No exceptions occurred, but expected ";
69  if (!vector_["director"]["update"]["is_success"].asBool()) {
70  std::cout << "exception from director: '" << vector_["director"]["update"]["err"]
71  << " with message: " << vector_["director"]["update"]["err_msg"] << "\n";
72  } else if (!vector_["image_repo"]["update"]["is_success"].asBool()) {
73  std::cout << "exception from image_repo: '" << vector_["image_repo"]["update"]["err"]
74  << " with message: " << vector_["image_repo"]["update"]["err_msg"] << "\n";
75  } else {
76  std::cout << "an exception while fetching Targets metadata.\n";
77  }
78  }
79 
80  private:
81  Json::Value vector_;
82 };
83 
84 class UptaneVector : public ::testing::TestWithParam<std::string> {};
85 
86 /**
87  * Check that aktualizr fails on expired metadata.
88  * RecordProperty("zephyr_key", "REQ-150,TST-49");
89  * Check that aktualizr fails on bad threshold.
90  * RecordProperty("zephyr_key", "REQ-153,TST-52");
91  */
92 TEST_P(UptaneVector, Test) {
93  const std::string test_name = GetParam();
94  std::cout << "Running test vector " << test_name << "\n";
95 
96  TemporaryDirectory temp_dir;
97  Config config;
98  config.provision.primary_ecu_serial = "test_primary_ecu_serial";
99  config.provision.primary_ecu_hardware_id = "test_primary_hardware_id";
100  config.uptane.director_server = address + test_name + "/director";
101  config.uptane.repo_server = address + test_name + "/image_repo";
102  config.storage.path = temp_dir.Path();
103  config.storage.uptane_metadata_path = utils::BasedPath(temp_dir.Path() / "metadata");
104  config.pacman.images_path = temp_dir.Path() / "images";
105  config.pacman.type = PACKAGE_MANAGER_NONE;
106  logger_set_threshold(boost::log::trivial::trace);
107 
108  auto storage = INvStorage::newStorage(config.storage);
109  auto uptane_client = std_::make_unique<SotaUptaneClient>(config, storage);
110  Uptane::EcuSerial ecu_serial(config.provision.primary_ecu_serial);
111  Uptane::HardwareIdentifier hw_id(config.provision.primary_ecu_hardware_id);
112  uptane_client->primary_ecu_serial_ = ecu_serial;
113  uptane_client->primary_ecu_hw_id_ = hw_id;
114  Uptane::EcuMap ecu_map{{ecu_serial, hw_id}};
115  Uptane::Target target("test_filename", ecu_map, {{Hash::Type::kSha256, "sha256"}}, 1, "");
116  storage->saveInstalledVersion(ecu_serial.ToString(), target, InstalledVersionUpdateMode::kCurrent);
117 
118  HttpClient http_client;
119  while (true) {
120  HttpResponse response = http_client.post(address + test_name + "/step", Json::Value());
121  if (response.http_status_code == 204) {
122  return;
123  }
124  const auto vector_json(response.getJson());
125  std::cout << "VECTOR: " << vector_json;
126  VectorWrapper vector(vector_json);
127 
128  bool should_fail = vector.shouldFail();
129 
130  try {
131  /* Fetch metadata from the Director.
132  * Check metadata from the Director.
133  * Identify targets for known ECUs.
134  * Fetch metadata from the Image repo.
135  * Check metadata from the Image repo.
136  *
137  * It would be simpler to just call fetchMeta() here, but that calls
138  * putManifestSimple(), which will fail here. */
139  uptane_client->uptaneIteration(nullptr, nullptr);
140 
141  result::UpdateCheck updates = uptane_client->checkUpdates();
142  if (updates.status == result::UpdateStatus::kError) {
143  ASSERT_TRUE(should_fail) << "checkUpdates unexpectedly failed.";
144  if (uptane_client->getLastException() != nullptr) {
145  std::rethrow_exception(uptane_client->getLastException());
146  }
147  }
148  if (updates.ecus_count > 0) {
149  /* Download a binary package.
150  * Verify a binary package. */
151  result::Download result = uptane_client->downloadImages(updates.updates);
152  if (result.status != result::DownloadStatus::kSuccess) {
153  ASSERT_TRUE(should_fail) << "downloadImages unexpectedly failed.";
154  if (uptane_client->getLastException() != nullptr) {
155  std::rethrow_exception(uptane_client->getLastException());
156  }
157  }
158  }
159 
160  } catch (const Uptane::Exception& e) {
161  ASSERT_TRUE(vector.matchError(e)) << "libaktualizr threw a different exception than expected!";
162  continue;
163  } catch (const std::exception& e) {
164  FAIL() << "libaktualizr failed with unrecognized exception " << typeid(e).name() << ": " << e.what();
165  }
166 
167  if (should_fail) {
168  vector.printExpectedFailure();
169  FAIL();
170  }
171  }
172  FAIL() << "Step sequence unexpectedly aborted.";
173 }
174 
175 std::vector<std::string> GetVectors() {
176  HttpClient http_client;
177  const Json::Value json_vectors = http_client.get(address, HttpInterface::kNoLimit).getJson();
178  std::vector<std::string> vectors;
179  for (Json::ValueConstIterator it = json_vectors.begin(); it != json_vectors.end(); it++) {
180  vectors.emplace_back((*it).asString());
181  }
182  return vectors;
183 }
184 
185 INSTANTIATE_TEST_SUITE_P(UptaneVectorSuite, UptaneVector, ::testing::ValuesIn(GetVectors()));
186 
187 int main(int argc, char* argv[]) {
188  logger_init();
189  logger_set_threshold(boost::log::trivial::trace);
190 
191  if (argc < 2) {
192  std::cerr << "This program is intended to be run from run_vector_tests.sh!\n";
193  return 1;
194  }
195 
196  /* Use ports to distinguish both the server connection and local storage so
197  * that parallel runs of this code don't cause problems that are difficult to
198  * debug. */
199  const std::string port = argv[1];
200  address = "http://localhost:" + port + "/";
201 
202  ::testing::InitGoogleTest(&argc, argv);
203  return RUN_ALL_TESTS();
204 }
VectorWrapper
Definition: uptane_vector_tests.cc:20
UptaneVector
Definition: uptane_vector_tests.cc:84
result::UpdateCheck
Container for information about available updates.
Definition: results.h:37
Uptane::HardwareIdentifier
Definition: types.h:315
HttpResponse
Definition: httpinterface.h:17
utils::BasedPath
The BasedPath class Can represent an absolute or relative path, only readable through the BasePath::g...
Definition: types.h:31
Config
Configuration object for an aktualizr instance running on a Primary ECU.
Definition: config.h:208
Uptane::EcuSerial
Definition: types.h:346
HttpClient
Definition: httpclient.h:28
result::Download
Container for information about downloading an update.
Definition: results.h:116
Uptane::Exception
Definition: exceptions.h:10
TemporaryDirectory
Definition: utils.h:82
result
Results of libaktualizr API calls.
Definition: results.h:12
Uptane::Target
Definition: types.h:379