Aktualizr
C++ SOTA Client
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  try {
50  Initializer initializer(conf.provision, store, http, keys, {});
51  result = true;
52  } catch (const std::exception &e) {
53  result = false;
54  }
55  }
56  if (device_register_state != "noerrors" || ecu_register_state != "noerrors") {
57  EXPECT_FALSE(result);
58  LOG_INFO << "Second attempt to initialize.";
59  conf.provision.server = good_url;
60  conf.provision.expiry_days = "noerrors";
61  conf.provision.primary_ecu_serial = "noerrors";
62 
63  KeyManager keys(store, conf.keymanagerConfig());
64  try {
65  Initializer initializer(conf.provision, store, http, keys, {});
66  result = true;
67  } catch (const std::exception &e) {
68  result = false;
69  }
70  }
71 
72  return result;
73 }
74 
75 TEST(UptaneNetwork, device_drop_request_sqlite) {
76  RecordProperty("zephyr_key", "OTA-991,TST-158");
77  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "drop_request", "noerrors"));
78 }
79 
80 TEST(UptaneNetwork, device_drop_body_sqlite) {
81  RecordProperty("zephyr_key", "OTA-991,TST-158");
82  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "drop_body", "noerrors"));
83 }
84 
85 TEST(UptaneNetwork, device_503_sqlite) {
86  RecordProperty("zephyr_key", "OTA-991,TST-158");
87  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "status_503", "noerrors"));
88 }
89 
90 TEST(UptaneNetwork, device_408_sqlite) {
91  RecordProperty("zephyr_key", "OTA-991,TST-158");
92  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "status_408", "noerrors"));
93 }
94 
95 TEST(UptaneNetwork, ecu_drop_request_sqlite) {
96  RecordProperty("zephyr_key", "OTA-991,TST-158");
97  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "noerrors", "drop_request"));
98 }
99 
100 TEST(UptaneNetwork, ecu_503_sqlite) {
101  RecordProperty("zephyr_key", "OTA-991,TST-158");
102  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "noerrors", "status_503"));
103 }
104 
105 TEST(UptaneNetwork, ecu_408_sqlite) {
106  RecordProperty("zephyr_key", "OTA-991,TST-158");
107  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "noerrors", "status_408"));
108 }
109 
110 TEST(UptaneNetwork, no_connection_sqlite) {
111  RecordProperty("zephyr_key", "OTA-991,TST-158");
112  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "noconnection", "noerrors"));
113 }
114 
115 TEST(UptaneNetwork, no_errors_sqlite) {
116  RecordProperty("zephyr_key", "OTA-991,TST-158");
117  EXPECT_TRUE(doTestInit(StorageType::kSqlite, "noerrors", "noerrors"));
118 }
119 
120 TEST(UptaneNetwork, DownloadFailure) {
121  TemporaryDirectory temp_dir;
122  conf.storage.path = temp_dir.Path();
123  conf.pacman.images_path = temp_dir.Path() / "images";
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 
191  auto storage = INvStorage::newStorage(config.storage);
192  auto up = std_::make_unique<UptaneTestCommon::TestUptaneClient>(config, storage, http);
193  EXPECT_NO_THROW(up->initialize());
194 
195  result::UpdateCheck result = up->fetchMeta();
196  EXPECT_EQ(result.status, result::UpdateStatus::kUpdatesAvailable);
197 
198  http->connectSwitch = false;
199  result = up->fetchMeta();
200  EXPECT_EQ(result.status, result::UpdateStatus::kError);
201 
202  http->connectSwitch = true;
203  testing::internal::CaptureStdout();
204  result = up->fetchMeta();
205  EXPECT_EQ(result.status, result::UpdateStatus::kUpdatesAvailable);
206  EXPECT_NE(std::string::npos, testing::internal::GetCapturedStdout().find("Connectivity is restored."));
207 }
208 
209 #ifndef __NO_MAIN__
210 int main(int argc, char **argv) {
211  ::testing::InitGoogleTest(&argc, argv);
212  logger_set_threshold(boost::log::trivial::trace);
213 
214  port = TestUtils::getFreePort();
215  boost::process::child server_process("tests/fake_http_server/fake_uptane_server.py", port);
216  TestUtils::waitForServer("http://127.0.0.1:" + port + "/");
217 
218  conf.provision.server = "http://127.0.0.1:" + port;
219  conf.tls.server = "http://127.0.0.1:" + port;
220  conf.provision.ecu_registration_endpoint = conf.tls.server + "/director/ecus";
221  conf.uptane.repo_server = conf.tls.server + "/repo";
222  conf.uptane.director_server = conf.tls.server + "/director";
223  conf.pacman.ostree_server = conf.tls.server + "/treehub";
224 
225  return RUN_ALL_TESTS();
226 }
227 #endif
HttpFake
Definition: httpfake.h:20
HttpUnstable
Definition: uptane_network_test.cc:147
KeyManager
Definition: keymanager.h:13
result::UpdateCheck
Container for information about available updates.
Definition: results.h:37
data
General data structures.
Definition: types.h:217
HttpResponse
Definition: httpinterface.h:17
Config
Configuration object for an aktualizr instance running on a Primary ECU.
Definition: config.h:208
TemporaryDirectory
Definition: utils.h:82
result
Results of libaktualizr API calls.
Definition: results.h:12
Initializer
Definition: initializer.h:14
Uptane::Target
Definition: types.h:379