Commit 5d5173ef authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner
Browse files

Merge branch 'work/abbreviated'

parents 7cc074aa 55689c55
......@@ -24,6 +24,10 @@
namespace isc {
namespace acl {
class AnyOfSpec;
class AllOfSpec;
template<typename Mode, typename Context> class LogicOperator;
/**
* \brief Exception for bad ACL specifications.
*
......@@ -367,18 +371,45 @@ private:
}
if (creatorIt->second->allowListAbbreviation() &&
checkDesc->second->getType() == data::Element::list) {
isc_throw_1(LoaderError,
"Not implemented (OR-abbreviated form)",
checkDesc->second);
// Or-abbreviated form - create an OR and put everything
// inside.
const std::vector<data::ConstElementPtr>&
params(checkDesc->second->listValue());
boost::shared_ptr<LogicOperator<AnyOfSpec, Context> >
oper(new LogicOperator<AnyOfSpec, Context>);
for (std::vector<data::ConstElementPtr>::const_iterator
i(params.begin());
i != params.end(); ++i) {
oper->addSubexpression(
creatorIt->second->create(name, *i, *this));
}
return (oper);
}
// Create the check and return it
return (creatorIt->second->create(name, checkDesc->second,
*this));
}
default:
isc_throw_1(LoaderError,
"Not implemented (AND-abbreviated form)",
description);
default: {
// This is the AND-abbreviated form. We need to create an
// AND (or "ALL") operator, loop trough the whole map and
// fill it in. We do a small trick - we create bunch of
// single-item maps, call this loader recursively (therefore
// it will get into the "case 1" branch, where there is
// the actual loading) and use the results to fill the map.
//
// We keep the description the same, there's nothing we could
// take out (we could create a new one, but that would be
// confusing, as it is used for error messages only).
boost::shared_ptr<LogicOperator<AllOfSpec, Context> >
oper(new LogicOperator<AllOfSpec, Context>);
for (Map::const_iterator i(map.begin()); i != map.end(); ++i) {
Map singleSubexpr;
singleSubexpr.insert(*i);
oper->addSubexpression(loadCheck(description,
singleSubexpr));
}
return (oper);
}
}
}
/**
......@@ -401,4 +432,17 @@ private:
}
}
/*
* This include at the end of the file is unusual. But we need to include it,
* we use template classes from there. However, they need to be present only
* at instantiation of our class, which will happen below this header.
*
* The problem is, the header uses us as well, therefore there's a circular
* dependency. If we loaded it at the beginning and someone loaded us first,
* the logic_check header wouldn't have our definitions. This way, no matter
* in which order they are loaded, the definitions from this header will be
* above the ones from logic_check.
*/
#include "logic_check.h"
#endif
......@@ -76,16 +76,21 @@ public:
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) {
template<class Result> shared_ptr<Result> loadCheckAny(const string&
definition)
{
SCOPED_TRACE("Loading check " + definition);
shared_ptr<Check<Log> > loaded;
EXPECT_NO_THROW(loaded = loader_.loadCheck(el(definition)));
shared_ptr<NamedCheck> result(dynamic_pointer_cast<NamedCheck>(
shared_ptr<Result> result(dynamic_pointer_cast<Result>(
loaded));
EXPECT_TRUE(result);
return (result);
}
// Load a check and convert it to named check to examine it
shared_ptr<NamedCheck> loadCheck(const string& definition) {
return (loadCheckAny<NamedCheck>(definition));
}
// The loadCheck throws an exception
void checkException(const string& JSON) {
SCOPED_TRACE("Loading check exception: " + JSON);
......@@ -133,6 +138,20 @@ public:
aclSetup();
EXPECT_THROW(loader_.load(el(JSON)), LoaderError);
}
// Check that the subexpression is NamedCheck with correct data
void isSubexprNamed(const CompoundCheck<Log>* compound, size_t index,
const string& name, ConstElementPtr data)
{
if (index < compound->getSubexpressions().size()) {
const NamedCheck*
check(dynamic_cast<const NamedCheck*>(compound->
getSubexpressions()
[index]));
ASSERT_TRUE(check) << "The subexpression is of different type";
EXPECT_EQ(name, check->name_);
EXPECT_TRUE(data->equals(*check->data_));
}
}
};
// Test that it does not accept duplicate creator
......@@ -209,19 +228,67 @@ TEST_F(LoaderTest, CheckPropagate) {
EXPECT_THROW(loader_.loadCheck(el("{\"throw\": null}")), TestCreatorError);
}
// The abbreviated form is not yet implemented
// (we need the operators to be implemented)
// The abbreviated form of check
TEST_F(LoaderTest, AndAbbrev) {
addNamed("name1");
addNamed("name2");
EXPECT_THROW(loader_.loadCheck(el("{\"name1\": 1, \"name2\": 2}")),
LoaderError);
shared_ptr<LogicOperator<AllOfSpec, Log> > oper(
loadCheckAny<LogicOperator<AllOfSpec, Log> >("{\"name1\": 1, \"name2\": 2}"));
// If we don't have anything loaded, the rest would crash. It is already
// reported from within loadCheckAny if it isn't loaded.
if (oper) {
// The subexpressions are correct
EXPECT_EQ(2, oper->getSubexpressions().size());
// Note: this test relies on the ordering in which map returns it's
// elements, which is in the lexicographical order of the strings.
// This is not required from our interface, but is easier to write
// the test.
isSubexprNamed(&*oper, 0, "name1", el("1"));
isSubexprNamed(&*oper, 1, "name2", el("2"));
}
}
// The abbreviated form of parameters
TEST_F(LoaderTest, OrAbbrev) {
addNamed("name1");
EXPECT_THROW(loader_.loadCheck(el("{\"name1\": [1, 2]}")),
LoaderError);
shared_ptr<LogicOperator<AnyOfSpec, Log> > oper(
loadCheckAny<LogicOperator<AnyOfSpec, Log> >("{\"name1\": [1, 2]}"));
// If we don't have anything loaded, the rest would crash. It is already
// reported from within loadCheckAny if it isn't loaded.
if (oper) {
// The subexpressions are correct
EXPECT_EQ(2, oper->getSubexpressions().size());
isSubexprNamed(&*oper, 0, "name1", el("1"));
isSubexprNamed(&*oper, 1, "name1", el("2"));
}
}
// Combined abbreviated form, both at once
// The abbreviated form of check
TEST_F(LoaderTest, BothAbbrev) {
addNamed("name1");
addNamed("name2");
shared_ptr<LogicOperator<AllOfSpec, Log> > oper(
loadCheckAny<LogicOperator<AllOfSpec, Log> >("{\"name1\": 1, \"name2\": [3, 4]}"));
// If we don't have anything loaded, the rest would crash. It is already
// reported from within loadCheckAny if it isn't loaded.
if (oper) {
// The subexpressions are correct
ASSERT_EQ(2, oper->getSubexpressions().size());
// Note: this test relies on the ordering in which map returns it's
// elements, which is in the lexicographical order of the strings.
// This is not required from our interface, but is easier to write
// the test.
isSubexprNamed(&*oper, 0, "name1", el("1"));
const LogicOperator<AnyOfSpec, Log>*
orOper(dynamic_cast<const LogicOperator<AnyOfSpec, Log>*>(
oper->getSubexpressions()[1]));
ASSERT_TRUE(orOper) << "Different type than AnyOf operator";
EXPECT_EQ(2, orOper->getSubexpressions().size());
isSubexprNamed(orOper, 0, "name2", el("3"));
isSubexprNamed(orOper, 1, "name2", el("4"));
}
}
// But this is not abbreviated form, this should be passed directly to the
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment