mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 05:55:28 +00:00
[2679] extracted test fixture classes into a separate header file.
along with declarations of some common test data. this is for making it easier to share the test cases with various database accessor implementations. to resolve inter-class dependencies there are some non trivial changes (e.g. moving in-class definitions to out-of-class ones in .cc), but this is basically reordering existing code. no behavior change.
This commit is contained in:
@@ -51,7 +51,7 @@ run_unittests_SOURCES += test_client.h test_client.cc
|
||||
run_unittests_SOURCES += rbtree_unittest.cc
|
||||
run_unittests_SOURCES += logger_unittest.cc
|
||||
run_unittests_SOURCES += client_unittest.cc
|
||||
run_unittests_SOURCES += database_unittest.cc
|
||||
run_unittests_SOURCES += database_unittest.h database_unittest.cc
|
||||
run_unittests_SOURCES += sqlite3_accessor_unittest.cc
|
||||
run_unittests_SOURCES += memory_datasrc_unittest.cc
|
||||
run_unittests_SOURCES += rbnode_rrset_unittest.cc
|
||||
|
@@ -12,9 +12,8 @@
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "faked_nsec3.h"
|
||||
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <datasrc/tests/database_unittest.h>
|
||||
#include <datasrc/tests/faked_nsec3.h>
|
||||
|
||||
#include <dns/masterload.h>
|
||||
#include <dns/name.h>
|
||||
@@ -40,6 +39,7 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace isc::datasrc;
|
||||
@@ -53,206 +53,11 @@ using namespace isc::testutils;
|
||||
using namespace isc::datasrc::test;
|
||||
|
||||
namespace {
|
||||
|
||||
// Imaginary zone IDs used in the mock accessor below.
|
||||
const int READONLY_ZONE_ID = 42;
|
||||
const int NEW_ZONE_ID = 420;
|
||||
const int WRITABLE_ZONE_ID = 4200;
|
||||
|
||||
// Commonly used test data
|
||||
const char* const TEST_RECORDS[][5] = {
|
||||
// some plain data
|
||||
{"www.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"www.example.org.", "AAAA", "3600", "", "2001:db8::1"},
|
||||
{"www.example.org.", "AAAA", "3600", "", "2001:db8::2"},
|
||||
{"www.example.org.", "NSEC", "3600", "", "www2.example.org. A AAAA NSEC RRSIG"},
|
||||
{"www.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"www2.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"www2.example.org.", "AAAA", "3600", "", "2001:db8::1"},
|
||||
{"www2.example.org.", "A", "3600", "", "192.0.2.2"},
|
||||
|
||||
{"cname.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
|
||||
// some DNSSEC-'signed' data
|
||||
{"signed1.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"signed1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"signed1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE"},
|
||||
{"signed1.example.org.", "AAAA", "3600", "", "2001:db8::1"},
|
||||
{"signed1.example.org.", "AAAA", "3600", "", "2001:db8::2"},
|
||||
{"signed1.example.org.", "RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"signedcname1.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
{"signedcname1.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
// special case might fail; sig is for cname, which isn't there (should be ignored)
|
||||
// (ignoring of 'normal' other type is done above by www.)
|
||||
{"acnamesig1.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"acnamesig1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"acnamesig1.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
// let's pretend we have a database that is not careful
|
||||
// about the order in which it returns data
|
||||
{"signed2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"signed2.example.org.", "AAAA", "3600", "", "2001:db8::2"},
|
||||
{"signed2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE"},
|
||||
{"signed2.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"signed2.example.org.", "RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"signed2.example.org.", "AAAA", "3600", "", "2001:db8::1"},
|
||||
|
||||
{"signedcname2.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"signedcname2.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
|
||||
{"acnamesig2.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"acnamesig2.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"acnamesig2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"acnamesig3.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"acnamesig3.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"acnamesig3.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
|
||||
{"ttldiff1.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"ttldiff1.example.org.", "A", "360", "", "192.0.2.2"},
|
||||
|
||||
{"ttldiff2.example.org.", "A", "360", "", "192.0.2.1"},
|
||||
{"ttldiff2.example.org.", "A", "3600", "", "192.0.2.2"},
|
||||
|
||||
// also add some intentionally bad data
|
||||
{"badcname1.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"badcname1.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
|
||||
{"badcname2.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
{"badcname2.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
|
||||
{"badcname3.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
{"badcname3.example.org.", "CNAME", "3600", "", "www.example2.org."},
|
||||
|
||||
{"badrdata.example.org.", "A", "3600", "", "bad"},
|
||||
|
||||
{"badtype.example.org.", "BAD_TYPE", "3600", "", "192.0.2.1"},
|
||||
|
||||
{"badttl.example.org.", "A", "badttl", "", "192.0.2.1"},
|
||||
|
||||
{"badsig.example.org.", "A", "badttl", "", "192.0.2.1"},
|
||||
{"badsig.example.org.", "RRSIG", "3600", "", "A 5 3 3600 somebaddata 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"badsigtype.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"badsigtype.example.org.", "RRSIG", "3600", "TXT", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
// Data for testing delegation (with NS and DNAME)
|
||||
{"delegation.example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
{"delegation.example.org.", "NS", "3600", "",
|
||||
"ns.delegation.example.org."},
|
||||
{"delegation.example.org.", "DS", "3600", "", "1 1 2 abcd"},
|
||||
{"delegation.example.org.", "RRSIG", "3600", "", "NS 5 3 3600 "
|
||||
"20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"delegation.example.org.", "RRSIG", "3600", "", "DS 5 3 3600 "
|
||||
"20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"ns.delegation.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"deep.below.delegation.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
|
||||
{"dname.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"dname.example.org.", "DNAME", "3600", "", "dname.example.com."},
|
||||
{"dname.example.org.", "RRSIG", "3600", "",
|
||||
"DNAME 5 3 3600 20000101000000 20000201000000 12345 "
|
||||
"example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"below.dname.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
|
||||
// Insecure delegation (i.e., no DS at the delegation point)
|
||||
{"insecdelegation.example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
{"insecdelegation.example.org.", "NSEC", "3600", "",
|
||||
"dummy.example.org. NS NSEC"},
|
||||
// and a DS under the zone cut. Such an RR shouldn't exist in a sane zone,
|
||||
// but it could by error or some malicious attempt. It shouldn't confuse
|
||||
// the implementation)
|
||||
{"child.insecdelegation.example.org.", "DS", "3600", "", "DS 5 3 3600 "
|
||||
"20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
// Delegation NS and other ordinary type of RR coexist at the same
|
||||
// name. This is deviant (except for some special cases like the other
|
||||
// RR could be used for addressing the NS name), but as long as the
|
||||
// other records are hidden behind the delegation for normal queries
|
||||
// it's not necessarily harmful. (so "broken" may be too strong, but we
|
||||
// keep the name since it could be in a chain of sorted names for DNSSEC
|
||||
// processing and renaming them may have other bad effects for tests).
|
||||
{"brokenns1.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
|
||||
// Now double DNAME, to test failure mode
|
||||
{"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
|
||||
{"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
|
||||
|
||||
// Put some data into apex (including NS) so we can check our NS
|
||||
// doesn't break anything
|
||||
{"example.org.", "SOA", "3600", "", "ns1.example.org. admin.example.org. "
|
||||
"1234 3600 1800 2419200 7200" },
|
||||
{"example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
{"example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
// Note that the RDATA text is "normalized", i.e., identical to what
|
||||
// Rdata::toText() would produce. some tests rely on that behavior.
|
||||
{"example.org.", "NSEC", "3600", "",
|
||||
"acnamesig1.example.org. A NS RRSIG NSEC"},
|
||||
{"example.org.", "RRSIG", "3600", "", "SOA 5 3 3600 20000101000000 "
|
||||
"20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 "
|
||||
"20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"example.org.", "RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
|
||||
"20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
// This is because of empty domain test
|
||||
{"a.b.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
|
||||
// Something for wildcards
|
||||
{"*.wild.example.org.", "A", "3600", "", "192.0.2.5"},
|
||||
{"*.wild.example.org.", "RRSIG", "3600", "A", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"*.wild.example.org.", "NSEC", "3600", "", "cancel.here.wild.example.org. A NSEC RRSIG"},
|
||||
{"*.wild.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"cancel.here.wild.example.org.", "AAAA", "3600", "", "2001:db8::5"},
|
||||
{"delegatedwild.example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
{"*.delegatedwild.example.org.", "A", "3600", "", "192.0.2.5"},
|
||||
{"wild.*.foo.example.org.", "A", "3600", "", "192.0.2.5"},
|
||||
{"wild.*.foo.*.bar.example.org.", "A", "3600", "", "192.0.2.5"},
|
||||
{"wild.*.foo.*.bar.example.org.", "NSEC", "3600", "",
|
||||
"brokenns1.example.org. A NSEC"},
|
||||
{"bao.example.org.", "NSEC", "3600", "", "wild.*.foo.*.bar.example.org. NSEC"},
|
||||
{"*.cnamewild.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
{"*.dnamewild.example.org.", "DNAME", "3600", "", "dname.example.com."},
|
||||
{"*.nswild.example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
// For NSEC empty non-terminal
|
||||
{"l.example.org.", "NSEC", "3600", "", "empty.nonterminal.example.org. NSEC"},
|
||||
{"empty.nonterminal.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
// Invalid rdata
|
||||
{"invalidrdata.example.org.", "A", "3600", "", "Bunch of nonsense"},
|
||||
{"invalidrdata2.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"invalidrdata2.example.org.", "RRSIG", "3600", "", "Nonsense"},
|
||||
|
||||
{NULL, NULL, NULL, NULL, NULL},
|
||||
};
|
||||
|
||||
// NSEC3PARAM at the zone origin and its RRSIG. These will be added
|
||||
// separately for some NSEC3 related tests.
|
||||
const char* TEST_NSEC3PARAM_RECORDS[][5] = {
|
||||
{"example.org.", "NSEC3PARAM", "3600", "", "1 0 12 aabbccdd"},
|
||||
{"example.org.", "RRSIG", "3600", "", "NSEC3PARAM 5 3 3600 20000101000000 "
|
||||
"20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
// FIXME: Taken from a different test. Fill with proper data when creating a test.
|
||||
const char* TEST_NSEC3_RECORDS[][5] = {
|
||||
{apex_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
|
||||
{apex_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
|
||||
{ns1_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
|
||||
{ns1_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
|
||||
{w_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
|
||||
{w_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
|
||||
{zzz_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
|
||||
{zzz_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
|
||||
{NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/*
|
||||
* An accessor with minimum implementation, keeping the original
|
||||
* "NotImplemented" methods.
|
||||
@@ -359,52 +164,6 @@ private:
|
||||
std::map<std::string, int> zones_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Single journal entry in the mock database.
|
||||
*
|
||||
* All the members there are public for simplicity, as it only stores data.
|
||||
* We use the implicit constructor and operator. The members can't be const
|
||||
* because of the assignment operator (used in the vectors).
|
||||
*/
|
||||
struct JournalEntry {
|
||||
JournalEntry(int id, uint32_t serial,
|
||||
DatabaseAccessor::DiffOperation operation,
|
||||
const std::string (&data)[DatabaseAccessor::DIFF_PARAM_COUNT])
|
||||
: id_(id), serial_(serial), operation_(operation)
|
||||
{
|
||||
data_[DatabaseAccessor::DIFF_NAME] = data[DatabaseAccessor::DIFF_NAME];
|
||||
data_[DatabaseAccessor::DIFF_TYPE] = data[DatabaseAccessor::DIFF_TYPE];
|
||||
data_[DatabaseAccessor::DIFF_TTL] = data[DatabaseAccessor::DIFF_TTL];
|
||||
data_[DatabaseAccessor::DIFF_RDATA] =
|
||||
data[DatabaseAccessor::DIFF_RDATA];
|
||||
}
|
||||
JournalEntry(int id, uint32_t serial,
|
||||
DatabaseAccessor::DiffOperation operation,
|
||||
const std::string& name, const std::string& type,
|
||||
const std::string& ttl, const std::string& rdata):
|
||||
id_(id), serial_(serial), operation_(operation)
|
||||
{
|
||||
data_[DatabaseAccessor::DIFF_NAME] = name;
|
||||
data_[DatabaseAccessor::DIFF_TYPE] = type;
|
||||
data_[DatabaseAccessor::DIFF_TTL] = ttl;
|
||||
data_[DatabaseAccessor::DIFF_RDATA] = rdata;
|
||||
}
|
||||
int id_;
|
||||
uint32_t serial_;
|
||||
DatabaseAccessor::DiffOperation operation_;
|
||||
std::string data_[DatabaseAccessor::DIFF_PARAM_COUNT];
|
||||
bool operator==(const JournalEntry& other) const {
|
||||
for (size_t i = 0; i < DatabaseAccessor::DIFF_PARAM_COUNT; ++ i) {
|
||||
if (data_[i] != other.data_[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// No need to check data here, checked above
|
||||
return (id_ == other.id_ && serial_ == other.serial_ &&
|
||||
operation_ == other.operation_);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* A virtual database accessor that pretends it contains single zone --
|
||||
* example.org.
|
||||
@@ -1133,7 +892,379 @@ public:
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace isc {
|
||||
namespace datasrc {
|
||||
namespace test {
|
||||
|
||||
const char* const TEST_RECORDS[][5] = {
|
||||
// some plain data
|
||||
{"www.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"www.example.org.", "AAAA", "3600", "", "2001:db8::1"},
|
||||
{"www.example.org.", "AAAA", "3600", "", "2001:db8::2"},
|
||||
{"www.example.org.", "NSEC", "3600", "", "www2.example.org. A AAAA NSEC RRSIG"},
|
||||
{"www.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"www2.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"www2.example.org.", "AAAA", "3600", "", "2001:db8::1"},
|
||||
{"www2.example.org.", "A", "3600", "", "192.0.2.2"},
|
||||
|
||||
{"cname.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
|
||||
// some DNSSEC-'signed' data
|
||||
{"signed1.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"signed1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"signed1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE"},
|
||||
{"signed1.example.org.", "AAAA", "3600", "", "2001:db8::1"},
|
||||
{"signed1.example.org.", "AAAA", "3600", "", "2001:db8::2"},
|
||||
{"signed1.example.org.", "RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"signedcname1.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
{"signedcname1.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
// special case might fail; sig is for cname, which isn't there (should be ignored)
|
||||
// (ignoring of 'normal' other type is done above by www.)
|
||||
{"acnamesig1.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"acnamesig1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"acnamesig1.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
// let's pretend we have a database that is not careful
|
||||
// about the order in which it returns data
|
||||
{"signed2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"signed2.example.org.", "AAAA", "3600", "", "2001:db8::2"},
|
||||
{"signed2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE"},
|
||||
{"signed2.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"signed2.example.org.", "RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"signed2.example.org.", "AAAA", "3600", "", "2001:db8::1"},
|
||||
|
||||
{"signedcname2.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"signedcname2.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
|
||||
{"acnamesig2.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"acnamesig2.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"acnamesig2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"acnamesig3.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"acnamesig3.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"acnamesig3.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
|
||||
{"ttldiff1.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"ttldiff1.example.org.", "A", "360", "", "192.0.2.2"},
|
||||
|
||||
{"ttldiff2.example.org.", "A", "360", "", "192.0.2.1"},
|
||||
{"ttldiff2.example.org.", "A", "3600", "", "192.0.2.2"},
|
||||
|
||||
// also add some intentionally bad data
|
||||
{"badcname1.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"badcname1.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
|
||||
{"badcname2.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
{"badcname2.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
|
||||
{"badcname3.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
{"badcname3.example.org.", "CNAME", "3600", "", "www.example2.org."},
|
||||
|
||||
{"badrdata.example.org.", "A", "3600", "", "bad"},
|
||||
|
||||
{"badtype.example.org.", "BAD_TYPE", "3600", "", "192.0.2.1"},
|
||||
|
||||
{"badttl.example.org.", "A", "badttl", "", "192.0.2.1"},
|
||||
|
||||
{"badsig.example.org.", "A", "badttl", "", "192.0.2.1"},
|
||||
{"badsig.example.org.", "RRSIG", "3600", "", "A 5 3 3600 somebaddata 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"badsigtype.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"badsigtype.example.org.", "RRSIG", "3600", "TXT", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
// Data for testing delegation (with NS and DNAME)
|
||||
{"delegation.example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
{"delegation.example.org.", "NS", "3600", "",
|
||||
"ns.delegation.example.org."},
|
||||
{"delegation.example.org.", "DS", "3600", "", "1 1 2 abcd"},
|
||||
{"delegation.example.org.", "RRSIG", "3600", "", "NS 5 3 3600 "
|
||||
"20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"delegation.example.org.", "RRSIG", "3600", "", "DS 5 3 3600 "
|
||||
"20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"ns.delegation.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"deep.below.delegation.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
|
||||
{"dname.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"dname.example.org.", "DNAME", "3600", "", "dname.example.com."},
|
||||
{"dname.example.org.", "RRSIG", "3600", "",
|
||||
"DNAME 5 3 3600 20000101000000 20000201000000 12345 "
|
||||
"example.org. FAKEFAKEFAKE"},
|
||||
|
||||
{"below.dname.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
|
||||
// Insecure delegation (i.e., no DS at the delegation point)
|
||||
{"insecdelegation.example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
{"insecdelegation.example.org.", "NSEC", "3600", "",
|
||||
"dummy.example.org. NS NSEC"},
|
||||
// and a DS under the zone cut. Such an RR shouldn't exist in a sane zone,
|
||||
// but it could by error or some malicious attempt. It shouldn't confuse
|
||||
// the implementation)
|
||||
{"child.insecdelegation.example.org.", "DS", "3600", "", "DS 5 3 3600 "
|
||||
"20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
// Delegation NS and other ordinary type of RR coexist at the same
|
||||
// name. This is deviant (except for some special cases like the other
|
||||
// RR could be used for addressing the NS name), but as long as the
|
||||
// other records are hidden behind the delegation for normal queries
|
||||
// it's not necessarily harmful. (so "broken" may be too strong, but we
|
||||
// keep the name since it could be in a chain of sorted names for DNSSEC
|
||||
// processing and renaming them may have other bad effects for tests).
|
||||
{"brokenns1.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
|
||||
// Now double DNAME, to test failure mode
|
||||
{"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
|
||||
{"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
|
||||
|
||||
// Put some data into apex (including NS) so we can check our NS
|
||||
// doesn't break anything
|
||||
{"example.org.", "SOA", "3600", "", "ns1.example.org. admin.example.org. "
|
||||
"1234 3600 1800 2419200 7200" },
|
||||
{"example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
{"example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
// Note that the RDATA text is "normalized", i.e., identical to what
|
||||
// Rdata::toText() would produce. some tests rely on that behavior.
|
||||
{"example.org.", "NSEC", "3600", "",
|
||||
"acnamesig1.example.org. A NS RRSIG NSEC"},
|
||||
{"example.org.", "RRSIG", "3600", "", "SOA 5 3 3600 20000101000000 "
|
||||
"20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 "
|
||||
"20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"example.org.", "RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
|
||||
"20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
|
||||
// This is because of empty domain test
|
||||
{"a.b.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
|
||||
// Something for wildcards
|
||||
{"*.wild.example.org.", "A", "3600", "", "192.0.2.5"},
|
||||
{"*.wild.example.org.", "RRSIG", "3600", "A", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"*.wild.example.org.", "NSEC", "3600", "", "cancel.here.wild.example.org. A NSEC RRSIG"},
|
||||
{"*.wild.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{"cancel.here.wild.example.org.", "AAAA", "3600", "", "2001:db8::5"},
|
||||
{"delegatedwild.example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
{"*.delegatedwild.example.org.", "A", "3600", "", "192.0.2.5"},
|
||||
{"wild.*.foo.example.org.", "A", "3600", "", "192.0.2.5"},
|
||||
{"wild.*.foo.*.bar.example.org.", "A", "3600", "", "192.0.2.5"},
|
||||
{"wild.*.foo.*.bar.example.org.", "NSEC", "3600", "",
|
||||
"brokenns1.example.org. A NSEC"},
|
||||
{"bao.example.org.", "NSEC", "3600", "", "wild.*.foo.*.bar.example.org. NSEC"},
|
||||
{"*.cnamewild.example.org.", "CNAME", "3600", "", "www.example.org."},
|
||||
{"*.dnamewild.example.org.", "DNAME", "3600", "", "dname.example.com."},
|
||||
{"*.nswild.example.org.", "NS", "3600", "", "ns.example.com."},
|
||||
// For NSEC empty non-terminal
|
||||
{"l.example.org.", "NSEC", "3600", "", "empty.nonterminal.example.org. NSEC"},
|
||||
{"empty.nonterminal.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
// Invalid rdata
|
||||
{"invalidrdata.example.org.", "A", "3600", "", "Bunch of nonsense"},
|
||||
{"invalidrdata2.example.org.", "A", "3600", "", "192.0.2.1"},
|
||||
{"invalidrdata2.example.org.", "RRSIG", "3600", "", "Nonsense"},
|
||||
|
||||
{NULL, NULL, NULL, NULL, NULL},
|
||||
};
|
||||
|
||||
const char* TEST_NSEC3PARAM_RECORDS[][5] = {
|
||||
{"example.org.", "NSEC3PARAM", "3600", "", "1 0 12 aabbccdd"},
|
||||
{"example.org.", "RRSIG", "3600", "", "NSEC3PARAM 5 3 3600 20000101000000 "
|
||||
"20000201000000 12345 example.org. FAKEFAKEFAKE"},
|
||||
{NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
const char* TEST_NSEC3_RECORDS[][5] = {
|
||||
{apex_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
|
||||
{apex_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
|
||||
{ns1_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
|
||||
{ns1_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
|
||||
{w_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
|
||||
{w_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
|
||||
{zzz_hash, "NSEC3", "300", "", "1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"},
|
||||
{zzz_hash, "RRSIG", "300", "", "NSEC3 5 4 7200 20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02 xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o 8gHSY5vYTtothcZQa4BMKhmGQEk="},
|
||||
{NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
DatabaseClientTest::DatabaseClientTest() :
|
||||
zname_("example.org"), qname_("www.example.org"),
|
||||
qclass_(dns::RRClass::IN()),
|
||||
qtype_(dns::RRType::A()),
|
||||
rrttl_(3600)
|
||||
{
|
||||
// Test IN/A RDATA to be added in update tests. Intentionally using
|
||||
// different data than the initial data configured in the MockAccessor.
|
||||
rrset_.reset(new RRset(qname_, qclass_, qtype_, rrttl_));
|
||||
rrset_->addRdata(rdata::createRdata(rrset_->getType(),
|
||||
rrset_->getClass(), "192.0.2.2"));
|
||||
soa_.reset(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
|
||||
soa_->addRdata(rdata::createRdata(soa_->getType(), soa_->getClass(),
|
||||
"ns1.example.org. admin.example.org. "
|
||||
"1234 3600 1800 2419200 7200"));
|
||||
|
||||
// And its RRSIG. Also different from the configured one.
|
||||
rrsigset_.reset(new RRset(qname_, qclass_, RRType::RRSIG(),
|
||||
rrttl_));
|
||||
rrsigset_->addRdata(rdata::createRdata(rrsigset_->getType(),
|
||||
rrsigset_->getClass(),
|
||||
"A 5 3 0 20000101000000 "
|
||||
"20000201000000 0 example.org. "
|
||||
"FAKEFAKEFAKE"));
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseClientTest::createClient(const DatabaseClientTestParam* test_param) {
|
||||
// To make sure we always have empty diffs table at the beginning of
|
||||
// each test, we re-install the writable data source here.
|
||||
// Note: this is SQLite3 specific and a waste (though otherwise
|
||||
// harmless) for other types of data sources. If and when we support
|
||||
// more types of data sources in this test framework, we should
|
||||
// probably move this to some specialized templated method specific
|
||||
// to SQLite3 (or for even a longer term we should add an API to
|
||||
// purge the diffs table).
|
||||
const char* const install_cmd = INSTALL_PROG " -c " TEST_DATA_COMMONDIR
|
||||
"/rwtest.sqlite3 " TEST_DATA_BUILDDIR
|
||||
"/rwtest.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);
|
||||
}
|
||||
|
||||
current_accessor_ = test_param->accessor_creator();
|
||||
is_mock_ = (dynamic_cast<MockAccessor*>(current_accessor_.get()) !=
|
||||
NULL);
|
||||
client_.reset(new DatabaseClient(qclass_, current_accessor_));
|
||||
|
||||
// set up the commonly used finder.
|
||||
const DataSourceClient::FindResult result(client_->findZone(zname_));
|
||||
assert(result.code == result::SUCCESS);
|
||||
finder_ = dynamic_pointer_cast<DatabaseClient::Finder>(
|
||||
result.zone_finder);
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseClientTest::checkZoneFinder(const DataSourceClient::FindResult& zone) {
|
||||
ASSERT_NE(ZoneFinderPtr(), zone.zone_finder) << "No zone finder";
|
||||
boost::shared_ptr<DatabaseClient::Finder> finder(
|
||||
boost::dynamic_pointer_cast<DatabaseClient::Finder>(
|
||||
zone.zone_finder));
|
||||
ASSERT_NE(boost::shared_ptr<DatabaseClient::Finder>(), finder) <<
|
||||
"Wrong type of finder";
|
||||
if (is_mock_) {
|
||||
EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
|
||||
}
|
||||
EXPECT_EQ(current_accessor_.get(), &finder->getAccessor());
|
||||
}
|
||||
|
||||
boost::shared_ptr<DatabaseClient::Finder>
|
||||
DatabaseClientTest::getFinder() {
|
||||
DataSourceClient::FindResult zone(client_->findZone(zname_));
|
||||
EXPECT_EQ(result::SUCCESS, zone.code);
|
||||
boost::shared_ptr<DatabaseClient::Finder> finder(
|
||||
boost::dynamic_pointer_cast<DatabaseClient::Finder>(
|
||||
zone.zone_finder));
|
||||
if (is_mock_) {
|
||||
EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
|
||||
}
|
||||
|
||||
return (finder);
|
||||
}
|
||||
|
||||
bool
|
||||
DatabaseClientTest::isRollbacked(bool expected) const {
|
||||
if (is_mock_) {
|
||||
const MockAccessor& mock_accessor =
|
||||
dynamic_cast<const MockAccessor&>(*update_accessor_);
|
||||
return (mock_accessor.isRollbacked());
|
||||
} else {
|
||||
return (expected);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseClientTest::checkLastAdded(const char* const expected[]) const {
|
||||
if (is_mock_) {
|
||||
const MockAccessor* mock_accessor =
|
||||
dynamic_cast<const MockAccessor*>(current_accessor_.get());
|
||||
for (int i = 0; i < DatabaseAccessor::ADD_COLUMN_COUNT; ++i) {
|
||||
EXPECT_EQ(expected[i],
|
||||
mock_accessor->getLatestClone()->getLastAdded()[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseClientTest::setUpdateAccessor() {
|
||||
if (is_mock_) {
|
||||
const MockAccessor* mock_accessor =
|
||||
dynamic_cast<const MockAccessor*>(current_accessor_.get());
|
||||
update_accessor_ = mock_accessor->getLatestClone();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseClientTest::checkJournal(const std::vector<JournalEntry>& expected) {
|
||||
if (is_mock_) {
|
||||
const MockAccessor* mock_accessor =
|
||||
dynamic_cast<const MockAccessor*>(current_accessor_.get());
|
||||
mock_accessor->checkJournal(expected);
|
||||
} else {
|
||||
// For other generic databases, retrieve the diff using the
|
||||
// reader class and compare the resulting sequence of RRset.
|
||||
// For simplicity we only consider the case where the expected
|
||||
// sequence is not empty.
|
||||
ASSERT_FALSE(expected.empty());
|
||||
const Name zone_name(expected.front().
|
||||
data_[DatabaseAccessor::DIFF_NAME]);
|
||||
ZoneJournalReaderPtr jnl_reader =
|
||||
client_->getJournalReader(zone_name,
|
||||
expected.front().serial_,
|
||||
expected.back().serial_).second;
|
||||
ASSERT_TRUE(jnl_reader);
|
||||
ConstRRsetPtr rrset;
|
||||
std::vector<JournalEntry>::const_iterator it = expected.begin();
|
||||
for (rrset = jnl_reader->getNextDiff();
|
||||
rrset && it != expected.end();
|
||||
rrset = jnl_reader->getNextDiff(), ++it) {
|
||||
typedef DatabaseAccessor Accessor;
|
||||
RRsetPtr expected_rrset(
|
||||
new RRset(Name((*it).data_[Accessor::DIFF_NAME]),
|
||||
qclass_,
|
||||
RRType((*it).data_[Accessor::DIFF_TYPE]),
|
||||
RRTTL((*it).data_[Accessor::DIFF_TTL])));
|
||||
expected_rrset->addRdata(
|
||||
rdata::createRdata(expected_rrset->getType(),
|
||||
expected_rrset->getClass(),
|
||||
(*it).data_[Accessor::DIFF_RDATA]));
|
||||
rrsetCheck(expected_rrset, rrset);
|
||||
}
|
||||
// We should have examined all entries of both expected and
|
||||
// actual data.
|
||||
EXPECT_TRUE(it == expected.end());
|
||||
ASSERT_FALSE(rrset);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DatabaseClientTest::allowMoreTransaction(bool is_allowed) {
|
||||
if (is_mock_) {
|
||||
// Use a separate variable for MockAccessor&; some compilers
|
||||
// would be confused otherwise.
|
||||
MockAccessor& mock_accessor =
|
||||
dynamic_cast<MockAccessor&>(*current_accessor_);
|
||||
mock_accessor.allowMoreTransaction(is_allowed);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace datasrc
|
||||
} // namespace isc
|
||||
|
||||
namespace {
|
||||
// This tests the default getRecords behaviour, throwing NotImplemented
|
||||
TEST(DatabaseConnectionTest, getRecords) {
|
||||
EXPECT_THROW(NopAccessor().getRecords(".", 1, false),
|
||||
@@ -1147,236 +1278,6 @@ TEST(DatabaseConnectionTest, getAllRecords) {
|
||||
isc::NotImplemented);
|
||||
}
|
||||
|
||||
// This is the type used as the test parameter. Note that this is
|
||||
// intentionally a plain old type (i.e. a function pointer), not a class;
|
||||
// otherwise it could cause initialization fiasco at the instantiation time.
|
||||
struct DatabaseClientTestParam {
|
||||
boost::shared_ptr<DatabaseAccessor> (*accessor_creator)();
|
||||
void (*enable_nsec3_fn)(DatabaseAccessor& accessor);
|
||||
};
|
||||
|
||||
// This test fixture is parameterized so that we can share (most of) the test
|
||||
// cases with different types of data sources.
|
||||
class DatabaseClientTest :
|
||||
public ::testing::TestWithParam<const DatabaseClientTestParam*>
|
||||
{
|
||||
public:
|
||||
DatabaseClientTest() : zname_("example.org"), qname_("www.example.org"),
|
||||
qclass_(RRClass::IN()), qtype_(RRType::A()),
|
||||
rrttl_(3600)
|
||||
{
|
||||
// Test IN/A RDATA to be added in update tests. Intentionally using
|
||||
// different data than the initial data configured in the MockAccessor.
|
||||
rrset_.reset(new RRset(qname_, qclass_, qtype_, rrttl_));
|
||||
rrset_->addRdata(rdata::createRdata(rrset_->getType(),
|
||||
rrset_->getClass(), "192.0.2.2"));
|
||||
soa_.reset(new RRset(zname_, qclass_, RRType::SOA(), rrttl_));
|
||||
soa_->addRdata(rdata::createRdata(soa_->getType(), soa_->getClass(),
|
||||
"ns1.example.org. admin.example.org. "
|
||||
"1234 3600 1800 2419200 7200"));
|
||||
|
||||
// And its RRSIG. Also different from the configured one.
|
||||
rrsigset_.reset(new RRset(qname_, qclass_, RRType::RRSIG(),
|
||||
rrttl_));
|
||||
rrsigset_->addRdata(rdata::createRdata(rrsigset_->getType(),
|
||||
rrsigset_->getClass(),
|
||||
"A 5 3 0 20000101000000 "
|
||||
"20000201000000 0 example.org. "
|
||||
"FAKEFAKEFAKE"));
|
||||
}
|
||||
|
||||
// We create accessor and other objects that depend on it in SetUp, not
|
||||
// in the constructor, so derived test classes can override the behavior.
|
||||
virtual void SetUp() {
|
||||
createClient(GetParam());
|
||||
}
|
||||
|
||||
~DatabaseClientTest() {
|
||||
// Make sure we return the default creator no matter if we set it or
|
||||
// not
|
||||
setNSEC3HashCreator(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* We initialize the client from a function, so we can call it multiple
|
||||
* times per test.
|
||||
*/
|
||||
void createClient(const DatabaseClientTestParam* test_param) {
|
||||
// To make sure we always have empty diffs table at the beginning of
|
||||
// each test, we re-install the writable data source here.
|
||||
// Note: this is SQLite3 specific and a waste (though otherwise
|
||||
// harmless) for other types of data sources. If and when we support
|
||||
// more types of data sources in this test framework, we should
|
||||
// probably move this to some specialized templated method specific
|
||||
// to SQLite3 (or for even a longer term we should add an API to
|
||||
// purge the diffs table).
|
||||
const char* const install_cmd = INSTALL_PROG " -c " TEST_DATA_COMMONDIR
|
||||
"/rwtest.sqlite3 " TEST_DATA_BUILDDIR
|
||||
"/rwtest.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);
|
||||
}
|
||||
|
||||
current_accessor_ = test_param->accessor_creator();
|
||||
is_mock_ = (dynamic_cast<MockAccessor*>(current_accessor_.get()) !=
|
||||
NULL);
|
||||
client_.reset(new DatabaseClient(qclass_, current_accessor_));
|
||||
|
||||
// set up the commonly used finder.
|
||||
const DataSourceClient::FindResult result(client_->findZone(zname_));
|
||||
assert(result.code == result::SUCCESS);
|
||||
finder_ = dynamic_pointer_cast<DatabaseClient::Finder>(
|
||||
result.zone_finder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the zone finder is a valid one and references the zone ID and
|
||||
* database available here.
|
||||
*/
|
||||
void checkZoneFinder(const DataSourceClient::FindResult& zone) {
|
||||
ASSERT_NE(ZoneFinderPtr(), zone.zone_finder) << "No zone finder";
|
||||
boost::shared_ptr<DatabaseClient::Finder> finder(
|
||||
dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
|
||||
ASSERT_NE(boost::shared_ptr<DatabaseClient::Finder>(), finder) <<
|
||||
"Wrong type of finder";
|
||||
if (is_mock_) {
|
||||
EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
|
||||
}
|
||||
EXPECT_EQ(current_accessor_.get(), &finder->getAccessor());
|
||||
}
|
||||
|
||||
boost::shared_ptr<DatabaseClient::Finder> getFinder() {
|
||||
DataSourceClient::FindResult zone(client_->findZone(zname_));
|
||||
EXPECT_EQ(result::SUCCESS, zone.code);
|
||||
boost::shared_ptr<DatabaseClient::Finder> finder(
|
||||
dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
|
||||
if (is_mock_) {
|
||||
EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
|
||||
}
|
||||
|
||||
return (finder);
|
||||
}
|
||||
|
||||
// Helper methods for update tests
|
||||
bool isRollbacked(bool expected = false) const {
|
||||
if (is_mock_) {
|
||||
const MockAccessor& mock_accessor =
|
||||
dynamic_cast<const MockAccessor&>(*update_accessor_);
|
||||
return (mock_accessor.isRollbacked());
|
||||
} else {
|
||||
return (expected);
|
||||
}
|
||||
}
|
||||
|
||||
void checkLastAdded(const char* const expected[]) const {
|
||||
if (is_mock_) {
|
||||
const MockAccessor* mock_accessor =
|
||||
dynamic_cast<const MockAccessor*>(current_accessor_.get());
|
||||
for (int i = 0; i < DatabaseAccessor::ADD_COLUMN_COUNT; ++i) {
|
||||
EXPECT_EQ(expected[i],
|
||||
mock_accessor->getLatestClone()->getLastAdded()[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setUpdateAccessor() {
|
||||
if (is_mock_) {
|
||||
const MockAccessor* mock_accessor =
|
||||
dynamic_cast<const MockAccessor*>(current_accessor_.get());
|
||||
update_accessor_ = mock_accessor->getLatestClone();
|
||||
}
|
||||
}
|
||||
|
||||
void checkJournal(const vector<JournalEntry>& expected) {
|
||||
if (is_mock_) {
|
||||
const MockAccessor* mock_accessor =
|
||||
dynamic_cast<const MockAccessor*>(current_accessor_.get());
|
||||
mock_accessor->checkJournal(expected);
|
||||
} else {
|
||||
// For other generic databases, retrieve the diff using the
|
||||
// reader class and compare the resulting sequence of RRset.
|
||||
// For simplicity we only consider the case where the expected
|
||||
// sequence is not empty.
|
||||
ASSERT_FALSE(expected.empty());
|
||||
const Name zone_name(expected.front().
|
||||
data_[DatabaseAccessor::DIFF_NAME]);
|
||||
ZoneJournalReaderPtr jnl_reader =
|
||||
client_->getJournalReader(zone_name,
|
||||
expected.front().serial_,
|
||||
expected.back().serial_).second;
|
||||
ASSERT_TRUE(jnl_reader);
|
||||
ConstRRsetPtr rrset;
|
||||
vector<JournalEntry>::const_iterator it = expected.begin();
|
||||
for (rrset = jnl_reader->getNextDiff();
|
||||
rrset && it != expected.end();
|
||||
rrset = jnl_reader->getNextDiff(), ++it) {
|
||||
typedef DatabaseAccessor Accessor;
|
||||
RRsetPtr expected_rrset(
|
||||
new RRset(Name((*it).data_[Accessor::DIFF_NAME]),
|
||||
qclass_,
|
||||
RRType((*it).data_[Accessor::DIFF_TYPE]),
|
||||
RRTTL((*it).data_[Accessor::DIFF_TTL])));
|
||||
expected_rrset->addRdata(
|
||||
rdata::createRdata(expected_rrset->getType(),
|
||||
expected_rrset->getClass(),
|
||||
(*it).data_[Accessor::DIFF_RDATA]));
|
||||
rrsetCheck(expected_rrset, rrset);
|
||||
}
|
||||
// We should have examined all entries of both expected and
|
||||
// actual data.
|
||||
EXPECT_TRUE(it == expected.end());
|
||||
ASSERT_FALSE(rrset);
|
||||
}
|
||||
}
|
||||
|
||||
// Mock-only; control whether to allow subsequent transaction.
|
||||
void allowMoreTransaction(bool is_allowed) {
|
||||
if (is_mock_) {
|
||||
// Use a separate variable for MockAccessor&; some compilers
|
||||
// would be confused otherwise.
|
||||
MockAccessor& mock_accessor =
|
||||
dynamic_cast<MockAccessor&>(*current_accessor_);
|
||||
mock_accessor.allowMoreTransaction(is_allowed);
|
||||
}
|
||||
}
|
||||
|
||||
// Some tests only work for MockAccessor. We remember whether our accessor
|
||||
// is of that type.
|
||||
bool is_mock_;
|
||||
|
||||
boost::shared_ptr<DatabaseAccessor> current_accessor_;
|
||||
boost::shared_ptr<DatabaseClient> client_;
|
||||
const std::string database_name_;
|
||||
|
||||
// The zone finder of the test zone commonly used in various tests.
|
||||
boost::shared_ptr<DatabaseClient::Finder> finder_;
|
||||
|
||||
// Some shortcut variables for commonly used test parameters
|
||||
const Name zname_; // the zone name stored in the test data source
|
||||
const Name qname_; // commonly used name to be found
|
||||
const RRClass qclass_; // commonly used RR class used with qname
|
||||
const RRType qtype_; // commonly used RR type used with qname
|
||||
const RRTTL rrttl_; // commonly used RR TTL
|
||||
RRsetPtr rrset_; // for adding/deleting an RRset
|
||||
RRsetPtr rrsigset_; // for adding/deleting an RRset
|
||||
RRsetPtr soa_; // for adding/deleting an RRset
|
||||
|
||||
// update related objects to be tested
|
||||
ZoneUpdaterPtr updater_;
|
||||
boost::shared_ptr<const DatabaseAccessor> update_accessor_;
|
||||
|
||||
// placeholders
|
||||
const std::vector<std::string> empty_rdatas_; // for NXRRSET/NXDOMAIN
|
||||
std::vector<std::string> expected_rdatas_;
|
||||
std::vector<std::string> expected_sig_rdatas_;
|
||||
|
||||
// A creator for use in several NSEC3 related tests.
|
||||
TestNSEC3HashCreator test_nsec3_hash_creator_;
|
||||
};
|
||||
|
||||
// The following two lines instantiate test cases with concrete accessor
|
||||
// classes to be tested.
|
||||
|
||||
@@ -4317,22 +4218,6 @@ TEST_P(DatabaseClientTest, deleteZoneRollbackOnNotFind) {
|
||||
EXPECT_TRUE(client_->deleteZone(zname_));
|
||||
}
|
||||
|
||||
// This test fixture is parameterized so that we can share (most of) the test
|
||||
// cases with different types of data sources.
|
||||
class RRsetCollectionTest : public DatabaseClientTest {
|
||||
protected:
|
||||
RRsetCollectionTest() : collection(NULL) {}
|
||||
|
||||
virtual void SetUp() {
|
||||
DatabaseClientTest::SetUp();
|
||||
updater = client_->getUpdater(zname_, false);
|
||||
collection = &updater->getRRsetCollection();
|
||||
}
|
||||
|
||||
ZoneUpdaterPtr updater;
|
||||
isc::dns::RRsetCollectionBase* collection;
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(, RRsetCollectionTest,
|
||||
::testing::Values(&mock_param, &sqlite3_param));
|
||||
|
||||
@@ -4457,18 +4342,6 @@ TEST_F(MockRRsetCollectionTest, findError) {
|
||||
}, RRsetCollectionError);
|
||||
}
|
||||
|
||||
// This test fixture is parameterized so that we can share (most of) the test
|
||||
// cases with different types of data sources.
|
||||
class RRsetCollectionAndUpdaterTest : public DatabaseClientTest {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
DatabaseClientTest::SetUp();
|
||||
updater_ = client_->getUpdater(zname_, false);
|
||||
}
|
||||
|
||||
ZoneUpdaterPtr updater_;
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(, RRsetCollectionAndUpdaterTest,
|
||||
::testing::Values(&mock_param, &sqlite3_param));
|
||||
|
||||
|
216
src/lib/datasrc/tests/database_unittest.h
Normal file
216
src/lib/datasrc/tests/database_unittest.h
Normal file
@@ -0,0 +1,216 @@
|
||||
// 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.
|
||||
|
||||
#include <datasrc/database.h>
|
||||
#include <datasrc/tests/faked_nsec3.h>
|
||||
|
||||
#include <dns/name.h>
|
||||
#include <dns/rrclass.h>
|
||||
#include <dns/rrtype.h>
|
||||
#include <dns/rrttl.h>
|
||||
#include <dns/rrset.h>
|
||||
#include <dns/rrset_collection_base.h>
|
||||
#include <dns/nsec3hash.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace isc {
|
||||
namespace datasrc {
|
||||
namespace test {
|
||||
|
||||
// Commonly used test data
|
||||
extern const char* const TEST_RECORDS[][5];
|
||||
|
||||
// NSEC3PARAM at the zone origin and its RRSIG. These will be added
|
||||
// separately for some NSEC3 related tests.
|
||||
extern const char* TEST_NSEC3PARAM_RECORDS[][5];
|
||||
|
||||
// FIXME: Taken from a different test. Fill with proper data when creating a
|
||||
// test.
|
||||
extern const char* TEST_NSEC3_RECORDS[][5];
|
||||
|
||||
/**
|
||||
* Single journal entry in the mock database.
|
||||
*
|
||||
* All the members there are public for simplicity, as it only stores data.
|
||||
* We use the implicit constructor and operator. The members can't be const
|
||||
* because of the assignment operator (used in the vectors).
|
||||
*/
|
||||
struct JournalEntry {
|
||||
JournalEntry(int id, uint32_t serial,
|
||||
DatabaseAccessor::DiffOperation operation,
|
||||
const std::string (&data)[DatabaseAccessor::DIFF_PARAM_COUNT])
|
||||
: id_(id), serial_(serial), operation_(operation)
|
||||
{
|
||||
data_[DatabaseAccessor::DIFF_NAME] = data[DatabaseAccessor::DIFF_NAME];
|
||||
data_[DatabaseAccessor::DIFF_TYPE] = data[DatabaseAccessor::DIFF_TYPE];
|
||||
data_[DatabaseAccessor::DIFF_TTL] = data[DatabaseAccessor::DIFF_TTL];
|
||||
data_[DatabaseAccessor::DIFF_RDATA] =
|
||||
data[DatabaseAccessor::DIFF_RDATA];
|
||||
}
|
||||
JournalEntry(int id, uint32_t serial,
|
||||
DatabaseAccessor::DiffOperation operation,
|
||||
const std::string& name, const std::string& type,
|
||||
const std::string& ttl, const std::string& rdata):
|
||||
id_(id), serial_(serial), operation_(operation)
|
||||
{
|
||||
data_[DatabaseAccessor::DIFF_NAME] = name;
|
||||
data_[DatabaseAccessor::DIFF_TYPE] = type;
|
||||
data_[DatabaseAccessor::DIFF_TTL] = ttl;
|
||||
data_[DatabaseAccessor::DIFF_RDATA] = rdata;
|
||||
}
|
||||
int id_;
|
||||
uint32_t serial_;
|
||||
DatabaseAccessor::DiffOperation operation_;
|
||||
std::string data_[DatabaseAccessor::DIFF_PARAM_COUNT];
|
||||
bool operator==(const JournalEntry& other) const {
|
||||
for (size_t i = 0; i < DatabaseAccessor::DIFF_PARAM_COUNT; ++ i) {
|
||||
if (data_[i] != other.data_[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// No need to check data here, checked above
|
||||
return (id_ == other.id_ && serial_ == other.serial_ &&
|
||||
operation_ == other.operation_);
|
||||
}
|
||||
};
|
||||
|
||||
// This is the type used as the test parameter. Note that this is
|
||||
// intentionally a plain old type (i.e. a function pointer), not a class;
|
||||
// otherwise it could cause initialization fiasco at the instantiation time.
|
||||
struct DatabaseClientTestParam {
|
||||
boost::shared_ptr<DatabaseAccessor> (*accessor_creator)();
|
||||
void (*enable_nsec3_fn)(DatabaseAccessor& accessor);
|
||||
};
|
||||
|
||||
// This test fixture is parameterized so that we can share (most of) the test
|
||||
// cases with different types of data sources.
|
||||
class DatabaseClientTest :
|
||||
public ::testing::TestWithParam<const DatabaseClientTestParam*>
|
||||
{
|
||||
public:
|
||||
DatabaseClientTest();
|
||||
|
||||
// We create accessor and other objects that depend on it in SetUp, not
|
||||
// in the constructor, so derived test classes can override the behavior.
|
||||
virtual void SetUp() {
|
||||
createClient(GetParam());
|
||||
}
|
||||
|
||||
~DatabaseClientTest() {
|
||||
// Make sure we return the default creator no matter if we set it or
|
||||
// not
|
||||
dns::setNSEC3HashCreator(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* We initialize the client from a function, so we can call it multiple
|
||||
* times per test.
|
||||
*/
|
||||
void createClient(const DatabaseClientTestParam* test_param);
|
||||
|
||||
/**
|
||||
* Check the zone finder is a valid one and references the zone ID and
|
||||
* database available here.
|
||||
*/
|
||||
void checkZoneFinder(const DataSourceClient::FindResult& zone);
|
||||
|
||||
boost::shared_ptr<DatabaseClient::Finder> getFinder();
|
||||
|
||||
// Helper methods for update tests
|
||||
bool isRollbacked(bool expected = false) const;
|
||||
|
||||
void checkLastAdded(const char* const expected[]) const;
|
||||
|
||||
void setUpdateAccessor();
|
||||
|
||||
void checkJournal(const std::vector<JournalEntry>& expected);
|
||||
|
||||
// Mock-only; control whether to allow subsequent transaction.
|
||||
void allowMoreTransaction(bool is_allowed);
|
||||
|
||||
// Some tests only work for MockAccessor. We remember whether our accessor
|
||||
// is of that type.
|
||||
bool is_mock_;
|
||||
|
||||
boost::shared_ptr<DatabaseAccessor> current_accessor_;
|
||||
boost::shared_ptr<DatabaseClient> client_;
|
||||
const std::string database_name_;
|
||||
|
||||
// The zone finder of the test zone commonly used in various tests.
|
||||
boost::shared_ptr<DatabaseClient::Finder> finder_;
|
||||
|
||||
// Some shortcut variables for commonly used test parameters
|
||||
const dns::Name zname_; // the zone name stored in the test data source
|
||||
const dns::Name qname_; // commonly used name to be found
|
||||
const dns::RRClass qclass_; // commonly used RR class used with qname
|
||||
const dns::RRType qtype_; // commonly used RR type used with qname
|
||||
const dns::RRTTL rrttl_; // commonly used RR TTL
|
||||
dns::RRsetPtr rrset_; // for adding/deleting an RRset
|
||||
dns::RRsetPtr rrsigset_; // for adding/deleting an RRset
|
||||
dns::RRsetPtr soa_; // for adding/deleting an RRset
|
||||
|
||||
// update related objects to be tested
|
||||
ZoneUpdaterPtr updater_;
|
||||
boost::shared_ptr<const DatabaseAccessor> update_accessor_;
|
||||
|
||||
// placeholders
|
||||
const std::vector<std::string> empty_rdatas_; // for NXRRSET/NXDOMAIN
|
||||
std::vector<std::string> expected_rdatas_;
|
||||
std::vector<std::string> expected_sig_rdatas_;
|
||||
|
||||
// A creator for use in several NSEC3 related tests.
|
||||
TestNSEC3HashCreator test_nsec3_hash_creator_;
|
||||
};
|
||||
|
||||
// This test fixture is parameterized so that we can share (most of) the test
|
||||
// cases with different types of data sources.
|
||||
class RRsetCollectionTest : public DatabaseClientTest {
|
||||
protected:
|
||||
RRsetCollectionTest() : collection(NULL) {}
|
||||
|
||||
virtual void SetUp() {
|
||||
DatabaseClientTest::SetUp();
|
||||
updater = client_->getUpdater(zname_, false);
|
||||
collection = &updater->getRRsetCollection();
|
||||
}
|
||||
|
||||
ZoneUpdaterPtr updater;
|
||||
isc::dns::RRsetCollectionBase* collection;
|
||||
};
|
||||
|
||||
// This test fixture is parameterized so that we can share (most of) the test
|
||||
// cases with different types of data sources.
|
||||
class RRsetCollectionAndUpdaterTest : public DatabaseClientTest {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
DatabaseClientTest::SetUp();
|
||||
updater_ = client_->getUpdater(zname_, false);
|
||||
}
|
||||
|
||||
ZoneUpdaterPtr updater_;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace datasrc
|
||||
} // namespace isc
|
||||
|
||||
// Local Variables:
|
||||
// mode: c++
|
||||
// End:
|
Reference in New Issue
Block a user