Aktualizr
C++ SOTA Client
utils_test.cc
Go to the documentation of this file.
1 /**
2  * \file
3  */
4 
5 #include <gtest/gtest.h>
6 
7 #include <sys/stat.h>
8 #include <fstream>
9 #include <map>
10 #include <random>
11 #include <set>
12 
13 #include <boost/algorithm/hex.hpp>
14 #include <boost/archive/iterators/dataflow_exception.hpp>
15 #include <boost/random/uniform_smallint.hpp>
16 
17 #include "utilities/utils.h"
18 
19 bool CharOk(char c) {
20  if (('a' <= c) && (c <= 'z')) {
21  return true;
22  } else if (('0' <= c) && (c <= '9')) {
23  return true;
24  } else if (c == '-') {
25  return true;
26  } else {
27  return false;
28  }
29 }
30 
31 bool PrettyNameOk(const std::string &name) {
32  if (name.size() < 5) {
33  return false;
34  }
35  for (std::string::const_iterator c = name.begin(); c != name.end(); ++c) {
36  if (!CharOk(*c)) {
37  return false;
38  }
39  }
40  return true;
41 }
42 
43 TEST(Utils, PrettyNameOk) {
44  EXPECT_TRUE(PrettyNameOk("foo-bar-123"));
45  EXPECT_FALSE(PrettyNameOk("NoCapitals"));
46  EXPECT_FALSE(PrettyNameOk(""));
47  EXPECT_FALSE(PrettyNameOk("foo-bar-123&"));
48 }
49 
50 TEST(Utils, getNetworkInfo) {
51  Json::Value netinfo = Utils::getNetworkInfo();
52 
53  EXPECT_NE(netinfo["local_ipv4"].asString(), "");
54  EXPECT_NE(netinfo["mac"].asString(), "");
55  EXPECT_NE(netinfo["hostname"].asString(), "");
56 }
57 
58 TEST(Utils, getHostname) { EXPECT_NE(Utils::getHostname(), ""); }
59 
60 /**
61  * \verify{\tst{144}} Check that aktualizr can generate a pet name
62  */
63 TEST(Utils, GenPrettyNameSane) {
64  std::set<std::string> names;
65  for (int i = 0; i < 100; i++) {
66  std::string name = Utils::genPrettyName();
67  names.insert(name);
68  auto count = names.count(name);
69  if (count > 2) {
70  std::cerr << "Something wrong with randomness: " << name;
71  FAIL();
72  } else if (count == 2) {
73  std::cerr << "Lucky draw: " << name;
74  }
75  }
76 }
77 
78 TEST(Utils, RandomUuidSane) {
79  std::set<std::string> uuids;
80  for (int i = 0; i < 1000; i++) {
81  std::string uuid = Utils::randomUuid();
82  EXPECT_EQ(0, uuids.count(uuid));
83  uuids.insert(uuid);
84  EXPECT_EQ(1, uuids.count(uuid));
85  }
86 }
87 
88 TEST(Utils, ToBase64) {
89  // Generated using python's base64.b64encode
90  EXPECT_EQ("aGVsbG8=", Utils::toBase64("hello"));
91  EXPECT_EQ("", Utils::toBase64(""));
92  EXPECT_EQ("CQ==", Utils::toBase64("\t"));
93  EXPECT_EQ("YWI=", Utils::toBase64("ab"));
94  EXPECT_EQ("YWJj", Utils::toBase64("abc"));
95 }
96 
97 TEST(Utils, FromBase64) {
98  EXPECT_EQ(Utils::fromBase64("aGVsbG8="), "hello");
99  EXPECT_EQ(Utils::fromBase64(""), "");
100  EXPECT_EQ(Utils::fromBase64("YWI="), "ab");
101  EXPECT_EQ(Utils::fromBase64("YWJj"), "abc");
102 }
103 
104 TEST(Utils, FromBase64Wrong) {
105  EXPECT_THROW(Utils::fromBase64("Привіт"), boost::archive::iterators::dataflow_exception);
106  EXPECT_THROW(Utils::fromBase64("aGVsbG8=="), boost::archive::iterators::dataflow_exception);
107  EXPECT_THROW(Utils::fromBase64("CQ==="), boost::archive::iterators::dataflow_exception);
108 }
109 
110 TEST(Utils, Base64RoundTrip) {
111  std::mt19937 gen;
112  boost::random::uniform_smallint<char> chars(std::numeric_limits<char>::min(), std::numeric_limits<char>::max());
113 
114  boost::random::uniform_smallint<int> length(0, 20);
115 
116  for (int test = 0; test < 100; test++) {
117  int len = length(gen);
118  std::string original;
119  for (int i = 0; i < len; i++) {
120  original += chars(gen);
121  }
122  std::string b64 = Utils::toBase64(original);
123  std::string output = Utils::fromBase64(b64);
124  EXPECT_EQ(original, output);
125  }
126 }
127 
128 TEST(Utils, ArchiveRead) {
129  const std::string archive_path = "tests/test_data/credentials.zip";
130 
131  {
132  std::ifstream as(archive_path, std::ios::binary | std::ios::in);
133  EXPECT_FALSE(as.fail());
134  EXPECT_THROW(Utils::readFileFromArchive(as, "bogus_filename"), std::runtime_error);
135  }
136 
137  {
138  std::ifstream as(archive_path, std::ios::binary | std::ios::in);
139  EXPECT_FALSE(as.fail());
140 
141  std::string url = Utils::readFileFromArchive(as, "autoprov.url");
142  EXPECT_EQ(url.rfind("https://", 0), 0);
143  }
144 }
145 
146 TEST(Utils, ArchiveWrite) {
147  std::string archive_bytes;
148  {
149  std::map<std::string, std::string> fm{{"test", "A"}};
150  std::stringstream as;
151  Utils::writeArchive(fm, as);
152  archive_bytes = as.str();
153  }
154 
155  {
156  std::stringstream as(archive_bytes);
157  EXPECT_EQ(Utils::readFileFromArchive(as, "test"), "A");
158  }
159 }
160 
162  boost::filesystem::path p;
163  {
164  TemporaryDirectory f("ahint");
165  p = f.Path();
166  EXPECT_TRUE(boost::filesystem::exists(p)); // The dir should exist
167  EXPECT_NE(p.string().find("ahint"), std::string::npos); // The hint is included in the filename
168 
169  struct stat statbuf;
170  stat(p.parent_path().c_str(), &statbuf);
171  EXPECT_EQ(statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), S_IRWXU);
172  }
173  EXPECT_FALSE(boost::filesystem::exists(p));
174 }
175 
177  boost::filesystem::path p;
178  {
179  TemporaryFile f("ahint");
180  p = f.Path();
181  EXPECT_FALSE(boost::filesystem::exists(p)); // The file shouldn't already exist
182  std::ofstream file(p.c_str());
183  file << "test";
184  file.close();
185  EXPECT_TRUE(file); // The write succeeded
186  EXPECT_TRUE(boost::filesystem::exists(p)); // The file should exist here
187  EXPECT_NE(p.string().find("ahint"), std::string::npos); // The hint is included in the filename
188 
189  struct stat statbuf;
190  stat(p.parent_path().c_str(), &statbuf);
191  EXPECT_EQ(statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), S_IRWXU);
192  }
193  EXPECT_FALSE(boost::filesystem::exists(p)); // The file gets deleted by the RAII dtor
194 }
195 
196 TEST(Utils, TemporaryFilePutContents) {
197  TemporaryFile f("ahint");
198  f.PutContents("thecontents");
199  EXPECT_TRUE(boost::filesystem::exists(f.Path()));
200  std::ifstream a(f.Path().c_str());
201  std::string b;
202  a >> b;
203  EXPECT_EQ(b, "thecontents");
204 }
205 
206 TEST(Utils, copyDir) {
207  TemporaryDirectory temp_dir;
208 
209  Utils::writeFile(temp_dir.Path() / "from/1/foo", std::string("foo"));
210  Utils::writeFile(temp_dir.Path() / "from/1/2/bar", std::string("bar"));
211  Utils::writeFile(temp_dir.Path() / "from/1/2/baz", std::string("baz"));
212 
213  Utils::copyDir(temp_dir.Path() / "from", temp_dir.Path() / "to");
214  EXPECT_TRUE(boost::filesystem::exists(temp_dir.Path() / "to"));
215  EXPECT_TRUE(boost::filesystem::exists(temp_dir.Path() / "to/1"));
216  EXPECT_TRUE(boost::filesystem::exists(temp_dir.Path() / "to/1/foo"));
217  EXPECT_TRUE(boost::filesystem::exists(temp_dir.Path() / "to/1/2"));
218  EXPECT_TRUE(boost::filesystem::exists(temp_dir.Path() / "to/1/2/bar"));
219  EXPECT_TRUE(boost::filesystem::exists(temp_dir.Path() / "to/1/2/baz"));
220  EXPECT_EQ(Utils::readFile(temp_dir.Path() / "to/1/foo"), "foo");
221  EXPECT_EQ(Utils::readFile(temp_dir.Path() / "to/1/2/bar"), "bar");
222  EXPECT_EQ(Utils::readFile(temp_dir.Path() / "to/1/2/baz"), "baz");
223 }
224 
225 TEST(Utils, writeFileWithoutDirAutoCreation) {
226  TemporaryDirectory temp_dir;
227 
228  boost::filesystem::create_directories(temp_dir.Path() / "1/2");
229  Utils::writeFile(temp_dir.Path() / "1/foo", std::string("foo"), false);
230  Utils::writeFile(temp_dir.Path() / "1/2/bar", std::string("bar"), false);
231 
232  EXPECT_EQ(Utils::readFile(temp_dir.Path() / "1/foo"), "foo");
233  EXPECT_EQ(Utils::readFile(temp_dir.Path() / "1/2/bar"), "bar");
234 }
235 
236 TEST(Utils, writeFileWithDirAutoCreation) {
237  TemporaryDirectory temp_dir;
238 
239  Utils::writeFile(temp_dir.Path() / "1/foo", std::string("foo"), true);
240  Utils::writeFile(temp_dir.Path() / "1/2/bar", std::string("bar"), true);
241 
242  EXPECT_EQ(Utils::readFile(temp_dir.Path() / "1/foo"), "foo");
243  EXPECT_EQ(Utils::readFile(temp_dir.Path() / "1/2/bar"), "bar");
244 }
245 
246 TEST(Utils, writeFileWithDirAutoCreationDefault) {
247  TemporaryDirectory temp_dir;
248 
249  Utils::writeFile(temp_dir.Path() / "1/foo", std::string("foo"));
250  Utils::writeFile(temp_dir.Path() / "1/2/bar", std::string("bar"));
251 
252  EXPECT_EQ(Utils::readFile(temp_dir.Path() / "1/foo"), "foo");
253  EXPECT_EQ(Utils::readFile(temp_dir.Path() / "1/2/bar"), "bar");
254 }
255 
256 TEST(Utils, writeFileWithoutDirAutoCreationException) {
257  TemporaryDirectory temp_dir;
258 
259  try {
260  Utils::writeFile(temp_dir.Path() / "1/foo", std::string("foo"), false);
261  EXPECT_TRUE(false);
262  } catch (...) {
263  }
264 }
265 
266 TEST(Utils, writeFileJson) {
267  TemporaryDirectory temp_dir;
268 
269  Json::Value val;
270  val["key"] = "val";
271 
272  Utils::writeFile(temp_dir.Path() / "1/foo", val);
273  Json::Value result_json = Utils::parseJSONFile(temp_dir.Path() / "1/foo");
274  EXPECT_EQ(result_json["key"].asString(), val["key"].asString());
275 }
276 
277 TEST(Utils, ipUtils) {
278  int fd = socket(AF_INET6, SOCK_STREAM, 0);
279 
280  EXPECT_NE(fd, -1);
281  SocketHandle hdl(new int(fd));
282 
283  sockaddr_in6 sa;
284 
285  memset(&sa, 0, sizeof(sa));
286  sa.sin6_family = AF_INET6;
287  sa.sin6_port = htons(0);
288  sa.sin6_addr = IN6ADDR_ANY_INIT;
289 
290  int reuseaddr = 1;
291  if (setsockopt(*hdl, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) < 0) {
292  throw std::runtime_error("setsockopt(SO_REUSEADDR) failed");
293  }
294 
295  EXPECT_NE(bind(*hdl, reinterpret_cast<const sockaddr *>(&sa), sizeof(sa)), -1);
296 
297  sockaddr_storage ss;
298  EXPECT_NO_THROW(ss = Utils::ipGetSockaddr(*hdl));
299 
300  EXPECT_NE(Utils::ipDisplayName(ss), "unknown");
301  EXPECT_NE(Utils::ipPort(ss), -1);
302 }
303 
304 TEST(Utils, shell) {
305  std::string out;
306  int statuscode = Utils::shell("ls /", &out);
307  EXPECT_EQ(statuscode, 0);
308 
309  statuscode = Utils::shell("ls /nonexistentdir123", &out);
310  EXPECT_NE(statuscode, 0);
311 }
312 
313 TEST(Utils, BasedPath) {
314  BasedPath bp("a/test.xml");
315 
316  EXPECT_EQ(BasedPath(bp.get("")), bp);
317  EXPECT_EQ(bp.get("/"), "/a/test.xml");
318  EXPECT_EQ(bp.get("/x"), "/x/a/test.xml");
319 
320  BasedPath abp("/a/test.xml");
321 
322  EXPECT_EQ(abp.get(""), "/a/test.xml");
323  EXPECT_EQ(abp.get("/root/var"), "/a/test.xml");
324 }
325 
326 #ifndef __NO_MAIN__
327 int main(int argc, char **argv) {
328  ::testing::InitGoogleTest(&argc, argv);
329  return RUN_ALL_TESTS();
330 }
331 #endif
TEST(Utils, GenPrettyNameSane)
Definition: utils_test.cc:63
Definition: utils.h:14
RAII Temporary file creation.
Definition: utils.h:52