2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 21:45:37 +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:
JINMEI Tatuya
2013-02-07 15:33:49 -08:00
parent f866170c9a
commit b2ac76a62e
3 changed files with 592 additions and 503 deletions

View File

@@ -51,7 +51,7 @@ run_unittests_SOURCES += test_client.h test_client.cc
run_unittests_SOURCES += rbtree_unittest.cc run_unittests_SOURCES += rbtree_unittest.cc
run_unittests_SOURCES += logger_unittest.cc run_unittests_SOURCES += logger_unittest.cc
run_unittests_SOURCES += client_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 += sqlite3_accessor_unittest.cc
run_unittests_SOURCES += memory_datasrc_unittest.cc run_unittests_SOURCES += memory_datasrc_unittest.cc
run_unittests_SOURCES += rbnode_rrset_unittest.cc run_unittests_SOURCES += rbnode_rrset_unittest.cc

View File

@@ -12,9 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE. // PERFORMANCE OF THIS SOFTWARE.
#include "faked_nsec3.h" #include <datasrc/tests/database_unittest.h>
#include <datasrc/tests/faked_nsec3.h>
#include <exceptions/exceptions.h>
#include <dns/masterload.h> #include <dns/masterload.h>
#include <dns/name.h> #include <dns/name.h>
@@ -40,6 +39,7 @@
#include <cstdlib> #include <cstdlib>
#include <map> #include <map>
#include <string>
#include <vector> #include <vector>
using namespace isc::datasrc; using namespace isc::datasrc;
@@ -53,206 +53,11 @@ using namespace isc::testutils;
using namespace isc::datasrc::test; using namespace isc::datasrc::test;
namespace { namespace {
// Imaginary zone IDs used in the mock accessor below. // Imaginary zone IDs used in the mock accessor below.
const int READONLY_ZONE_ID = 42; const int READONLY_ZONE_ID = 42;
const int NEW_ZONE_ID = 420; const int NEW_ZONE_ID = 420;
const int WRITABLE_ZONE_ID = 4200; 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 * An accessor with minimum implementation, keeping the original
* "NotImplemented" methods. * "NotImplemented" methods.
@@ -359,52 +164,6 @@ private:
std::map<std::string, int> zones_; 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 -- * A virtual database accessor that pretends it contains single zone --
* example.org. * 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 // This tests the default getRecords behaviour, throwing NotImplemented
TEST(DatabaseConnectionTest, getRecords) { TEST(DatabaseConnectionTest, getRecords) {
EXPECT_THROW(NopAccessor().getRecords(".", 1, false), EXPECT_THROW(NopAccessor().getRecords(".", 1, false),
@@ -1147,236 +1278,6 @@ TEST(DatabaseConnectionTest, getAllRecords) {
isc::NotImplemented); 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 // The following two lines instantiate test cases with concrete accessor
// classes to be tested. // classes to be tested.
@@ -4317,22 +4218,6 @@ TEST_P(DatabaseClientTest, deleteZoneRollbackOnNotFind) {
EXPECT_TRUE(client_->deleteZone(zname_)); 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, INSTANTIATE_TEST_CASE_P(, RRsetCollectionTest,
::testing::Values(&mock_param, &sqlite3_param)); ::testing::Values(&mock_param, &sqlite3_param));
@@ -4457,18 +4342,6 @@ TEST_F(MockRRsetCollectionTest, findError) {
}, RRsetCollectionError); }, 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, INSTANTIATE_TEST_CASE_P(, RRsetCollectionAndUpdaterTest,
::testing::Values(&mock_param, &sqlite3_param)); ::testing::Values(&mock_param, &sqlite3_param));

View 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: