Skip to content

Commit

Permalink
Fix parsing of config sub-messgaes, add a unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
rojer committed Nov 24, 2021
1 parent ec3e6e2 commit 4181acf
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 67 deletions.
9 changes: 6 additions & 3 deletions include/mgos_config_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ struct mgos_config;
* checking keys against `acl`.
*/
bool mgos_conf_parse(const struct mg_str json, const char *acl,
const struct mgos_conf_entry *schema, void *cfg);
struct mgos_config *cfg);

/*
* Identical to `mgos_conf_parse()` but allows the caller to get an error
Expand All @@ -94,8 +94,7 @@ bool mgos_conf_parse(const struct mg_str json, const char *acl,
* is owned by the caller and has to be free()d.
*/
bool mgos_conf_parse_msg(const struct mg_str json, const char *acl,
const struct mgos_conf_entry *schema, void *cfg,
char **msg);
struct mgos_config *cfg, char **msg);

/*
* Parse a sub-section of the config.
Expand All @@ -107,6 +106,10 @@ bool mgos_conf_parse_sub_f(const char *fname,
const struct mgos_conf_entry *sub_schema,
const void *cfg);

bool mgos_conf_parse_sub_msg(const struct mg_str json,
const struct mgos_conf_entry *sub_schema,
const char *acl, void *cfg, char **msg);

/*
* Callback for `mgos_conf_emit_cb` (see below); `data` is the emitted data and
* `param` is user-defined param given to `mgos_conf_emit_cb`.
Expand Down
72 changes: 40 additions & 32 deletions src/mgos_config_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ bool mgos_conf_check_access_n(const struct mg_str key, struct mg_str acl) {

struct parse_ctx {
const struct mgos_conf_entry *schema;
const char *acl;
char *acl;
void *cfg;
bool result;
int offset_adj;
char **msg;
bool result;
};

const struct mgos_conf_entry *mgos_conf_find_schema_entry_s(
Expand Down Expand Up @@ -92,27 +92,24 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len,
const char *path, const struct json_token *tok) {
struct parse_ctx *ctx = (struct parse_ctx *) data;
char *endptr = NULL;

(void) name;
(void) name_len;

if (!ctx->result) return;
if (path[0] != '.') {
if (path[0] == '\0') return; /* Last entry, the entire object */
mg_asprintf(ctx->msg, 0, "Not an object");
ctx->result = false;
if (tok->type == JSON_TYPE_OBJECT_START ||
tok->type == JSON_TYPE_OBJECT_END) {
return;
}
path++;
const struct mgos_conf_entry *e =
mgos_conf_find_schema_entry(path, ctx->schema);
if (e == NULL) {
LOG(LL_DEBUG, ("Unknown key [%s]", path));
return;
if (!ctx->result) return;
const struct mgos_conf_entry *e;
if (path[0] == '.') {
path++;
e = mgos_conf_find_schema_entry(path, ctx->schema);
if (e == NULL) {
LOG(LL_DEBUG, ("Unknown key [%s]", path));
return;
}
} else {
e = ctx->schema;
}
#ifndef MGOS_BOOT_BUILD
if (e->type != CONF_TYPE_OBJECT &&
!mgos_conf_check_access(mg_mk_str(path), ctx->acl)) {
if (!mgos_conf_check_access(mg_mk_str(path), ctx->acl)) {
LOG(LL_ERROR, ("Not allowed to set [%s]", path));
return;
}
Expand Down Expand Up @@ -208,40 +205,44 @@ void mgos_conf_parse_cb(void *data, const char *name, size_t name_len,
}
}
LOG(LL_DEBUG, ("Set [%s] = [%.*s]", path, (int) tok->len, tok->ptr));
(void) name_len;
(void) name;
}

static bool mgos_conf_parse_off(const struct mg_str json, const char *acl,
const struct mgos_conf_entry *schema,
int offset_adj, void *cfg, char **msg) {
char *err_msg = NULL;
struct parse_ctx ctx = {.schema = schema,
.acl = acl,
.cfg = cfg,
.result = true,
.offset_adj = offset_adj,
.msg = msg};
if (!msg) {
ctx.msg = &err_msg;
}
if (msg == NULL) ctx.msg = &err_msg;
/* Make a temporary copy, in case it gets overridden while loading. */
if (acl != NULL) ctx.acl = strdup(acl);
int ret = json_walk(json.p, json.len, mgos_conf_parse_cb, &ctx);
if (*ctx.msg) {
if ((!ctx.result || ret <= 0) && *ctx.msg == NULL) {
mg_asprintf(ctx.msg, 0, "Invalid JSON");
}
if (*ctx.msg != NULL) {
LOG(LL_ERROR, ("%s", *ctx.msg));
if (ctx.msg == &err_msg) {
free((void *) err_msg);
free(err_msg);
}
}
return ret > 0 && ctx.result == true;
free(ctx.acl);
return (ret > 0 && ctx.result == true);
}

bool mgos_conf_parse(const struct mg_str json, const char *acl,
const struct mgos_conf_entry *schema, void *cfg) {
return mgos_conf_parse_off(json, acl, schema, 0, cfg, NULL);
struct mgos_config *cfg) {
return mgos_conf_parse_off(json, acl, mgos_config_schema(), 0, cfg, NULL);
}

bool mgos_conf_parse_msg(const struct mg_str json, const char *acl,
const struct mgos_conf_entry *schema, void *cfg,
char **msg) {
return mgos_conf_parse_off(json, acl, schema, 0, cfg, msg);
struct mgos_config *cfg, char **msg) {
return mgos_conf_parse_off(json, acl, mgos_config_schema(), 0, cfg, msg);
}

bool mgos_conf_parse_sub(const struct mg_str json,
Expand All @@ -250,6 +251,13 @@ bool mgos_conf_parse_sub(const struct mg_str json,
NULL);
}

bool mgos_conf_parse_sub_msg(const struct mg_str json,
const struct mgos_conf_entry *sub_schema,
const char *acl, void *sub_cfg, char **msg) {
return mgos_conf_parse_off(json, acl, sub_schema, sub_schema->offset, sub_cfg,
msg);
}

struct emit_ctx {
const void *cfg;
const void *base;
Expand Down Expand Up @@ -696,7 +704,7 @@ bool mgos_config_set(const struct mg_str key, const struct mg_str value,
break;
}
case CONF_TYPE_OBJECT: {
ret = mgos_conf_parse(value, "*", e, cfg);
ret = mgos_conf_parse_sub(value, e, cfg);
break;
}
}
Expand Down
12 changes: 2 additions & 10 deletions src/mgos_sys_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,10 @@ static bool load_config(const char *name, struct mg_str cfg_data,
const char *acl, const struct mgos_conf_entry *schema,
void *cfg) {
bool result = true;
/* Make a temporary copy, in case it gets overridden while loading. */
char *acl_copy = (acl != NULL ? strdup(acl) : NULL);
if (!mgos_conf_parse(cfg_data, acl_copy, schema, cfg)) {
if (!mgos_conf_parse_sub_msg(cfg_data, schema, acl, cfg, NULL)) {
LOG(LL_ERROR, ("Failed to parse %s", name));
result = false;
}
free(acl_copy);
(void) name;
return result;
}
Expand Down Expand Up @@ -498,13 +495,8 @@ void mgos_sys_config_register_validator(mgos_config_validator_fn fn) {
}

bool mgos_config_apply_s(const struct mg_str json, bool save) {
/* Make a temporary copy, in case it gets overridden while loading. */
char *acl_copy = (mgos_sys_config_get_conf_acl() != NULL
? strdup(mgos_sys_config_get_conf_acl())
: NULL);
bool res =
mgos_conf_parse(json, acl_copy, mgos_config_schema(), &mgos_sys_config);
free(acl_copy);
mgos_conf_parse(json, mgos_sys_config_get_conf_acl(), &mgos_sys_config);
if (save) save_cfg(&mgos_sys_config, NULL);
return res;
}
Expand Down
41 changes: 24 additions & 17 deletions src/test/data/golden/mgos_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@

/* struct mgos_config */
static const struct mgos_conf_entry mgos_config_schema_[] = {
{.type = CONF_TYPE_OBJECT, .key = "", .offset = 0, .num_desc = 42},
{.type = CONF_TYPE_OBJECT, .key = "wifi", .offset = offsetof(struct mgos_config, wifi), .num_desc = 8},
{.type = CONF_TYPE_OBJECT, .key = "", .offset = 0, .num_desc = 43},
{.type = CONF_TYPE_OBJECT, .key = "wifi", .offset = offsetof(struct mgos_config, wifi), .num_desc = 9},
{.type = CONF_TYPE_OBJECT, .key = "sta", .offset = offsetof(struct mgos_config, wifi.sta), .num_desc = 2},
{.type = CONF_TYPE_STRING, .key = "ssid", .offset = offsetof(struct mgos_config, wifi.sta.ssid)},
{.type = CONF_TYPE_STRING, .key = "pass", .offset = offsetof(struct mgos_config, wifi.sta.pass)},
{.type = CONF_TYPE_OBJECT, .key = "ap", .offset = offsetof(struct mgos_config, wifi.ap), .num_desc = 4},
{.type = CONF_TYPE_OBJECT, .key = "ap", .offset = offsetof(struct mgos_config, wifi.ap), .num_desc = 5},
{.type = CONF_TYPE_BOOL, .key = "enable", .offset = offsetof(struct mgos_config, wifi.ap.enable)},
{.type = CONF_TYPE_STRING, .key = "ssid", .offset = offsetof(struct mgos_config, wifi.ap.ssid)},
{.type = CONF_TYPE_STRING, .key = "pass", .offset = offsetof(struct mgos_config, wifi.ap.pass)},
{.type = CONF_TYPE_INT, .key = "channel", .offset = offsetof(struct mgos_config, wifi.ap.channel)},
Expand Down Expand Up @@ -93,6 +94,7 @@ const struct mgos_conf_entry *mgos_config_wifi_ap_get_schema(void) {
}

void mgos_config_wifi_ap_set_defaults(struct mgos_config_wifi_ap *cfg) {
cfg->enable = false;
cfg->ssid = "Quote \" me \\\\ please";
cfg->pass = "\u043c\u0430\u043b\u043e\u0432\u0430\u0442\u043e \u0431\u0443\u0434\u0435\u0442";
cfg->channel = 6;
Expand Down Expand Up @@ -127,7 +129,7 @@ bool mgos_config_wifi_parse_f(const char *fname, struct mgos_config_wifi *cfg) {

/* struct mgos_config_http */
const struct mgos_conf_entry *mgos_config_http_get_schema(void) {
return &mgos_config_schema_[11];
return &mgos_config_schema_[12];
}

void mgos_config_http_set_defaults(struct mgos_config_http *cfg) {
Expand All @@ -145,7 +147,7 @@ bool mgos_config_http_parse_f(const char *fname, struct mgos_config_http *cfg) {

/* struct mgos_config_debug_empty */
const struct mgos_conf_entry *mgos_config_debug_empty_get_schema(void) {
return &mgos_config_schema_[25];
return &mgos_config_schema_[26];
}

void mgos_config_debug_empty_set_defaults(struct mgos_config_debug_empty *cfg) {
Expand All @@ -162,7 +164,7 @@ bool mgos_config_debug_empty_parse_f(const char *fname, struct mgos_config_debug

/* struct mgos_config_debug */
const struct mgos_conf_entry *mgos_config_debug_get_schema(void) {
return &mgos_config_schema_[14];
return &mgos_config_schema_[15];
}

void mgos_config_debug_set_defaults(struct mgos_config_debug *cfg) {
Expand All @@ -189,7 +191,7 @@ bool mgos_config_debug_parse_f(const char *fname, struct mgos_config_debug *cfg)

/* struct mgos_config_baz */
const struct mgos_conf_entry *mgos_config_baz_get_schema(void) {
return &mgos_config_schema_[41];
return &mgos_config_schema_[42];
}

void mgos_config_baz_set_defaults(struct mgos_config_baz *cfg) {
Expand All @@ -206,7 +208,7 @@ bool mgos_config_baz_parse_f(const char *fname, struct mgos_config_baz *cfg) {

/* struct mgos_config_bar_inner */
const struct mgos_conf_entry *mgos_config_bar_inner_get_schema(void) {
return &mgos_config_schema_[38];
return &mgos_config_schema_[39];
}

void mgos_config_bar_inner_set_defaults(struct mgos_config_bar_inner *cfg) {
Expand All @@ -224,7 +226,7 @@ bool mgos_config_bar_inner_parse_f(const char *fname, struct mgos_config_bar_inn

/* struct mgos_config_baz */
const struct mgos_conf_entry *mgos_config_bar_baz_get_schema(void) {
return &mgos_config_schema_[41];
return &mgos_config_schema_[42];
}

void mgos_config_bar_baz_set_defaults(struct mgos_config_baz *cfg) {
Expand All @@ -241,7 +243,7 @@ bool mgos_config_bar_baz_parse_f(const char *fname, struct mgos_config_baz *cfg)

/* struct mgos_config_bar */
const struct mgos_conf_entry *mgos_config_bar_get_schema(void) {
return &mgos_config_schema_[35];
return &mgos_config_schema_[36];
}

void mgos_config_bar_set_defaults(struct mgos_config_bar *cfg) {
Expand All @@ -261,7 +263,7 @@ bool mgos_config_bar_parse_f(const char *fname, struct mgos_config_bar *cfg) {

/* struct mgos_config_bar_inner */
const struct mgos_conf_entry *mgos_config_test_bar1_inner_get_schema(void) {
return &mgos_config_schema_[38];
return &mgos_config_schema_[39];
}

void mgos_config_test_bar1_inner_set_defaults(struct mgos_config_bar_inner *cfg) {
Expand All @@ -279,7 +281,7 @@ bool mgos_config_test_bar1_inner_parse_f(const char *fname, struct mgos_config_b

/* struct mgos_config_baz */
const struct mgos_conf_entry *mgos_config_test_bar1_baz_get_schema(void) {
return &mgos_config_schema_[41];
return &mgos_config_schema_[42];
}

void mgos_config_test_bar1_baz_set_defaults(struct mgos_config_baz *cfg) {
Expand All @@ -296,7 +298,7 @@ bool mgos_config_test_bar1_baz_parse_f(const char *fname, struct mgos_config_baz

/* struct mgos_config_bar */
const struct mgos_conf_entry *mgos_config_test_bar1_get_schema(void) {
return &mgos_config_schema_[35];
return &mgos_config_schema_[36];
}

void mgos_config_test_bar1_set_defaults(struct mgos_config_bar *cfg) {
Expand All @@ -316,7 +318,7 @@ bool mgos_config_test_bar1_parse_f(const char *fname, struct mgos_config_bar *cf

/* struct mgos_config_bar_inner */
const struct mgos_conf_entry *mgos_config_test_bar2_inner_get_schema(void) {
return &mgos_config_schema_[38];
return &mgos_config_schema_[39];
}

void mgos_config_test_bar2_inner_set_defaults(struct mgos_config_bar_inner *cfg) {
Expand All @@ -334,7 +336,7 @@ bool mgos_config_test_bar2_inner_parse_f(const char *fname, struct mgos_config_b

/* struct mgos_config_baz */
const struct mgos_conf_entry *mgos_config_test_bar2_baz_get_schema(void) {
return &mgos_config_schema_[41];
return &mgos_config_schema_[42];
}

void mgos_config_test_bar2_baz_set_defaults(struct mgos_config_baz *cfg) {
Expand All @@ -351,7 +353,7 @@ bool mgos_config_test_bar2_baz_parse_f(const char *fname, struct mgos_config_baz

/* struct mgos_config_bar */
const struct mgos_conf_entry *mgos_config_test_bar2_get_schema(void) {
return &mgos_config_schema_[35];
return &mgos_config_schema_[36];
}

void mgos_config_test_bar2_set_defaults(struct mgos_config_bar *cfg) {
Expand All @@ -371,7 +373,7 @@ bool mgos_config_test_bar2_parse_f(const char *fname, struct mgos_config_bar *cf

/* struct mgos_config_test */
const struct mgos_conf_entry *mgos_config_test_get_schema(void) {
return &mgos_config_schema_[26];
return &mgos_config_schema_[27];
}

void mgos_config_test_set_defaults(struct mgos_config_test *cfg) {
Expand Down Expand Up @@ -468,6 +470,11 @@ void mgos_config_set_wifi_sta_pass(struct mgos_config *cfg, const char * v) { mg
/* wifi.ap */
const struct mgos_config_wifi_ap *mgos_config_get_wifi_ap(const struct mgos_config *cfg) { return &cfg->wifi.ap; }

/* wifi.ap.enable */
int mgos_config_get_wifi_ap_enable(const struct mgos_config *cfg) { return cfg->wifi.ap.enable; }
int mgos_config_get_default_wifi_ap_enable(void) { return false; }
void mgos_config_set_wifi_ap_enable(struct mgos_config *cfg, int v) { cfg->wifi.ap.enable = v; }

/* wifi.ap.ssid */
const char * mgos_config_get_wifi_ap_ssid(const struct mgos_config *cfg) { return cfg->wifi.ap.ssid; }
const char * mgos_config_get_default_wifi_ap_ssid(void) { return "Quote \" me \\\\ please"; }
Expand Down
11 changes: 11 additions & 0 deletions src/test/data/golden/mgos_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ static inline void mgos_config_wifi_sta_free(struct mgos_config_wifi_sta *cfg) {

/* wifi.ap type struct mgos_config_wifi_ap */
struct mgos_config_wifi_ap {
int enable;
const char * ssid;
const char * pass;
int channel;
Expand Down Expand Up @@ -542,6 +543,16 @@ static inline void mgos_sys_config_set_wifi_sta_pass(const char * v) { mgos_conf
const struct mgos_config_wifi_ap *mgos_config_get_wifi_ap(const struct mgos_config *cfg);
static inline const struct mgos_config_wifi_ap *mgos_sys_config_get_wifi_ap(void) { return mgos_config_get_wifi_ap(&mgos_sys_config); }

/* wifi.ap.enable */
#define MGOS_CONFIG_HAVE_WIFI_AP_ENABLE
#define MGOS_SYS_CONFIG_HAVE_WIFI_AP_ENABLE
int mgos_config_get_wifi_ap_enable(const struct mgos_config *cfg);
int mgos_config_get_default_wifi_ap_enable(void);
static inline int mgos_sys_config_get_wifi_ap_enable(void) { return mgos_config_get_wifi_ap_enable(&mgos_sys_config); }
static inline int mgos_sys_config_get_default_wifi_ap_enable(void) { return mgos_config_get_default_wifi_ap_enable(); }
void mgos_config_set_wifi_ap_enable(struct mgos_config *cfg, int v);
static inline void mgos_sys_config_set_wifi_ap_enable(int v) { mgos_config_set_wifi_ap_enable(&mgos_sys_config, v); }

/* wifi.ap.ssid */
#define MGOS_CONFIG_HAVE_WIFI_AP_SSID
#define MGOS_SYS_CONFIG_HAVE_WIFI_AP_SSID
Expand Down
2 changes: 1 addition & 1 deletion src/test/data/golden/mgos_config.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"wifi":{"sta":{"ssid":"cookadoodadoo","pass":"try less cork"},"ap":{"ssid":"Quote \" me \\\\ please","pass":"","channel":6,"dhcp_end":"192.168.4.200"}},"foo":123,"http":{"enable":false,"port":80},"debug":{"level":1,"dest":"uart1","file_level":"mgos_bar=1","test_d1":2.000000,"test_d2":111.000000,"test_d3":0.000100,"test_f1":0.123000,"test_f2":11.500000,"test_f3":0.000010,"test_ui":4294967295,"empty":{}},"test":{"bar1":{"enable":false,"param1":1111,"inner":{"param2":"p2","param3":3333},"baz":{"bazaar":false}},"bar2":{"enable":false,"param1":2222,"inner":{"param2":"p2","param3":3333},"baz":{"bazaar":true}}}}
{"wifi":{"sta":{"ssid":"cookadoodadoo","pass":"try less cork"},"ap":{"enable":false,"ssid":"Quote \" me \\\\ please","pass":"","channel":6,"dhcp_end":"192.168.4.200"}},"foo":123,"http":{"enable":false,"port":80},"debug":{"level":1,"dest":"uart1","file_level":"mgos_bar=1","test_d1":2.000000,"test_d2":111.000000,"test_d3":0.000100,"test_f1":0.123000,"test_f2":11.500000,"test_f3":0.000010,"test_ui":4294967295,"empty":{}},"test":{"bar1":{"enable":false,"param1":1111,"inner":{"param2":"p2","param3":3333},"baz":{"bazaar":false}},"bar2":{"enable":false,"param1":2222,"inner":{"param2":"p2","param3":3333},"baz":{"bazaar":true}}}}
1 change: 1 addition & 0 deletions src/test/data/golden/mgos_config_pretty.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"pass": "try less cork"
},
"ap": {
"enable": false,
"ssid": "Quote \" me \\\\ please",
"pass": "",
"channel": 6,
Expand Down
Loading

0 comments on commit 4181acf

Please sign in to comment.