Parcourir la source

[trac978] Tests for the check loader

Michal 'vorner' Vaner il y a 14 ans
Parent
commit
a9d549be74
2 fichiers modifiés avec 187 ajouts et 4 suppressions
  1. 3 3
      src/lib/acl/loader.h
  2. 184 1
      src/lib/acl/tests/loader_test.cc

+ 3 - 3
src/lib/acl/loader.h

@@ -140,7 +140,7 @@ public:
          *     to validate the data and throw if it is bad.
          */
         virtual boost::shared_ptr<Check<Context> > create(
-            const std::string& name, data::ConstElementPtr definition);
+            const std::string& name, data::ConstElementPtr definition) = 0;
         /**
          * \brief Is list or-abbreviation allowed?
          *
@@ -185,7 +185,7 @@ public:
      *
      * \param description The JSON description of the check.
      */
-    boost::shared_ptr<Check<Context> > loadCheck(data::ConstElementPtr&
+    boost::shared_ptr<Check<Context> > loadCheck(const data::ConstElementPtr&
                                                  description);
     /**
      * \brief Load an ACL.
@@ -198,7 +198,7 @@ public:
      *
      * \param description The JSON list of ACL.
      */
-    boost::shared_ptr<Acl<Context, Action> > load(data::ConstElementPtr&
+    boost::shared_ptr<Acl<Context, Action> > load(const data::ConstElementPtr&
                                                   description);
 };
 

+ 184 - 1
src/lib/acl/tests/loader_test.cc

@@ -19,6 +19,7 @@
 
 using namespace isc::acl;
 using namespace std;
+using namespace boost;
 using isc::data::ConstElementPtr;
 
 namespace {
@@ -61,6 +62,188 @@ TEST(LoaderHelpers, DefaultActionLoader) {
     testActionLoaderException("{}");
 }
 
-Loader<bool> loader;
+// We need to pass a context, but it doesn't matter here which one
+class NullContext {};
+
+// A check that doesn't check anything but remembers it's own name
+// and data
+class NamedCheck : public Check<NullContext> {
+public:
+    NamedCheck(const string& name, ConstElementPtr data) :
+        name_(name),
+        data_(data)
+    {}
+    const string name_;
+    const ConstElementPtr data_;
+};
+
+// The creator of NamedCheck
+class NamedCreator : public Loader<NullContext>::CheckCreator {
+public:
+    NamedCreator(const string& name, bool abbreviatedList = true) :
+        abbreviated_list_(abbreviatedList)
+    {
+        names_.push_back(name);
+    }
+    NamedCreator(const vector<string>& names) :
+        names_(names),
+        abbreviated_list_(true)
+    {}
+    vector<string> names() const {
+        return (names_);
+    }
+    shared_ptr<Check<NullContext> > create(const string&, ConstElementPtr) {
+        return (shared_ptr<Check<NullContext> >());
+    }
+    bool allowListAbbreviation() const {
+        return (abbreviated_list_);
+    }
+private:
+    vector<string> names_;
+    const bool abbreviated_list_;
+};
+
+// To be thrown in tests internally
+class TestCreatorError {};
+
+// This will throw every time it should create something
+class ThrowCreator : public Loader<NullContext>::CheckCreator {
+public:
+    vector<string> names() const {
+        vector<string> result;
+        result.push_back("throw");
+        return (result);
+    }
+    shared_ptr<Check<NullContext> > create(const string&, ConstElementPtr) {
+        throw TestCreatorError();
+    }
+};
+
+class LoaderTest : public ::testing::Test {
+public:
+    Loader<NullContext> loader_;
+    // Some convenience functions to set up
+
+    // Create a NamedCreator, convert to shared pointer
+    shared_ptr<NamedCreator> namedCreator(const string& name,
+                                          bool abbreviatedList = true)
+    {
+        return (shared_ptr<NamedCreator>(new NamedCreator(name,
+                                                          abbreviatedList)));
+    }
+    // Create and add a NamedCreator
+    void addNamed(const string& name, bool abbreviatedList = true) {
+        EXPECT_NO_THROW(loader_.registerCreator(
+            namedCreator(name, abbreviatedList)));
+    }
+    // Load a check and convert it to named check to examine it
+    shared_ptr<NamedCheck> loadCheck(const string& definition) {
+        SCOPED_TRACE("Loading check " + definition);
+        shared_ptr<Check<NullContext> > loaded;
+        EXPECT_NO_THROW(loaded = loader_.loadCheck(el(definition)));
+        shared_ptr<NamedCheck> result(dynamic_pointer_cast<NamedCheck>(
+            loaded));
+        EXPECT_TRUE(result);
+        return (result);
+    }
+    // The loadCheck throws an exception
+    void checkException(const string& JSON) {
+        SCOPED_TRACE("Loading check exception: " + JSON);
+        ConstElementPtr input(el(JSON));
+        // Not using EXPECT_THROW, we want to examine the exception
+        try {
+            loader_.loadCheck(input);
+            FAIL() << "Should have thrown";
+        }
+        catch (const LoaderError& e) {
+            // It should be identical copy, so checking pointers
+            EXPECT_EQ(input, e.element());
+        }
+    }
+};
+
+// Test that it does not accept duplicate creator
+TEST_F(LoaderTest, CreatorDuplicity) {
+    addNamed("name");
+    EXPECT_THROW(loader_.registerCreator(namedCreator("name")), LoaderError);
+}
+
+// Test that we can register a creator and load a check with the name
+TEST_F(LoaderTest, SimpleCheckLoad) {
+    addNamed("name");
+    shared_ptr<NamedCheck> check(loadCheck("{\"name\": 42}"));
+    EXPECT_EQ("name", check->name_);
+    EXPECT_TRUE(check->data_->equals(*el("42")));
+}
+
+// As above, but there are multiple creators registered within the loader
+TEST_F(LoaderTest, MultiCreatorCheckLoad) {
+    addNamed("name1");
+    addNamed("name2");
+    shared_ptr<NamedCheck> check(loadCheck("{\"name2\": 42}"));
+    EXPECT_EQ("name2", check->name_);
+    EXPECT_TRUE(check->data_->equals(*el("42")));
+}
+
+// Similar to above, but there's a creator with multiple names
+TEST_F(LoaderTest, MultiNameCheckLoad) {
+    addNamed("name1");
+    vector<string> names;
+    names.push_back("name2");
+    names.push_back("name3");
+    EXPECT_NO_THROW(loader_.registerCreator(shared_ptr<NamedCreator>(
+        new NamedCreator(names))));
+    shared_ptr<NamedCheck> check(loadCheck("{\"name3\": 42}"));
+    EXPECT_EQ("name3", check->name_);
+    EXPECT_TRUE(check->data_->equals(*el("42")));
+}
+
+// Invalid format is rejected
+TEST_F(LoaderTest, InvalidFormatCheck) {
+    checkException("[]");
+    checkException("42");
+    checkException("\"hello\"");
+    checkException("null");
+}
+
+// Empty check is rejected
+TEST_F(LoaderTest, EmptyCheck) {
+    checkException("{}");
+}
+
+// The name isn't known
+TEST_F(LoaderTest, UnkownName) {
+    checkException("{\"unknown\": null}");
+}
+
+// Exception from the creator is propagated
+TEST_F(LoaderTest, CheckPropagate) {
+    loader_.registerCreator(shared_ptr<ThrowCreator>(new ThrowCreator()));
+    EXPECT_THROW(loader_.loadCheck(el("{\"throw\": null}")), TestCreatorError);
+}
+
+// The abbreviated form is not yet implemented
+// (we need the operators to be implemented)
+TEST_F(LoaderTest, AndAbbrev) {
+    addNamed("name1");
+    addNamed("name2");
+    EXPECT_THROW(loader_.loadCheck(el("{\"name1\": 1, \"name2\": 2}")),
+                 LoaderError);
+}
+
+TEST_F(LoaderTest, OrAbbrev) {
+    addNamed("name1");
+    EXPECT_THROW(loader_.loadCheck(el("{\"name1\": [1, 2]}")),
+                 LoaderError);
+}
+
+// But this is not abbreviated form, this should be passed directly to the
+// creator
+TEST_F(LoaderTest, ListCheck) {
+    addNamed("name1", false);
+    shared_ptr<NamedCheck> check(loadCheck("{\"name1\": [1, 2]}"));
+    EXPECT_EQ("name1", check->name_);
+    EXPECT_TRUE(check->data_->equals(*el("[1, 2]")));
+}
 
 }