Commit 8fe58157 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[1068] refactoring for the test code so that it will be easily used

by update tests.  the semantics should be preserved at the moment.
making a commit at this point mainly as a checkpoint.
parent 2812fa5c
......@@ -12,6 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <boost/foreach.hpp>
#include <gtest/gtest.h>
#include <dns/name.h>
......@@ -35,6 +37,10 @@ using namespace isc::dns;
namespace {
// Imaginary zone IDs used in the mock accessor below.
const int READONLY_ZONE_ID = 42;
const int WRITABLE_ZONE_ID = 4200;
/*
* An accessor with minimum implementation, keeping the original
* "NotImplemented" methods.
......@@ -46,7 +52,7 @@ public:
virtual std::pair<bool, int> getZone(const std::string& name) const {
if (name == "example.org.") {
return (std::pair<bool, int>(true, 42));
return (std::pair<bool, int>(true, READONLY_ZONE_ID));
} else if (name == "null.example.org.") {
return (std::pair<bool, int>(true, 13));
} else if (name == "empty.example.org.") {
......@@ -99,9 +105,15 @@ private:
* implementation of the optional functionality.
*/
class MockAccessor : public NopAccessor {
// Type of mock database "row"s
typedef std::map<std::string, std::vector< std::vector<std::string> > >
Domains;
public:
MockAccessor()
{
MockAccessor() {
readonly_records_ = &readonly_records_master_;
update_records_ = &update_records_master_;
empty_records_ = &empty_records_master_;
fillData();
}
private:
......@@ -122,32 +134,27 @@ private:
throw std::exception();
}
if (zone_id == 42) {
if (subdomains) {
cur_name.clear();
// Just walk everything and check if it is a subdomain.
// If it is, just copy all data from there.
for (Domains::const_iterator
i(mock_accessor.records.begin());
i != mock_accessor.records.end(); ++ i) {
Name local(i->first);
if (local.compare(isc::dns::Name(name)).
getRelation() ==
isc::dns::NameComparisonResult::SUBDOMAIN) {
cur_name.insert(cur_name.end(), i->second.begin(),
i->second.end());
}
}
} else {
cur_record_ = 0;
const Domains& cur_records = mock_accessor.getMockRecords(zone_id);
if (cur_records.count(name) > 0) {
// we're not aiming for efficiency in this test, simply
// copy the relevant vector from records
if (mock_accessor.records.count(searched_name_) > 0) {
cur_name = mock_accessor.records.find(searched_name_)->
second;
} else {
cur_name.clear();
cur_name = cur_records.find(name)->second;
} else if (subdomains) {
cur_name.clear();
// Just walk everything and check if it is a subdomain.
// If it is, just copy all data from there.
for (Domains::const_iterator i(cur_records.begin());
i != cur_records.end(); ++i) {
const Name local(i->first);
if (local.compare(Name(name)).getRelation() ==
isc::dns::NameComparisonResult::SUBDOMAIN) {
cur_name.insert(cur_name.end(), i->second.begin(),
i->second.end());
}
}
} else {
cur_name.clear();
}
}
......@@ -262,7 +269,7 @@ private:
};
public:
virtual IteratorContextPtr getAllRecords(int id) const {
if (id == 42) {
if (id == READONLY_ZONE_ID) {
return (IteratorContextPtr(new MockIteratorContext()));
} else if (id == 13) {
return (IteratorContextPtr());
......@@ -278,7 +285,7 @@ public:
virtual IteratorContextPtr getRecords(const std::string& name, int id,
bool subdomains) const
{
if (id == 42) {
if (id == READONLY_ZONE_ID) {
return (IteratorContextPtr(new MockNameIteratorContext(*this, id,
name, subdomains)));
} else {
......@@ -286,15 +293,64 @@ public:
}
}
//
// Helper methods to keep track of some update related activities
//
bool isRollbacked() const {
return (rollbacked_);
}
const vector<string>& getLastAdded() const {
return (columns_lastadded_);
}
// This allows the test code to get the accessor used in an update context
shared_ptr<const MockAccessor> getLatestClone() const {
return (latest_clone_);
}
private:
typedef std::map<std::string, std::vector< std::vector<std::string> > >
Domains;
// The following member variables are storage and/or update work space
// of the test zone. The "master"s are the real objects that contain
// the data, and they are shared among by all accessors cloned from
// an initially created one. The pointer members allow the sharing.
// "readonly" is for normal lookups. "update" is the workspace for
// updates. When update starts it will be initialized either as an
// empty set (when replacing the entire zone) or as a copy of the
// "readonly" one. "empty" is a sentinel to produce negative results.
Domains readonly_records_master_;
Domains* readonly_records_;
Domains update_records_master_;
Domains* update_records_;
const Domains empty_records_master_;
const Domains* empty_records_;
// used as temporary storage during the building of the fake data
Domains records;
//Domains records;
// used as temporary storage after searchForRecord() and during
// getNextRecord() calls, as well as during the building of the
// fake data
std::vector< std::vector<std::string> > cur_name;
std::vector< std::vector<std::string> > cur_name_;
// The columns that were most recently added via addRecordToZone()
vector<string> columns_lastadded_;
// Whether rollback operation has been performed for the database.
// Not useful except for purely testing purpose.
bool rollbacked_;
// Remember the mock accessor that was last cloned
boost::shared_ptr<MockAccessor> latest_clone_;
const Domains& getMockRecords(int zone_id) const {
if (zone_id == READONLY_ZONE_ID) {
return (*readonly_records_);
} else if (zone_id == WRITABLE_ZONE_ID) {
return (*update_records_);
}
return (*empty_records_);
}
// Adds one record to the current name in the database
// The actual data will not be added to 'records' until
......@@ -308,21 +364,21 @@ private:
columns.push_back(type);
columns.push_back(sigtype);
columns.push_back(rdata);
cur_name.push_back(columns);
cur_name_.push_back(columns);
}
// Adds all records we just built with calls to addRecords
// to the actual fake database. This will clear cur_name,
// to the actual fake database. This will clear cur_name_,
// so we can immediately start adding new records.
void addCurName(const std::string& name) {
ASSERT_EQ(0, records.count(name));
ASSERT_EQ(0, readonly_records_->count(name));
// Append the name to all of them
for (std::vector<std::vector<std::string> >::iterator
i(cur_name.begin()); i != cur_name.end(); ++ i) {
i(cur_name_.begin()); i != cur_name_.end(); ++ i) {
i->push_back(name);
}
records[name] = cur_name;
cur_name.clear();
(*readonly_records_)[name] = cur_name_;
cur_name_.clear();
}
// Fills the database with zone data.
......@@ -503,23 +559,44 @@ TEST(DatabaseConnectionTest, getAllRecords) {
class DatabaseClientTest : public ::testing::Test {
public:
DatabaseClientTest() {
DatabaseClientTest() : zname_("example.org"), qname_("www.example.org"),
qclass_(RRClass::IN()), qtype_(RRType::A()),
rrttl_(3600)
{
createClient();
// set up the commonly used finder.
DataSourceClient::FindResult zone(client_->findZone(zname_));
assert(zone.code == result::SUCCESS);
finder_ = dynamic_pointer_cast<DatabaseClient::Finder>(
zone.zone_finder);
// 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"));
// 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 initialize the client from a function, so we can call it multiple
* times per test.
*/
void createClient() {
current_accessor_ = new MockAccessor();
client_.reset(new DatabaseClient(RRClass::IN(),
client_.reset(new DatabaseClient(qclass_,
shared_ptr<DatabaseAccessor>(
current_accessor_)));
}
// Will be deleted by client_, just keep the current value for comparison.
MockAccessor* current_accessor_;
shared_ptr<DatabaseClient> client_;
const std::string database_name_;
/**
* Check the zone finder is a valid one and references the zone ID and
......@@ -531,21 +608,61 @@ public:
dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
ASSERT_NE(shared_ptr<DatabaseClient::Finder>(), finder) <<
"Wrong type of finder";
EXPECT_EQ(42, finder->zone_id());
EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
EXPECT_EQ(current_accessor_, &finder->getAccessor());
}
shared_ptr<DatabaseClient::Finder> getFinder() {
DataSourceClient::FindResult zone(
client_->findZone(Name("example.org")));
DataSourceClient::FindResult zone(client_->findZone(zname_));
EXPECT_EQ(result::SUCCESS, zone.code);
shared_ptr<DatabaseClient::Finder> finder(
dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
EXPECT_EQ(42, finder->zone_id());
EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
return (finder);
}
// Helper methods for update tests
//bool isRollbacked(bool expected = false) const {
bool isRollbacked() const {
return (update_accessor_->isRollbacked());
}
void checkLastAdded(const char* const expected[]) const {
int i = 0;
BOOST_FOREACH(const string& column,
current_accessor_->getLastAdded()) {
EXPECT_EQ(expected[i++], column);
}
}
void setUpdateAccessor() {
update_accessor_ = current_accessor_->getLatestClone();
}
// Will be deleted by client_, just keep the current value for comparison.
MockAccessor* current_accessor_;
shared_ptr<DatabaseClient> client_;
const std::string database_name_;
// The zone finder of the test zone commonly used in various tests.
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
// update related objects to be tested
ZoneUpdaterPtr updater_;
shared_ptr<const MockAccessor> 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_;
};
......@@ -1299,8 +1416,7 @@ TEST_F(DatabaseClientTest, getOrigin) {
ASSERT_EQ(result::SUCCESS, zone.code);
shared_ptr<DatabaseClient::Finder> finder(
dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
EXPECT_EQ(42, finder->zone_id());
EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
EXPECT_EQ(isc::dns::Name("example.org"), finder->getOrigin());
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment