123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- // Copyright (C) 2010 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 <gtest/gtest.h>
- #include <exceptions/exceptions.h>
- #include <dns/rrclass.h>
- #include <dns/masterload.h>
- #include <cc/data.h>
- #include <datasrc/memory_datasrc.h>
- #include <xfr/xfrout_client.h>
- #include <auth/auth_srv.h>
- #include <auth/auth_config.h>
- #include <auth/common.h>
- #include <testutils/mockups.h>
- #include <testutils/portconfig.h>
- using namespace isc::dns;
- using namespace isc::data;
- using namespace isc::datasrc;
- using namespace asiolink;
- namespace {
- class AuthConfigTest : public ::testing::Test {
- protected:
- AuthConfigTest() :
- dnss_(ios_, NULL, NULL, NULL),
- rrclass(RRClass::IN()),
- server(true, xfrout)
- {
- server.setDNSService(dnss_);
- }
- IOService ios_;
- DNSService dnss_;
- const RRClass rrclass;
- MockXfroutClient xfrout;
- AuthSrv server;
- };
- TEST_F(AuthConfigTest, datasourceConfig) {
- // By default, we don't have any in-memory data source.
- EXPECT_EQ(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
- configureAuthServer(server, Element::fromJSON(
- "{\"datasources\": [{\"type\": \"memory\"}]}"));
- // after successful configuration, we should have one (with empty zoneset).
- ASSERT_NE(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
- EXPECT_EQ(0, server.getMemoryDataSrc(rrclass)->getZoneCount());
- }
- TEST_F(AuthConfigTest, databaseConfig) {
- // right now, "database_file" is handled separately, so the parser
- // doesn't recognize it, but it shouldn't throw an exception due to that.
- EXPECT_NO_THROW(configureAuthServer(
- server,
- Element::fromJSON(
- "{\"database_file\": \"should_be_ignored\"}")));
- }
- TEST_F(AuthConfigTest, exceptionGuarantee) {
- EXPECT_EQ(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
- // This configuration contains an invalid item, which will trigger
- // an exception.
- EXPECT_THROW(configureAuthServer(
- server,
- Element::fromJSON(
- "{\"datasources\": [{\"type\": \"memory\"}], "
- " \"no_such_config_var\": 1}")),
- AuthConfigError);
- // The server state shouldn't change
- EXPECT_EQ(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
- }
- TEST_F(AuthConfigTest, exceptionConversion) {
- // This configuration contains a bogus RR class, which will trigger an
- // exception from libdns++. configureAuthServer() should convert this
- // to AuthConfigError and rethrow the converted one.
- EXPECT_THROW(configureAuthServer(
- server,
- Element::fromJSON(
- "{\"datasources\": "
- " [{\"type\": \"memory\","
- " \"class\": \"BADCLASS\","
- " \"zones\": [{\"origin\": \"example.com\","
- " \"file\": \"example.zone\"}]}]}")),
- AuthConfigError);
- }
- TEST_F(AuthConfigTest, badConfig) {
- // These should normally not happen, but should be handled to avoid
- // an unexpected crash due to a bug of the caller.
- EXPECT_THROW(configureAuthServer(server, ElementPtr()), AuthConfigError);
- EXPECT_THROW(configureAuthServer(server, Element::fromJSON("[]")),
- AuthConfigError);
- }
- TEST_F(AuthConfigTest, unknownConfigVar) {
- EXPECT_THROW(createAuthConfigParser(server, "no_such_config_var"),
- AuthConfigError);
- }
- TEST_F(AuthConfigTest, exceptionFromCommit) {
- EXPECT_THROW(configureAuthServer(server, Element::fromJSON(
- "{\"_commit_throw\": 10}")),
- FatalError);
- }
- // Test invalid address configs are rejected
- TEST_F(AuthConfigTest, invalidListenAddressConfig) {
- // This currently passes simply because the config doesn't know listen_on
- isc::testutils::portconfig::invalidListenAddressConfig(server);
- }
- // Try setting addresses trough config
- TEST_F(AuthConfigTest, listenAddressConfig) {
- isc::testutils::portconfig::listenAddressConfig(server);
- }
- class MemoryDatasrcConfigTest : public AuthConfigTest {
- protected:
- MemoryDatasrcConfigTest() :
- parser(createAuthConfigParser(server, "datasources"))
- {}
- ~MemoryDatasrcConfigTest() {
- delete parser;
- }
- AuthConfigParser* parser;
- };
- TEST_F(MemoryDatasrcConfigTest, addZeroDataSrc) {
- parser->build(Element::fromJSON("[]"));
- parser->commit();
- EXPECT_EQ(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
- }
- TEST_F(MemoryDatasrcConfigTest, addEmpty) {
- // By default, we don't have any in-memory data source.
- EXPECT_EQ(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
- parser->build(Element::fromJSON("[{\"type\": \"memory\"}]"));
- parser->commit();
- EXPECT_EQ(0, server.getMemoryDataSrc(rrclass)->getZoneCount());
- }
- TEST_F(MemoryDatasrcConfigTest, addZeroZone) {
- parser->build(Element::fromJSON("[{\"type\": \"memory\","
- " \"zones\": []}]"));
- parser->commit();
- EXPECT_EQ(0, server.getMemoryDataSrc(rrclass)->getZoneCount());
- }
- TEST_F(MemoryDatasrcConfigTest, addOneZone) {
- EXPECT_NO_THROW(parser->build(Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"origin\": \"example.com\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.zone\"}]}]")));
- EXPECT_NO_THROW(parser->commit());
- EXPECT_EQ(1, server.getMemoryDataSrc(rrclass)->getZoneCount());
- // Check it actually loaded something
- EXPECT_EQ(Zone::SUCCESS, server.getMemoryDataSrc(rrclass)->findZone(
- Name("ns.example.com.")).zone->find(Name("ns.example.com."),
- RRType::A()).code);
- }
- TEST_F(MemoryDatasrcConfigTest, addMultiZones) {
- EXPECT_NO_THROW(parser->build(Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"origin\": \"example.com\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.zone\"},"
- " {\"origin\": \"example.org\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.org.zone\"},"
- " {\"origin\": \"example.net\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.net.zone\"}]}]")));
- EXPECT_NO_THROW(parser->commit());
- EXPECT_EQ(3, server.getMemoryDataSrc(rrclass)->getZoneCount());
- }
- TEST_F(MemoryDatasrcConfigTest, replace) {
- EXPECT_NO_THROW(parser->build(Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"origin\": \"example.com\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.zone\"}]}]")));
- EXPECT_NO_THROW(parser->commit());
- EXPECT_EQ(1, server.getMemoryDataSrc(rrclass)->getZoneCount());
- EXPECT_EQ(isc::datasrc::result::SUCCESS,
- server.getMemoryDataSrc(rrclass)->findZone(
- Name("example.com")).code);
- // create a new parser, and install a new set of configuration. It
- // should replace the old one.
- delete parser;
- parser = createAuthConfigParser(server, "datasources");
- EXPECT_NO_THROW(parser->build(Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"origin\": \"example.org\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.org.zone\"},"
- " {\"origin\": \"example.net\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.net.zone\"}]}]")));
- EXPECT_NO_THROW(parser->commit());
- EXPECT_EQ(2, server.getMemoryDataSrc(rrclass)->getZoneCount());
- EXPECT_EQ(isc::datasrc::result::NOTFOUND,
- server.getMemoryDataSrc(rrclass)->findZone(
- Name("example.com")).code);
- }
- TEST_F(MemoryDatasrcConfigTest, exception) {
- // Load a zone
- EXPECT_NO_THROW(parser->build(Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"origin\": \"example.com\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.zone\"}]}]")));
- EXPECT_NO_THROW(parser->commit());
- EXPECT_EQ(1, server.getMemoryDataSrc(rrclass)->getZoneCount());
- EXPECT_EQ(isc::datasrc::result::SUCCESS,
- server.getMemoryDataSrc(rrclass)->findZone(
- Name("example.com")).code);
- // create a new parser, and try to load something. It will throw,
- // the given master file should not exist
- delete parser;
- parser = createAuthConfigParser(server, "datasources");
- EXPECT_THROW(parser->build(Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"origin\": \"example.org\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.org.zone\"},"
- " {\"origin\": \"example.net\","
- " \"file\": \"" TEST_DATA_DIR
- "/nonexistent.zone\"}]}]")), isc::dns::MasterLoadError);
- // As that one throwed exception, it is not expected from us to
- // commit it
- // The original should be untouched
- EXPECT_EQ(1, server.getMemoryDataSrc(rrclass)->getZoneCount());
- EXPECT_EQ(isc::datasrc::result::SUCCESS,
- server.getMemoryDataSrc(rrclass)->findZone(
- Name("example.com")).code);
- }
- TEST_F(MemoryDatasrcConfigTest, remove) {
- EXPECT_NO_THROW(parser->build(Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"origin\": \"example.com\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.zone\"}]}]")));
- EXPECT_NO_THROW(parser->commit());
- EXPECT_EQ(1, server.getMemoryDataSrc(rrclass)->getZoneCount());
- delete parser;
- parser = createAuthConfigParser(server, "datasources");
- EXPECT_NO_THROW(parser->build(Element::fromJSON("[]")));
- EXPECT_NO_THROW(parser->commit());
- EXPECT_EQ(AuthSrv::MemoryDataSrcPtr(), server.getMemoryDataSrc(rrclass));
- }
- TEST_F(MemoryDatasrcConfigTest, adDuplicateZones) {
- EXPECT_THROW(parser->build(
- Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"origin\": \"example.com\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.zone\"},"
- " {\"origin\": \"example.com\","
- " \"file\": \"" TEST_DATA_DIR
- "/example.com.zone\"}]}]")),
- AuthConfigError);
- }
- TEST_F(MemoryDatasrcConfigTest, addBadZone) {
- // origin is missing
- EXPECT_THROW(parser->build(
- Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"file\": \"example.zone\"}]}]")),
- AuthConfigError);
- // missing zone file
- EXPECT_THROW(parser->build(
- Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"origin\": \"example.com\"}]}]")),
- AuthConfigError);
- // bogus origin name
- EXPECT_THROW(parser->build(Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"zones\": [{\"origin\": \"example..com\","
- " \"file\": \"example.zone\"}]}]")),
- EmptyLabel);
- // bogus RR class name
- EXPECT_THROW(parser->build(
- Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"class\": \"BADCLASS\","
- " \"zones\": [{\"origin\": \"example.com\","
- " \"file\": \"example.zone\"}]}]")),
- InvalidRRClass);
- // valid RR class, but not currently supported
- EXPECT_THROW(parser->build(
- Element::fromJSON(
- "[{\"type\": \"memory\","
- " \"class\": \"CH\","
- " \"zones\": [{\"origin\": \"example.com\","
- " \"file\": \"example.zone\"}]}]")),
- isc::InvalidParameter);
- }
- TEST_F(MemoryDatasrcConfigTest, badDatasrcType) {
- EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": \"badsrc\"}]")),
- AuthConfigError);
- EXPECT_THROW(parser->build(Element::fromJSON("[{\"notype\": \"memory\"}]")),
- AuthConfigError);
- EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": 1}]")),
- isc::data::TypeError);
- EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": \"memory\"},"
- " {\"type\": \"memory\"}]")),
- AuthConfigError);
- }
- class StatisticsIntervalConfigTest : public AuthConfigTest {
- protected:
- StatisticsIntervalConfigTest() :
- parser(createAuthConfigParser(server, "statistics-interval"))
- {}
- ~StatisticsIntervalConfigTest() {
- delete parser;
- }
- AuthConfigParser* parser;
- };
- TEST_F(StatisticsIntervalConfigTest, setInterval) {
- // initially the timer is not configured.
- EXPECT_EQ(0, server.getStatisticsTimerInterval());
- // initialize the timer
- parser->build(Element::fromJSON("5"));
- parser->commit();
- EXPECT_EQ(5, server.getStatisticsTimerInterval());
- // reset the timer with a new interval
- delete parser;
- parser = createAuthConfigParser(server, "statistics-interval");
- ASSERT_NE(static_cast<void*>(NULL), parser);
- parser->build(Element::fromJSON("10"));
- parser->commit();
- EXPECT_EQ(10, server.getStatisticsTimerInterval());
- // disable the timer again
- delete parser;
- parser = createAuthConfigParser(server, "statistics-interval");
- ASSERT_NE(static_cast<void*>(NULL), parser);
- parser->build(Element::fromJSON("0"));
- parser->commit();
- EXPECT_EQ(0, server.getStatisticsTimerInterval());
- }
- TEST_F(StatisticsIntervalConfigTest, badInterval) {
- EXPECT_THROW(parser->build(Element::fromJSON("\"should be integer\"")),
- isc::data::TypeError);
- EXPECT_THROW(parser->build(Element::fromJSON("2.5")),
- isc::data::TypeError);
- EXPECT_THROW(parser->build(Element::fromJSON("-1")), AuthConfigError);
- // bounds check: interval value must be equal to or shorter than
- // 86400 seconds (1 day)
- EXPECT_NO_THROW(parser->build(Element::fromJSON("86400")));
- EXPECT_THROW(parser->build(Element::fromJSON("86401")), AuthConfigError);
- }
- }
|