|
@@ -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]")));
|
|
|
+}
|
|
|
|
|
|
}
|