Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
uptane_network_test.cc
Go to the documentation of this file.
1 /**
2  * \file
3  *
4  * Check that aktualizr can complete provisioning after encountering various
5  * network issues.
6  */
7 #include <gtest/gtest.h>
8 #include <gtest/internal/gtest-port.h>
9 
10 #include <boost/process.hpp>
11 #include <fstream>
12 #include <iostream>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 
17 #include "http/httpclient.h"
18 #include "httpfake.h"
19 #include "logging/logging.h"
20 #include "primary/initializer.h"
21 #include "primary/sotauptaneclient.h"
22 #include "storage/invstorage.h"
23 #include "test_utils.h"
24 #include "uptane/uptanerepository.h"
25 #include "uptane_test_common.h"
26 #include "utilities/utils.h"
27 
28 Config conf("tests/config/basic.toml");
29 std::string port;
30 
31 bool doTestInit(StorageType storage_type, const std::string &device_register_state,
32  const std::string &ecu_register_state) {
33  LOG_INFO << "First attempt to initialize.";
34  TemporaryDirectory temp_dir;
35  conf.storage.type = storage_type;
36  conf.storage.path = temp_dir.Path();
37  conf.provision.expiry_days = device_register_state;
38  conf.provision.primary_ecu_serial = ecu_register_state;
39  const std::string good_url = conf.provision.server;
40  if (device_register_state == "noconnection") {
41  conf.provision.server = conf.provision.server.substr(conf.provision.server.size() - 2) + "11";
42  }
43 
44  bool result;
45  auto http = std::make_shared<HttpClient>();
46  auto store = INvStorage::newStorage(conf.storage);
47  {
48  KeyManager keys(store, conf.keymanagerConfig());
49  Initializer initializer(conf.provision, store, http, keys, {});
50  result = initializer.isSuccessful();
51  }
52  if (device_register_state != "noerrors" || ecu_register_state != "noerrors") {
53  EXPECT_FALSE(result);
54  LOG_INFO << "Second attempt to initialize.";
55  conf.provision.server = good_url;
56  conf.provision.expiry_days = "noerrors";
57  conf.provision.primary_ecu_serial = "noerrors";
58 
59  if (device_register_state == "noerrors" && ecu_register_state != "noerrors") {
60  // restore a "good" ecu serial in the ecu register fault injection case
61  // (the bad value has been cached in storage)
62  EcuSerials serials;
63  store->loadEcuSerials(&serials);
64  serials[0].first = Uptane::EcuSerial(conf.provision.primary_ecu_serial);
65  store->storeEcuSerials(serials);
66  }
67 
68  KeyManager keys(store, conf.keymanagerConfig());
69  Initializer initializer(conf.provision, store, http, keys, {});
70  result = initializer.isSuccessful();
71  }
72 
73  return result;
74 }
75 
76 TEST(UptaneNetwork, device_drop_request_sqlite) {
77  RecordProperty("zephyr_key", "OTA-991,TST-158");
78  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "drop_request", "noerrors"));
79 }
80 
81 TEST(UptaneNetwork, device_drop_body_sqlite) {
82  RecordProperty("zephyr_key", "OTA-991,TST-158");
83  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "drop_body", "noerrors"));
84 }
85 
86 TEST(UptaneNetwork, device_503_sqlite) {
87  RecordProperty("zephyr_key", "OTA-991,TST-158");
88  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "status_503", "noerrors"));
89 }
90 
91 TEST(UptaneNetwork, device_408_sqlite) {
92  RecordProperty("zephyr_key", "OTA-991,TST-158");
93  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "status_408", "noerrors"));
94 }
95 
96 TEST(UptaneNetwork, ecu_drop_request_sqlite) {
97  RecordProperty("zephyr_key", "OTA-991,TST-158");
98  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "noerrors", "drop_request"));
99 }
100 
101 TEST(UptaneNetwork, ecu_503_sqlite) {
102  RecordProperty("zephyr_key", "OTA-991,TST-158");
103  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "noerrors", "status_503"));
104 }
105 
106 TEST(UptaneNetwork, ecu_408_sqlite) {
107  RecordProperty("zephyr_key", "OTA-991,TST-158");
108  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "noerrors", "status_408"));
109 }
110 
111 TEST(UptaneNetwork, no_connection_sqlite) {
112  RecordProperty("zephyr_key", "OTA-991,TST-158");
113  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "noconnection", "noerrors"));
114 }
115 
116 TEST(UptaneNetwork, no_errors_sqlite) {
117  RecordProperty("zephyr_key", "OTA-991,TST-158");
118  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "noerrors", "noerrors"));
119 }
120 
121 TEST(UptaneNetwork, DownloadFailure) {
122  TemporaryDirectory temp_dir;
123  conf.storage.path = temp_dir.Path();
124  conf.provision.expiry_days = "download_failure";
125  conf.provision.primary_ecu_serial = "download_failure";
126  conf.provision.primary_ecu_hardware_id = "hardware_id";
127 
128  auto storage = INvStorage::newStorage(conf.storage);
129  auto up = std_::make_unique<SotaUptaneClient>(conf, storage);
130  EXPECT_NO_THROW(up->initialize());
131 
132  Json::Value ot_json;
133  ot_json["custom"]["ecuIdentifiers"][conf.provision.primary_ecu_serial]["hardwareId"] =
134  conf.provision.primary_ecu_hardware_id;
135  ot_json["custom"]["targetFormat"] = "binary";
136  ot_json["length"] = 2048;
137  ot_json["hashes"]["sha256"] = "d03b1a2081755f3a5429854cc3e700f8cbf125db2bd77098ae79a7d783256a7d";
138  Uptane::Target package_to_install{conf.provision.primary_ecu_serial, ot_json};
139 
140  std::pair<bool, Uptane::Target> result = up->downloadImage(package_to_install);
141  EXPECT_TRUE(result.first);
142 }
143 
144 /*
145  * Output a log when connectivity is restored.
146  */
147 class HttpUnstable : public HttpFake {
148  public:
149  HttpUnstable(const boost::filesystem::path &test_dir_in) : HttpFake(test_dir_in, "hasupdates") {}
150  HttpResponse get(const std::string &url, int64_t maxsize) override {
151  if (!connectSwitch) {
152  return HttpResponse({}, 503, CURLE_OK, "");
153  } else {
154  return HttpFake::get(url, maxsize);
155  }
156  }
157 
158  HttpResponse put(const std::string &url, const Json::Value &data) override {
159  if (!connectSwitch) {
160  (void)data;
161  return HttpResponse(url, 503, CURLE_OK, "");
162  } else {
163  return HttpFake::put(url, data);
164  }
165  }
166 
167  HttpResponse post(const std::string &url, const Json::Value &data) override {
168  if (!connectSwitch) {
169  (void)data;
170  return HttpResponse(url, 503, CURLE_OK, "");
171  } else {
172  return HttpFake::post(url, data);
173  }
174  }
175 
176  bool connectSwitch = true;
177 };
178 
179 TEST(UptaneNetwork, LogConnectivityRestored) {
180  TemporaryDirectory temp_dir;
181  auto http = std::make_shared<HttpUnstable>(temp_dir.Path());
182  Config config = UptaneTestCommon::makeTestConfig(temp_dir, http->tls_server);
183  config.uptane.director_server = http->tls_server + "director";
184  config.uptane.repo_server = http->tls_server + "repo";
185  config.pacman.type = PACKAGE_MANAGER_NONE;
186  config.provision.primary_ecu_serial = "CA:FE:A6:D2:84:9D";
187  config.provision.primary_ecu_hardware_id = "primary_hw";
188  config.storage.path = temp_dir.Path();
189  config.tls.server = http->tls_server;
190  UptaneTestCommon::addDefaultSecondary(config, temp_dir, "secondary_ecu_serial", "secondary_hw");
191 
192  auto storage = INvStorage::newStorage(config.storage);
193  auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
194  EXPECT_NO_THROW(up->initialize());
195 
196  result::UpdateCheck result = up->fetchMeta();
197  EXPECT_EQ(result.status, result::UpdateStatus::kUpdatesAvailable);
198 
199  http->connectSwitch = false;
200  result = up->fetchMeta();
201  EXPECT_EQ(result.status, result::UpdateStatus::kError);
202 
203  http->connectSwitch = true;
204  testing::internal::CaptureStdout();
205  result = up->fetchMeta();
206  EXPECT_EQ(result.status, result::UpdateStatus::kUpdatesAvailable);
207  EXPECT_NE(std::string::npos, testing::internal::GetCapturedStdout().find("Connectivity is restored."));
208 }
209 
210 #ifndef __NO_MAIN__
211 int main(int argc, char **argv) {
212  ::testing::InitGoogleTest(&argc, argv);
213  logger_set_threshold(boost::log::trivial::trace);
214 
215  port = TestUtils::getFreePort();
216  boost::process::child server_process("tests/fake_http_server/fake_uptane_server.py", port);
217  TestUtils::waitForServer("http://127.0.0.1:" + port + "/");
218 
219  conf.provision.server = "http://127.0.0.1:" + port;
220  conf.tls.server = "http://127.0.0.1:" + port;
221  conf.provision.ecu_registration_endpoint = conf.tls.server + "/director/ecus";
222  conf.uptane.repo_server = conf.tls.server + "/repo";
223  conf.uptane.director_server = conf.tls.server + "/director";
224  conf.pacman.ostree_server = conf.tls.server + "/treehub";
225 
226  return RUN_ALL_TESTS();
227 }
228 #endif
HttpFake
Definition: httpfake.h:22
HttpUnstable
Definition: uptane_network_test.cc:147
KeyManager
Definition: keymanager.h:13
result::UpdateCheck
Container for information about available updates.
Definition: results.h:38
data
General data structures.
Definition: types.cc:54
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
TemporaryDirectory
Definition: utils.h:82
result
Results of libaktualizr API calls.
Definition: results.h:13
Initializer
Definition: initializer.h:13
Uptane::Target
Definition: tuf.h:238