123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- // Copyright (C) 2012 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 <exceptions/exceptions.h>
- #include <dns/rrclass.h>
- #include <cc/data.h>
- #include <datasrc/client_list.h>
- #include <auth/datasrc_clients_mgr.h>
- #include "test_datasrc_clients_mgr.h"
- #include <gtest/gtest.h>
- #include <boost/function.hpp>
- using namespace isc::dns;
- using namespace isc::data;
- using namespace isc::datasrc;
- using namespace isc::auth;
- using namespace isc::auth::datasrc_clientmgr_internal;
- namespace {
- void
- shutdownCheck() {
- // Check for common points on shutdown. The manager should have acquired
- // the lock, put a SHUTDOWN command to the queue, and should have signaled
- // the builder.
- EXPECT_EQ(1, FakeDataSrcClientsBuilder::queue_mutex->lock_count);
- EXPECT_EQ(1, FakeDataSrcClientsBuilder::cond->signal_count);
- EXPECT_EQ(1, FakeDataSrcClientsBuilder::command_queue->size());
- const Command& cmd = FakeDataSrcClientsBuilder::command_queue->front();
- EXPECT_EQ(SHUTDOWN, cmd.id);
- EXPECT_FALSE(cmd.params); // no argument
- // Finally, the manager should wait for the thread to terminate.
- EXPECT_TRUE(FakeDataSrcClientsBuilder::thread_waited);
- }
- // Commonly used pattern of checking member variables shared between the
- // manager and builder.
- void
- checkSharedMembers(size_t expected_queue_lock_count,
- size_t expected_queue_unlock_count,
- size_t expected_map_lock_count,
- size_t expected_map_unlock_count,
- size_t expected_cond_signal_count,
- size_t expected_command_queue_size)
- {
- EXPECT_EQ(expected_queue_lock_count,
- FakeDataSrcClientsBuilder::queue_mutex->lock_count);
- EXPECT_EQ(expected_queue_unlock_count,
- FakeDataSrcClientsBuilder::queue_mutex->unlock_count);
- EXPECT_EQ(expected_map_lock_count,
- FakeDataSrcClientsBuilder::map_mutex->lock_count);
- EXPECT_EQ(expected_map_unlock_count,
- FakeDataSrcClientsBuilder::map_mutex->unlock_count);
- EXPECT_EQ(expected_cond_signal_count,
- FakeDataSrcClientsBuilder::cond->signal_count);
- EXPECT_EQ(expected_command_queue_size,
- FakeDataSrcClientsBuilder::command_queue->size());
- }
- TEST(DataSrcClientsMgrTest, start) {
- // When we create a manager, builder's run() method should be called.
- FakeDataSrcClientsBuilder::started = false;
- {
- TestDataSrcClientsMgr mgr;
- EXPECT_TRUE(FakeDataSrcClientsBuilder::started);
- EXPECT_TRUE(FakeDataSrcClientsBuilder::command_queue->empty());
- // Check pre-destroy conditions
- EXPECT_EQ(0, FakeDataSrcClientsBuilder::cond->signal_count);
- EXPECT_FALSE(FakeDataSrcClientsBuilder::thread_waited);
- } // mgr and builder have been destroyed by this point.
- // We stopped the manager implicitly (without shutdown()). The manager
- // will internally notify it
- shutdownCheck();
- }
- TEST(DataSrcClientsMgrTest, shutdownWithUncaughtException) {
- // Emulating the case when the builder exists on exception. shutdown()
- // will encounter UncaughtException exception and catch it.
- EXPECT_NO_THROW({
- TestDataSrcClientsMgr mgr;
- FakeDataSrcClientsBuilder::thread_throw_on_wait =
- FakeDataSrcClientsBuilder::THROW_UNCAUGHT_EX;
- });
- }
- TEST(DataSrcClientsMgrTest, shutdownWithException) {
- EXPECT_NO_THROW({
- TestDataSrcClientsMgr mgr;
- FakeDataSrcClientsBuilder::thread_throw_on_wait =
- FakeDataSrcClientsBuilder::THROW_OTHER;
- });
- }
- TEST(DataSrcClientsMgrTest, reconfigure) {
- TestDataSrcClientsMgr mgr;
- // Check pre-command condition
- checkSharedMembers(0, 0, 0, 0, 0, 0);
- // A valid reconfigure argument
- ConstElementPtr reconfigure_arg = Element::fromJSON(
- "{""\"IN\": [{\"type\": \"MasterFiles\", \"params\": {},"
- " \"cache-enable\": true}]}");
- // On reconfigure(), it just send the RECONFIGURE command to the builder
- // thread with the given argument intact.
- mgr.reconfigure(reconfigure_arg);
- // The manager should have acquired the queue lock, send RECONFIGURE
- // command with the arg, wake up the builder thread by signal. It doesn't
- // touch or refer to the map, so it shouldn't acquire the map lock.
- checkSharedMembers(1, 1, 0, 0, 1, 1);
- const Command& cmd1 = FakeDataSrcClientsBuilder::command_queue->front();
- EXPECT_EQ(RECONFIGURE, cmd1.id);
- EXPECT_EQ(reconfigure_arg, cmd1.params);
- // Non-null, but semantically invalid argument. The manager doesn't do
- // this check, so it should result in the same effect.
- FakeDataSrcClientsBuilder::command_queue->clear();
- reconfigure_arg = isc::data::Element::create("{ \"foo\": \"bar\" }");
- mgr.reconfigure(reconfigure_arg);
- checkSharedMembers(2, 2, 0, 0, 2, 1);
- const Command& cmd2 = FakeDataSrcClientsBuilder::command_queue->front();
- EXPECT_EQ(RECONFIGURE, cmd2.id);
- EXPECT_EQ(reconfigure_arg, cmd2.params);
- // Passing NULL argument is immediately rejected
- EXPECT_THROW(mgr.reconfigure(ConstElementPtr()), isc::InvalidParameter);
- checkSharedMembers(2, 2, 0, 0, 2, 1); // no state change
- }
- TEST(DataSrcClientsMgrTest, holder) {
- TestDataSrcClientsMgr mgr;
- {
- // Initially it's empty, so findClientList() will always return NULL
- TestDataSrcClientsMgr::Holder holder(mgr);
- EXPECT_FALSE(holder.findClientList(RRClass::IN()));
- EXPECT_FALSE(holder.findClientList(RRClass::CH()));
- // map should be protected here
- EXPECT_EQ(1, FakeDataSrcClientsBuilder::map_mutex->lock_count);
- EXPECT_EQ(0, FakeDataSrcClientsBuilder::map_mutex->unlock_count);
- }
- // map lock has been released
- EXPECT_EQ(1, FakeDataSrcClientsBuilder::map_mutex->unlock_count);
- // Put something in, that should become visible.
- ConstElementPtr reconfigure_arg = Element::fromJSON(
- "{\"IN\": [{\"type\": \"MasterFiles\", \"params\": {},"
- " \"cache-enable\": true}],"
- " \"CH\": [{\"type\": \"MasterFiles\", \"params\": {},"
- " \"cache-enable\": true}]}");
- mgr.reconfigure(reconfigure_arg);
- {
- TestDataSrcClientsMgr::Holder holder(mgr);
- EXPECT_TRUE(holder.findClientList(RRClass::IN()));
- EXPECT_TRUE(holder.findClientList(RRClass::CH()));
- }
- // We need to clear command queue by hand
- FakeDataSrcClientsBuilder::command_queue->clear();
- // Replace the lists with new lists containing only one list.
- // The CH will disappear again.
- reconfigure_arg = Element::fromJSON(
- "{\"IN\": [{\"type\": \"MasterFiles\", \"params\": {},"
- " \"cache-enable\": true}]}");
- mgr.reconfigure(reconfigure_arg);
- {
- TestDataSrcClientsMgr::Holder holder(mgr);
- EXPECT_TRUE(holder.findClientList(RRClass::IN()));
- EXPECT_FALSE(holder.findClientList(RRClass::CH()));
- }
- // Duplicate lock acquisition is prohibited (only test mgr can detect
- // this reliably, so this test may not be that useful)
- TestDataSrcClientsMgr::Holder holder1(mgr);
- EXPECT_THROW(TestDataSrcClientsMgr::Holder holder2(mgr), isc::Unexpected);
- }
- TEST(DataSrcClientsMgrTest, reload) {
- TestDataSrcClientsMgr mgr;
- EXPECT_TRUE(FakeDataSrcClientsBuilder::started);
- EXPECT_TRUE(FakeDataSrcClientsBuilder::command_queue->empty());
- isc::data::ElementPtr args =
- isc::data::Element::fromJSON("{ \"class\": \"IN\","
- " \"origin\": \"example.com\" }");
- mgr.loadZone(args);
- EXPECT_EQ(1, FakeDataSrcClientsBuilder::command_queue->size());
- mgr.loadZone(args);
- EXPECT_EQ(2, FakeDataSrcClientsBuilder::command_queue->size());
- // Should fail with non-string 'class' value
- args->set("class", Element::create(1));
- EXPECT_THROW(mgr.loadZone(args), CommandError);
- EXPECT_EQ(2, FakeDataSrcClientsBuilder::command_queue->size());
- // And with badclass
- args->set("class", Element::create("BADCLASS"));
- EXPECT_THROW(mgr.loadZone(args), CommandError);
- EXPECT_EQ(2, FakeDataSrcClientsBuilder::command_queue->size());
- // Should succeed without 'class'
- args->remove("class");
- mgr.loadZone(args);
- EXPECT_EQ(3, FakeDataSrcClientsBuilder::command_queue->size());
- // but fail without origin, without sending new commands
- args->remove("origin");
- EXPECT_THROW(mgr.loadZone(args), CommandError);
- EXPECT_EQ(3, FakeDataSrcClientsBuilder::command_queue->size());
- // And for 'origin' that is not a string
- args->set("origin", Element::create(1));
- EXPECT_THROW(mgr.loadZone(args), CommandError);
- EXPECT_EQ(3, FakeDataSrcClientsBuilder::command_queue->size());
- // And origin that is not a correct name
- args->set("origin", Element::create(".."));
- EXPECT_THROW(mgr.loadZone(args), CommandError);
- EXPECT_EQ(3, FakeDataSrcClientsBuilder::command_queue->size());
- // same for empty data and data that is not a map
- EXPECT_THROW(mgr.loadZone(isc::data::ConstElementPtr()), CommandError);
- EXPECT_THROW(mgr.loadZone(isc::data::Element::createList()), CommandError);
- EXPECT_EQ(3, FakeDataSrcClientsBuilder::command_queue->size());
- }
- TEST(DataSrcClientsMgrTest, realThread) {
- // Using the non-test definition with a real thread. Just checking
- // no disruption happens.
- DataSrcClientsMgr mgr;
- }
- } // unnamed namespace
|