????
Current Path : /opt/cpanel/ea-ruby27/src/passenger-release-6.0.23/test/cxx/ConfigKit/ |
Current File : //opt/cpanel/ea-ruby27/src/passenger-release-6.0.23/test/cxx/ConfigKit/StoreTest.cpp |
#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); } }