1*b0d29bc4SBrooks Davis // Copyright 2011 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis // documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis // may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis // without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis
29*b0d29bc4SBrooks Davis #include "store/read_transaction.hpp"
30*b0d29bc4SBrooks Davis
31*b0d29bc4SBrooks Davis #include <map>
32*b0d29bc4SBrooks Davis #include <string>
33*b0d29bc4SBrooks Davis
34*b0d29bc4SBrooks Davis #include <atf-c++.hpp>
35*b0d29bc4SBrooks Davis
36*b0d29bc4SBrooks Davis #include "model/context.hpp"
37*b0d29bc4SBrooks Davis #include "model/metadata.hpp"
38*b0d29bc4SBrooks Davis #include "model/test_program.hpp"
39*b0d29bc4SBrooks Davis #include "model/test_result.hpp"
40*b0d29bc4SBrooks Davis #include "store/exceptions.hpp"
41*b0d29bc4SBrooks Davis #include "store/read_backend.hpp"
42*b0d29bc4SBrooks Davis #include "store/write_backend.hpp"
43*b0d29bc4SBrooks Davis #include "store/write_transaction.hpp"
44*b0d29bc4SBrooks Davis #include "utils/datetime.hpp"
45*b0d29bc4SBrooks Davis #include "utils/fs/path.hpp"
46*b0d29bc4SBrooks Davis #include "utils/logging/operations.hpp"
47*b0d29bc4SBrooks Davis #include "utils/optional.ipp"
48*b0d29bc4SBrooks Davis #include "utils/sqlite/database.hpp"
49*b0d29bc4SBrooks Davis #include "utils/sqlite/statement.ipp"
50*b0d29bc4SBrooks Davis
51*b0d29bc4SBrooks Davis namespace datetime = utils::datetime;
52*b0d29bc4SBrooks Davis namespace fs = utils::fs;
53*b0d29bc4SBrooks Davis namespace logging = utils::logging;
54*b0d29bc4SBrooks Davis namespace sqlite = utils::sqlite;
55*b0d29bc4SBrooks Davis
56*b0d29bc4SBrooks Davis
57*b0d29bc4SBrooks Davis ATF_TEST_CASE(get_context__missing);
ATF_TEST_CASE_HEAD(get_context__missing)58*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(get_context__missing)
59*b0d29bc4SBrooks Davis {
60*b0d29bc4SBrooks Davis logging::set_inmemory();
61*b0d29bc4SBrooks Davis set_md_var("require.files", store::detail::schema_file().c_str());
62*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(get_context__missing)63*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(get_context__missing)
64*b0d29bc4SBrooks Davis {
65*b0d29bc4SBrooks Davis store::write_backend::open_rw(fs::path("test.db")); // Create database.
66*b0d29bc4SBrooks Davis store::read_backend backend = store::read_backend::open_ro(
67*b0d29bc4SBrooks Davis fs::path("test.db"));
68*b0d29bc4SBrooks Davis
69*b0d29bc4SBrooks Davis store::read_transaction tx = backend.start_read();
70*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(store::error, "context: no data", tx.get_context());
71*b0d29bc4SBrooks Davis }
72*b0d29bc4SBrooks Davis
73*b0d29bc4SBrooks Davis
74*b0d29bc4SBrooks Davis ATF_TEST_CASE(get_context__invalid_cwd);
ATF_TEST_CASE_HEAD(get_context__invalid_cwd)75*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(get_context__invalid_cwd)
76*b0d29bc4SBrooks Davis {
77*b0d29bc4SBrooks Davis logging::set_inmemory();
78*b0d29bc4SBrooks Davis set_md_var("require.files", store::detail::schema_file().c_str());
79*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(get_context__invalid_cwd)80*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(get_context__invalid_cwd)
81*b0d29bc4SBrooks Davis {
82*b0d29bc4SBrooks Davis {
83*b0d29bc4SBrooks Davis store::write_backend backend = store::write_backend::open_rw(
84*b0d29bc4SBrooks Davis fs::path("test.db"));
85*b0d29bc4SBrooks Davis
86*b0d29bc4SBrooks Davis sqlite::statement stmt = backend.database().create_statement(
87*b0d29bc4SBrooks Davis "INSERT INTO contexts (cwd) VALUES (:cwd)");
88*b0d29bc4SBrooks Davis const char buffer[10] = "foo bar";
89*b0d29bc4SBrooks Davis stmt.bind(":cwd", sqlite::blob(buffer, sizeof(buffer)));
90*b0d29bc4SBrooks Davis stmt.step_without_results();
91*b0d29bc4SBrooks Davis }
92*b0d29bc4SBrooks Davis
93*b0d29bc4SBrooks Davis store::read_backend backend = store::read_backend::open_ro(
94*b0d29bc4SBrooks Davis fs::path("test.db"));
95*b0d29bc4SBrooks Davis store::read_transaction tx = backend.start_read();
96*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(store::error, "context: .*cwd.*not a string",
97*b0d29bc4SBrooks Davis tx.get_context());
98*b0d29bc4SBrooks Davis }
99*b0d29bc4SBrooks Davis
100*b0d29bc4SBrooks Davis
101*b0d29bc4SBrooks Davis ATF_TEST_CASE(get_context__invalid_env_vars);
ATF_TEST_CASE_HEAD(get_context__invalid_env_vars)102*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(get_context__invalid_env_vars)
103*b0d29bc4SBrooks Davis {
104*b0d29bc4SBrooks Davis logging::set_inmemory();
105*b0d29bc4SBrooks Davis set_md_var("require.files", store::detail::schema_file().c_str());
106*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(get_context__invalid_env_vars)107*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(get_context__invalid_env_vars)
108*b0d29bc4SBrooks Davis {
109*b0d29bc4SBrooks Davis {
110*b0d29bc4SBrooks Davis store::write_backend backend = store::write_backend::open_rw(
111*b0d29bc4SBrooks Davis fs::path("test-bad-name.db"));
112*b0d29bc4SBrooks Davis backend.database().exec("INSERT INTO contexts (cwd) "
113*b0d29bc4SBrooks Davis "VALUES ('/foo/bar')");
114*b0d29bc4SBrooks Davis const char buffer[10] = "foo bar";
115*b0d29bc4SBrooks Davis
116*b0d29bc4SBrooks Davis sqlite::statement stmt = backend.database().create_statement(
117*b0d29bc4SBrooks Davis "INSERT INTO env_vars (var_name, var_value) "
118*b0d29bc4SBrooks Davis "VALUES (:var_name, 'abc')");
119*b0d29bc4SBrooks Davis stmt.bind(":var_name", sqlite::blob(buffer, sizeof(buffer)));
120*b0d29bc4SBrooks Davis stmt.step_without_results();
121*b0d29bc4SBrooks Davis }
122*b0d29bc4SBrooks Davis {
123*b0d29bc4SBrooks Davis store::read_backend backend = store::read_backend::open_ro(
124*b0d29bc4SBrooks Davis fs::path("test-bad-name.db"));
125*b0d29bc4SBrooks Davis store::read_transaction tx = backend.start_read();
126*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(store::error, "context: .*var_name.*not a string",
127*b0d29bc4SBrooks Davis tx.get_context());
128*b0d29bc4SBrooks Davis }
129*b0d29bc4SBrooks Davis
130*b0d29bc4SBrooks Davis {
131*b0d29bc4SBrooks Davis store::write_backend backend = store::write_backend::open_rw(
132*b0d29bc4SBrooks Davis fs::path("test-bad-value.db"));
133*b0d29bc4SBrooks Davis backend.database().exec("INSERT INTO contexts (cwd) "
134*b0d29bc4SBrooks Davis "VALUES ('/foo/bar')");
135*b0d29bc4SBrooks Davis const char buffer[10] = "foo bar";
136*b0d29bc4SBrooks Davis
137*b0d29bc4SBrooks Davis sqlite::statement stmt = backend.database().create_statement(
138*b0d29bc4SBrooks Davis "INSERT INTO env_vars (var_name, var_value) "
139*b0d29bc4SBrooks Davis "VALUES ('abc', :var_value)");
140*b0d29bc4SBrooks Davis stmt.bind(":var_value", sqlite::blob(buffer, sizeof(buffer)));
141*b0d29bc4SBrooks Davis stmt.step_without_results();
142*b0d29bc4SBrooks Davis }
143*b0d29bc4SBrooks Davis {
144*b0d29bc4SBrooks Davis store::read_backend backend = store::read_backend::open_ro(
145*b0d29bc4SBrooks Davis fs::path("test-bad-value.db"));
146*b0d29bc4SBrooks Davis store::read_transaction tx = backend.start_read();
147*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(store::error, "context: .*var_value.*not a string",
148*b0d29bc4SBrooks Davis tx.get_context());
149*b0d29bc4SBrooks Davis }
150*b0d29bc4SBrooks Davis }
151*b0d29bc4SBrooks Davis
152*b0d29bc4SBrooks Davis
153*b0d29bc4SBrooks Davis ATF_TEST_CASE(get_results__none);
ATF_TEST_CASE_HEAD(get_results__none)154*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(get_results__none)
155*b0d29bc4SBrooks Davis {
156*b0d29bc4SBrooks Davis logging::set_inmemory();
157*b0d29bc4SBrooks Davis set_md_var("require.files", store::detail::schema_file().c_str());
158*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(get_results__none)159*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(get_results__none)
160*b0d29bc4SBrooks Davis {
161*b0d29bc4SBrooks Davis store::write_backend::open_rw(fs::path("test.db")); // Create database.
162*b0d29bc4SBrooks Davis store::read_backend backend = store::read_backend::open_ro(
163*b0d29bc4SBrooks Davis fs::path("test.db"));
164*b0d29bc4SBrooks Davis store::read_transaction tx = backend.start_read();
165*b0d29bc4SBrooks Davis store::results_iterator iter = tx.get_results();
166*b0d29bc4SBrooks Davis ATF_REQUIRE(!iter);
167*b0d29bc4SBrooks Davis }
168*b0d29bc4SBrooks Davis
169*b0d29bc4SBrooks Davis
170*b0d29bc4SBrooks Davis ATF_TEST_CASE(get_results__many);
ATF_TEST_CASE_HEAD(get_results__many)171*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(get_results__many)
172*b0d29bc4SBrooks Davis {
173*b0d29bc4SBrooks Davis logging::set_inmemory();
174*b0d29bc4SBrooks Davis set_md_var("require.files", store::detail::schema_file().c_str());
175*b0d29bc4SBrooks Davis }
ATF_TEST_CASE_BODY(get_results__many)176*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(get_results__many)
177*b0d29bc4SBrooks Davis {
178*b0d29bc4SBrooks Davis store::write_backend backend = store::write_backend::open_rw(
179*b0d29bc4SBrooks Davis fs::path("test.db"));
180*b0d29bc4SBrooks Davis
181*b0d29bc4SBrooks Davis store::write_transaction tx = backend.start_write();
182*b0d29bc4SBrooks Davis
183*b0d29bc4SBrooks Davis const model::context context(fs::path("/foo/bar"),
184*b0d29bc4SBrooks Davis std::map< std::string, std::string >());
185*b0d29bc4SBrooks Davis tx.put_context(context);
186*b0d29bc4SBrooks Davis
187*b0d29bc4SBrooks Davis const datetime::timestamp start_time1 = datetime::timestamp::from_values(
188*b0d29bc4SBrooks Davis 2012, 01, 30, 22, 10, 00, 0);
189*b0d29bc4SBrooks Davis const datetime::timestamp end_time1 = datetime::timestamp::from_values(
190*b0d29bc4SBrooks Davis 2012, 01, 30, 22, 15, 30, 1234);
191*b0d29bc4SBrooks Davis const datetime::timestamp start_time2 = datetime::timestamp::from_values(
192*b0d29bc4SBrooks Davis 2012, 01, 30, 22, 15, 40, 987);
193*b0d29bc4SBrooks Davis const datetime::timestamp end_time2 = datetime::timestamp::from_values(
194*b0d29bc4SBrooks Davis 2012, 01, 30, 22, 16, 0, 0);
195*b0d29bc4SBrooks Davis
196*b0d29bc4SBrooks Davis atf::utils::create_file("unused.txt", "unused file\n");
197*b0d29bc4SBrooks Davis
198*b0d29bc4SBrooks Davis const model::test_program test_program_1 = model::test_program_builder(
199*b0d29bc4SBrooks Davis "plain", fs::path("a/prog1"), fs::path("/the/root"), "suite1")
200*b0d29bc4SBrooks Davis .add_test_case("main")
201*b0d29bc4SBrooks Davis .build();
202*b0d29bc4SBrooks Davis const model::test_result result_1(model::test_result_passed);
203*b0d29bc4SBrooks Davis {
204*b0d29bc4SBrooks Davis const int64_t tp_id = tx.put_test_program(test_program_1);
205*b0d29bc4SBrooks Davis const int64_t tc_id = tx.put_test_case(test_program_1, "main", tp_id);
206*b0d29bc4SBrooks Davis atf::utils::create_file("prog1.out", "stdout of prog1\n");
207*b0d29bc4SBrooks Davis tx.put_test_case_file("__STDOUT__", fs::path("prog1.out"), tc_id);
208*b0d29bc4SBrooks Davis tx.put_test_case_file("unused.txt", fs::path("unused.txt"), tc_id);
209*b0d29bc4SBrooks Davis tx.put_result(result_1, tc_id, start_time1, end_time1);
210*b0d29bc4SBrooks Davis }
211*b0d29bc4SBrooks Davis
212*b0d29bc4SBrooks Davis const model::test_program test_program_2 = model::test_program_builder(
213*b0d29bc4SBrooks Davis "plain", fs::path("b/prog2"), fs::path("/the/root"), "suite2")
214*b0d29bc4SBrooks Davis .add_test_case("main")
215*b0d29bc4SBrooks Davis .build();
216*b0d29bc4SBrooks Davis const model::test_result result_2(model::test_result_failed,
217*b0d29bc4SBrooks Davis "Some text");
218*b0d29bc4SBrooks Davis {
219*b0d29bc4SBrooks Davis const int64_t tp_id = tx.put_test_program(test_program_2);
220*b0d29bc4SBrooks Davis const int64_t tc_id = tx.put_test_case(test_program_2, "main", tp_id);
221*b0d29bc4SBrooks Davis atf::utils::create_file("prog2.err", "stderr of prog2\n");
222*b0d29bc4SBrooks Davis tx.put_test_case_file("__STDERR__", fs::path("prog2.err"), tc_id);
223*b0d29bc4SBrooks Davis tx.put_test_case_file("unused.txt", fs::path("unused.txt"), tc_id);
224*b0d29bc4SBrooks Davis tx.put_result(result_2, tc_id, start_time2, end_time2);
225*b0d29bc4SBrooks Davis }
226*b0d29bc4SBrooks Davis
227*b0d29bc4SBrooks Davis tx.commit();
228*b0d29bc4SBrooks Davis backend.close();
229*b0d29bc4SBrooks Davis
230*b0d29bc4SBrooks Davis store::read_backend backend2 = store::read_backend::open_ro(
231*b0d29bc4SBrooks Davis fs::path("test.db"));
232*b0d29bc4SBrooks Davis store::read_transaction tx2 = backend2.start_read();
233*b0d29bc4SBrooks Davis store::results_iterator iter = tx2.get_results();
234*b0d29bc4SBrooks Davis ATF_REQUIRE(iter);
235*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(test_program_1, *iter.test_program());
236*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ("main", iter.test_case_name());
237*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ("stdout of prog1\n", iter.stdout_contents());
238*b0d29bc4SBrooks Davis ATF_REQUIRE(iter.stderr_contents().empty());
239*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(result_1, iter.result());
240*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(start_time1, iter.start_time());
241*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(end_time1, iter.end_time());
242*b0d29bc4SBrooks Davis ATF_REQUIRE(++iter);
243*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(test_program_2, *iter.test_program());
244*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ("main", iter.test_case_name());
245*b0d29bc4SBrooks Davis ATF_REQUIRE(iter.stdout_contents().empty());
246*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ("stderr of prog2\n", iter.stderr_contents());
247*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(result_2, iter.result());
248*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(start_time2, iter.start_time());
249*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(end_time2, iter.end_time());
250*b0d29bc4SBrooks Davis ATF_REQUIRE(!++iter);
251*b0d29bc4SBrooks Davis }
252*b0d29bc4SBrooks Davis
253*b0d29bc4SBrooks Davis
ATF_INIT_TEST_CASES(tcs)254*b0d29bc4SBrooks Davis ATF_INIT_TEST_CASES(tcs)
255*b0d29bc4SBrooks Davis {
256*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, get_context__missing);
257*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, get_context__invalid_cwd);
258*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, get_context__invalid_env_vars);
259*b0d29bc4SBrooks Davis
260*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, get_results__none);
261*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, get_results__many);
262*b0d29bc4SBrooks Davis }
263