Skip to content
Snippets Groups Projects
Commit bd6973e6 authored by Jakob Olsson's avatar Jakob Olsson
Browse files

add support for seperate definitions file, add corresponding tests

Separate definition files may be stored at /usr/share/rpcd/schemas/definitions/
parent 4e87cc52
No related branches found
No related tags found
No related merge requests found
...@@ -170,6 +170,10 @@ EXPOSE 22 ...@@ -170,6 +170,10 @@ EXPOSE 22
RUN mkdir -p /var/log/supervisor RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Prepare JSON Schemas
RUN mkdir -p /usr/share/rpcd/schemas
#COPY cmocka_test/files/usr/share/rpcd/schemas/* /usr/share/rpcd/schemas/
# Start entrypoint # Start entrypoint
COPY entrypoint.sh /usr/local/bin/entrypoint.sh COPY entrypoint.sh /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
...@@ -29,16 +29,37 @@ using nlohmann::json_schema::json_validator; ...@@ -29,16 +29,37 @@ using nlohmann::json_schema::json_validator;
bool initialized; bool initialized;
static void loader(const json_uri &uri, json &schema)
{
struct schema_definition *s_def;
char *str;
s_def = schema_get_definitions_schema(uri.url().c_str());
if (!s_def)
return;
str = blobmsg_format_json(s_def->definitions, true);
if (!str)
return;
schema = json::parse(str);
free(str);
}
bool json_object_validate_schema(json obj, json sch) bool json_object_validate_schema(json obj, json sch)
{ {
/* json-parse the schema */ /* json-parse the schema */
json_validator validator; // create validator dbg("validation object -- %s\n", obj.dump().c_str());
dbg("validation schema -- %s\n", sch.dump().c_str());
json_validator validator(loader);
try { try {
validator.set_root_schema(sch); // insert root-schema validator.set_root_schema(sch); // insert root-schema
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << "Validation of schema failed, here is why: " << e.what() << "\n"; //std::cerr << "Validation of schema failed, here is why: " << e.what() << "\n";
return 0; return 0;
} }
...@@ -48,7 +69,7 @@ bool json_object_validate_schema(json obj, json sch) ...@@ -48,7 +69,7 @@ bool json_object_validate_schema(json obj, json sch)
void error(const nlohmann::json::json_pointer &ptr, const json &instance, const std::string &message) override void error(const nlohmann::json::json_pointer &ptr, const json &instance, const std::string &message) override
{ {
nlohmann::json_schema::basic_error_handler::error(ptr, instance, message); nlohmann::json_schema::basic_error_handler::error(ptr, instance, message);
std::cerr << "ERROR: '" << ptr << "' - '" << instance << "': " << message << "\n"; //std::cerr << "ERROR: '" << ptr << "' - '" << instance << "': " << message << "\n";
} }
}; };
...@@ -65,7 +86,7 @@ int schema_validator_destroy(void) ...@@ -65,7 +86,7 @@ int schema_validator_destroy(void)
if (!initialized) if (!initialized)
return 0; return 0;
schema_flush_objects(); schema_destroy();
initialized = false; initialized = false;
return 0; return 0;
} }
...@@ -75,7 +96,7 @@ int schema_validator_init(void) ...@@ -75,7 +96,7 @@ int schema_validator_init(void)
if (initialized) if (initialized)
return 0; return 0;
schema_setup_json(); schema_setup();
initialized = true; initialized = true;
return 0; return 0;
} }
...@@ -181,8 +202,6 @@ bool schema_validator_validate_jobj(struct json_object *j_object, const char *ob ...@@ -181,8 +202,6 @@ bool schema_validator_validate_jobj(struct json_object *j_object, const char *ob
obj = json::parse(json_object_get_string(j_object)); obj = json::parse(json_object_get_string(j_object));
dbg("validation object -- %s\n", obj.dump().c_str());
dbg("validation schema -- %s\n", sch.dump().c_str());
rv = json_object_validate_schema(obj, sch); rv = json_object_validate_schema(obj, sch);
out_definitions: out_definitions:
......
...@@ -65,7 +65,7 @@ static void schema_flush_object(struct schema_object *s_object) ...@@ -65,7 +65,7 @@ static void schema_flush_object(struct schema_object *s_object)
return; return;
} }
void schema_flush_objects(void) static void schema_flush_objects(void)
{ {
struct schema_object *s_object, *tmp; struct schema_object *s_object, *tmp;
...@@ -79,6 +79,39 @@ void schema_flush_objects(void) ...@@ -79,6 +79,39 @@ void schema_flush_objects(void)
return; return;
} }
static void schema_flush_definition(struct schema_definition *s_def)
{
dbg("cleaning object %s\n", (char *)s_def->avl.key);
free((void *)s_def->avl.key);
if (s_def->definitions)
free(s_def->definitions);
free(s_def);
return;
}
static void schema_flush_definitions(void)
{
struct schema_definition *s_def, *tmp;
dbg("cleaning all schema objects\n");
avl_for_each_element_safe(&s_ctx.schema_definitions, s_def, avl, tmp) {
avl_delete(&s_ctx.schema_objects, &s_def->avl);
schema_flush_definition(s_def);
}
return;
}
void schema_destroy(void)
{
schema_flush_definitions();
schema_flush_objects();
}
static void schema_parse_object(struct schema_object *schema_object, struct blob_attr *object) static void schema_parse_object(struct schema_object *schema_object, struct blob_attr *object)
{ {
struct blob_attr *method, *properties; struct blob_attr *method, *properties;
...@@ -90,7 +123,7 @@ static void schema_parse_object(struct schema_object *schema_object, struct blob ...@@ -90,7 +123,7 @@ static void schema_parse_object(struct schema_object *schema_object, struct blob
continue; continue;
dbg("%s %d method name = %s\n", __func__, __LINE__, blobmsg_name(object)); dbg("%s %d method name = %s\n", __func__, __LINE__, blobmsg_name(object));
s_method = (struct schema_method *)calloc(1, sizeof(*s_method)); s_method = (struct schema_method *)calloc(1, sizeof(struct schema_method));
if (!s_method) if (!s_method)
continue; continue;
...@@ -116,29 +149,76 @@ static void schema_parse_object(struct schema_object *schema_object, struct blob ...@@ -116,29 +149,76 @@ static void schema_parse_object(struct schema_object *schema_object, struct blob
} }
static void static void
schema_setup_file(const char *path) schema_setup_definitions(const char *path)
{
struct blob_buf def;
struct blob_attr *root;
int rem, len;
struct schema_definition *s_def;
memset(&def, 0, sizeof(struct blob_buf));
blob_buf_init(&def, 0);
if (!blobmsg_add_json_from_file(&def, path)) {
dbg("Failed to parse %s\n", path);
goto out;
}
s_def = (struct schema_definition *) calloc(1, sizeof(struct schema_definition));
if (!s_def)
goto out;
len = blob_raw_len(def.head);
s_def->definitions = (struct blob_attr *) calloc(1, sizeof(struct blob_attr) + len);
memcpy(s_def->definitions, def.head, len);
/* find the key properties of root */
blob_for_each_attr(root, def.head, rem) {
if (!strncmp(blobmsg_name(root), "$id", 4)) {
s_def->avl.key = strdup(blobmsg_get_string(root));
if (!s_def->avl.key)
goto out_flush;
}
}
if (!s_def->avl.key)
goto out_flush;
avl_insert(&s_ctx.schema_definitions, &s_def->avl);
out:
blob_buf_free(&def);
return;
out_flush:
schema_flush_definition(s_def);
blob_buf_free(&def);
}
static void
schema_setup_documents(const char *path)
{ {
struct blob_buf acl; struct blob_buf doc;
struct blob_attr *root, *object; struct blob_attr *root, *object;
int rem, rem2; int rem, rem2;
struct schema_object *schema_object; struct schema_object *schema_object;
memset(&acl, 0, sizeof(acl)); memset(&doc, 0, sizeof(struct blob_buf));
blob_buf_init(&acl, 0); blob_buf_init(&doc, 0);
if (!blobmsg_add_json_from_file(&acl, path)) { if (!blobmsg_add_json_from_file(&doc, path)) {
dbg("Failed to parse %s\n", path); dbg("Failed to parse %s\n", path);
goto out; goto out;
} }
schema_object = (struct schema_object *) calloc(1, sizeof(*schema_object)); schema_object = (struct schema_object *) calloc(1, sizeof(struct schema_object));
if (!schema_object) if (!schema_object)
goto out; goto out;
avl_init(&schema_object->schema_methods, avl_strcmp, false, NULL); avl_init(&schema_object->schema_methods, avl_strcmp, false, NULL);
/* find the key properties of root */ /* find the key properties of root */
blob_for_each_attr(root, acl.head, rem) { blob_for_each_attr(root, doc.head, rem) {
if (!strncmp(blobmsg_name(root), "regex", 6)) { if (!strncmp(blobmsg_name(root), "regex", 6)) {
schema_object->regex = blobmsg_get_bool(root); schema_object->regex = blobmsg_get_bool(root);
dbg("%s: regex enabled %d\n", __func__, schema_object->regex); dbg("%s: regex enabled %d\n", __func__, schema_object->regex);
...@@ -166,7 +246,6 @@ schema_setup_file(const char *path) ...@@ -166,7 +246,6 @@ schema_setup_file(const char *path)
continue; continue;
schema_parse_object(schema_object, object); schema_parse_object(schema_object, object);
dbg("added schema %s\n", schema_object->object_name);
} }
} }
...@@ -187,11 +266,11 @@ schema_setup_file(const char *path) ...@@ -187,11 +266,11 @@ schema_setup_file(const char *path)
avl_insert(&s_ctx.schema_objects, &schema_object->avl); avl_insert(&s_ctx.schema_objects, &schema_object->avl);
out: out:
blob_buf_free(&acl); blob_buf_free(&doc);
return; return;
out_flush: out_flush:
schema_flush_object(schema_object); schema_flush_object(schema_object);
blob_buf_free(&acl); blob_buf_free(&doc);
} }
struct schema_method *schema_get_method_schema(const char *object, const char *method) struct schema_method *schema_get_method_schema(const char *object, const char *method)
...@@ -213,15 +292,17 @@ struct schema_method *schema_get_method_schema(const char *object, const char *m ...@@ -213,15 +292,17 @@ struct schema_method *schema_get_method_schema(const char *object, const char *m
return NULL; return NULL;
} }
struct blob_attr *schema_get_definitions_schema(const char *object) struct schema_definition *schema_get_definitions_schema(const char *id)
{ {
struct schema_object *s_object; struct schema_definition *s_def;
s_object = schema_get_object_schema(object); avl_for_each_element(&s_ctx.schema_definitions, s_def, avl) {
if (!s_object) dbg("%s: definition = %s, avl.key = %s\n", __func__, id, (char *)s_def->avl.key);
return NULL; if (!strncmp(id, (char *) s_def->avl.key, DEFINITION_NAME_MAX_LEN))
return s_def;
}
return s_object->definitions; return NULL;
} }
struct schema_object *schema_get_object_schema(const char *object) struct schema_object *schema_get_object_schema(const char *object)
...@@ -245,19 +326,33 @@ struct schema_object *schema_get_object_schema(const char *object) ...@@ -245,19 +326,33 @@ struct schema_object *schema_get_object_schema(const char *object)
} }
void void
schema_setup_json(void) schema_setup(void)
{ {
unsigned int i; unsigned int i;
glob_t gl; glob_t gl;
/* setup docs */
if (glob(JSON_SCHEMA_DIR "/*.json", 0, NULL, &gl))
return;
avl_init(&s_ctx.schema_objects, avl_strcmp, false, NULL); avl_init(&s_ctx.schema_objects, avl_strcmp, false, NULL);
if (glob(JSON_SCHEMA_DIR "/*.json", 0, NULL, &gl)) for (i = 0; i < gl.gl_pathc; i++) {
dbg("doc path = %s\n", gl.gl_pathv[i]);
schema_setup_documents(gl.gl_pathv[i]);
}
globfree(&gl);
/* setup definitions */
if (glob(JSON_SCHEMA_DIR "/definitions/*.json", 0, NULL, &gl))
return; return;
avl_init(&s_ctx.schema_definitions, avl_strcmp, false, NULL);
for (i = 0; i < gl.gl_pathc; i++) { for (i = 0; i < gl.gl_pathc; i++) {
dbg("path = %s\n", gl.gl_pathv[i]); dbg("def path = %s\n", gl.gl_pathv[i]);
schema_setup_file(gl.gl_pathv[i]); schema_setup_definitions(gl.gl_pathv[i]);
} }
globfree(&gl); globfree(&gl);
......
...@@ -8,14 +8,14 @@ extern "C" ...@@ -8,14 +8,14 @@ extern "C"
#define METHOD_NAME_MAX_LEN 64 #define METHOD_NAME_MAX_LEN 64
#define OBJECT_NAME_MAX_LEN 64 #define OBJECT_NAME_MAX_LEN 64
#define DEFINITION_NAME_MAX_LEN 128
struct schema_context { struct schema_context {
struct avl_tree schema_objects; struct avl_tree schema_objects;
struct avl_tree schema_definitions;
}; };
struct schema_method { struct schema_method {
char method_name[METHOD_NAME_MAX_LEN];
struct blob_attr *b_input; struct blob_attr *b_input;
struct blob_attr *b_output; struct blob_attr *b_output;
...@@ -23,8 +23,6 @@ struct schema_method { ...@@ -23,8 +23,6 @@ struct schema_method {
}; };
struct schema_object { struct schema_object {
char object_name[OBJECT_NAME_MAX_LEN];
struct blob_attr *definitions; struct blob_attr *definitions;
bool regex; bool regex;
...@@ -34,11 +32,17 @@ struct schema_object { ...@@ -34,11 +32,17 @@ struct schema_object {
struct avl_node avl; struct avl_node avl;
}; };
struct schema_definition {
struct blob_attr *definitions;
struct avl_node avl;
};
struct schema_method *schema_get_method_schema(const char *object, const char *method); struct schema_method *schema_get_method_schema(const char *object, const char *method);
struct blob_attr *schema_get_definitions_schema(const char *object); struct schema_definition *schema_get_definitions_schema(const char *object);
struct schema_object *schema_get_object_schema(const char *object); struct schema_object *schema_get_object_schema(const char *object);
void schema_setup_json(); void schema_setup(void);
void schema_flush_objects(); void schema_destroy(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
...@@ -215,6 +215,30 @@ static void test_validate_output_document_blob(void **state) ...@@ -215,6 +215,30 @@ static void test_validate_output_document_blob(void **state)
schema_validator_destroy(); schema_validator_destroy();
} }
static void test_validate_definitions_file(void **state)
{
(void *) state;
schema_validator_init();
validate_doc_blob("/opt/work/test/files/definition/doc.json", "wifi", "status", true, SCHEMA_OUTPUT_CALL);
validate_doc_blob("/opt/work/test/files/definition/doc.json", "wifi", "status", true, SCHEMA_OUTPUT_CALL);
schema_validator_destroy();
}
static void test_validate_definitions_mixed(void **state)
{
(void *) state;
schema_validator_init();
validate_doc_blob("/opt/work/test/files/definition/doc.json", "wifi", "status", true, SCHEMA_OUTPUT_CALL);
validate_doc_blob("/opt/work/test/files/definition/doc.json", "wifi", "status", true, SCHEMA_OUTPUT_CALL);
schema_validator_destroy();
}
static int create_setup(void** state) { static int create_setup(void** state) {
printf("copy schemas\n"); printf("copy schemas\n");
cp("/usr/share/rpcd/schemas/wifi.json", "/opt/work/ubus/wifi.json"); cp("/usr/share/rpcd/schemas/wifi.json", "/opt/work/ubus/wifi.json");
...@@ -235,6 +259,37 @@ static int create_teardown(void** state) { ...@@ -235,6 +259,37 @@ static int create_teardown(void** state) {
return 0; return 0;
} }
static int definition_setup(void** state) {
printf("copy schemas\n");
cp("/usr/share/rpcd/schemas/wifi.json", "/opt/work/test/files/definition/schema.json");
cp("/usr/share/rpcd/schemas/definitions/definitions.json", "/opt/work/test/files/definition/definitions.json");
printf("finished copying schemas\n");
return 0;
}
static int definition_teardown(void** state) {
printf("removing schemas\n");
remove("/usr/share/rpcd/schemas/wifi.json");
remove("/usr/share/rpcd/schemas/definition.json");
return 0;
}
static int mixed_setup(void** state) {
printf("copy schemas\n");
cp("/usr/share/rpcd/schemas/wifi.json", "/opt/work/test/files/definition/mixed_schema.json");
cp("/usr/share/rpcd/schemas/definitions/definitions.json", "/opt/work/test/files/definition/definitions.json");
printf("finished copying schemas\n");
return 0;
}
static int mixed_teardown(void** state) {
printf("removing schemas\n");
remove("/usr/share/rpcd/schemas/wifi.json");
remove("/usr/share/rpcd/schemas/definition.json");
return 0;
}
int main(void) { int main(void) {
const struct CMUnitTest tests[] = { const struct CMUnitTest tests[] = {
cmocka_unit_test(test_validator_create_nothing), cmocka_unit_test(test_validator_create_nothing),
...@@ -244,6 +299,8 @@ int main(void) { ...@@ -244,6 +299,8 @@ int main(void) {
cmocka_unit_test_setup_teardown(test_validate_output_document_jobj, create_setup, create_teardown), cmocka_unit_test_setup_teardown(test_validate_output_document_jobj, create_setup, create_teardown),
cmocka_unit_test_setup_teardown(test_validate_input_document_blob, create_setup, create_teardown), cmocka_unit_test_setup_teardown(test_validate_input_document_blob, create_setup, create_teardown),
cmocka_unit_test_setup_teardown(test_validate_output_document_blob, create_setup, create_teardown), cmocka_unit_test_setup_teardown(test_validate_output_document_blob, create_setup, create_teardown),
cmocka_unit_test_setup_teardown(test_validate_definitions_file, definition_setup, definition_teardown),
cmocka_unit_test_setup_teardown(test_validate_definitions_mixed, definition_setup, definition_teardown)
}; };
return cmocka_run_group_tests(tests, NULL, NULL); return cmocka_run_group_tests(tests, NULL, NULL);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment