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