Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/kyua/store/write_transaction_test.cpp
39478 views
1
// Copyright 2011 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/write_transaction.hpp"
30
31
#include <cstring>
32
#include <map>
33
#include <string>
34
35
#include <atf-c++.hpp>
36
37
#include "model/context.hpp"
38
#include "model/metadata.hpp"
39
#include "model/test_case.hpp"
40
#include "model/test_program.hpp"
41
#include "model/test_result.hpp"
42
#include "store/exceptions.hpp"
43
#include "store/write_backend.hpp"
44
#include "utils/datetime.hpp"
45
#include "utils/fs/path.hpp"
46
#include "utils/logging/operations.hpp"
47
#include "utils/optional.ipp"
48
#include "utils/sqlite/database.hpp"
49
#include "utils/sqlite/exceptions.hpp"
50
#include "utils/sqlite/statement.ipp"
51
52
namespace datetime = utils::datetime;
53
namespace fs = utils::fs;
54
namespace logging = utils::logging;
55
namespace sqlite = utils::sqlite;
56
57
using utils::optional;
58
59
60
namespace {
61
62
63
/// Performs a test for a working put_result
64
///
65
/// \param result The result object to put.
66
/// \param result_type The textual name of the result to expect in the
67
/// database.
68
/// \param exp_reason The reason to expect in the database. This is separate
69
/// from the result parameter so that we can handle passed() here as well.
70
/// Just provide NULL in this case.
71
static void
72
do_put_result_ok_test(const model::test_result& result,
73
const char* result_type, const char* exp_reason)
74
{
75
store::write_backend backend = store::write_backend::open_rw(
76
fs::path("test.db"));
77
backend.database().exec("PRAGMA foreign_keys = OFF");
78
store::write_transaction tx = backend.start_write();
79
const datetime::timestamp start_time = datetime::timestamp::from_values(
80
2012, 01, 30, 22, 10, 00, 0);
81
const datetime::timestamp end_time = datetime::timestamp::from_values(
82
2012, 01, 30, 22, 15, 30, 123456);
83
tx.put_result(result, 312, start_time, end_time);
84
tx.commit();
85
86
sqlite::statement stmt = backend.database().create_statement(
87
"SELECT test_case_id, result_type, result_reason "
88
"FROM test_results");
89
90
ATF_REQUIRE(stmt.step());
91
ATF_REQUIRE_EQ(312, stmt.column_int64(0));
92
ATF_REQUIRE_EQ(result_type, stmt.column_text(1));
93
if (exp_reason != NULL)
94
ATF_REQUIRE_EQ(exp_reason, stmt.column_text(2));
95
else
96
ATF_REQUIRE(stmt.column_type(2) == sqlite::type_null);
97
ATF_REQUIRE(!stmt.step());
98
}
99
100
101
} // anonymous namespace
102
103
104
ATF_TEST_CASE(commit__ok);
105
ATF_TEST_CASE_HEAD(commit__ok)
106
{
107
logging::set_inmemory();
108
set_md_var("require.files", store::detail::schema_file().c_str());
109
}
110
ATF_TEST_CASE_BODY(commit__ok)
111
{
112
store::write_backend backend = store::write_backend::open_rw(
113
fs::path("test.db"));
114
store::write_transaction tx = backend.start_write();
115
backend.database().exec("CREATE TABLE a (b INTEGER PRIMARY KEY)");
116
backend.database().exec("SELECT * FROM a");
117
tx.commit();
118
backend.database().exec("SELECT * FROM a");
119
}
120
121
122
ATF_TEST_CASE(commit__fail);
123
ATF_TEST_CASE_HEAD(commit__fail)
124
{
125
logging::set_inmemory();
126
set_md_var("require.files", store::detail::schema_file().c_str());
127
}
128
ATF_TEST_CASE_BODY(commit__fail)
129
{
130
store::write_backend backend = store::write_backend::open_rw(
131
fs::path("test.db"));
132
const model::context context(fs::path("/foo/bar"),
133
std::map< std::string, std::string >());
134
{
135
store::write_transaction tx = backend.start_write();
136
tx.put_context(context);
137
backend.database().exec(
138
"CREATE TABLE foo ("
139
"a REFERENCES env_vars(var_name) DEFERRABLE INITIALLY DEFERRED)");
140
backend.database().exec("INSERT INTO foo VALUES (\"WHAT\")");
141
ATF_REQUIRE_THROW(store::error, tx.commit());
142
}
143
// If the code attempts to maintain any state regarding the already-put
144
// objects and the commit does not clean up correctly, this would fail in
145
// some manner.
146
store::write_transaction tx = backend.start_write();
147
tx.put_context(context);
148
tx.commit();
149
}
150
151
152
ATF_TEST_CASE(rollback__ok);
153
ATF_TEST_CASE_HEAD(rollback__ok)
154
{
155
logging::set_inmemory();
156
set_md_var("require.files", store::detail::schema_file().c_str());
157
}
158
ATF_TEST_CASE_BODY(rollback__ok)
159
{
160
store::write_backend backend = store::write_backend::open_rw(
161
fs::path("test.db"));
162
store::write_transaction tx = backend.start_write();
163
backend.database().exec("CREATE TABLE a_table (b INTEGER PRIMARY KEY)");
164
backend.database().exec("SELECT * FROM a_table");
165
tx.rollback();
166
ATF_REQUIRE_THROW_RE(sqlite::error, "a_table",
167
backend.database().exec("SELECT * FROM a_table"));
168
}
169
170
171
ATF_TEST_CASE(put_test_program__ok);
172
ATF_TEST_CASE_HEAD(put_test_program__ok)
173
{
174
logging::set_inmemory();
175
set_md_var("require.files", store::detail::schema_file().c_str());
176
}
177
ATF_TEST_CASE_BODY(put_test_program__ok)
178
{
179
const model::metadata md = model::metadata_builder()
180
.add_custom("var1", "value1")
181
.add_custom("var2", "value2")
182
.build();
183
const model::test_program test_program(
184
"mock", fs::path("the/binary"), fs::path("/some//root"),
185
"the-suite", md, model::test_cases_map());
186
187
store::write_backend backend = store::write_backend::open_rw(
188
fs::path("test.db"));
189
backend.database().exec("PRAGMA foreign_keys = OFF");
190
store::write_transaction tx = backend.start_write();
191
const int64_t test_program_id = tx.put_test_program(test_program);
192
tx.commit();
193
194
{
195
sqlite::statement stmt = backend.database().create_statement(
196
"SELECT * FROM test_programs");
197
198
ATF_REQUIRE(stmt.step());
199
ATF_REQUIRE_EQ(test_program_id,
200
stmt.safe_column_int64("test_program_id"));
201
ATF_REQUIRE_EQ("/some/root/the/binary",
202
stmt.safe_column_text("absolute_path"));
203
ATF_REQUIRE_EQ("/some/root", stmt.safe_column_text("root"));
204
ATF_REQUIRE_EQ("the/binary", stmt.safe_column_text("relative_path"));
205
ATF_REQUIRE_EQ("the-suite", stmt.safe_column_text("test_suite_name"));
206
ATF_REQUIRE(!stmt.step());
207
}
208
}
209
210
211
ATF_TEST_CASE(put_test_case__fail);
212
ATF_TEST_CASE_HEAD(put_test_case__fail)
213
{
214
logging::set_inmemory();
215
set_md_var("require.files", store::detail::schema_file().c_str());
216
}
217
ATF_TEST_CASE_BODY(put_test_case__fail)
218
{
219
const model::test_program test_program = model::test_program_builder(
220
"plain", fs::path("the/binary"), fs::path("/some/root"), "the-suite")
221
.add_test_case("main")
222
.build();
223
224
store::write_backend backend = store::write_backend::open_rw(
225
fs::path("test.db"));
226
store::write_transaction tx = backend.start_write();
227
ATF_REQUIRE_THROW(store::error, tx.put_test_case(test_program, "main", -1));
228
tx.commit();
229
}
230
231
232
ATF_TEST_CASE(put_test_case_file__empty);
233
ATF_TEST_CASE_HEAD(put_test_case_file__empty)
234
{
235
logging::set_inmemory();
236
set_md_var("require.files", store::detail::schema_file().c_str());
237
}
238
ATF_TEST_CASE_BODY(put_test_case_file__empty)
239
{
240
atf::utils::create_file("input.txt", "");
241
242
store::write_backend backend = store::write_backend::open_rw(
243
fs::path("test.db"));
244
backend.database().exec("PRAGMA foreign_keys = OFF");
245
store::write_transaction tx = backend.start_write();
246
const optional< int64_t > file_id = tx.put_test_case_file(
247
"my-file", fs::path("input.txt"), 123L);
248
tx.commit();
249
ATF_REQUIRE(!file_id);
250
251
sqlite::statement stmt = backend.database().create_statement(
252
"SELECT * FROM test_case_files NATURAL JOIN files");
253
ATF_REQUIRE(!stmt.step());
254
}
255
256
257
ATF_TEST_CASE(put_test_case_file__some);
258
ATF_TEST_CASE_HEAD(put_test_case_file__some)
259
{
260
logging::set_inmemory();
261
set_md_var("require.files", store::detail::schema_file().c_str());
262
}
263
ATF_TEST_CASE_BODY(put_test_case_file__some)
264
{
265
const char contents[] = "This is a test!";
266
267
atf::utils::create_file("input.txt", contents);
268
269
store::write_backend backend = store::write_backend::open_rw(
270
fs::path("test.db"));
271
backend.database().exec("PRAGMA foreign_keys = OFF");
272
store::write_transaction tx = backend.start_write();
273
const optional< int64_t > file_id = tx.put_test_case_file(
274
"my-file", fs::path("input.txt"), 123L);
275
tx.commit();
276
ATF_REQUIRE(file_id);
277
278
sqlite::statement stmt = backend.database().create_statement(
279
"SELECT * FROM test_case_files NATURAL JOIN files");
280
281
ATF_REQUIRE(stmt.step());
282
ATF_REQUIRE_EQ(123L, stmt.safe_column_int64("test_case_id"));
283
ATF_REQUIRE_EQ("my-file", stmt.safe_column_text("file_name"));
284
const sqlite::blob blob = stmt.safe_column_blob("contents");
285
ATF_REQUIRE(std::strlen(contents) == static_cast< std::size_t >(blob.size));
286
ATF_REQUIRE(std::memcmp(contents, blob.memory, blob.size) == 0);
287
ATF_REQUIRE(!stmt.step());
288
}
289
290
291
ATF_TEST_CASE(put_test_case_file__fail);
292
ATF_TEST_CASE_HEAD(put_test_case_file__fail)
293
{
294
logging::set_inmemory();
295
set_md_var("require.files", store::detail::schema_file().c_str());
296
}
297
ATF_TEST_CASE_BODY(put_test_case_file__fail)
298
{
299
store::write_backend backend = store::write_backend::open_rw(
300
fs::path("test.db"));
301
backend.database().exec("PRAGMA foreign_keys = OFF");
302
store::write_transaction tx = backend.start_write();
303
ATF_REQUIRE_THROW(store::error,
304
tx.put_test_case_file("foo", fs::path("missing"), 1L));
305
tx.commit();
306
307
sqlite::statement stmt = backend.database().create_statement(
308
"SELECT * FROM test_case_files NATURAL JOIN files");
309
ATF_REQUIRE(!stmt.step());
310
}
311
312
313
ATF_TEST_CASE(put_result__ok__broken);
314
ATF_TEST_CASE_HEAD(put_result__ok__broken)
315
{
316
logging::set_inmemory();
317
set_md_var("require.files", store::detail::schema_file().c_str());
318
}
319
ATF_TEST_CASE_BODY(put_result__ok__broken)
320
{
321
const model::test_result result(model::test_result_broken, "a b cd");
322
do_put_result_ok_test(result, "broken", "a b cd");
323
}
324
325
326
ATF_TEST_CASE(put_result__ok__expected_failure);
327
ATF_TEST_CASE_HEAD(put_result__ok__expected_failure)
328
{
329
logging::set_inmemory();
330
set_md_var("require.files", store::detail::schema_file().c_str());
331
}
332
ATF_TEST_CASE_BODY(put_result__ok__expected_failure)
333
{
334
const model::test_result result(model::test_result_expected_failure,
335
"a b cd");
336
do_put_result_ok_test(result, "expected_failure", "a b cd");
337
}
338
339
340
ATF_TEST_CASE(put_result__ok__failed);
341
ATF_TEST_CASE_HEAD(put_result__ok__failed)
342
{
343
logging::set_inmemory();
344
set_md_var("require.files", store::detail::schema_file().c_str());
345
}
346
ATF_TEST_CASE_BODY(put_result__ok__failed)
347
{
348
const model::test_result result(model::test_result_failed, "a b cd");
349
do_put_result_ok_test(result, "failed", "a b cd");
350
}
351
352
353
ATF_TEST_CASE(put_result__ok__passed);
354
ATF_TEST_CASE_HEAD(put_result__ok__passed)
355
{
356
logging::set_inmemory();
357
set_md_var("require.files", store::detail::schema_file().c_str());
358
}
359
ATF_TEST_CASE_BODY(put_result__ok__passed)
360
{
361
const model::test_result result(model::test_result_passed);
362
do_put_result_ok_test(result, "passed", NULL);
363
}
364
365
366
ATF_TEST_CASE(put_result__ok__skipped);
367
ATF_TEST_CASE_HEAD(put_result__ok__skipped)
368
{
369
logging::set_inmemory();
370
set_md_var("require.files", store::detail::schema_file().c_str());
371
}
372
ATF_TEST_CASE_BODY(put_result__ok__skipped)
373
{
374
const model::test_result result(model::test_result_skipped, "a b cd");
375
do_put_result_ok_test(result, "skipped", "a b cd");
376
}
377
378
379
ATF_TEST_CASE(put_result__fail);
380
ATF_TEST_CASE_HEAD(put_result__fail)
381
{
382
logging::set_inmemory();
383
set_md_var("require.files", store::detail::schema_file().c_str());
384
}
385
ATF_TEST_CASE_BODY(put_result__fail)
386
{
387
const model::test_result result(model::test_result_broken, "foo");
388
389
store::write_backend backend = store::write_backend::open_rw(
390
fs::path("test.db"));
391
store::write_transaction tx = backend.start_write();
392
const datetime::timestamp zero = datetime::timestamp::from_microseconds(0);
393
ATF_REQUIRE_THROW(store::error, tx.put_result(result, -1, zero, zero));
394
tx.commit();
395
}
396
397
398
ATF_INIT_TEST_CASES(tcs)
399
{
400
ATF_ADD_TEST_CASE(tcs, commit__ok);
401
ATF_ADD_TEST_CASE(tcs, commit__fail);
402
ATF_ADD_TEST_CASE(tcs, rollback__ok);
403
404
ATF_ADD_TEST_CASE(tcs, put_test_program__ok);
405
ATF_ADD_TEST_CASE(tcs, put_test_case__fail);
406
ATF_ADD_TEST_CASE(tcs, put_test_case_file__empty);
407
ATF_ADD_TEST_CASE(tcs, put_test_case_file__some);
408
ATF_ADD_TEST_CASE(tcs, put_test_case_file__fail);
409
410
ATF_ADD_TEST_CASE(tcs, put_result__ok__broken);
411
ATF_ADD_TEST_CASE(tcs, put_result__ok__expected_failure);
412
ATF_ADD_TEST_CASE(tcs, put_result__ok__failed);
413
ATF_ADD_TEST_CASE(tcs, put_result__ok__passed);
414
ATF_ADD_TEST_CASE(tcs, put_result__ok__skipped);
415
ATF_ADD_TEST_CASE(tcs, put_result__fail);
416
}
417
418