Note: currently called createZone so as not to interfere with an existing addZone() call in MemoryClient.
Instead of pure virtual I made it have a default 'NotImplemented' method.
Also, the DatabaseClient holds the transaction (not the SQLite3Accessor); we could do it on that level but we already have a transaction API on a higher level and it makes a little bit more sense to me to do it there
isc_throw(isc::NotImplemented,
"Data source doesn't support getZoneCount");
}
+
+ // It first checks if the specified name of the zone exists. If it
+ // exists it returns false; otherwise it adds information of the
+ // new zone in backend-dependent manner and returns true.
+ // The DB-based version of this method would perform the check and add in
+ // a single transaction.
+ //
+ // Throws on any unexpected failure.
+ // Default implementation throws isc::NotImplemented
+
+ virtual bool createZone(const dns::Name&) {
+ isc_throw(isc::NotImplemented,
+ "Data source doesn't support addZone");
+ };
};
}
}
namespace isc {
namespace datasrc {
+// RAII-style transaction holder; roll back the transaction unless explicitely committed
+namespace {
+class TransactionHolder {
+public:
+ TransactionHolder(DatabaseAccessor& accessor) : accessor_(accessor),
+ committed_(false)
+ {
+ accessor_.startTransaction();
+ }
+ ~TransactionHolder() {
+ if (!committed_) {
+ accessor_.rollback();
+ }
+ }
+ void commit() {
+ accessor_.commit();
+ committed_ = true;
+ }
+private:
+ DatabaseAccessor& accessor_;
+ bool committed_;
+};
+} // end unnamed namespace
+
DatabaseClient::DatabaseClient(RRClass rrclass,
boost::shared_ptr<DatabaseAccessor>
return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
}
+bool
+DatabaseClient::createZone(const Name& name) {
+ TransactionHolder transaction(*accessor_);
+ std::pair<bool, int> zone(accessor_->getZone(name.toText()));
+ if (zone.first) {
+ return (false);
+ }
+ accessor_->addZone(name.toText());
+ transaction.commit();
+ return (true);
+}
+
DatabaseClient::Finder::Finder(boost::shared_ptr<DatabaseAccessor> accessor,
int zone_id, const isc::dns::Name& origin) :
accessor_(accessor),
/// should use it as a ZoneFinder only.
virtual FindResult findZone(const isc::dns::Name& name) const;
+ virtual bool createZone(const isc::dns::Name&);
+
/// \brief Get the zone iterator
///
/// The iterator allows going through the whole zone content. If the
EXPECT_THROW(client_.getZoneCount(), isc::NotImplemented);
}
+TEST_F(ClientTest, defaultCreateZone) {
+ EXPECT_THROW(client_.createZone(Name("example.com.")), isc::NotImplemented);
+}
+
}
isc_throw(isc::NotImplemented,
"This test database knows nothing about NSEC3 nor order");
}
+
private:
const std::string database_name_;
performNSEC3Test(*finder, true);
}
+TYPED_TEST(DatabaseClientTest, createZone) {
+ const Name new_name("example.com");
+ const DataSourceClient::FindResult
+ zone(this->client_->findZone(new_name));
+ ASSERT_EQ(result::NOTFOUND, zone.code);
+ // The mock implementation does not do createZone,
+ // in which case it should throw NotImplemented (from
+ // the base class)
+ if(this->is_mock_) {
+ ASSERT_THROW(this->client_->createZone(new_name), isc::NotImplemented);
+ } else {
+ // But in the real case, it should work and return true
+ ASSERT_TRUE(this->client_->createZone(new_name));
+ const DataSourceClient::FindResult
+ zone2(this->client_->findZone(new_name));
+ ASSERT_EQ(result::SUCCESS, zone2.code);
+ // And the second call should return false since
+ // it already exists
+ ASSERT_FALSE(this->client_->createZone(new_name));
+ }
+}
+
}