Your IP : 3.21.244.34
#include <TestSupport.h>
#include <ConfigKit/Store.h>
#include <boost/bind/bind.hpp>
#include <algorithm>
using namespace Passenger;
using namespace std;
namespace tut {
struct ConfigKit_StoreTest: public TestBase {
ConfigKit::Schema schema;
ConfigKit::Store *config;
Json::Value doc;
vector<ConfigKit::Error> errors;
ConfigKit_StoreTest() {
config = NULL;
}
~ConfigKit_StoreTest() {
delete config;
}
void init() {
schema.finalize();
config = new ConfigKit::Store(schema);
}
};
DEFINE_TEST_GROUP(ConfigKit_StoreTest);
/*********** Test validation ***********/
TEST_METHOD(1) {
set_test_name("Validating an empty schema against an empty update set succeeds");
init();
config->previewUpdate(doc, errors);
ensure(errors.empty());
}
TEST_METHOD(2) {
set_test_name("Validating an empty schema against a non-empty update set succeeds");
init();
doc["foo"] = "bar";
config->previewUpdate(doc, errors);
ensure(errors.empty());
}
TEST_METHOD(3) {
set_test_name("Validating a non-object update set");
init();
doc = Json::Value("hello");
config->previewUpdate(doc, errors);
ensure_equals(errors.size(), 1u);
ensure_equals(errors[0].getMessage(), "The JSON document must be an object");
}
TEST_METHOD(4) {
set_test_name("Validating values through ConfigKit::Schema");
schema.add("foo", ConfigKit::STRING_TYPE, ConfigKit::REQUIRED);
schema.add("bar", ConfigKit::INT_TYPE, ConfigKit::REQUIRED);
init();
doc["bar"] = "string";
config->previewUpdate(doc, errors);
std::sort(errors.begin(), errors.end());
ensure_equals(errors.size(), 2u);
ensure_equals(errors[0].getMessage(), "'bar' must be an integer");
ensure_equals(errors[1].getMessage(), "'foo' is required");
}
static void addErrorValidator(const ConfigKit::Store &store,
vector<ConfigKit::Error> &errors)
{
errors.push_back(ConfigKit::Error("Cannot read '{{foo}}'!"));
}
static void logSecretValidator(const ConfigKit::Store &store,
vector<ConfigKit::Error> &errors)
{
errors.push_back(ConfigKit::Error("'{{secret}}' is " + store["secret"].asString()));
}
TEST_METHOD(5) {
set_test_name("Custom validators");
schema.add("foo", ConfigKit::STRING_TYPE, ConfigKit::REQUIRED);
schema.add("secret", ConfigKit::STRING_TYPE, ConfigKit::REQUIRED | ConfigKit::SECRET);
schema.addValidator(addErrorValidator);
schema.addValidator(addErrorValidator);
schema.addValidator(logSecretValidator);
init();
doc["secret"] = "42";
config->previewUpdate(doc, errors);
std::sort(errors.begin(), errors.end());
ensure_equals(errors.size(), 4u);
ensure_equals(errors[0].getMessage(), "'foo' is required");
ensure_equals(errors[1].getMessage(), "'secret' is 42");
ensure_equals(errors[2].getMessage(), "Cannot read 'foo'!");
ensure_equals(errors[3].getMessage(), "Cannot read 'foo'!");
}
/*********** Test other stuff ***********/
TEST_METHOD(10) {
set_test_name("previewUpdate()");
schema.add("foo", ConfigKit::STRING_TYPE, ConfigKit::REQUIRED);
schema.add("bar", ConfigKit::INT_TYPE, ConfigKit::REQUIRED);
schema.add("secret", ConfigKit::STRING_TYPE, ConfigKit::REQUIRED | ConfigKit::SECRET);
schema.add("secret_default", ConfigKit::STRING_TYPE, ConfigKit::OPTIONAL | ConfigKit::SECRET, "default");
schema.add("secret_null", ConfigKit::STRING_TYPE, ConfigKit::OPTIONAL | ConfigKit::SECRET);
init();
doc["foo"] = "string";
doc["baz"] = true;
doc["secret"] = "my secret";
Json::Value preview = config->previewUpdate(doc, errors);
ensure_equals("1 error", errors.size(), 1u);
ensure_equals(errors[0].getMessage(), "'bar' is required");
ensure("foo exists", preview.isMember("foo"));
ensure("bar exists", preview.isMember("bar"));
ensure("baz does not exists", !preview.isMember("baz"));
ensure_equals("foo is a string", preview["foo"]["user_value"].asString(), "string");
ensure("bar is null", preview["bar"]["user_value"].isNull());
ensure_equals("secret user value is filtered",
preview["secret"]["user_value"].asString(), "[FILTERED]");
ensure("secret default value is null",
preview["secret"]["default_value"].isNull());
ensure_equals("secret effective value is filtered",
preview["secret"]["effective_value"].asString(), "[FILTERED]");
ensure("secret_default user value is null",
preview["secret_default"]["user_value"].isNull());
ensure_equals("secret_default default value is filtered",
preview["secret_default"]["default_value"].asString(), "[FILTERED]");
ensure_equals("secret_default effective value is filtered",
preview["secret_default"]["effective_value"].asString(), "[FILTERED]");
ensure("secret_null user value is null",
preview["secret_null"]["user_value"].isNull());
ensure("secret_null has no default value",
preview["secret_null"]["default_value"].isNull());
ensure("secret_null effective value is null",
preview["secret_null"]["effective_value"].isNull());
}
TEST_METHOD(12) {
set_test_name("inspect()");
schema.add("foo", ConfigKit::STRING_TYPE, ConfigKit::REQUIRED);
schema.add("bar", ConfigKit::INT_TYPE, ConfigKit::REQUIRED);
schema.add("secret", ConfigKit::STRING_TYPE, ConfigKit::REQUIRED | ConfigKit::SECRET);
schema.add("secret_default", ConfigKit::STRING_TYPE, ConfigKit::OPTIONAL | ConfigKit::SECRET, "default");
schema.add("secret_null", ConfigKit::STRING_TYPE, ConfigKit::OPTIONAL | ConfigKit::SECRET);
init();
doc["foo"] = "string";
doc["bar"] = 123;
doc["secret"] = "my secret";
ensure("update succeeds", config->update(doc, errors));
ensure("no errors", errors.empty());
Json::Value dump = config->inspect();
ensure_equals("foo user value", dump["foo"]["user_value"].asString(), "string");
ensure_equals("foo effective value", dump["foo"]["effective_value"].asString(), "string");
ensure_equals("bar user value", dump["bar"]["user_value"].asInt(), 123);
ensure_equals("bar effective value", dump["bar"]["effective_value"].asInt(), 123);
ensure_equals("secret user value is filtered",
dump["secret"]["user_value"].asString(), "[FILTERED]");
ensure("secret default value is null",
dump["secret"]["default_value"].isNull());
ensure_equals("secret effective value is filtered",
dump["secret"]["effective_value"].asString(), "[FILTERED]");
ensure("secret_default user value is null",
dump["secret_default"]["user_value"].isNull());
ensure_equals("secret_default default value is filtered",
dump["secret_default"]["default_value"].asString(), "[FILTERED]");
ensure_equals("secret_default effective value is filtered",
dump["secret_default"]["effective_value"].asString(), "[FILTERED]");
ensure("secret_null user value is null",
dump["secret_null"]["user_value"].isNull());
ensure("secret_null has no default value",
dump["secret_null"]["default_value"].isNull());
ensure("secret_null effective value is null",
dump["secret_null"]["effective_value"].isNull());
}
TEST_METHOD(13) {
set_test_name("Default values");
schema.add("foo", ConfigKit::STRING_TYPE, ConfigKit::OPTIONAL, "string");
schema.add("bar", ConfigKit::INT_TYPE, ConfigKit::OPTIONAL, 123);
init();
ensure_equals(config->get("foo").asString(), "string");
ensure_equals(config->get("bar").asInt(), 123);
Json::Value dump = config->inspect();
ensure("foo user value", dump["foo"]["user_value"].isNull());
ensure_equals("foo default value", dump["foo"]["default_value"].asString(), "string");
ensure_equals("foo effective value", dump["foo"]["effective_value"].asString(), "string");
ensure("bar user value", dump["bar"]["user_value"].isNull());
ensure_equals("bar default value", dump["bar"]["default_value"].asInt(), 123);
ensure_equals("bar effective value", dump["bar"]["effective_value"].asInt(), 123);
}
static Json::Value
getNextValueAndBump(unsigned int *nextValue) {
unsigned int result = *nextValue;
(*nextValue)++;
return result;
}
TEST_METHOD(14) {
set_test_name("Dynamic default values and caching them");
unsigned int nextValue = 0;
schema.addWithDynamicDefault("foo", ConfigKit::INT_TYPE,
ConfigKit::OPTIONAL,
boost::bind(getNextValueAndBump, &nextValue));
schema.addWithDynamicDefault("bar", ConfigKit::INT_TYPE,
ConfigKit::OPTIONAL | ConfigKit::CACHE_DEFAULT_VALUE,
boost::bind(getNextValueAndBump, &nextValue));
init();
ensure_equals("(1)", config->get("foo").asUInt(), 0u);
ensure_equals("(2)", config->get("foo").asUInt(), 1u);
ensure_equals("(3)", config->get("bar").asUInt(), 2u);
ensure_equals("(4)", config->get("bar").asUInt(), 2u);
}
TEST_METHOD(15) {
set_test_name("Read-only keys can only be written to once");
schema.add("foo", ConfigKit::INT_TYPE,
ConfigKit::OPTIONAL | ConfigKit::READ_ONLY);
schema.add("foo2", ConfigKit::INT_TYPE,
ConfigKit::OPTIONAL | ConfigKit::READ_ONLY);
init();
doc["foo"] = 123;
ensure(config->update(doc, errors));
doc["foo2"] = 123;
ensure(config->update(doc, errors));
ensure_equals(config->get("foo").asInt(), 123);
ensure(config->get("foo2").isNull());
}
static Json::Value normalizeTargetAndLevel(const Json::Value &values) {
Json::Value updates(Json::objectValue);
if (values["target"].isString()) {
updates["target"]["path"] = values["target"];
}
if (!startsWith(values["level"].asString(), "L")) {
updates["level"] = "L" + values["level"].asString();
}
return updates;
}
TEST_METHOD(17) {
set_test_name("Normalizers");
schema.add("target", ConfigKit::ANY_TYPE, ConfigKit::REQUIRED);
schema.add("level", ConfigKit::STRING_TYPE, ConfigKit::REQUIRED | ConfigKit::READ_ONLY);
schema.addNormalizer(normalizeTargetAndLevel);
init();
doc["target"] = "/path";
doc["level"] = "1";
ensure("(1)", config->update(doc, errors));
doc = config->inspect();
ensure("(2)", config->get("target").isObject());
ensure_equals("(3)", config->get("target")["path"].asString(), "/path");
ensure("(4)", doc["target"]["user_value"].isObject());
ensure_equals("(5)", doc["target"]["user_value"]["path"].asString(), "/path");
ensure_equals("(6)", config->get("level").asString(), "L1");
ensure_equals("(7)", doc["level"]["user_value"].asString(), "L1");
doc = Json::objectValue;
doc["level"] = "2";
ensure("(10)", config->update(doc, errors));
doc = config->inspect();
ensure("(11)", config->get("target").isObject());
ensure_equals("(12)", config->get("target")["path"].asString(), "/path");
ensure("(13)", doc["target"]["user_value"].isObject());
ensure_equals("(14)", doc["target"]["user_value"]["path"].asString(), "/path");
ensure_equals("(15)", config->get("level").asString(), "L1");
ensure_equals("(16)", doc["level"]["user_value"].asString(), "L1");
}
TEST_METHOD(18) {
set_test_name("Typecasting");
schema.add("string", ConfigKit::STRING_TYPE, ConfigKit::REQUIRED);
schema.add("int", ConfigKit::INT_TYPE, ConfigKit::REQUIRED);
schema.add("uint", ConfigKit::UINT_TYPE, ConfigKit::REQUIRED);
schema.add("float", ConfigKit::FLOAT_TYPE, ConfigKit::REQUIRED);
schema.add("bool", ConfigKit::BOOL_TYPE, ConfigKit::REQUIRED);
schema.add("array", ConfigKit::ARRAY_TYPE, ConfigKit::REQUIRED);
schema.add("object", ConfigKit::OBJECT_TYPE, ConfigKit::REQUIRED);
schema.add("any", ConfigKit::ANY_TYPE, ConfigKit::REQUIRED);
init();
doc["string"] = 123;
doc["int"] = -456.78;
doc["uint"] = 456.78;
doc["float"] = 123;
doc["bool"] = 1;
doc["array"] = Json::arrayValue;
doc["object"] = Json::objectValue;
doc["any"] = Json::objectValue;
Json::Value preview = config->previewUpdate(doc, errors);
ensure_equals("Validation passes (1)", errors.size(), 0u);
ensure("Validation passes", config->update(doc, errors));
ensure(preview["string"]["user_value"].isString());
ensure(preview["int"]["user_value"].isInt());
ensure(preview["uint"]["user_value"].isUInt());
ensure(preview["float"]["user_value"].isDouble());
ensure(preview["bool"]["user_value"].isBool());
ensure(preview["array"]["user_value"].isArray());
ensure(preview["object"]["user_value"].isObject());
ensure(preview["any"]["user_value"].isObject());
ensure(config->get("string").isString());
ensure(config->get("int").isInt());
ensure(config->get("uint").isUInt());
ensure(config->get("float").isDouble());
ensure(config->get("bool").isBool());
ensure(config->get("array").isArray());
ensure(config->get("object").isObject());
ensure(config->get("any").isObject());
ensure_equals(preview["string"]["user_value"].asString(), "123");
ensure_equals(preview["int"]["user_value"].asInt(), -456);
ensure_equals(preview["uint"]["user_value"].asUInt(), 456u);
ensure_equals(preview["float"]["user_value"].asDouble(), 123);
ensure_equals(preview["bool"]["user_value"].asBool(), true);
ensure_equals(config->get("string").asString(), "123");
ensure_equals(config->get("int").asInt(), -456);
ensure_equals(config->get("uint").asUInt(), 456u);
ensure_equals(config->get("float").asDouble(), 123);
ensure_equals(config->get("bool").asBool(), true);
}
static Json::Value addExclamationFilter(const Json::Value &val) {
return val.asString() + "!";
}
TEST_METHOD(19) {
set_test_name("Inspect filters");
schema.add("foo", ConfigKit::STRING_TYPE, ConfigKit::REQUIRED)
.setInspectFilter(addExclamationFilter);
init();
doc["foo"] = "hello";
ensure("(1)", config->update(doc, errors));
doc = config->inspect();
ensure_equals("(2)", config->get("foo").asString(), "hello");
ensure_equals("(3)", doc["foo"]["user_value"].asString(), "hello!");
ensure_equals("(4)", doc["foo"]["effective_value"].asString(), "hello!");
}
static Json::Value getTest20Default(const ConfigKit::Store &store) {
return store["a1"].asInt() +
store["a2"].asInt() +
store["a4"].asInt() +
store["a5"].asInt();
}
TEST_METHOD(20) {
set_test_name("Cached dynamic default values that depend on other values");
using namespace ConfigKit;
schema.add("a1", INT_TYPE, REQUIRED);
schema.add("a2", INT_TYPE, REQUIRED);
schema.addWithDynamicDefault("a3", INT_TYPE,
OPTIONAL | CACHE_DEFAULT_VALUE, getTest20Default);
schema.add("a4", INT_TYPE, REQUIRED);
schema.add("a5", INT_TYPE, REQUIRED);
init();
doc["a1"] = 1;
doc["a2"] = 10;
doc["a4"] = 100;
doc["a5"] = 1000;
ensure("(1)", config->update(doc, errors));
doc = config->inspect();
ensure_equals("(2)", config->get("a3").asInt(), 1111);
}
}