1 // Copyright 2013 Google Inc.
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/backend.hpp"
30
31 #include <fstream>
32 #include <map>
33
34 #include <atf-c++.hpp>
35
36 #include "engine/action.hpp"
37 #include "engine/context.hpp"
38 #include "engine/test_case.hpp"
39 #include "engine/test_program.hpp"
40 #include "engine/test_result.hpp"
41 #include "store/backend.hpp"
42 #include "store/transaction.hpp"
43 #include "utils/format/macros.hpp"
44 #include "utils/fs/path.hpp"
45 #include "utils/logging/operations.hpp"
46 #include "utils/sqlite/database.hpp"
47 #include "utils/stream.hpp"
48 #include "utils/units.hpp"
49
50 namespace datetime = utils::datetime;
51 namespace fs = utils::fs;
52 namespace logging = utils::logging;
53 namespace sqlite = utils::sqlite;
54 namespace units = utils::units;
55
56
57 /// Executes an SQL script within a database.
58 ///
59 /// \param db Database in which to run the script.
60 /// \param path Path to the data file.
61 static void
exec_db_file(sqlite::database & db,const fs::path & path)62 exec_db_file(sqlite::database& db, const fs::path& path)
63 {
64 std::ifstream input(path.c_str());
65 if (!input)
66 ATF_FAIL(F("Failed to open %s") % path);
67 db.exec(utils::read_stream(input));
68 }
69
70
71 /// Validates the contents of the action with identifier 1.
72 ///
73 /// \param transaction An open read transaction in the backend.
74 static void
check_action_1(store::transaction & transaction)75 check_action_1(store::transaction& transaction)
76 {
77 const fs::path root("/some/root");
78 std::map< std::string, std::string > environment;
79 const engine::context context_1(root, environment);
80
81 const engine::action action_1(context_1);
82
83 ATF_REQUIRE_EQ(action_1, transaction.get_action(1));
84
85 store::results_iterator iter = transaction.get_action_results(1);
86 ATF_REQUIRE(!iter);
87 }
88
89
90 /// Validates the contents of the action with identifier 2.
91 ///
92 /// \param transaction An open read transaction in the backend.
93 static void
check_action_2(store::transaction & transaction)94 check_action_2(store::transaction& transaction)
95 {
96 const fs::path root("/test/suite/root");
97 std::map< std::string, std::string > environment;
98 environment["HOME"] = "/home/test";
99 environment["PATH"] = "/bin:/usr/bin";
100 const engine::context context_2(root, environment);
101
102 const engine::action action_2(context_2);
103
104 ATF_REQUIRE_EQ(action_2, transaction.get_action(2));
105
106 engine::test_program test_program_1(
107 "plain", fs::path("foo_test"), fs::path("/test/suite/root"),
108 "suite-name", engine::metadata_builder().build());
109 {
110 const engine::test_case_ptr test_case_1(new engine::test_case(
111 "plain", test_program_1, "main",
112 engine::metadata_builder().build()));
113 engine::test_cases_vector test_cases;
114 test_cases.push_back(test_case_1);
115 test_program_1.set_test_cases(test_cases);
116 }
117 const engine::test_result result_1(engine::test_result::passed);
118
119 engine::test_program test_program_2(
120 "plain", fs::path("subdir/another_test"), fs::path("/test/suite/root"),
121 "subsuite-name", engine::metadata_builder()
122 .set_timeout(datetime::delta(10, 0)).build());
123 {
124 const engine::test_case_ptr test_case_2(new engine::test_case(
125 "plain", test_program_2, "main", engine::metadata_builder()
126 .set_timeout(datetime::delta(10, 0)).build()));
127 engine::test_cases_vector test_cases;
128 test_cases.push_back(test_case_2);
129 test_program_2.set_test_cases(test_cases);
130 }
131 const engine::test_result result_2(engine::test_result::failed,
132 "Exited with code 1");
133
134 engine::test_program test_program_3(
135 "plain", fs::path("subdir/bar_test"), fs::path("/test/suite/root"),
136 "subsuite-name", engine::metadata_builder().build());
137 {
138 const engine::test_case_ptr test_case_3(new engine::test_case(
139 "plain", test_program_3, "main",
140 engine::metadata_builder().build()));
141 engine::test_cases_vector test_cases;
142 test_cases.push_back(test_case_3);
143 test_program_3.set_test_cases(test_cases);
144 }
145 const engine::test_result result_3(engine::test_result::broken,
146 "Received signal 1");
147
148 engine::test_program test_program_4(
149 "plain", fs::path("top_test"), fs::path("/test/suite/root"),
150 "suite-name", engine::metadata_builder().build());
151 {
152 const engine::test_case_ptr test_case_4(new engine::test_case(
153 "plain", test_program_4, "main",
154 engine::metadata_builder().build()));
155 engine::test_cases_vector test_cases;
156 test_cases.push_back(test_case_4);
157 test_program_4.set_test_cases(test_cases);
158 }
159 const engine::test_result result_4(engine::test_result::expected_failure,
160 "Known bug");
161
162 engine::test_program test_program_5(
163 "plain", fs::path("last_test"), fs::path("/test/suite/root"),
164 "suite-name", engine::metadata_builder().build());
165 {
166 const engine::test_case_ptr test_case_5(new engine::test_case(
167 "plain", test_program_5, "main",
168 engine::metadata_builder().build()));
169 engine::test_cases_vector test_cases;
170 test_cases.push_back(test_case_5);
171 test_program_5.set_test_cases(test_cases);
172 }
173 const engine::test_result result_5(engine::test_result::skipped,
174 "Does not apply");
175
176 store::results_iterator iter = transaction.get_action_results(2);
177 ATF_REQUIRE(iter);
178 ATF_REQUIRE_EQ(test_program_1, *iter.test_program());
179 ATF_REQUIRE_EQ("main", iter.test_case_name());
180 ATF_REQUIRE_EQ(result_1, iter.result());
181 ATF_REQUIRE(iter.stdout_contents().empty());
182 ATF_REQUIRE(iter.stderr_contents().empty());
183 ATF_REQUIRE_EQ(datetime::delta(10, 500), iter.duration());
184
185 ++iter;
186 ATF_REQUIRE(iter);
187 ATF_REQUIRE_EQ(test_program_5, *iter.test_program());
188 ATF_REQUIRE_EQ("main", iter.test_case_name());
189 ATF_REQUIRE_EQ(result_5, iter.result());
190 ATF_REQUIRE(iter.stdout_contents().empty());
191 ATF_REQUIRE(iter.stderr_contents().empty());
192 ATF_REQUIRE_EQ(datetime::delta(6, 0), iter.duration());
193
194 ++iter;
195 ATF_REQUIRE(iter);
196 ATF_REQUIRE_EQ(test_program_2, *iter.test_program());
197 ATF_REQUIRE_EQ("main", iter.test_case_name());
198 ATF_REQUIRE_EQ(result_2, iter.result());
199 ATF_REQUIRE_EQ("Test stdout", iter.stdout_contents());
200 ATF_REQUIRE_EQ("Test stderr", iter.stderr_contents());
201 ATF_REQUIRE_EQ(datetime::delta(0, 898821), iter.duration());
202
203 ++iter;
204 ATF_REQUIRE(iter);
205 ATF_REQUIRE_EQ(test_program_3, *iter.test_program());
206 ATF_REQUIRE_EQ("main", iter.test_case_name());
207 ATF_REQUIRE_EQ(result_3, iter.result());
208 ATF_REQUIRE(iter.stdout_contents().empty());
209 ATF_REQUIRE(iter.stderr_contents().empty());
210 ATF_REQUIRE_EQ(datetime::delta(7, 481932), iter.duration());
211
212 ++iter;
213 ATF_REQUIRE(iter);
214 ATF_REQUIRE_EQ(test_program_4, *iter.test_program());
215 ATF_REQUIRE_EQ("main", iter.test_case_name());
216 ATF_REQUIRE_EQ(result_4, iter.result());
217 ATF_REQUIRE(iter.stdout_contents().empty());
218 ATF_REQUIRE(iter.stderr_contents().empty());
219 ATF_REQUIRE_EQ(datetime::delta(0, 20000), iter.duration());
220
221 ++iter;
222 ATF_REQUIRE(!iter);
223 }
224
225
226 /// Validates the contents of the action with identifier 3.
227 ///
228 /// \param transaction An open read transaction in the backend.
229 static void
check_action_3(store::transaction & transaction)230 check_action_3(store::transaction& transaction)
231 {
232 const fs::path root("/usr/tests");
233 std::map< std::string, std::string > environment;
234 environment["PATH"] = "/bin:/usr/bin";
235 const engine::context context_3(root, environment);
236
237 const engine::action action_3(context_3);
238
239 ATF_REQUIRE_EQ(action_3, transaction.get_action(3));
240
241 engine::test_program test_program_6(
242 "atf", fs::path("complex_test"), fs::path("/usr/tests"),
243 "suite-name", engine::metadata_builder().build());
244 {
245 const engine::test_case_ptr test_case_6(new engine::test_case(
246 "atf", test_program_6, "this_passes",
247 engine::metadata_builder().build()));
248 const engine::test_case_ptr test_case_7(new engine::test_case(
249 "atf", test_program_6, "this_fails",
250 engine::metadata_builder()
251 .set_description("Test description")
252 .set_has_cleanup(true)
253 .set_required_memory(units::bytes(128))
254 .set_required_user("root").build()));
255 const engine::test_case_ptr test_case_8(new engine::test_case(
256 "atf", test_program_6, "this_skips",
257 engine::metadata_builder()
258 .add_allowed_architecture("powerpc")
259 .add_allowed_architecture("x86_64")
260 .add_allowed_platform("amd64")
261 .add_allowed_platform("macppc")
262 .add_required_config("X-foo")
263 .add_required_config("unprivileged_user")
264 .add_required_file(fs::path("/the/data/file"))
265 .add_required_program(fs::path("/bin/ls"))
266 .add_required_program(fs::path("cp"))
267 .set_description("Test explanation")
268 .set_has_cleanup(true)
269 .set_required_memory(units::bytes(512))
270 .set_required_user("unprivileged")
271 .set_timeout(datetime::delta(600, 0))
272 .build()));
273 engine::test_cases_vector test_cases;
274 test_cases.push_back(test_case_6);
275 test_cases.push_back(test_case_7);
276 test_cases.push_back(test_case_8);
277 test_program_6.set_test_cases(test_cases);
278 }
279 const engine::test_result result_6(engine::test_result::passed);
280 const engine::test_result result_7(engine::test_result::failed,
281 "Some reason");
282 const engine::test_result result_8(engine::test_result::skipped,
283 "Another reason");
284
285 engine::test_program test_program_7(
286 "atf", fs::path("simple_test"), fs::path("/usr/tests"),
287 "subsuite-name", engine::metadata_builder().build());
288 {
289 const engine::test_case_ptr test_case_9(new engine::test_case(
290 "atf", test_program_7, "main",
291 engine::metadata_builder()
292 .set_description("More text")
293 .set_has_cleanup(true)
294 .set_required_memory(units::bytes(128))
295 .set_required_user("unprivileged")
296 .build()));
297 engine::test_cases_vector test_cases;
298 test_cases.push_back(test_case_9);
299 test_program_7.set_test_cases(test_cases);
300 }
301 const engine::test_result result_9(engine::test_result::failed,
302 "Exited with code 1");
303
304 store::results_iterator iter = transaction.get_action_results(3);
305 ATF_REQUIRE(iter);
306 ATF_REQUIRE_EQ(test_program_6, *iter.test_program());
307 ATF_REQUIRE_EQ("this_fails", iter.test_case_name());
308 ATF_REQUIRE_EQ(result_7, iter.result());
309 ATF_REQUIRE(iter.stdout_contents().empty());
310 ATF_REQUIRE(iter.stderr_contents().empty());
311 ATF_REQUIRE_EQ(datetime::delta(1, 897182), iter.duration());
312
313 ++iter;
314 ATF_REQUIRE(iter);
315 ATF_REQUIRE_EQ(test_program_6, *iter.test_program());
316 ATF_REQUIRE_EQ("this_passes", iter.test_case_name());
317 ATF_REQUIRE_EQ(result_6, iter.result());
318 ATF_REQUIRE(iter.stdout_contents().empty());
319 ATF_REQUIRE(iter.stderr_contents().empty());
320 ATF_REQUIRE_EQ(datetime::delta(6, 0), iter.duration());
321
322 ++iter;
323 ATF_REQUIRE(iter);
324 ATF_REQUIRE_EQ(test_program_6, *iter.test_program());
325 ATF_REQUIRE_EQ("this_skips", iter.test_case_name());
326 ATF_REQUIRE_EQ(result_8, iter.result());
327 ATF_REQUIRE_EQ("Another stdout", iter.stdout_contents());
328 ATF_REQUIRE(iter.stderr_contents().empty());
329 ATF_REQUIRE_EQ(datetime::delta(0, 817987), iter.duration());
330
331 ++iter;
332 ATF_REQUIRE(iter);
333 ATF_REQUIRE_EQ(test_program_7, *iter.test_program());
334 ATF_REQUIRE_EQ("main", iter.test_case_name());
335 ATF_REQUIRE_EQ(result_9, iter.result());
336 ATF_REQUIRE(iter.stdout_contents().empty());
337 ATF_REQUIRE_EQ("Another stderr", iter.stderr_contents());
338 ATF_REQUIRE_EQ(datetime::delta(9, 961700), iter.duration());
339
340 ++iter;
341 ATF_REQUIRE(!iter);
342 }
343
344
345 /// Validates the contents of the action with identifier 4.
346 ///
347 /// \param transaction An open read transaction in the backend.
348 static void
check_action_4(store::transaction & transaction)349 check_action_4(store::transaction& transaction)
350 {
351 const fs::path root("/usr/tests");
352 std::map< std::string, std::string > environment;
353 environment["LANG"] = "C";
354 environment["PATH"] = "/bin:/usr/bin";
355 environment["TERM"] = "xterm";
356 const engine::context context_4(root, environment);
357
358 const engine::action action_4(context_4);
359
360 ATF_REQUIRE_EQ(action_4, transaction.get_action(4));
361
362 engine::test_program test_program_8(
363 "plain", fs::path("subdir/another_test"), fs::path("/usr/tests"),
364 "subsuite-name", engine::metadata_builder()
365 .set_timeout(datetime::delta(10, 0)).build());
366 {
367 const engine::test_case_ptr test_case_10(new engine::test_case(
368 "plain", test_program_8, "main",
369 engine::metadata_builder()
370 .set_timeout(datetime::delta(10, 0)).build()));
371 engine::test_cases_vector test_cases;
372 test_cases.push_back(test_case_10);
373 test_program_8.set_test_cases(test_cases);
374 }
375 const engine::test_result result_10(engine::test_result::failed,
376 "Exit failure");
377
378 engine::test_program test_program_9(
379 "atf", fs::path("complex_test"), fs::path("/usr/tests"),
380 "suite-name", engine::metadata_builder().build());
381 {
382 const engine::test_case_ptr test_case_11(new engine::test_case(
383 "atf", test_program_9, "this_passes",
384 engine::metadata_builder().build()));
385 const engine::test_case_ptr test_case_12(new engine::test_case(
386 "atf", test_program_9, "this_fails",
387 engine::metadata_builder()
388 .set_description("Test description")
389 .set_required_user("root")
390 .build()));
391 engine::test_cases_vector test_cases;
392 test_cases.push_back(test_case_11);
393 test_cases.push_back(test_case_12);
394 test_program_9.set_test_cases(test_cases);
395 }
396 const engine::test_result result_11(engine::test_result::passed);
397 const engine::test_result result_12(engine::test_result::failed,
398 "Some reason");
399
400 store::results_iterator iter = transaction.get_action_results(4);
401 ATF_REQUIRE(iter);
402 ATF_REQUIRE_EQ(test_program_9, *iter.test_program());
403 ATF_REQUIRE_EQ("this_fails", iter.test_case_name());
404 ATF_REQUIRE_EQ(result_12, iter.result());
405 ATF_REQUIRE(iter.stdout_contents().empty());
406 ATF_REQUIRE(iter.stderr_contents().empty());
407 ATF_REQUIRE_EQ(datetime::delta(1, 905000), iter.duration());
408
409 ++iter;
410 ATF_REQUIRE(iter);
411 ATF_REQUIRE_EQ(test_program_9, *iter.test_program());
412 ATF_REQUIRE_EQ("this_passes", iter.test_case_name());
413 ATF_REQUIRE_EQ(result_11, iter.result());
414 ATF_REQUIRE(iter.stdout_contents().empty());
415 ATF_REQUIRE(iter.stderr_contents().empty());
416 ATF_REQUIRE_EQ(datetime::delta(0, 500000), iter.duration());
417
418 ++iter;
419 ATF_REQUIRE(iter);
420 ATF_REQUIRE_EQ(test_program_8, *iter.test_program());
421 ATF_REQUIRE_EQ("main", iter.test_case_name());
422 ATF_REQUIRE_EQ(result_10, iter.result());
423 ATF_REQUIRE_EQ("Test stdout", iter.stdout_contents());
424 ATF_REQUIRE_EQ("Test stderr", iter.stderr_contents());
425 ATF_REQUIRE_EQ(datetime::delta(1, 0), iter.duration());
426
427 ++iter;
428 ATF_REQUIRE(!iter);
429 }
430
431
432 /// Validates the contents of an open database agains good known values.
433 ///
434 /// \param transaction An open read-only backend.
435 static void
check_data(store::backend & backend)436 check_data(store::backend& backend)
437 {
438 store::transaction transaction = backend.start();
439 check_action_1(transaction);
440 check_action_2(transaction);
441 check_action_3(transaction);
442 check_action_4(transaction);
443 }
444
445
446 ATF_TEST_CASE(current_schema);
ATF_TEST_CASE_HEAD(current_schema)447 ATF_TEST_CASE_HEAD(current_schema)
448 {
449 logging::set_inmemory();
450 const std::string required_files =
451 store::detail::schema_file().str()
452 + " " + (fs::path(get_config_var("srcdir")) / "testdata_v2.sql").str();
453 set_md_var("require.files", required_files);
454 }
ATF_TEST_CASE_BODY(current_schema)455 ATF_TEST_CASE_BODY(current_schema)
456 {
457 const fs::path testpath("test.db");
458
459 sqlite::database db = sqlite::database::open(
460 testpath, sqlite::open_readwrite | sqlite::open_create);
461 exec_db_file(db, store::detail::schema_file());
462 exec_db_file(db, fs::path(get_config_var("srcdir")) / "testdata_v2.sql");
463 db.close();
464
465 store::backend backend = store::backend::open_ro(testpath);
466 check_data(backend);
467 }
468
469
470 ATF_TEST_CASE(migrate_schema__v1_to_v2);
ATF_TEST_CASE_HEAD(migrate_schema__v1_to_v2)471 ATF_TEST_CASE_HEAD(migrate_schema__v1_to_v2)
472 {
473 logging::set_inmemory();
474 const std::string required_files =
475 store::detail::migration_file(1, 2).str()
476 + " " + (fs::path(get_config_var("srcdir")) / "schema_v1.sql").str()
477 + " " + (fs::path(get_config_var("srcdir")) / "testdata_v1.sql").str();
478 set_md_var("require.files", required_files);
479 }
ATF_TEST_CASE_BODY(migrate_schema__v1_to_v2)480 ATF_TEST_CASE_BODY(migrate_schema__v1_to_v2)
481 {
482 const fs::path testpath("test.db");
483
484 sqlite::database db = sqlite::database::open(
485 testpath, sqlite::open_readwrite | sqlite::open_create);
486 exec_db_file(db, fs::path(get_config_var("srcdir")) / "schema_v1.sql");
487 exec_db_file(db, fs::path(get_config_var("srcdir")) / "testdata_v1.sql");
488 db.close();
489
490 store::migrate_schema(fs::path("test.db"));
491
492 store::backend backend = store::backend::open_ro(testpath);
493 check_data(backend);
494 }
495
496
ATF_INIT_TEST_CASES(tcs)497 ATF_INIT_TEST_CASES(tcs)
498 {
499 ATF_ADD_TEST_CASE(tcs, current_schema);
500
501 ATF_ADD_TEST_CASE(tcs, migrate_schema__v1_to_v2);
502 }
503