sqlite3_accessor_unittest.cc 28.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
14

15
#include <algorithm>
16
17
#include <vector>

18
#include <datasrc/sqlite3_accessor.h>
19

20
21
#include <datasrc/data_source.h>

22
23
#include <dns/rrclass.h>

24
#include <gtest/gtest.h>
25
#include <boost/scoped_ptr.hpp>
26
27
#include <fstream>
#include <sqlite3.h>
28

29
using namespace std;
30
using namespace isc::datasrc;
31
using boost::shared_ptr;
32
33
using isc::data::ConstElementPtr;
using isc::data::Element;
34
35
using isc::dns::RRClass;
using isc::dns::Name;
36
37
38

namespace {
// Some test data
39
40
std::string SQLITE_DBFILE_EXAMPLE = TEST_DATA_DIR "/test.sqlite3";
std::string SQLITE_DBFILE_EXAMPLE2 = TEST_DATA_DIR "/example2.com.sqlite3";
41
std::string SQLITE_DBNAME_EXAMPLE2 = "sqlite3_example2.com.sqlite3";
42
std::string SQLITE_DBFILE_EXAMPLE_ROOT = TEST_DATA_DIR "/test-root.sqlite3";
43
std::string SQLITE_DBNAME_EXAMPLE_ROOT = "sqlite3_test-root.sqlite3";
44
std::string SQLITE_DBFILE_BROKENDB = TEST_DATA_DIR "/brokendb.sqlite3";
45
std::string SQLITE_DBFILE_MEMORY = ":memory:";
46
std::string SQLITE_DBFILE_EXAMPLE_ORG = TEST_DATA_DIR "/example.org.sqlite3";
47
48
49
50
51

// The following file must be non existent and must be non"creatable";
// the sqlite3 library will try to create a new DB file if it doesn't exist,
// so to test a failure case the create operation should also fail.
// The "nodir", a non existent directory, is inserted for this purpose.
52
std::string SQLITE_DBFILE_NOTEXIST = TEST_DATA_DIR "/nodir/notexist";
53

54
55
// new db file, we don't need this to be a std::string, and given the
// raw calls we use it in a const char* is more convenient
56
const char* SQLITE_NEW_DBFILE = TEST_DATA_BUILDDIR "/newdb.sqlite3";
57

58
59
// Opening works (the content is tested in different tests)
TEST(SQLite3Open, common) {
60
61
    EXPECT_NO_THROW(SQLite3Accessor accessor(SQLITE_DBFILE_EXAMPLE,
                                             RRClass::IN()));
62
63
64
65
}

// The file can't be opened
TEST(SQLite3Open, notExist) {
66
67
    EXPECT_THROW(SQLite3Accessor accessor(SQLITE_DBFILE_NOTEXIST,
                                          RRClass::IN()), SQLite3Error);
68
69
70
71
}

// It rejects broken DB
TEST(SQLite3Open, brokenDB) {
72
73
    EXPECT_THROW(SQLite3Accessor accessor(SQLITE_DBFILE_BROKENDB,
                                          RRClass::IN()), SQLite3Error);
74
75
76
77
}

// Test we can create the schema on the fly
TEST(SQLite3Open, memoryDB) {
78
79
    EXPECT_NO_THROW(SQLite3Accessor accessor(SQLITE_DBFILE_MEMORY,
                                             RRClass::IN()));
80
81
}

82
// Test fixture for querying the db
83
class SQLite3AccessorTest : public ::testing::Test {
84
public:
85
    SQLite3AccessorTest() {
86
        initAccessor(SQLITE_DBFILE_EXAMPLE, RRClass::IN());
87
88
    }
    // So it can be re-created with different data
89
    void initAccessor(const std::string& filename, const RRClass& rrclass) {
90
        accessor.reset(new SQLite3Accessor(filename, rrclass));
91
    }
92
93
    // The tested accessor
    boost::shared_ptr<SQLite3Accessor> accessor;
94
95
96
};

// This zone exists in the data, so it should be found
97
TEST_F(SQLite3AccessorTest, getZone) {
98
    std::pair<bool, int> result(accessor->getZone("example.com."));
99
100
101
102
103
    EXPECT_TRUE(result.first);
    EXPECT_EQ(1, result.second);
}

// But it should find only the zone, nothing below it
104
TEST_F(SQLite3AccessorTest, subZone) {
105
    EXPECT_FALSE(accessor->getZone("sub.example.com.").first);
106
107
108
}

// This zone is not there at all
109
TEST_F(SQLite3AccessorTest, noZone) {
110
    EXPECT_FALSE(accessor->getZone("example.org.").first);
111
112
113
}

// This zone is there, but in different class
114
TEST_F(SQLite3AccessorTest, noClass) {
115
    initAccessor(SQLITE_DBFILE_EXAMPLE, RRClass::CH());
116
    EXPECT_FALSE(accessor->getZone("example.com.").first);
117
118
}

119
// This tests the iterator context
120
TEST_F(SQLite3AccessorTest, iterator) {
121
    // Our test zone is conveniently small, but not empty
122
123
    initAccessor(SQLITE_DBFILE_EXAMPLE_ORG, RRClass::IN());

124
    const std::pair<bool, int> zone_info(accessor->getZone("example.org."));
125
    ASSERT_TRUE(zone_info.first);
126
127

    // Get the iterator context
128
    DatabaseAccessor::IteratorContextPtr
129
        context(accessor->getAllRecords(zone_info.second));
130
    ASSERT_NE(DatabaseAccessor::IteratorContextPtr(), context);
131

132
    std::string data[DatabaseAccessor::COLUMN_COUNT];
133
    // Get and check the first and only record
134
    EXPECT_TRUE(context->getNext(data));
135
136
137
138
    EXPECT_EQ("DNAME", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("dname.example.info.", data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("dname.example.org.", data[DatabaseAccessor::NAME_COLUMN]);
139

140
141
142
143
144
    EXPECT_TRUE(context->getNext(data));
    EXPECT_EQ("DNAME", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("dname2.example.info.", data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("dname2.foo.example.org.", data[DatabaseAccessor::NAME_COLUMN]);
145

146
147
148
149
150
    EXPECT_TRUE(context->getNext(data));
    EXPECT_EQ("MX", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("10 mail.example.org.", data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("example.org.", data[DatabaseAccessor::NAME_COLUMN]);
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
    EXPECT_TRUE(context->getNext(data));
    EXPECT_EQ("NS", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("ns1.example.org.", data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("example.org.", data[DatabaseAccessor::NAME_COLUMN]);

    EXPECT_TRUE(context->getNext(data));
    EXPECT_EQ("NS", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("ns2.example.org.", data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("example.org.", data[DatabaseAccessor::NAME_COLUMN]);

    EXPECT_TRUE(context->getNext(data));
    EXPECT_EQ("NS", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("ns3.example.org.", data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("example.org.", data[DatabaseAccessor::NAME_COLUMN]);

    EXPECT_TRUE(context->getNext(data));
    EXPECT_EQ("SOA", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("ns1.example.org. admin.example.org. "
              "1234 3600 1800 2419200 7200",
              data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("example.org.", data[DatabaseAccessor::NAME_COLUMN]);

    EXPECT_TRUE(context->getNext(data));
    EXPECT_EQ("A", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("192.0.2.10", data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("mail.example.org.", data[DatabaseAccessor::NAME_COLUMN]);

    EXPECT_TRUE(context->getNext(data));
    EXPECT_EQ("A", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("192.0.2.101", data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("ns.sub.example.org.", data[DatabaseAccessor::NAME_COLUMN]);

    EXPECT_TRUE(context->getNext(data));
    EXPECT_EQ("NS", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("ns.sub.example.org.", data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("sub.example.org.", data[DatabaseAccessor::NAME_COLUMN]);

    EXPECT_TRUE(context->getNext(data));
    EXPECT_EQ("A", data[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ("3600", data[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ("192.0.2.1", data[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ("www.example.org.", data[DatabaseAccessor::NAME_COLUMN]);

    // Check there's no other
    EXPECT_FALSE(context->getNext(data));
204
205
206

    // And make sure calling it again won't cause problems.
    EXPECT_FALSE(context->getNext(data));
207
208
}

209
TEST(SQLite3Open, getDBNameExample2) {
210
211
    SQLite3Accessor accessor(SQLITE_DBFILE_EXAMPLE2, RRClass::IN());
    EXPECT_EQ(SQLITE_DBNAME_EXAMPLE2, accessor.getDBName());
212
}
213
214

TEST(SQLite3Open, getDBNameExampleROOT) {
215
216
    SQLite3Accessor accessor(SQLITE_DBFILE_EXAMPLE_ROOT, RRClass::IN());
    EXPECT_EQ(SQLITE_DBNAME_EXAMPLE_ROOT, accessor.getDBName());
217
218
}

219
220
221
222
223
224
225
// Simple function to cound the number of records for
// any name
void
checkRecordRow(const std::string columns[],
               const std::string& field0,
               const std::string& field1,
               const std::string& field2,
226
227
               const std::string& field3,
               const std::string& field4)
228
{
229
230
231
232
233
    EXPECT_EQ(field0, columns[DatabaseAccessor::TYPE_COLUMN]);
    EXPECT_EQ(field1, columns[DatabaseAccessor::TTL_COLUMN]);
    EXPECT_EQ(field2, columns[DatabaseAccessor::SIGTYPE_COLUMN]);
    EXPECT_EQ(field3, columns[DatabaseAccessor::RDATA_COLUMN]);
    EXPECT_EQ(field4, columns[DatabaseAccessor::NAME_COLUMN]);
Jelte Jansen's avatar
Jelte Jansen committed
234
235
}

236
TEST_F(SQLite3AccessorTest, getRecords) {
237
    const std::pair<bool, int> zone_info(accessor->getZone("example.com."));
Jelte Jansen's avatar
Jelte Jansen committed
238
239
    ASSERT_TRUE(zone_info.first);

240
    const int zone_id = zone_info.second;
Jelte Jansen's avatar
Jelte Jansen committed
241
242
    ASSERT_EQ(1, zone_id);

243
    std::string columns[DatabaseAccessor::COLUMN_COUNT];
Jelte Jansen's avatar
Jelte Jansen committed
244

245
    DatabaseAccessor::IteratorContextPtr
246
        context(accessor->getRecords("foo.bar", 1));
247
248
    ASSERT_NE(DatabaseAccessor::IteratorContextPtr(),
              context);
249
    EXPECT_FALSE(context->getNext(columns));
250
    checkRecordRow(columns, "", "", "", "", "");
251
252

    // now try some real searches
253
    context = accessor->getRecords("foo.example.com.", zone_id);
254
    ASSERT_TRUE(context->getNext(columns));
255
    checkRecordRow(columns, "CNAME", "3600", "",
256
                   "cnametest.example.org.", "");
257
    ASSERT_TRUE(context->getNext(columns));
258
259
    checkRecordRow(columns, "RRSIG", "3600", "CNAME",
                   "CNAME 5 3 3600 20100322084538 20100220084538 33495 "
260
                   "example.com. FAKEFAKEFAKEFAKE", "");
261
    ASSERT_TRUE(context->getNext(columns));
262
    checkRecordRow(columns, "NSEC", "7200", "",
263
                   "mail.example.com. CNAME RRSIG NSEC", "");
264
    ASSERT_TRUE(context->getNext(columns));
265
266
    checkRecordRow(columns, "RRSIG", "7200", "NSEC",
                   "NSEC 5 3 7200 20100322084538 20100220084538 33495 "
267
                   "example.com. FAKEFAKEFAKEFAKE", "");
268
    EXPECT_FALSE(context->getNext(columns));
269

270
271
272
    // with no more records, the array should not have been modified
    checkRecordRow(columns, "RRSIG", "7200", "NSEC",
                   "NSEC 5 3 7200 20100322084538 20100220084538 33495 "
273
                   "example.com. FAKEFAKEFAKEFAKE", "");
274

275
    context = accessor->getRecords("example.com.", zone_id);
276
    ASSERT_TRUE(context->getNext(columns));
277
278
    checkRecordRow(columns, "SOA", "3600", "",
                   "master.example.com. admin.example.com. "
279
                   "1234 3600 1800 2419200 7200", "");
280
    ASSERT_TRUE(context->getNext(columns));
281
282
    checkRecordRow(columns, "RRSIG", "3600", "SOA",
                   "SOA 5 2 3600 20100322084538 20100220084538 "
283
                   "33495 example.com. FAKEFAKEFAKEFAKE", "");
284
    ASSERT_TRUE(context->getNext(columns));
285
    checkRecordRow(columns, "NS", "1200", "", "dns01.example.com.", "");
286
    ASSERT_TRUE(context->getNext(columns));
287
    checkRecordRow(columns, "NS", "3600", "", "dns02.example.com.", "");
288
    ASSERT_TRUE(context->getNext(columns));
289
    checkRecordRow(columns, "NS", "1800", "", "dns03.example.com.", "");
290
    ASSERT_TRUE(context->getNext(columns));
291
292
    checkRecordRow(columns, "RRSIG", "3600", "NS",
                   "NS 5 2 3600 20100322084538 20100220084538 "
293
                   "33495 example.com. FAKEFAKEFAKEFAKE", "");
294
    ASSERT_TRUE(context->getNext(columns));
295
    checkRecordRow(columns, "MX", "3600", "", "10 mail.example.com.", "");
296
    ASSERT_TRUE(context->getNext(columns));
297
    checkRecordRow(columns, "MX", "3600", "",
298
                   "20 mail.subzone.example.com.", "");
299
    ASSERT_TRUE(context->getNext(columns));
300
301
    checkRecordRow(columns, "RRSIG", "3600", "MX",
                   "MX 5 2 3600 20100322084538 20100220084538 "
302
                   "33495 example.com. FAKEFAKEFAKEFAKE", "");
303
    ASSERT_TRUE(context->getNext(columns));
304
    checkRecordRow(columns, "NSEC", "7200", "",
305
                   "cname-ext.example.com. NS SOA MX RRSIG NSEC DNSKEY", "");
306
    ASSERT_TRUE(context->getNext(columns));
307
308
    checkRecordRow(columns, "RRSIG", "7200", "NSEC",
                   "NSEC 5 2 7200 20100322084538 20100220084538 "
309
                   "33495 example.com. FAKEFAKEFAKEFAKE", "");
310
    ASSERT_TRUE(context->getNext(columns));
311
312
313
314
    checkRecordRow(columns, "DNSKEY", "3600", "",
                   "256 3 5 AwEAAcOUBllYc1hf7ND9uDy+Yz1BF3sI0m4q NGV7W"
                   "cTD0WEiuV7IjXgHE36fCmS9QsUxSSOV o1I/FMxI2PJVqTYHkX"
                   "FBS7AzLGsQYMU7UjBZ SotBJ6Imt5pXMu+lEDNy8TOUzG3xm7g"
315
                   "0qcbW YF6qCEfvZoBtAqi5Rk7Mlrqs8agxYyMx", "");
316
    ASSERT_TRUE(context->getNext(columns));
317
318
319
320
321
322
323
324
    checkRecordRow(columns, "DNSKEY", "3600", "",
                   "257 3 5 AwEAAe5WFbxdCPq2jZrZhlMj7oJdff3W7syJ tbvzg"
                   "62tRx0gkoCDoBI9DPjlOQG0UAbj+xUV 4HQZJStJaZ+fHU5AwV"
                   "NT+bBZdtV+NujSikhd THb4FYLg2b3Cx9NyJvAVukHp/91HnWu"
                   "G4T36 CzAFrfPwsHIrBz9BsaIQ21VRkcmj7DswfI/i DGd8j6b"
                   "qiODyNZYQ+ZrLmF0KIJ2yPN3iO6Zq 23TaOrVTjB7d1a/h31OD"
                   "fiHAxFHrkY3t3D5J R9Nsl/7fdRmSznwtcSDgLXBoFEYmw6p86"
                   "Acv RyoYNcL1SXjaKVLG5jyU3UR+LcGZT5t/0xGf oIK/aKwEN"
325
                   "rsjcKZZj660b1M=", "");
326
    ASSERT_TRUE(context->getNext(columns));
327
328
    checkRecordRow(columns, "RRSIG", "3600", "DNSKEY",
                   "DNSKEY 5 2 3600 20100322084538 20100220084538 "
329
                   "4456 example.com. FAKEFAKEFAKEFAKE", "");
330
    ASSERT_TRUE(context->getNext(columns));
331
332
    checkRecordRow(columns, "RRSIG", "3600", "DNSKEY",
                   "DNSKEY 5 2 3600 20100322084538 20100220084538 "
333
                   "33495 example.com. FAKEFAKEFAKEFAKE", "");
334
    EXPECT_FALSE(context->getNext(columns));
335
336
337
    // getnextrecord returning false should mean array is not altered
    checkRecordRow(columns, "RRSIG", "3600", "DNSKEY",
                   "DNSKEY 5 2 3600 20100322084538 20100220084538 "
338
                   "33495 example.com. FAKEFAKEFAKEFAKE", "");
339
340
341

    // check that another getNext does not cause problems
    EXPECT_FALSE(context->getNext(columns));
342
343
344

    // Try searching for subdomain
    // There's foo.bar.example.com in the data
345
    context = accessor->getRecords("bar.example.com.", zone_id, true);
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
346
347
348
    ASSERT_TRUE(context->getNext(columns));
    checkRecordRow(columns, "A", "3600", "", "192.0.2.1", "");
    EXPECT_FALSE(context->getNext(columns));
349
    // But we shouldn't match mix.example.com here
350
    context = accessor->getRecords("ix.example.com.", zone_id, true);
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
351
    EXPECT_FALSE(context->getNext(columns));
352
}
353

354
355
356
357
358
359
360
361
362
363
364
365
366
// Test fixture for creating a db that automatically deletes it before start,
// and when done
class SQLite3Create : public ::testing::Test {
public:
    SQLite3Create() {
        remove(SQLITE_NEW_DBFILE);
    }

    ~SQLite3Create() {
        remove(SQLITE_NEW_DBFILE);
    }
};

367
368
bool isReadable(const char* filename) {
    return (std::ifstream(filename).is_open());
369
370
371
}

TEST_F(SQLite3Create, creationtest) {
372
    ASSERT_FALSE(isReadable(SQLITE_NEW_DBFILE));
373
    // Should simply be created
374
    SQLite3Accessor accessor(SQLITE_NEW_DBFILE, RRClass::IN());
375
    ASSERT_TRUE(isReadable(SQLITE_NEW_DBFILE));
376
377
378
}

TEST_F(SQLite3Create, emptytest) {
379
    ASSERT_FALSE(isReadable(SQLITE_NEW_DBFILE));
380
381
382
383
384
385

    // open one manualle
    sqlite3* db;
    ASSERT_EQ(SQLITE_OK, sqlite3_open(SQLITE_NEW_DBFILE, &db));

    // empty, but not locked, so creating it now should work
386
    SQLite3Accessor accessor2(SQLITE_NEW_DBFILE, RRClass::IN());
387
388
389
390

    sqlite3_close(db);

    // should work now that we closed it
391
    SQLite3Accessor accessor3(SQLITE_NEW_DBFILE, RRClass::IN());
392
393
394
}

TEST_F(SQLite3Create, lockedtest) {
395
    ASSERT_FALSE(isReadable(SQLITE_NEW_DBFILE));
396
397
398
399
400
401
402

    // open one manually
    sqlite3* db;
    ASSERT_EQ(SQLITE_OK, sqlite3_open(SQLITE_NEW_DBFILE, &db));
    sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION", NULL, NULL, NULL);

    // should not be able to open it
403
    EXPECT_THROW(SQLite3Accessor accessor2(SQLITE_NEW_DBFILE, RRClass::IN()),
404
405
406
407
408
                 SQLite3Error);

    sqlite3_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, NULL);

    // should work now that we closed it
409
    SQLite3Accessor accessor3(SQLITE_NEW_DBFILE, RRClass::IN());
410
411
}

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
//
// Commonly used data for update tests
//
const char* const common_expected_data[] = {
    // Test record already stored in the tested sqlite3 DB file.
    "foo.bar.example.com.", "com.example.bar.foo.", "3600", "A", "",
    "192.0.2.1"
};
const char* const new_data[] = {
    // Newly added data commonly used by some of the tests below
    "newdata.example.com.", "com.example.newdata.", "3600", "A", "",
    "192.0.2.1"
};
const char* const deleted_data[] = {
    // Existing data to be removed commonly used by some of the tests below
    "foo.bar.example.com.", "A", "192.0.2.1"
};

430
class SQLite3Update : public SQLite3AccessorTest {
431
432
protected:
    SQLite3Update() {
433
        // Note: if "installing" the test file fails some of the subsequent
434
435
436
437
438
439
440
441
442
443
        // tests would fail.
        const char *install_cmd = INSTALL_PROG " " TEST_DATA_DIR
                                  "/test.sqlite3 " TEST_DATA_BUILDDIR
                                  "/test.sqlite3.copied";
        if (system(install_cmd) != 0) {
            // any exception will do, this is failure in test setup, but nice
            // to show the command that fails, and shouldn't be caught
            isc_throw(isc::Exception,
                      "Error setting up; command failed: " << install_cmd);
        };
444
        initAccessor(TEST_DATA_BUILDDIR "/test.sqlite3.copied", RRClass::IN());
445
        zone_id = accessor->getZone("example.com.").second;
446
447
448
        another_accessor.reset(new SQLite3Accessor(
                                   TEST_DATA_BUILDDIR "/test.sqlite3.copied",
                                   RRClass::IN()));
449
450
451
452
453
        expected_stored.push_back(common_expected_data);
    }

    int zone_id;
    std::string get_columns[DatabaseAccessor::COLUMN_COUNT];
454
455
    std::string add_columns[DatabaseAccessor::ADD_COLUMN_COUNT];
    std::string del_params[DatabaseAccessor::DEL_PARAM_COUNT];
456
457
458
459
460

    vector<const char* const*> expected_stored; // placeholder for checkRecords
    vector<const char* const*> empty_stored; // indicate no corresponding data

    // Another accessor, emulating one running on a different process/thread
461
    shared_ptr<SQLite3Accessor> another_accessor;
462
    DatabaseAccessor::IteratorContextPtr iterator;
463
464
465
};

void
466
checkRecords(SQLite3Accessor& accessor, int zone_id, const std::string& name,
467
468
             vector<const char* const*> expected_rows)
{
469
    DatabaseAccessor::IteratorContextPtr iterator =
470
        accessor.getRecords(name, zone_id);
471
472
    std::string columns[DatabaseAccessor::COLUMN_COUNT];
    vector<const char* const*>::const_iterator it = expected_rows.begin();
473
    while (iterator->getNext(columns)) {
474
        ASSERT_TRUE(it != expected_rows.end());
475
        checkRecordRow(columns, (*it)[3], (*it)[2], (*it)[4], (*it)[5], "");
476
477
478
479
480
481
482
483
484
        ++it;
    }
    EXPECT_TRUE(it == expected_rows.end());
}

TEST_F(SQLite3Update, emptyUpdate) {
    // If we do nothing between start and commit, the zone content
    // should be intact.

485
486
487
488
489
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
    zone_id = accessor->startUpdateZone("example.com.", false).second;
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
    accessor->commitUpdateZone();
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
490
491
492
493
494
495
}

TEST_F(SQLite3Update, flushZone) {
    // With 'replace' being true startUpdateZone() will flush the existing
    // zone content.

496
497
498
499
500
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
    zone_id = accessor->startUpdateZone("example.com.", true).second;
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
    accessor->commitUpdateZone();
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
501
502
503
}

TEST_F(SQLite3Update, readWhileUpdate) {
504
505
    zone_id = accessor->startUpdateZone("example.com.", true).second;
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
506
507

    // Until commit is done, the other accessor should see the old data
508
    checkRecords(*another_accessor, zone_id, "foo.bar.example.com.",
509
510
511
512
                 expected_stored);

    // Once the changes are committed, the other accessor will see the new
    // data.
513
514
515
    accessor->commitUpdateZone();
    checkRecords(*another_accessor, zone_id, "foo.bar.example.com.",
                 empty_stored);
516
517
518
}

TEST_F(SQLite3Update, rollback) {
519
520
    zone_id = accessor->startUpdateZone("example.com.", true).second;
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
521
522

    // Rollback will revert the change made by startUpdateZone(, true).
523
524
    accessor->rollbackUpdateZone();
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
525
526
}

527
528
529
530
531
532
TEST_F(SQLite3Update, rollbackFailure) {
    // This test emulates a rare scenario of making rollback attempt fail.
    // The iterator is paused in the middle of getting records, which prevents
    // the rollback operation at the end of the test.

    string columns[DatabaseAccessor::COLUMN_COUNT];
533
    iterator = accessor->getRecords("example.com.", zone_id);
534
535
    EXPECT_TRUE(iterator->getNext(columns));

536
537
    accessor->startUpdateZone("example.com.", true);
    EXPECT_THROW(accessor->rollbackUpdateZone(), DataSourceError);
538
539
}

540
541
542
TEST_F(SQLite3Update, commitConflict) {
    // Start reading the DB by another accessor.  We should stop at a single
    // call to getNextRecord() to keep holding the lock.
543
    iterator = another_accessor->getRecords("foo.example.com.", zone_id);
544
    EXPECT_TRUE(iterator->getNext(get_columns));
545
546
547

    // Due to getNextRecord() above, the other accessor holds a DB lock,
    // which will prevent commit.
548
549
550
551
    zone_id = accessor->startUpdateZone("example.com.", true).second;
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
    EXPECT_THROW(accessor->commitUpdateZone(), DataSourceError);
    accessor->rollbackUpdateZone();   // rollback should still succeed
552

553
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
554
555
556
557
558
559
560
}

TEST_F(SQLite3Update, updateConflict) {
    // Similar to the previous case, but this is a conflict with another
    // update attempt.  Note that these two accessors modify disjoint sets
    // of data; sqlite3 only has a coarse-grained lock so we cannot allow
    // these updates to run concurrently.
561
562
563
564
565
    EXPECT_TRUE(another_accessor->startUpdateZone("sql1.example.com.",
                                                  true).first);
    EXPECT_THROW(accessor->startUpdateZone("example.com.", true),
                 DataSourceError);
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
566
567
568
569
570
571

    // Once we rollback the other attempt of change, we should be able to
    // start and commit the transaction using the main accessor.
    another_accessor->rollbackUpdateZone();
    accessor->startUpdateZone("example.com.", true);
    accessor->commitUpdateZone();
572
573
574
}

TEST_F(SQLite3Update, duplicateUpdate) {
575
576
577
    accessor->startUpdateZone("example.com.", false);
    EXPECT_THROW(accessor->startUpdateZone("example.com.", false),
                 DataSourceError);
578
579
580
}

TEST_F(SQLite3Update, commitWithoutTransaction) {
581
    EXPECT_THROW(accessor->commitUpdateZone(), DataSourceError);
582
583
584
}

TEST_F(SQLite3Update, rollbackWithoutTransaction) {
585
    EXPECT_THROW(accessor->rollbackUpdateZone(), DataSourceError);
586
587
588
589
}

TEST_F(SQLite3Update, addRecord) {
    // Before update, there should be no record for this name
590
    checkRecords(*accessor, zone_id, "newdata.example.com.", empty_stored);
591

592
    zone_id = accessor->startUpdateZone("example.com.", false).second;
593
594
595
    copy(new_data, new_data + DatabaseAccessor::ADD_COLUMN_COUNT,
         add_columns);
    accessor->addRecordToZone(add_columns);
596
597
598

    expected_stored.clear();
    expected_stored.push_back(new_data);
599
    checkRecords(*accessor, zone_id, "newdata.example.com.", expected_stored);
600
601

    // Commit the change, and confirm the new data is still there.
602
603
    accessor->commitUpdateZone();
    checkRecords(*accessor, zone_id, "newdata.example.com.", expected_stored);
604
605
606
}

TEST_F(SQLite3Update, addThenRollback) {
607
    zone_id = accessor->startUpdateZone("example.com.", false).second;
608
609
610
    copy(new_data, new_data + DatabaseAccessor::ADD_COLUMN_COUNT,
         add_columns);
    accessor->addRecordToZone(add_columns);
611
612
613

    expected_stored.clear();
    expected_stored.push_back(new_data);
614
    checkRecords(*accessor, zone_id, "newdata.example.com.", expected_stored);
615

616
617
    accessor->rollbackUpdateZone();
    checkRecords(*accessor, zone_id, "newdata.example.com.", empty_stored);
618
619
620
621
622
623
624
625
626
}

TEST_F(SQLite3Update, duplicateAdd) {
    const char* const dup_data[] = {
        "foo.bar.example.com.", "com.example.bar.foo.", "3600", "A", "",
        "192.0.2.1"
    };
    expected_stored.clear();
    expected_stored.push_back(dup_data);
627
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
628
629
630

    // Adding exactly the same data.  As this backend is "dumb", another
    // row of the same content will be inserted.
631
632
    copy(dup_data, dup_data + DatabaseAccessor::ADD_COLUMN_COUNT,
         add_columns);
633
    zone_id = accessor->startUpdateZone("example.com.", false).second;
634
    accessor->addRecordToZone(add_columns);
635
    expected_stored.push_back(dup_data);
636
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
637
638
639
640
}

TEST_F(SQLite3Update, invalidAdd) {
    // An attempt of add before an explicit start of transaction
641
    EXPECT_THROW(accessor->addRecordToZone(add_columns), DataSourceError);
642
643
644
}

TEST_F(SQLite3Update, deleteRecord) {
645
    zone_id = accessor->startUpdateZone("example.com.", false).second;
646

647
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
648

649
650
651
    copy(deleted_data, deleted_data + DatabaseAccessor::DEL_PARAM_COUNT,
         del_params);
    accessor->deleteRecordInZone(del_params);
652
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
653
654

    // Commit the change, and confirm the deleted data still isn't there.
655
656
    accessor->commitUpdateZone();
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
657
658
659
}

TEST_F(SQLite3Update, deleteThenRollback) {
660
    zone_id = accessor->startUpdateZone("example.com.", false).second;
661

662
663
664
    copy(deleted_data, deleted_data + DatabaseAccessor::DEL_PARAM_COUNT,
         del_params);
    accessor->deleteRecordInZone(del_params);
665
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", empty_stored);
666
667

    // Rollback the change, and confirm the data still exists.
668
669
    accessor->rollbackUpdateZone();
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
670
671
672
}

TEST_F(SQLite3Update, deleteNonexistent) {
673
    zone_id = accessor->startUpdateZone("example.com.", false).second;
674
675
    copy(deleted_data, deleted_data + DatabaseAccessor::DEL_PARAM_COUNT,
         del_params);
676
677
678

    // Replace the name with a non existent one, then try to delete it.
    // nothing should happen.
679
    del_params[DatabaseAccessor::DEL_NAME] = "no-such-name.example.com.";
680
681
    checkRecords(*accessor, zone_id, "no-such-name.example.com.",
                 empty_stored);
682
    accessor->deleteRecordInZone(del_params);
683
684
    checkRecords(*accessor, zone_id, "no-such-name.example.com.",
                 empty_stored);
685
686
687

    // Name exists but the RR type is different.  Delete attempt shouldn't
    // delete only by name.
688
689
690
691
    copy(deleted_data, deleted_data + DatabaseAccessor::DEL_PARAM_COUNT,
         del_params);
    del_params[DatabaseAccessor::DEL_TYPE] = "AAAA";
    accessor->deleteRecordInZone(del_params);
692
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
693
694

    // Similar to the previous case, but RDATA is different.
695
696
697
698
    copy(deleted_data, deleted_data + DatabaseAccessor::DEL_PARAM_COUNT,
         del_params);
    del_params[DatabaseAccessor::DEL_RDATA] = "192.0.2.2";
    accessor->deleteRecordInZone(del_params);
699
    checkRecords(*accessor, zone_id, "foo.bar.example.com.", expected_stored);
700
701
702
703
}

TEST_F(SQLite3Update, invalidDelete) {
    // An attempt of delete before an explicit start of transaction
704
    EXPECT_THROW(accessor->deleteRecordInZone(del_params), DataSourceError);
705
}
706
} // end anonymous namespace