blob: 8c0176fa19578c4d82dde053ffc0ebaed76cba49 [file] [log] [blame]
Radek Krejci038db942021-02-09 16:18:47 +01001/*
2 * @file test_yangdata.c
3 * @author: Radek Krejci <rkrejci@cesnet.cz>
4 * @brief unit tests for yang-data extensions support
5 *
6 * Copyright (c) 2019-2021 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14#define _UTEST_MAIN_
15#include "utests.h"
16
17#include "libyang.h"
18
19static int
20setup(void **state)
21{
22 UTEST_SETUP;
23
24 assert_int_equal(LY_SUCCESS, ly_ctx_set_searchdir(UTEST_LYCTX, TESTS_DIR_MODULES_YANG));
25 assert_non_null(ly_ctx_load_module(UTEST_LYCTX, "ietf-restconf", "2017-01-26", NULL));
26
27 return 0;
28}
29
30static void
31test_schema(void **state)
32{
Michal Vasko4de7d072021-07-09 09:13:18 +020033 struct lys_module *mod;
Radek Krejci038db942021-02-09 16:18:47 +010034 struct lysc_ext_instance *e;
35 char *printed = NULL;
36 const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
37 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
38 "feature x;"
39 "rc:yang-data template { container x { list l { leaf x { type string;}} leaf y {if-feature x; type string; config false;}}}}";
40 const char *info = "module a {\n"
41 " namespace \"urn:tests:extensions:yangdata:a\";\n"
42 " prefix self;\n\n"
43 " ietf-restconf:yang-data \"template\" {\n"
44 " container x {\n"
45 " status current;\n"
46 " list l {\n" /* no key */
47 " min-elements 0;\n"
48 " max-elements 4294967295;\n"
Michal Vaskoe78faec2021-04-08 17:24:43 +020049 " ordered-by user;\n"
Radek Krejci038db942021-02-09 16:18:47 +010050 " status current;\n"
51 " leaf x {\n"
52 " type string;\n"
53 " status current;\n"
54 " }\n"
55 " }\n"
56 " leaf y {\n" /* config and if-feature are ignored */
57 " type string;\n"
58 " status current;\n"
59 " }\n"
60 " }\n"
61 " }\n"
62 "}\n";
63
64 /* valid data */
65 assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
66 assert_non_null(e = mod->compiled->exts);
67 assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
68 assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
69 assert_string_equal(printed, info);
70 free(printed);
71
72 data = "module c {yang-version 1.1; namespace urn:tests:extensions:yangdata:c; prefix self;"
73 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
74 "grouping g { choice ch { container a {presence a; config false;} container b {presence b; config true;}}}"
75 "rc:yang-data template { uses g;}}";
76 info = "module c {\n"
77 " namespace \"urn:tests:extensions:yangdata:c\";\n"
78 " prefix self;\n\n"
79 " ietf-restconf:yang-data \"template\" {\n"
80 " choice ch {\n"
81 " status current;\n"
82 " case a {\n"
83 " status current;\n"
84 " container a {\n"
85 " presence \"true\";\n"
86 " status current;\n"
87 " }\n"
88 " }\n"
89 " case b {\n"
90 " status current;\n"
91 " container b {\n"
92 " presence \"true\";\n"
93 " status current;\n"
94 " }\n"
95 " }\n"
96 " }\n"
97 " }\n"
98 "}\n";
99 assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
100 assert_non_null(e = mod->compiled->exts);
101 assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 1);
102 assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
103 assert_string_equal(printed, info);
104 free(printed);
105
106 /* ignored - valid with warning */
107 data = "module b {yang-version 1.1; namespace urn:tests:extensions:yangdata:b; prefix self;"
108 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
109 "container b { rc:yang-data template { container x { leaf x {type string;}}}}}";
110 info = "module b {\n"
111 " namespace \"urn:tests:extensions:yangdata:b\";\n"
Radek Krejciaa14a0c2020-09-04 11:16:47 +0200112 " prefix self;\n\n"
Radek Krejci038db942021-02-09 16:18:47 +0100113 " container b {\n"
114 " config true;\n"
115 " status current;\n"
116 " }\n"
117 "}\n";
118 assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
119 assert_null(mod->compiled->exts);
Michal Vasko193dacd2022-10-13 08:43:05 +0200120 CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
Radek Krejciab430862021-03-02 20:13:40 +0100121 "Extension rc:yang-data is ignored since it appears as a non top-level statement in \"container\" statement.",
Radek Krejci038db942021-02-09 16:18:47 +0100122 "/b:b/{extension='rc:yang-data'}/template");
123 assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
124 assert_string_equal(printed, info);
125 free(printed);
126
127 /* sama data nodes name, but not conflicting */
128 data = "module d {yang-version 1.1; namespace urn:tests:extensions:yangdata:d; prefix self;"
129 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
130 "leaf d { type string;}"
131 "rc:yang-data template1 { container d {presence d;}}"
132 "rc:yang-data template2 { container d {presence d;}}}";
133 info = "module d {\n"
134 " namespace \"urn:tests:extensions:yangdata:d\";\n"
135 " prefix self;\n\n"
136 " ietf-restconf:yang-data \"template1\" {\n"
137 " container d {\n"
138 " presence \"true\";\n"
139 " status current;\n"
140 " }\n"
141 " }\n"
142 " ietf-restconf:yang-data \"template2\" {\n"
143 " container d {\n"
144 " presence \"true\";\n"
145 " status current;\n"
146 " }\n"
Radek Krejciaa14a0c2020-09-04 11:16:47 +0200147 " }\n\n"
Radek Krejci038db942021-02-09 16:18:47 +0100148 " leaf d {\n"
149 " type string;\n"
150 " config true;\n"
151 " status current;\n"
152 " }\n"
153 "}\n";
154 assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, &mod));
155 assert_non_null(e = mod->compiled->exts);
156 assert_int_equal(LY_ARRAY_COUNT(mod->compiled->exts), 2);
157 assert_int_equal(LY_SUCCESS, lys_print_mem(&printed, mod, LYS_OUT_YANG_COMPILED, 0));
158 assert_string_equal(printed, info);
159 free(printed);
160}
161
162static void
163test_schema_invalid(void **state)
164{
165 const char *data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
166 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
167 "rc:yang-data template { leaf x {type string;}}}";
168
169 assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
170 CHECK_LOG_CTX("Invalid keyword \"leaf\" as a child of \"rc:yang-data template\" extension instance.",
171 "/a:{extension='rc:yang-data'}/template");
172
173 data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
174 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
175 "rc:yang-data template { choice x { leaf x {type string;}}}}";
176 assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
Michal Vasko193dacd2022-10-13 08:43:05 +0200177 CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
Radek Krejci038db942021-02-09 16:18:47 +0100178 "Extension rc:yang-data is instantiated with leaf top level data node (inside a choice), "
179 "but only a single container data node is allowed.",
180 "/a:{extension='rc:yang-data'}/template");
181
182 data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
183 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
184 "rc:yang-data template { choice x { case x { container z {presence ppp;} leaf x {type string;}}}}}";
185 assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
Michal Vasko193dacd2022-10-13 08:43:05 +0200186 CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
Radek Krejci038db942021-02-09 16:18:47 +0100187 "Extension rc:yang-data is instantiated with multiple top level data nodes (inside a single choice's case), "
188 "but only a single container data node is allowed.",
189 "/a:{extension='rc:yang-data'}/template");
190
191 data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
192 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
193 "rc:yang-data template { container x { leaf x {type string;}} container y { leaf y {type string;}}}}";
194 assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
Michal Vasko193dacd2022-10-13 08:43:05 +0200195 CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
Radek Krejci038db942021-02-09 16:18:47 +0100196 "Extension rc:yang-data is instantiated with multiple top level data nodes, "
197 "but only a single container data node is allowed.",
198 "/a:{extension='rc:yang-data'}/template");
199
200 data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
201 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
202 "rc:yang-data template;}";
203 assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
Michal Vasko193dacd2022-10-13 08:43:05 +0200204 CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
Radek Krejci038db942021-02-09 16:18:47 +0100205 "Extension rc:yang-data is instantiated without any top level data node, "
206 "but exactly one container data node is expected.",
207 "/a:{extension='rc:yang-data'}/template");
208
209 data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
210 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
211 "rc:yang-data { container x { leaf x {type string;}}}}";
212 assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
Michal Vasko193dacd2022-10-13 08:43:05 +0200213 CHECK_LOG_CTX("Parsing module \"a\" failed.", NULL,
214 "Extension instance \"rc:yang-data\" missing argument element \"name\".", NULL);
Radek Krejci038db942021-02-09 16:18:47 +0100215
216 data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
217 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
218 "rc:yang-data template { container x { leaf x {type string;}}}"
219 "rc:yang-data template { container y { leaf y {type string;}}}}";
220 assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
Michal Vasko193dacd2022-10-13 08:43:05 +0200221 CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
Radek Krejci038db942021-02-09 16:18:47 +0100222 "Extension rc:yang-data is instantiated multiple times.",
223 "/a:{extension='rc:yang-data'}/template");
224
225 data = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
226 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
227 "grouping t { leaf-list x {type string;}}"
228 "rc:yang-data template { uses t;}}";
229 assert_int_equal(LY_EVALID, lys_parse_mem(UTEST_LYCTX, data, LYS_IN_YANG, NULL));
Michal Vasko193dacd2022-10-13 08:43:05 +0200230 CHECK_LOG_CTX("Ext plugin \"ly2 yang-data v1\": "
Radek Krejci038db942021-02-09 16:18:47 +0100231 "Extension rc:yang-data is instantiated with leaf-list top level data node, "
232 "but only a single container data node is allowed.",
233 "/a:{extension='rc:yang-data'}/template");
234}
235
Radek Krejcif16e2542021-02-17 15:39:23 +0100236static void
Michal Vasko8cc3f662022-03-29 11:25:51 +0200237test_parse(void **state)
Radek Krejcif16e2542021-02-17 15:39:23 +0100238{
Michal Vasko4de7d072021-07-09 09:13:18 +0200239 struct lys_module *mod;
Radek Krejcif16e2542021-02-17 15:39:23 +0100240 struct lysc_ext_instance *e;
241 struct lyd_node *tree = NULL;
242 const char *schema = "module a {yang-version 1.1; namespace urn:tests:extensions:yangdata:a; prefix self;"
243 "import ietf-restconf {revision-date 2017-01-26; prefix rc;}"
244 "rc:yang-data template { container x { leaf x { type string;}}}}";
245 const char *xml = "<x xmlns=\"urn:tests:extensions:yangdata:a\"><x>test</x></x>";
246 const char *json = "{\"a:x\":{\"x\":\"test\"}}";
247
248 assert_int_equal(LY_SUCCESS, lys_parse_mem(UTEST_LYCTX, schema, LYS_IN_YANG, &mod));
249 assert_non_null(e = mod->compiled->exts);
250
251 assert_int_equal(LY_SUCCESS, ly_in_new_memory(xml, &UTEST_IN));
252 assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_XML, 0, LYD_VALIDATE_PRESENT, &tree));
253 CHECK_LYD_STRING_PARAM(tree, xml, LYD_XML, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
254 lyd_free_all(tree);
255
256 ly_in_memory(UTEST_IN, json);
257 assert_int_equal(LY_SUCCESS, lyd_parse_ext_data(e, NULL, UTEST_IN, LYD_JSON, 0, LYD_VALIDATE_PRESENT, &tree));
258 CHECK_LYD_STRING_PARAM(tree, json, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS);
259
260 lyd_free_all(tree);
261}
262
Radek Krejci038db942021-02-09 16:18:47 +0100263int
264main(void)
265{
266 const struct CMUnitTest tests[] = {
267 UTEST(test_schema, setup),
268 UTEST(test_schema_invalid, setup),
Michal Vasko8cc3f662022-03-29 11:25:51 +0200269 UTEST(test_parse, setup),
Radek Krejci038db942021-02-09 16:18:47 +0100270 };
271
272 return cmocka_run_group_tests(tests, NULL, NULL);
273}