Browse Source

[3793] {create,parse}{Command,Answer} methods updated to new format

 createCommand, parseCommand, createAnswer, parseAnswer updated
 to an new format described here: http://kea.isc.org/wiki/StatsDesign
Tomek Mrugalski 10 years ago
parent
commit
ca03350e6f

+ 1 - 7
src/lib/cc/Makefile.am

@@ -17,7 +17,6 @@ lib_LTLIBRARIES = libkea-cc.la
 libkea_cc_la_SOURCES = data.cc data.h
 libkea_cc_la_SOURCES += logger.cc logger.h
 nodist_libkea_cc_la_SOURCES = cc_messages.cc cc_messages.h
-libkea_cc_la_SOURCES += proto_defs.cc proto_defs.h
 libkea_cc_la_LIBADD = $(top_builddir)/src/lib/log/libkea-log.la
 
 CLEANFILES = *.gcno *.gcda session_config.h cc_messages.cc cc_messages.h \
@@ -32,11 +31,6 @@ s-messages: cc_messages.mes
 	$(top_builddir)/src/lib/log/compiler/message $(top_srcdir)/src/lib/cc/cc_messages.mes
 	touch $@
 
-BUILT_SOURCES = session_config.h cc_messages.cc cc_messages.h proto_defs.h
-
-# This rule is here, but we added proto_defs.h to the git repo,
-# so the script is no longer needed.
-#proto_defs.h: $(top_srcdir)/src/lib/util/python/const2hdr.py proto_defs.cc
-#	$(PYTHON) $(top_srcdir)/src/lib/util/python/const2hdr.py $(srcdir)/proto_defs.cc $@
+BUILT_SOURCES = session_config.h cc_messages.cc cc_messages.h
 
 EXTRA_DIST = cc_messages.mes

+ 0 - 58
src/lib/cc/proto_defs.cc

@@ -1,58 +0,0 @@
-// Copyright (C) 2013  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 <cc/proto_defs.h>
-
-namespace isc {
-namespace cc {
-
-// Aside from defining the values for the C++ library, this file is also
-// used as direct input of the generator of the python counterpart. Please,
-// keep the syntax here simple and check the generated file
-// (lib/python/isc/cc/proto_defs.py) is correct and sane.
-
-// The constants used in the CC protocol
-// First the header names
-const char* const CC_HEADER_TYPE = "type";
-const char* const CC_HEADER_FROM = "from";
-const char* const CC_HEADER_TO = "to";
-const char* const CC_HEADER_GROUP = "group";
-const char* const CC_HEADER_INSTANCE = "instance";
-const char* const CC_HEADER_SEQ = "seq";
-const char* const CC_HEADER_WANT_ANSWER = "want_answer";
-const char* const CC_HEADER_REPLY = "reply";
-// The commands in the "type" header
-const char* const CC_COMMAND_SEND = "send";
-const char* const CC_COMMAND_SUBSCRIBE = "subscribe";
-const char* const CC_COMMAND_UNSUBSCRIBE = "unsubscribe";
-const char* const CC_COMMAND_GET_LNAME = "getlname";
-const char* const CC_COMMAND_PING = "ping";
-const char* const CC_COMMAND_PONG = "pong";
-const char* const CC_COMMAND_STOP = "stop";
-// The wildcards of some headers
-const char* const CC_TO_WILDCARD = "*";
-const char* const CC_INSTANCE_WILDCARD = "*";
-// Prefixes for groups
-const char* const CC_GROUP_NOTIFICATION_PREFIX = "notifications/";
-// Reply codes
-const int CC_REPLY_NO_RECPT = -1;
-const int CC_REPLY_SUCCESS = 0;
-// Payload in the message
-const char *const CC_PAYLOAD_LNAME = "lname";
-const char *const CC_PAYLOAD_RESULT = "result";
-const char *const CC_PAYLOAD_COMMAND = "command";
-const char *const CC_PAYLOAD_NOTIFICATION = "notification";
-
-}
-}

+ 0 - 73
src/lib/cc/proto_defs.h

@@ -1,73 +0,0 @@
-// This file is generated from ./proto_defs.cc
-// by the const2hdr.py script.
-// Do not edit, all changes will be lost.
-
-// Copyright (C) 2013  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.
-
-#ifndef KEA_COMMON_DEFS_H
-#define KEA_COMMON_DEFS_H
-
-// \file proto_defs.h
-// \brief Common shared constants
-
-// This file contains common definitions of constasts used across the sources.
-// It includes, but is not limited to the definitions of messages sent from
-// one process to another. Since the names should be self-explanatory and
-// the variables here are used mostly to synchronize the same values across
-// multiple programs, separate documentation for each variable is not provided.
-
-namespace isc {
-namespace cc {
-
-// Aside from defining the values for the C++ library, this file is also
-// used as direct input of the generator of the python counterpart. Please,
-// keep the syntax here simple and check the generated file
-// (lib/python/isc/cc/proto_defs.py) is correct and sane.
-
-// The constants used in the CC protocol
-// First the header names
-extern const char* const CC_HEADER_TYPE;
-extern const char* const CC_HEADER_FROM;
-extern const char* const CC_HEADER_TO;
-extern const char* const CC_HEADER_GROUP;
-extern const char* const CC_HEADER_INSTANCE;
-extern const char* const CC_HEADER_SEQ;
-extern const char* const CC_HEADER_WANT_ANSWER;
-extern const char* const CC_HEADER_REPLY;
-// The commands in the "type" header
-extern const char* const CC_COMMAND_SEND;
-extern const char* const CC_COMMAND_SUBSCRIBE;
-extern const char* const CC_COMMAND_UNSUBSCRIBE;
-extern const char* const CC_COMMAND_GET_LNAME;
-extern const char* const CC_COMMAND_PING;
-extern const char* const CC_COMMAND_PONG;
-extern const char* const CC_COMMAND_STOP;
-// The wildcards of some headers
-extern const char* const CC_TO_WILDCARD;
-extern const char* const CC_INSTANCE_WILDCARD;
-// Prefixes for groups
-extern const char* const CC_GROUP_NOTIFICATION_PREFIX;
-// Reply codes
-extern const int CC_REPLY_NO_RECPT;
-extern const int CC_REPLY_SUCCESS;
-// Payload in the message
-extern const char *const CC_PAYLOAD_LNAME;
-extern const char *const CC_PAYLOAD_RESULT;
-extern const char *const CC_PAYLOAD_COMMAND;
-extern const char *const CC_PAYLOAD_NOTIFICATION;
-
-}
-}
-#endif

+ 81 - 73
src/lib/config/ccsession.cc

@@ -53,70 +53,78 @@ using isc::data::JSONError;
 namespace isc {
 namespace config {
 
-/// Creates a standard config/command protocol answer message
-ConstElementPtr
-createAnswer() {
-    ElementPtr answer = Element::createMap();
-    ElementPtr answer_content = Element::createList();
-    answer_content->add(Element::create(isc::cc::CC_REPLY_SUCCESS));
-    answer->set(isc::cc::CC_PAYLOAD_RESULT, answer_content);
+const char *CONTROL_COMMAND="command";
 
-    return (answer);
-}
+const char *CONTROL_RESULT="result";
+const char *CONTROL_TEXT="text";
+const char *CONTROL_ARGUMENTS="arguments";
 
+// Full version, with status, text and arguments
 ConstElementPtr
-createAnswer(const int rcode, ConstElementPtr arg) {
-    if (rcode != 0 && (!arg || arg->getType() != Element::string)) {
-        isc_throw(CCSessionError, "Bad or no argument for rcode != 0");
+createAnswer(const int status_code, const std::string& text,
+             const ConstElementPtr& arg) {
+    if (status_code != 0 && text.empty()) {
+        isc_throw(CtrlChannelError, "Text has to be provided for status_code != 0");
     }
+
     ElementPtr answer = Element::createMap();
-    ElementPtr answer_content = Element::createList();
-    answer_content->add(Element::create(rcode));
-    answer_content->add(arg);
-    answer->set(isc::cc::CC_PAYLOAD_RESULT, answer_content);
+    ElementPtr result = Element::create(status_code);
+    answer->set(CONTROL_RESULT, result);
 
+    if (!text.empty()) {
+        answer->set(CONTROL_TEXT, Element::create(text));
+    }
+    if (arg) {
+        answer->set(CONTROL_ARGUMENTS, arg);
+    }
     return (answer);
 }
 
 ConstElementPtr
-createAnswer(const int rcode, const std::string& arg) {
-    ElementPtr answer = Element::createMap();
-    ElementPtr answer_content = Element::createList();
-    answer_content->add(Element::create(rcode));
-    answer_content->add(Element::create(arg));
-    answer->set(isc::cc::CC_PAYLOAD_RESULT, answer_content);
+createAnswer() {
+    return (createAnswer(0, string(""), ConstElementPtr()));
+}
 
-    return (answer);
+ConstElementPtr
+createAnswer(const int status_code, const std::string& text) {
+    return (createAnswer(status_code, text, ElementPtr()));
 }
 
 ConstElementPtr
-parseAnswer(int &rcode, ConstElementPtr msg) {
-    if (msg &&
-        msg->getType() == Element::map &&
-        msg->contains(isc::cc::CC_PAYLOAD_RESULT)) {
-        ConstElementPtr result = msg->get(isc::cc::CC_PAYLOAD_RESULT);
-        if (result->getType() != Element::list) {
-            isc_throw(CCSessionError, "Result element in answer message is not a list");
-        } else if (result->get(0)->getType() != Element::integer) {
-            isc_throw(CCSessionError, "First element of result is not an rcode in answer message");
-        }
-        rcode = result->get(0)->intValue();
-        if (result->size() > 1) {
-            if (rcode == 0 || result->get(1)->getType() == Element::string) {
-                return (result->get(1));
-            } else {
-                isc_throw(CCSessionError, "Error description in result with rcode != 0 is not a string");
-            }
-        } else {
-            if (rcode == 0) {
-                return (ElementPtr());
-            } else {
-                isc_throw(CCSessionError, "Result with rcode != 0 does not have an error description");
-            }
-        }
-    } else {
-        isc_throw(CCSessionError, "No result part in answer message");
+createAnswer(const int status_code, const ConstElementPtr& arg) {
+    return (createAnswer(status_code, "", arg));
+}
+
+ConstElementPtr
+parseAnswer(int &rcode, const ConstElementPtr& msg) {
+    if (!msg) {
+        isc_throw(CtrlChannelError, "No answer specified");
+    }
+    if (msg->getType() != Element::map) {
+        isc_throw(CtrlChannelError,
+                  "Invalid answer Element specified, expected map");
+    }
+    if (!msg->contains(CONTROL_RESULT)) {
+        isc_throw(CtrlChannelError,
+                  "Invalid answer specified, does not contain mandatory 'result'");
+    }
+
+    ConstElementPtr result = msg->get(CONTROL_RESULT);
+    if (result->getType() != Element::integer) {
+            isc_throw(CtrlChannelError,
+                      "Result element in answer message is not a string");
     }
+
+    rcode = result->intValue();
+
+    // If there are arguments, return them.
+    ConstElementPtr args = msg->get(CONTROL_ARGUMENTS);
+    if (args) {
+        return (args);
+    }
+
+    // There are no arguments, let's try to return just the text status
+    return (msg->get(CONTROL_TEXT));
 }
 
 ConstElementPtr
@@ -126,37 +134,37 @@ createCommand(const std::string& command) {
 
 ConstElementPtr
 createCommand(const std::string& command, ConstElementPtr arg) {
-    ElementPtr cmd = Element::createMap();
-    ElementPtr cmd_parts = Element::createList();
-    cmd_parts->add(Element::create(command));
+    ElementPtr query = Element::createMap();
+    ElementPtr cmd = Element::create(command);
+    query->set(CONTROL_COMMAND, cmd);
     if (arg) {
-        cmd_parts->add(arg);
+        query->set(CONTROL_ARGUMENTS, arg);
     }
-    cmd->set(isc::cc::CC_PAYLOAD_COMMAND, cmd_parts);
-    return (cmd);
+    return (query);
 }
 
 std::string
 parseCommand(ConstElementPtr& arg, ConstElementPtr command) {
-    if (command &&
-        command->getType() == Element::map &&
-        command->contains(isc::cc::CC_PAYLOAD_COMMAND)) {
-        ConstElementPtr cmd = command->get(isc::cc::CC_PAYLOAD_COMMAND);
-        if (cmd->getType() == Element::list &&
-            !cmd->empty() &&
-            cmd->get(0)->getType() == Element::string) {
-            if (cmd->size() > 1) {
-                arg = cmd->get(1);
-            } else {
-                arg = Element::createMap();
-            }
-            return (cmd->get(0)->stringValue());
-        } else {
-            isc_throw(CCSessionError, "Command part in command message missing, empty, or not a list");
-        }
-    } else {
-        isc_throw(CCSessionError, "Command Element empty or not a map with \"command\"");
+    if (!command) {
+        isc_throw(CtrlChannelError, "No command specified");
+    }
+    if (command->getType() != Element::map) {
+        isc_throw(CtrlChannelError, "Invalid command Element specified, expected map");
+    }
+    if (!command->contains(CONTROL_COMMAND)) {
+        isc_throw(CtrlChannelError,
+                  "Invalid answer specified, does not contain mandatory 'command'");
     }
+
+    ConstElementPtr cmd = command->get(CONTROL_COMMAND);
+    if (cmd->getType() != Element::string) {
+        isc_throw(CtrlChannelError,
+                  "'command' element in command message is not a string");
+    }
+
+    arg = command->get(CONTROL_ARGUMENTS);
+
+    return (cmd->stringValue());
 }
 
 namespace {

+ 62 - 78
src/lib/config/ccsession.h

@@ -19,7 +19,6 @@
 #include <config/module_spec.h>
 
 #include <cc/data.h>
-#include <cc/proto_defs.h>
 
 #include <string>
 #include <list>
@@ -28,112 +27,97 @@
 namespace isc {
 namespace config {
 
-///
-/// \brief Creates a standard config/command level success answer message
-///        (i.e. of the form { "result": [ 0 ] }
-/// \return Standard command/config success answer message
+extern const char *CONTROL_COMMAND;
+
+extern const char *CONTROL_RESULT;
+extern const char *CONTROL_TEXT;
+extern const char *CONTROL_ARGUMENTS;
+
+const int CONTROL_RESULT_SUCCESS = 0;
+const int CONTROL_RESULT_ERROR = 1;
+
+/// @brief Creates a standard config/command level success answer message
+///        (i.e. of the form { "result": 0 }
+/// @return Standard command/config success answer message
 isc::data::ConstElementPtr createAnswer();
 
+/// @brief Creates a standard config/command level answer message
+/// (i.e. of the form { "result": 1, "text": "Invalid command received" }
 ///
-/// \brief Creates a standard config/command level answer message
-///        (i.e. of the form { "result": [ rcode, arg ] }
-/// If rcode != 0, arg must be a StringElement
-///
-/// \param rcode The return code (0 for success)
-/// \param arg For rcode == 0, this is an optional argument of any
-///            Element type. For rcode == 1, this argument is mandatory,
-///            and must be a StringElement containing an error description
-/// \return Standard command/config answer message
-isc::data::ConstElementPtr createAnswer(const int rcode,
-                                        isc::data::ConstElementPtr arg);
-
+/// @param status_code The return code (0 for success)
+/// @param status_text A string to put into the "text" argument
+/// @return Standard command/config answer message
+isc::data::ConstElementPtr createAnswer(const int status_code,
+                                        const std::string& status_text);
+
+/// @brief Creates a standard config/command level answer message
+/// (i.e. of the form { "result": status_code, "arguments": arg }
 ///
-/// \brief Creates a standard config/command level answer message
-/// (i.e. of the form { "result": [ rcode, arg ] }
+/// @param status_code The return code (0 for success)
+/// @param status_text A string to put into the "text" argument
+/// @return Standard command/config answer message
+isc::data::ConstElementPtr createAnswer(const int status_code,
+                                        const isc::data::ConstElementPtr& arg);
+
+/// @brief Creates a standard config/command level answer message
+///        (i.e. of the form { "result": X, "[ rcode, arg ] }
+/// If rcode != 0, arg must be a StringElement
 ///
-/// \param rcode The return code (0 for success)
-/// \param arg A string to put into the StringElement argument
-/// \return Standard command/config answer message
-isc::data::ConstElementPtr createAnswer(const int rcode,
-                                        const std::string& arg);
-
+/// @param status_code The return code (0 for success)
+/// @param arg For status_code == 0, this is an optional argument of any
+///            Element type. For status_code == 1, this argument is mandatory,
+///            and may be any type of ElementPtr.
+/// @return Standard command/config answer message
+isc::data::ConstElementPtr createAnswer(const int status_code,
+                                        const std::string& status,
+                                        const isc::data::ConstElementPtr& arg);
+
+/// @brief Parses a standard config/command level answer message.
 ///
-/// Parses a standard config/command level answer message
-/// 
-/// \param rcode This value will be set to the return code contained in
+/// @param status_code This value will be set to the return code contained in
 ///              the message
-/// \param msg The message to parse
-/// \return The optional argument in the message, or an empty ElementPtr
+/// @param msg The message to parse
+/// @return The optional argument in the message, or an empty ElementPtr
 ///         if there was no argument. If rcode != 0, this contains a
 ///         StringElement with the error description.
-isc::data::ConstElementPtr parseAnswer(int &rcode,
-                                       isc::data::ConstElementPtr msg);
+isc::data::ConstElementPtr parseAnswer(int &status_code,
+                                       const isc::data::ConstElementPtr& msg);
 
+/// @brief Creates a standard config/command command message with no
+/// argument (of the form { "command": "my_command" }
 ///
-/// \brief Creates a standard config/command command message with no
-/// argument (of the form { "command": [ "my_command" ] }
-/// 
-/// \param command The command string
-/// \return The created message
+/// @param command The command string
+/// @return The created message
 isc::data::ConstElementPtr createCommand(const std::string& command);
 
+/// @brief Creates a standard config/command command message with the
+/// given argument (of the form { "command": "my_command", "arguments": arg }
 ///
-/// \brief Creates a standard config/command command message with the
-/// given argument (of the form { "command": [ "my_command", arg ] }
-/// 
-/// \param command The command string
-/// \param arg The optional argument for the command. This can be of 
+/// @param command The command string
+/// @param arg The optional argument for the command. This can be of
 ///        any Element type, but it should conform to the .spec file.
-/// \return The created message
+/// @return The created message
 isc::data::ConstElementPtr createCommand(const std::string& command,
                                          isc::data::ConstElementPtr arg);
 
-///
-/// \brief Parses the given command into a string containing the actual
+/// @brief Parses the given command into a string containing the actual
 ///        command and an ElementPtr containing the optional argument.
 ///
-/// Raises a CCSessionError if this is not a well-formed command
+/// @throw Raises a CtrlChannelError if this is not a well-formed command
 ///
-/// Example code: (command_message is a ConstElementPtr that is
-/// passed here)
-/// \code
-/// ElementPtr command_message = Element::fromJSON("{ \"command\": [\"foo\", { \"bar\": 123 } ] }");
-/// try {
-///     ConstElementPtr args;
-///     std::string command_str = parseCommand(args, command_message);
-///     if (command_str == "foo") {
-///         std::cout << "The command 'foo' was given" << std::endl;
-///         if (args->contains("bar")) {
-///             std::cout << "It had argument name 'bar' set, which has"
-///                       << "value " 
-///                       << args->get("bar")->intValue();
-///         }
-///     } else {
-///         std::cout << "Unknown command '" << command_str << std::endl;
-///     }
-/// } catch (CCSessionError cse) {
-///     std::cerr << "Bad command in CC Session: "
-///     << cse.what() << std::endl;
-/// }
-/// \endcode
-/// 
-/// \param arg This value will be set to the ElementPtr pointing to
+/// @param arg This value will be set to the ElementPtr pointing to
 ///        the argument, or to an empty Map (ElementPtr) if there was none.
-/// \param command The command message containing the command (as made
+/// @param command The command message containing the command (as made
 ///        by createCommand()
 /// \return The command name
 std::string parseCommand(isc::data::ConstElementPtr& arg,
                          isc::data::ConstElementPtr command);
 
-
-///
-/// \brief A standard cc session exception that is thrown if a function
+/// @brief A standard control channel exception that is thrown if a function
 /// is there is a problem with one of the messages
-///
-// todo: include types and called function in the exception
-class CCSessionError : public isc::Exception {
+class CtrlChannelError : public isc::Exception {
 public:
-    CCSessionError(const char* file, size_t line, const char* what) :
+    CtrlChannelError(const char* file, size_t line, const char* what) :
         isc::Exception(file, line, what) {}
 };
 

+ 38 - 34
src/lib/config/tests/ccsession_unittests.cc

@@ -24,7 +24,6 @@
 
 using namespace isc::data;
 using namespace isc::config;
-using namespace isc::cc;
 using namespace std;
 
 namespace {
@@ -50,16 +49,17 @@ protected:
 TEST_F(CCSessionTest, createAnswer) {
     ConstElementPtr answer;
     answer = createAnswer();
-    EXPECT_EQ("{ \"result\": [ 0 ] }", answer->str());
+    EXPECT_EQ("{ \"result\": 0 }", answer->str());
     answer = createAnswer(1, "error");
-    EXPECT_EQ("{ \"result\": [ 1, \"error\" ] }", answer->str());
+    EXPECT_EQ("{ \"result\": 1, \"text\": \"error\" }", answer->str());
 
-    EXPECT_THROW(createAnswer(1, ElementPtr()), CCSessionError);
-    EXPECT_THROW(createAnswer(1, Element::create(1)), CCSessionError);
+    EXPECT_THROW(createAnswer(1, ElementPtr()), CtrlChannelError);
+    EXPECT_THROW(createAnswer(1, Element::create(1)), CtrlChannelError);
 
     ConstElementPtr arg = el("[ \"just\", \"some\", \"data\" ]");
     answer = createAnswer(0, arg);
-    EXPECT_EQ("{ \"result\": [ 0, [ \"just\", \"some\", \"data\" ] ] }", answer->str());
+    EXPECT_EQ("{ \"arguments\": [ \"just\", \"some\", \"data\" ], \"result\": 0 }",
+              answer->str());
 }
 
 TEST_F(CCSessionTest, parseAnswer) {
@@ -67,27 +67,26 @@ TEST_F(CCSessionTest, parseAnswer) {
     ConstElementPtr arg;
     int rcode;
 
-    EXPECT_THROW(parseAnswer(rcode, ElementPtr()), CCSessionError);
-    EXPECT_THROW(parseAnswer(rcode, el("1")), CCSessionError);
-    EXPECT_THROW(parseAnswer(rcode, el("[]")), CCSessionError);
-    EXPECT_THROW(parseAnswer(rcode, el("{  }")), CCSessionError);
-    EXPECT_THROW(parseAnswer(rcode, el("{ \"something\": 1 }")), CCSessionError);
-    EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": 0 }")), CCSessionError);
-    EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": 1 }")), CCSessionError);
-    EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1 ] }")), CCSessionError);
-    EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1, 1 ] }")), CCSessionError);
+    EXPECT_THROW(parseAnswer(rcode, ElementPtr()), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("1")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("[]")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("{  }")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("{ \"something\": 1 }")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 0 ] }")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1 ] }")), CtrlChannelError);
+    EXPECT_THROW(parseAnswer(rcode, el("{ \"result\": [ 1, 1 ] }")), CtrlChannelError);
     
-    answer = el("{ \"result\": [ 0 ] }");
+    answer = el("{ \"result\": 0 }");
     arg = parseAnswer(rcode, answer);
     EXPECT_EQ(0, rcode);
     EXPECT_TRUE(isNull(arg));
 
-    answer = el("{ \"result\": [ 1, \"error\"] }");
+    answer = el("{ \"result\": 1, \"text\": \"error\" }");
     arg = parseAnswer(rcode, answer);
     EXPECT_EQ(1, rcode);
     EXPECT_EQ("error", arg->stringValue());
 
-    answer = el("{ \"result\": [ 0, [ \"just\", \"some\", \"data\" ] ] }");
+    answer = el("{ \"result\": 0, \"arguments\": [ \"just\", \"some\", \"data\" ] }");
     arg = parseAnswer(rcode, answer);
     EXPECT_EQ(0, rcode);
     EXPECT_EQ("[ \"just\", \"some\", \"data\" ]", arg->str());
@@ -98,19 +97,22 @@ TEST_F(CCSessionTest, createCommand) {
     ConstElementPtr arg;
 
     command = createCommand("my_command");
-    ASSERT_EQ("{ \"command\": [ \"my_command\" ] }", command->str());
+    ASSERT_EQ("{ \"command\": \"my_command\" }", command->str());
 
     arg = el("1");
     command = createCommand("my_command", arg);
-    ASSERT_EQ("{ \"command\": [ \"my_command\", 1 ] }", command->str());
+    ASSERT_EQ("{ \"arguments\": 1, \"command\": \"my_command\" }",
+              command->str());
 
     arg = el("[ \"a\", \"b\" ]");
     command = createCommand("my_cmd", arg);
-    ASSERT_EQ("{ \"command\": [ \"my_cmd\", [ \"a\", \"b\" ] ] }", command->str());
+    ASSERT_EQ("{ \"arguments\": [ \"a\", \"b\" ], \"command\": \"my_cmd\" }",
+              command->str());
 
     arg = el("{ \"a\": \"map\" }");
     command = createCommand("foo", arg);
-    ASSERT_EQ("{ \"command\": [ \"foo\", { \"a\": \"map\" } ] }", command->str());
+    ASSERT_EQ("{ \"arguments\": { \"a\": \"map\" }, \"command\": \"foo\" }",
+              command->str());
 }
 
 TEST_F(CCSessionTest, parseCommand) {
@@ -118,24 +120,26 @@ TEST_F(CCSessionTest, parseCommand) {
     std::string cmd;
 
     // should throw
-    EXPECT_THROW(parseCommand(arg, ElementPtr()), CCSessionError);
-    EXPECT_THROW(parseCommand(arg, el("1")), CCSessionError);
-    EXPECT_THROW(parseCommand(arg, el("{  }")), CCSessionError);
-    EXPECT_THROW(parseCommand(arg, el("{ \"not a command\": 1 }")), CCSessionError);
-    EXPECT_THROW(parseCommand(arg, el("{ \"command\": 1 }")), CCSessionError);
-    EXPECT_THROW(parseCommand(arg, el("{ \"command\": [] }")), CCSessionError);
-    EXPECT_THROW(parseCommand(arg, el("{ \"command\": [ 1 ] }")), CCSessionError);
-
-    cmd = parseCommand(arg, el("{ \"command\": [ \"my_command\" ] }"));
+    EXPECT_THROW(parseCommand(arg, ElementPtr()), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("1")), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("{  }")), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("{ \"not a command\": 1 }")), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("{ \"command\": 1 }")), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("{ \"command\": [] }")), CtrlChannelError);
+    EXPECT_THROW(parseCommand(arg, el("{ \"command\": [ 1 ] }")), CtrlChannelError);
+
+    cmd = parseCommand(arg, el("{ \"command\": \"my_command\" }"));
     EXPECT_EQ("my_command", cmd);
-    EXPECT_EQ(*arg, *Element::createMap());
+    EXPECT_FALSE(arg);
 
-    cmd = parseCommand(arg, el("{ \"command\": [ \"my_command\", 1 ] }"));
+    cmd = parseCommand(arg, el("{ \"command\": \"my_command\", \"arguments\": 1 }"));
+    ASSERT_TRUE(arg);
     EXPECT_EQ("my_command", cmd);
     EXPECT_EQ("1", arg->str());
 
-    parseCommand(arg, el("{ \"command\": [ \"my_command\", [ \"some\", \"argument\", \"list\" ] ] }"));
+    parseCommand(arg, el("{ \"command\": \"my_command\", \"arguments\": [ \"some\", \"argument\", \"list\" ] }"));
     EXPECT_EQ("my_command", cmd);
+    ASSERT_TRUE(arg);
     EXPECT_EQ("[ \"some\", \"argument\", \"list\" ]", arg->str());
 
 }

+ 7 - 6
src/lib/dhcpsrv/testutils/config_result_check.cc

@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <cc/proto_defs.h>
+#include <config/ccsession.h>
 #include <dhcpsrv/testutils/config_result_check.h>
 #include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/constants.hpp>
@@ -28,15 +28,16 @@ using namespace isc::data;
 
 bool errorContainsPosition(ConstElementPtr error_element,
                            const std::string& file_name) {
-    if (error_element->contains(isc::cc::CC_PAYLOAD_RESULT)) {
-        ConstElementPtr result = error_element->get(isc::cc::CC_PAYLOAD_RESULT);
-        if ((result->getType() != Element::list) || (result->size() < 2) ||
-            (result->get(1)->getType() != Element::string)) {
+    if (error_element->contains(isc::config::CONTROL_RESULT)) {
+        ConstElementPtr result = error_element->get(isc::config::CONTROL_RESULT);
+        ConstElementPtr text = error_element->get(isc::config::CONTROL_TEXT);
+        if (!result || (result->getType() != Element::integer) || !text
+            || (text->getType() != Element::string)) {
             return (false);
         }
 
         // Get the error message in the textual format.
-        std::string error_string = result->get(1)->stringValue();
+        std::string error_string = text->stringValue();
 
         // The position of the data element causing an error has the following
         // format: <filename>:<linenum>:<pos>. The <filename> has been specified