1 // Copyright 2014 The Kyua Authors.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 #include "store/layout.hpp"
30
31 extern "C" {
32 #include <unistd.h>
33 }
34
35 #include <iostream>
36
37 #include <atf-c++.hpp>
38
39 #include "store/exceptions.hpp"
40 #include "store/layout.hpp"
41 #include "utils/datetime.hpp"
42 #include "utils/env.hpp"
43 #include "utils/fs/operations.hpp"
44 #include "utils/fs/path.hpp"
45
46 namespace datetime = utils::datetime;
47 namespace fs = utils::fs;
48 namespace layout = store::layout;
49
50
51 ATF_TEST_CASE_WITHOUT_HEAD(find_results__latest);
ATF_TEST_CASE_BODY(find_results__latest)52 ATF_TEST_CASE_BODY(find_results__latest)
53 {
54 const fs::path store_dir = layout::query_store_dir();
55 fs::mkdir_p(store_dir, 0755);
56
57 const std::string test_suite = layout::test_suite_for_path(
58 fs::current_path());
59 const std::string base = (store_dir / (
60 "results." + test_suite + ".")).str();
61
62 atf::utils::create_file(base + "20140613-194515-000000.db", "");
63 ATF_REQUIRE_EQ(base + "20140613-194515-000000.db",
64 layout::find_results("LATEST").str());
65
66 atf::utils::create_file(base + "20140614-194515-123456.db", "");
67 ATF_REQUIRE_EQ(base + "20140614-194515-123456.db",
68 layout::find_results("LATEST").str());
69
70 atf::utils::create_file(base + "20130614-194515-999999.db", "");
71 ATF_REQUIRE_EQ(base + "20140614-194515-123456.db",
72 layout::find_results("LATEST").str());
73 }
74
75
76 ATF_TEST_CASE_WITHOUT_HEAD(find_results__directory);
ATF_TEST_CASE_BODY(find_results__directory)77 ATF_TEST_CASE_BODY(find_results__directory)
78 {
79 const fs::path store_dir = layout::query_store_dir();
80 fs::mkdir_p(store_dir, 0755);
81
82 const fs::path dir1("dir1/foo");
83 fs::mkdir_p(dir1, 0755);
84 const fs::path dir2("dir1/bar");
85 fs::mkdir_p(dir2, 0755);
86
87 const std::string base1 = (store_dir / (
88 "results." + layout::test_suite_for_path(dir1) + ".")).str();
89 const std::string base2 = (store_dir / (
90 "results." + layout::test_suite_for_path(dir2) + ".")).str();
91
92 atf::utils::create_file(base1 + "20140613-194515-000000.db", "");
93 ATF_REQUIRE_EQ(base1 + "20140613-194515-000000.db",
94 layout::find_results(dir1.str()).str());
95
96 atf::utils::create_file(base2 + "20140615-111111-000000.db", "");
97 ATF_REQUIRE_EQ(base2 + "20140615-111111-000000.db",
98 layout::find_results(dir2.str()).str());
99
100 atf::utils::create_file(base1 + "20140614-194515-123456.db", "");
101 ATF_REQUIRE_EQ(base1 + "20140614-194515-123456.db",
102 layout::find_results(dir1.str()).str());
103
104 atf::utils::create_file(base1 + "20130614-194515-999999.db", "");
105 ATF_REQUIRE_EQ(base1 + "20140614-194515-123456.db",
106 layout::find_results(dir1.str()).str());
107 }
108
109
110 ATF_TEST_CASE_WITHOUT_HEAD(find_results__file);
ATF_TEST_CASE_BODY(find_results__file)111 ATF_TEST_CASE_BODY(find_results__file)
112 {
113 const fs::path store_dir = layout::query_store_dir();
114 fs::mkdir_p(store_dir, 0755);
115
116 atf::utils::create_file("a-file.db", "");
117 ATF_REQUIRE_EQ(fs::path("a-file.db").to_absolute(),
118 layout::find_results("a-file.db"));
119 }
120
121
122 ATF_TEST_CASE_WITHOUT_HEAD(find_results__id);
ATF_TEST_CASE_BODY(find_results__id)123 ATF_TEST_CASE_BODY(find_results__id)
124 {
125 const fs::path store_dir = layout::query_store_dir();
126 fs::mkdir_p(store_dir, 0755);
127
128 const fs::path dir1("dir1/foo");
129 fs::mkdir_p(dir1, 0755);
130 const fs::path dir2("dir1/bar");
131 fs::mkdir_p(dir2, 0755);
132
133 const std::string id1 = layout::test_suite_for_path(dir1);
134 const std::string base1 = (store_dir / ("results." + id1 + ".")).str();
135 const std::string id2 = layout::test_suite_for_path(dir2);
136 const std::string base2 = (store_dir / ("results." + id2 + ".")).str();
137
138 atf::utils::create_file(base1 + "20140613-194515-000000.db", "");
139 ATF_REQUIRE_EQ(base1 + "20140613-194515-000000.db",
140 layout::find_results(id1).str());
141
142 atf::utils::create_file(base2 + "20140615-111111-000000.db", "");
143 ATF_REQUIRE_EQ(base2 + "20140615-111111-000000.db",
144 layout::find_results(id2).str());
145
146 atf::utils::create_file(base1 + "20140614-194515-123456.db", "");
147 ATF_REQUIRE_EQ(base1 + "20140614-194515-123456.db",
148 layout::find_results(id1).str());
149
150 atf::utils::create_file(base1 + "20130614-194515-999999.db", "");
151 ATF_REQUIRE_EQ(base1 + "20140614-194515-123456.db",
152 layout::find_results(id1).str());
153 }
154
155
156 ATF_TEST_CASE_WITHOUT_HEAD(find_results__id_with_timestamp);
ATF_TEST_CASE_BODY(find_results__id_with_timestamp)157 ATF_TEST_CASE_BODY(find_results__id_with_timestamp)
158 {
159 const fs::path store_dir = layout::query_store_dir();
160 fs::mkdir_p(store_dir, 0755);
161
162 const fs::path dir1("dir1/foo");
163 fs::mkdir_p(dir1, 0755);
164 const fs::path dir2("dir1/bar");
165 fs::mkdir_p(dir2, 0755);
166
167 const std::string id1 = layout::test_suite_for_path(dir1);
168 const std::string base1 = (store_dir / ("results." + id1 + ".")).str();
169 const std::string id2 = layout::test_suite_for_path(dir2);
170 const std::string base2 = (store_dir / ("results." + id2 + ".")).str();
171
172 atf::utils::create_file(base1 + "20140613-194515-000000.db", "");
173 atf::utils::create_file(base2 + "20140615-111111-000000.db", "");
174 atf::utils::create_file(base1 + "20140614-194515-123456.db", "");
175 atf::utils::create_file(base1 + "20130614-194515-999999.db", "");
176
177 ATF_REQUIRE_MATCH(
178 "_dir1_foo.20140613-194515-000000.db$",
179 layout::find_results(id1 + ".20140613-194515-000000").str());
180
181 ATF_REQUIRE_MATCH(
182 "_dir1_foo.20140614-194515-123456.db$",
183 layout::find_results(id1 + ".20140614-194515-123456").str());
184
185 ATF_REQUIRE_MATCH(
186 "_dir1_bar.20140615-111111-000000.db$",
187 layout::find_results(id2 + ".20140615-111111-000000").str());
188 }
189
190
191 ATF_TEST_CASE_WITHOUT_HEAD(find_results__not_found);
ATF_TEST_CASE_BODY(find_results__not_found)192 ATF_TEST_CASE_BODY(find_results__not_found)
193 {
194 ATF_REQUIRE_THROW_RE(
195 store::error,
196 "No previous results file found for test suite foo_bar",
197 layout::find_results("foo_bar"));
198
199 const fs::path store_dir = layout::query_store_dir();
200 fs::mkdir_p(store_dir, 0755);
201 ATF_REQUIRE_THROW_RE(
202 store::error,
203 "No previous results file found for test suite foo_bar",
204 layout::find_results("foo_bar"));
205
206 const char* candidates[] = {
207 "results.foo.20140613-194515-012345.db", // Bad test suite.
208 "results.foo_bar.20140613-194515-012345", // Missing extension.
209 "foo_bar.20140613-194515-012345.db", // Missing prefix.
210 "results.foo_bar.2010613-194515-012345.db", // Bad date.
211 "results.foo_bar.20140613-19515-012345.db", // Bad time.
212 "results.foo_bar.20140613-194515-01245.db", // Bad microseconds.
213 NULL,
214 };
215 for (const char** candidate = candidates; *candidate != NULL; ++candidate) {
216 std::cout << "Current candidate: " << *candidate << '\n';
217 atf::utils::create_file((store_dir / *candidate).str(), "");
218 ATF_REQUIRE_THROW_RE(
219 store::error,
220 "No previous results file found for test suite foo_bar",
221 layout::find_results("foo_bar"));
222 }
223
224 atf::utils::create_file(
225 (store_dir / "results.foo_bar.20140613-194515-012345.db").str(), "");
226 layout::find_results("foo_bar"); // Expected not to throw.
227 }
228
229
230 ATF_TEST_CASE_WITHOUT_HEAD(new_db__new);
ATF_TEST_CASE_BODY(new_db__new)231 ATF_TEST_CASE_BODY(new_db__new)
232 {
233 datetime::set_mock_now(2014, 6, 13, 19, 45, 15, 5000);
234 ATF_REQUIRE(!fs::exists(fs::path(".kyua/store")));
235 const layout::results_id_file_pair results = layout::new_db(
236 "NEW", fs::path("/some/path/to/the/suite"));
237 ATF_REQUIRE( fs::exists(fs::path(".kyua/store")));
238 ATF_REQUIRE( fs::is_directory(fs::path(".kyua/store")));
239
240 const std::string id = "some_path_to_the_suite.20140613-194515-005000";
241 ATF_REQUIRE_EQ(id, results.first);
242 ATF_REQUIRE_EQ(layout::query_store_dir() / ("results." + id + ".db"),
243 results.second);
244 }
245
246
247 ATF_TEST_CASE_WITHOUT_HEAD(new_db__explicit);
ATF_TEST_CASE_BODY(new_db__explicit)248 ATF_TEST_CASE_BODY(new_db__explicit)
249 {
250 ATF_REQUIRE(!fs::exists(fs::path(".kyua/store")));
251 const layout::results_id_file_pair results = layout::new_db(
252 "foo/results-file.db", fs::path("unused"));
253 ATF_REQUIRE(!fs::exists(fs::path(".kyua/store")));
254 ATF_REQUIRE(!fs::exists(fs::path("foo")));
255
256 ATF_REQUIRE(results.first.empty());
257 ATF_REQUIRE_EQ(fs::path("foo/results-file.db"), results.second);
258 }
259
260
261 ATF_TEST_CASE_WITHOUT_HEAD(new_db_for_migration);
ATF_TEST_CASE_BODY(new_db_for_migration)262 ATF_TEST_CASE_BODY(new_db_for_migration)
263 {
264 ATF_REQUIRE(!fs::exists(fs::path(".kyua/store")));
265 const fs::path results_file = layout::new_db_for_migration(
266 fs::path("/some/root"),
267 datetime::timestamp::from_values(2014, 7, 30, 10, 5, 20, 76500));
268 ATF_REQUIRE( fs::exists(fs::path(".kyua/store")));
269 ATF_REQUIRE( fs::is_directory(fs::path(".kyua/store")));
270
271 ATF_REQUIRE_EQ(
272 layout::query_store_dir() /
273 "results.some_root.20140730-100520-076500.db",
274 results_file);
275 }
276
277
278 ATF_TEST_CASE_WITHOUT_HEAD(query_store_dir__home_absolute);
ATF_TEST_CASE_BODY(query_store_dir__home_absolute)279 ATF_TEST_CASE_BODY(query_store_dir__home_absolute)
280 {
281 const fs::path home = fs::current_path() / "homedir";
282 utils::setenv("HOME", home.str());
283 const fs::path store_dir = layout::query_store_dir();
284 ATF_REQUIRE(store_dir.is_absolute());
285 ATF_REQUIRE_EQ(home / ".kyua/store", store_dir);
286 }
287
288
289 ATF_TEST_CASE_WITHOUT_HEAD(query_store_dir__home_relative);
ATF_TEST_CASE_BODY(query_store_dir__home_relative)290 ATF_TEST_CASE_BODY(query_store_dir__home_relative)
291 {
292 const fs::path home("homedir");
293 utils::setenv("HOME", home.str());
294 const fs::path store_dir = layout::query_store_dir();
295 ATF_REQUIRE(store_dir.is_absolute());
296 ATF_REQUIRE_MATCH((home / ".kyua/store").str(), store_dir.str());
297 }
298
299
300 ATF_TEST_CASE_WITHOUT_HEAD(query_store_dir__no_home);
ATF_TEST_CASE_BODY(query_store_dir__no_home)301 ATF_TEST_CASE_BODY(query_store_dir__no_home)
302 {
303 utils::unsetenv("HOME");
304 ATF_REQUIRE_EQ(fs::current_path(), layout::query_store_dir());
305 }
306
307
308 ATF_TEST_CASE_WITHOUT_HEAD(test_suite_for_path__absolute);
ATF_TEST_CASE_BODY(test_suite_for_path__absolute)309 ATF_TEST_CASE_BODY(test_suite_for_path__absolute)
310 {
311 ATF_REQUIRE_EQ("dir1_dir2_dir3",
312 layout::test_suite_for_path(fs::path("/dir1/dir2/dir3")));
313 ATF_REQUIRE_EQ("dir1",
314 layout::test_suite_for_path(fs::path("/dir1")));
315 ATF_REQUIRE_EQ("dir1_dir2",
316 layout::test_suite_for_path(fs::path("/dir1///dir2")));
317 }
318
319
320 ATF_TEST_CASE_WITHOUT_HEAD(test_suite_for_path__relative);
ATF_TEST_CASE_BODY(test_suite_for_path__relative)321 ATF_TEST_CASE_BODY(test_suite_for_path__relative)
322 {
323 const std::string test_suite = layout::test_suite_for_path(
324 fs::path("foo/bar"));
325 ATF_REQUIRE_MATCH("_foo_bar$", test_suite);
326 ATF_REQUIRE_MATCH("^[^_]", test_suite);
327 }
328
329
ATF_INIT_TEST_CASES(tcs)330 ATF_INIT_TEST_CASES(tcs)
331 {
332 ATF_ADD_TEST_CASE(tcs, find_results__latest);
333 ATF_ADD_TEST_CASE(tcs, find_results__directory);
334 ATF_ADD_TEST_CASE(tcs, find_results__file);
335 ATF_ADD_TEST_CASE(tcs, find_results__id);
336 ATF_ADD_TEST_CASE(tcs, find_results__id_with_timestamp);
337 ATF_ADD_TEST_CASE(tcs, find_results__not_found);
338
339 ATF_ADD_TEST_CASE(tcs, new_db__new);
340 ATF_ADD_TEST_CASE(tcs, new_db__explicit);
341
342 ATF_ADD_TEST_CASE(tcs, new_db_for_migration);
343
344 ATF_ADD_TEST_CASE(tcs, query_store_dir__home_absolute);
345 ATF_ADD_TEST_CASE(tcs, query_store_dir__home_relative);
346 ATF_ADD_TEST_CASE(tcs, query_store_dir__no_home);
347
348 ATF_ADD_TEST_CASE(tcs, test_suite_for_path__absolute);
349 ATF_ADD_TEST_CASE(tcs, test_suite_for_path__relative);
350 }
351