loader_test.cc 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <acl/loader.h>
  15. #include <string>
  16. #include <gtest/gtest.h>
  17. using namespace isc::acl;
  18. using namespace std;
  19. using namespace boost;
  20. using isc::data::ConstElementPtr;
  21. namespace {
  22. // Just for convenience, create JSON objects from JSON string
  23. ConstElementPtr el(const string& JSON) {
  24. return (isc::data::Element::fromJSON(JSON));
  25. }
  26. // We don't use the EXPECT_THROW macro, as it doesn't allow us
  27. // to examine the exception. We want to check the element is stored
  28. // there as well.
  29. void testActionLoaderException(const string& JSON) {
  30. SCOPED_TRACE("Should throw with input: " + JSON);
  31. ConstElementPtr elem(el(JSON));
  32. try {
  33. defaultActionLoader(elem);
  34. FAIL() << "It did not throw";
  35. }
  36. catch (const LoaderError& error) {
  37. // Yes, comparing for pointer equality, that is enough, it
  38. // should return the exact instance of the JSON object
  39. EXPECT_EQ(elem, error.element());
  40. }
  41. }
  42. // Test the defaultActionLoader function
  43. TEST(LoaderHelpers, DefaultActionLoader) {
  44. // First the three valid inputs
  45. EXPECT_EQ(ACCEPT, defaultActionLoader(el("\"ACCEPT\"")));
  46. EXPECT_EQ(REJECT, defaultActionLoader(el("\"REJECT\"")));
  47. EXPECT_EQ(DROP, defaultActionLoader(el("\"DROP\"")));
  48. // Now few invalid ones
  49. // String, but unknown one
  50. testActionLoaderException("\"UNKNOWN\"");
  51. testActionLoaderException("42");
  52. testActionLoaderException("true");
  53. testActionLoaderException("null");
  54. testActionLoaderException("[]");
  55. testActionLoaderException("{}");
  56. }
  57. // We need to pass a context, but it doesn't matter here which one
  58. class NullContext {};
  59. // A check that doesn't check anything but remembers it's own name
  60. // and data
  61. class NamedCheck : public Check<NullContext> {
  62. public:
  63. NamedCheck(const string& name, ConstElementPtr data) :
  64. name_(name),
  65. data_(data)
  66. {}
  67. const string name_;
  68. const ConstElementPtr data_;
  69. };
  70. // The creator of NamedCheck
  71. class NamedCreator : public Loader<NullContext>::CheckCreator {
  72. public:
  73. NamedCreator(const string& name, bool abbreviatedList = true) :
  74. abbreviated_list_(abbreviatedList)
  75. {
  76. names_.push_back(name);
  77. }
  78. NamedCreator(const vector<string>& names) :
  79. names_(names),
  80. abbreviated_list_(true)
  81. {}
  82. vector<string> names() const {
  83. return (names_);
  84. }
  85. shared_ptr<Check<NullContext> > create(const string&, ConstElementPtr) {
  86. return (shared_ptr<Check<NullContext> >());
  87. }
  88. bool allowListAbbreviation() const {
  89. return (abbreviated_list_);
  90. }
  91. private:
  92. vector<string> names_;
  93. const bool abbreviated_list_;
  94. };
  95. // To be thrown in tests internally
  96. class TestCreatorError {};
  97. // This will throw every time it should create something
  98. class ThrowCreator : public Loader<NullContext>::CheckCreator {
  99. public:
  100. vector<string> names() const {
  101. vector<string> result;
  102. result.push_back("throw");
  103. return (result);
  104. }
  105. shared_ptr<Check<NullContext> > create(const string&, ConstElementPtr) {
  106. throw TestCreatorError();
  107. }
  108. };
  109. class LoaderTest : public ::testing::Test {
  110. public:
  111. Loader<NullContext> loader_;
  112. // Some convenience functions to set up
  113. // Create a NamedCreator, convert to shared pointer
  114. shared_ptr<NamedCreator> namedCreator(const string& name,
  115. bool abbreviatedList = true)
  116. {
  117. return (shared_ptr<NamedCreator>(new NamedCreator(name,
  118. abbreviatedList)));
  119. }
  120. // Create and add a NamedCreator
  121. void addNamed(const string& name, bool abbreviatedList = true) {
  122. EXPECT_NO_THROW(loader_.registerCreator(
  123. namedCreator(name, abbreviatedList)));
  124. }
  125. // Load a check and convert it to named check to examine it
  126. shared_ptr<NamedCheck> loadCheck(const string& definition) {
  127. SCOPED_TRACE("Loading check " + definition);
  128. shared_ptr<Check<NullContext> > loaded;
  129. EXPECT_NO_THROW(loaded = loader_.loadCheck(el(definition)));
  130. shared_ptr<NamedCheck> result(dynamic_pointer_cast<NamedCheck>(
  131. loaded));
  132. EXPECT_TRUE(result);
  133. return (result);
  134. }
  135. // The loadCheck throws an exception
  136. void checkException(const string& JSON) {
  137. SCOPED_TRACE("Loading check exception: " + JSON);
  138. ConstElementPtr input(el(JSON));
  139. // Not using EXPECT_THROW, we want to examine the exception
  140. try {
  141. loader_.loadCheck(input);
  142. FAIL() << "Should have thrown";
  143. }
  144. catch (const LoaderError& e) {
  145. // It should be identical copy, so checking pointers
  146. EXPECT_EQ(input, e.element());
  147. }
  148. }
  149. };
  150. // Test that it does not accept duplicate creator
  151. TEST_F(LoaderTest, CreatorDuplicity) {
  152. addNamed("name");
  153. EXPECT_THROW(loader_.registerCreator(namedCreator("name")), LoaderError);
  154. }
  155. // Test that we can register a creator and load a check with the name
  156. TEST_F(LoaderTest, SimpleCheckLoad) {
  157. addNamed("name");
  158. shared_ptr<NamedCheck> check(loadCheck("{\"name\": 42}"));
  159. EXPECT_EQ("name", check->name_);
  160. EXPECT_TRUE(check->data_->equals(*el("42")));
  161. }
  162. // As above, but there are multiple creators registered within the loader
  163. TEST_F(LoaderTest, MultiCreatorCheckLoad) {
  164. addNamed("name1");
  165. addNamed("name2");
  166. shared_ptr<NamedCheck> check(loadCheck("{\"name2\": 42}"));
  167. EXPECT_EQ("name2", check->name_);
  168. EXPECT_TRUE(check->data_->equals(*el("42")));
  169. }
  170. // Similar to above, but there's a creator with multiple names
  171. TEST_F(LoaderTest, MultiNameCheckLoad) {
  172. addNamed("name1");
  173. vector<string> names;
  174. names.push_back("name2");
  175. names.push_back("name3");
  176. EXPECT_NO_THROW(loader_.registerCreator(shared_ptr<NamedCreator>(
  177. new NamedCreator(names))));
  178. shared_ptr<NamedCheck> check(loadCheck("{\"name3\": 42}"));
  179. EXPECT_EQ("name3", check->name_);
  180. EXPECT_TRUE(check->data_->equals(*el("42")));
  181. }
  182. // Invalid format is rejected
  183. TEST_F(LoaderTest, InvalidFormatCheck) {
  184. checkException("[]");
  185. checkException("42");
  186. checkException("\"hello\"");
  187. checkException("null");
  188. }
  189. // Empty check is rejected
  190. TEST_F(LoaderTest, EmptyCheck) {
  191. checkException("{}");
  192. }
  193. // The name isn't known
  194. TEST_F(LoaderTest, UnkownName) {
  195. checkException("{\"unknown\": null}");
  196. }
  197. // Exception from the creator is propagated
  198. TEST_F(LoaderTest, CheckPropagate) {
  199. loader_.registerCreator(shared_ptr<ThrowCreator>(new ThrowCreator()));
  200. EXPECT_THROW(loader_.loadCheck(el("{\"throw\": null}")), TestCreatorError);
  201. }
  202. // The abbreviated form is not yet implemented
  203. // (we need the operators to be implemented)
  204. TEST_F(LoaderTest, AndAbbrev) {
  205. addNamed("name1");
  206. addNamed("name2");
  207. EXPECT_THROW(loader_.loadCheck(el("{\"name1\": 1, \"name2\": 2}")),
  208. LoaderError);
  209. }
  210. TEST_F(LoaderTest, OrAbbrev) {
  211. addNamed("name1");
  212. EXPECT_THROW(loader_.loadCheck(el("{\"name1\": [1, 2]}")),
  213. LoaderError);
  214. }
  215. // But this is not abbreviated form, this should be passed directly to the
  216. // creator
  217. TEST_F(LoaderTest, ListCheck) {
  218. addNamed("name1", false);
  219. shared_ptr<NamedCheck> check(loadCheck("{\"name1\": [1, 2]}"));
  220. EXPECT_EQ("name1", check->name_);
  221. EXPECT_TRUE(check->data_->equals(*el("[1, 2]")));
  222. }
  223. // Check the action key is ignored as it should be
  224. TEST_F(LoaderTest, CheckNoAction) {
  225. addNamed("name1");
  226. shared_ptr<NamedCheck> check(loadCheck("{\"name1\": 1, \"action\": 2}"));
  227. EXPECT_EQ("name1", check->name_);
  228. EXPECT_TRUE(check->data_->equals(*el("1")));
  229. }
  230. }