1*edee0a37SEd Tanous /**
2*edee0a37SEd Tanous * Defines utility functions for testing CPER-JSON IR output from the cper-parse library.
3*edee0a37SEd Tanous *
4*edee0a37SEd Tanous * Author: Lawrence.Tang@arm.com
5*edee0a37SEd Tanous **/
6*edee0a37SEd Tanous
7*edee0a37SEd Tanous #include <stdio.h>
8*edee0a37SEd Tanous #include <stdlib.h>
9*edee0a37SEd Tanous #include <string.h>
10*edee0a37SEd Tanous #include "test-utils.h"
11*edee0a37SEd Tanous
12*edee0a37SEd Tanous #include <libcper/BaseTypes.h>
13*edee0a37SEd Tanous #include <libcper/generator/cper-generate.h>
14*edee0a37SEd Tanous
15*edee0a37SEd Tanous #include <jsoncdaccord.h>
16*edee0a37SEd Tanous #include <json.h>
17*edee0a37SEd Tanous #include <libcper/log.h>
18*edee0a37SEd Tanous
19*edee0a37SEd Tanous // Objects that have mutually exclusive fields (and thereforce can't have both
20*edee0a37SEd Tanous // required at the same time) can be added to this list.
21*edee0a37SEd Tanous // Truly optional properties that shouldn't be added to "required" field for
22*edee0a37SEd Tanous // validating the entire schema with validationbits=1
23*edee0a37SEd Tanous // In most cases making sure examples set all valid bits is preferable to adding to this list
24*edee0a37SEd Tanous static const char *optional_props[] = {
25*edee0a37SEd Tanous // Some sections don't parse header correctly?
26*edee0a37SEd Tanous "header",
27*edee0a37SEd Tanous
28*edee0a37SEd Tanous // Each section is optional
29*edee0a37SEd Tanous "GenericProcessor", "Ia32x64Processor", "ArmProcessor", "Memory",
30*edee0a37SEd Tanous "Memory2", "Pcie", "PciBus", "PciComponent", "Firmware", "GenericDmar",
31*edee0a37SEd Tanous "VtdDmar", "IommuDmar", "CcixPer", "CxlProtocol", "CxlComponent",
32*edee0a37SEd Tanous "Nvidia", "Ampere", "Unknown",
33*edee0a37SEd Tanous
34*edee0a37SEd Tanous // CXL? might have a bug?
35*edee0a37SEd Tanous "partitionID",
36*edee0a37SEd Tanous
37*edee0a37SEd Tanous // CXL protocol
38*edee0a37SEd Tanous "capabilityStructure", "deviceSerial",
39*edee0a37SEd Tanous
40*edee0a37SEd Tanous // CXL component
41*edee0a37SEd Tanous "cxlComponentEventLog", "addressSpace", "errorType",
42*edee0a37SEd Tanous "participationType", "timedOut", "level", "operation", "preciseIP",
43*edee0a37SEd Tanous "restartableIP", "overflow", "uncorrected", "transactionType",
44*edee0a37SEd Tanous
45*edee0a37SEd Tanous // PCIe AER
46*edee0a37SEd Tanous "addressSpace", "errorType", "participationType", "timedOut", "level",
47*edee0a37SEd Tanous "operation", "preciseIP", "restartableIP", "overflow", "uncorrected",
48*edee0a37SEd Tanous "transactionType"
49*edee0a37SEd Tanous };
50*edee0a37SEd Tanous
51*edee0a37SEd Tanous //Returns a ready-for-use memory stream containing a CPER record with the given sections inside.
generate_record_memstream(const char ** types,UINT16 num_types,char ** buf,size_t * buf_size,int single_section,GEN_VALID_BITS_TEST_TYPE validBitsType)52*edee0a37SEd Tanous FILE *generate_record_memstream(const char **types, UINT16 num_types,
53*edee0a37SEd Tanous char **buf, size_t *buf_size,
54*edee0a37SEd Tanous int single_section,
55*edee0a37SEd Tanous GEN_VALID_BITS_TEST_TYPE validBitsType)
56*edee0a37SEd Tanous {
57*edee0a37SEd Tanous //Open a memory stream.
58*edee0a37SEd Tanous FILE *stream = open_memstream(buf, buf_size);
59*edee0a37SEd Tanous
60*edee0a37SEd Tanous //Generate a section to the stream, close & return.
61*edee0a37SEd Tanous if (!single_section) {
62*edee0a37SEd Tanous generate_cper_record((char **)(types), num_types, stream,
63*edee0a37SEd Tanous validBitsType);
64*edee0a37SEd Tanous } else {
65*edee0a37SEd Tanous generate_single_section_record((char *)(types[0]), stream,
66*edee0a37SEd Tanous validBitsType);
67*edee0a37SEd Tanous }
68*edee0a37SEd Tanous fclose(stream);
69*edee0a37SEd Tanous
70*edee0a37SEd Tanous //Return fmemopen() buffer for reading.
71*edee0a37SEd Tanous return fmemopen(*buf, *buf_size, "r");
72*edee0a37SEd Tanous }
73*edee0a37SEd Tanous
iterate_make_required_props(json_object * jsonSchema,int all_valid_bits)74*edee0a37SEd Tanous int iterate_make_required_props(json_object *jsonSchema, int all_valid_bits)
75*edee0a37SEd Tanous {
76*edee0a37SEd Tanous //properties
77*edee0a37SEd Tanous json_object *properties =
78*edee0a37SEd Tanous json_object_object_get(jsonSchema, "properties");
79*edee0a37SEd Tanous
80*edee0a37SEd Tanous if (properties != NULL) {
81*edee0a37SEd Tanous json_object *requrired_arr = json_object_new_array();
82*edee0a37SEd Tanous
83*edee0a37SEd Tanous json_object_object_foreach(properties, property_name,
84*edee0a37SEd Tanous property_value)
85*edee0a37SEd Tanous {
86*edee0a37SEd Tanous (void)property_value;
87*edee0a37SEd Tanous int add_to_required = 1;
88*edee0a37SEd Tanous size_t num = sizeof(optional_props) /
89*edee0a37SEd Tanous sizeof(optional_props[0]);
90*edee0a37SEd Tanous for (size_t i = 0; i < num; i++) {
91*edee0a37SEd Tanous if (strcmp(optional_props[i], property_name) ==
92*edee0a37SEd Tanous 0) {
93*edee0a37SEd Tanous add_to_required = 0;
94*edee0a37SEd Tanous break;
95*edee0a37SEd Tanous }
96*edee0a37SEd Tanous }
97*edee0a37SEd Tanous
98*edee0a37SEd Tanous if (add_to_required) {
99*edee0a37SEd Tanous //Add to list if property is not optional
100*edee0a37SEd Tanous json_object_array_add(
101*edee0a37SEd Tanous requrired_arr,
102*edee0a37SEd Tanous json_object_new_string(property_name));
103*edee0a37SEd Tanous }
104*edee0a37SEd Tanous }
105*edee0a37SEd Tanous
106*edee0a37SEd Tanous json_object_object_foreach(properties, property_name2,
107*edee0a37SEd Tanous property_value2)
108*edee0a37SEd Tanous {
109*edee0a37SEd Tanous (void)property_name2;
110*edee0a37SEd Tanous if (iterate_make_required_props(property_value2,
111*edee0a37SEd Tanous all_valid_bits) < 0) {
112*edee0a37SEd Tanous json_object_put(requrired_arr);
113*edee0a37SEd Tanous return -1;
114*edee0a37SEd Tanous }
115*edee0a37SEd Tanous }
116*edee0a37SEd Tanous
117*edee0a37SEd Tanous if (all_valid_bits) {
118*edee0a37SEd Tanous json_object_object_add(jsonSchema, "required",
119*edee0a37SEd Tanous requrired_arr);
120*edee0a37SEd Tanous } else {
121*edee0a37SEd Tanous json_object_put(requrired_arr);
122*edee0a37SEd Tanous }
123*edee0a37SEd Tanous }
124*edee0a37SEd Tanous
125*edee0a37SEd Tanous // ref
126*edee0a37SEd Tanous json_object *ref = json_object_object_get(jsonSchema, "$ref");
127*edee0a37SEd Tanous if (ref != NULL) {
128*edee0a37SEd Tanous const char *ref_str = json_object_get_string(ref);
129*edee0a37SEd Tanous if (ref_str != NULL) {
130*edee0a37SEd Tanous if (strlen(ref_str) < 1) {
131*edee0a37SEd Tanous cper_print_log("Failed seek filepath: %s\n",
132*edee0a37SEd Tanous ref_str);
133*edee0a37SEd Tanous return -1;
134*edee0a37SEd Tanous }
135*edee0a37SEd Tanous size_t size =
136*edee0a37SEd Tanous strlen(LIBCPER_JSON_SPEC) + strlen(ref_str);
137*edee0a37SEd Tanous char *path = (char *)malloc(size);
138*edee0a37SEd Tanous int n = snprintf(path, size, "%s%s", LIBCPER_JSON_SPEC,
139*edee0a37SEd Tanous ref_str + 1);
140*edee0a37SEd Tanous if (n != (int)size - 1) {
141*edee0a37SEd Tanous cper_print_log("Failed concat filepath: %s\n",
142*edee0a37SEd Tanous ref_str);
143*edee0a37SEd Tanous free(path);
144*edee0a37SEd Tanous return -1;
145*edee0a37SEd Tanous }
146*edee0a37SEd Tanous json_object *ref_obj = json_object_from_file(path);
147*edee0a37SEd Tanous free(path);
148*edee0a37SEd Tanous if (ref_obj == NULL) {
149*edee0a37SEd Tanous cper_print_log("Failed to parse file: %s\n",
150*edee0a37SEd Tanous ref_str);
151*edee0a37SEd Tanous return -1;
152*edee0a37SEd Tanous }
153*edee0a37SEd Tanous
154*edee0a37SEd Tanous if (iterate_make_required_props(ref_obj,
155*edee0a37SEd Tanous all_valid_bits) < 0) {
156*edee0a37SEd Tanous json_object_put(ref_obj);
157*edee0a37SEd Tanous return -1;
158*edee0a37SEd Tanous }
159*edee0a37SEd Tanous
160*edee0a37SEd Tanous json_object_object_foreach(ref_obj, key, val)
161*edee0a37SEd Tanous {
162*edee0a37SEd Tanous json_object_object_add(jsonSchema, key,
163*edee0a37SEd Tanous json_object_get(val));
164*edee0a37SEd Tanous }
165*edee0a37SEd Tanous json_object_object_del(jsonSchema, "$ref");
166*edee0a37SEd Tanous
167*edee0a37SEd Tanous json_object_put(ref_obj);
168*edee0a37SEd Tanous }
169*edee0a37SEd Tanous }
170*edee0a37SEd Tanous
171*edee0a37SEd Tanous //oneOf
172*edee0a37SEd Tanous const json_object *oneOf = json_object_object_get(jsonSchema, "oneOf");
173*edee0a37SEd Tanous if (oneOf != NULL) {
174*edee0a37SEd Tanous size_t num_elements = json_object_array_length(oneOf);
175*edee0a37SEd Tanous
176*edee0a37SEd Tanous for (size_t i = 0; i < num_elements; i++) {
177*edee0a37SEd Tanous json_object *obj = json_object_array_get_idx(oneOf, i);
178*edee0a37SEd Tanous if (iterate_make_required_props(obj, all_valid_bits) <
179*edee0a37SEd Tanous 0) {
180*edee0a37SEd Tanous return -1;
181*edee0a37SEd Tanous }
182*edee0a37SEd Tanous }
183*edee0a37SEd Tanous }
184*edee0a37SEd Tanous
185*edee0a37SEd Tanous //items
186*edee0a37SEd Tanous const json_object *items = json_object_object_get(jsonSchema, "items");
187*edee0a37SEd Tanous if (items != NULL) {
188*edee0a37SEd Tanous json_object_object_foreach(items, key, val)
189*edee0a37SEd Tanous {
190*edee0a37SEd Tanous (void)key;
191*edee0a37SEd Tanous if (iterate_make_required_props(val, all_valid_bits) <
192*edee0a37SEd Tanous 0) {
193*edee0a37SEd Tanous return -1;
194*edee0a37SEd Tanous }
195*edee0a37SEd Tanous }
196*edee0a37SEd Tanous }
197*edee0a37SEd Tanous
198*edee0a37SEd Tanous return 1;
199*edee0a37SEd Tanous }
200*edee0a37SEd Tanous
schema_validate_from_file(json_object * to_test,int single_section,int all_valid_bits)201*edee0a37SEd Tanous int schema_validate_from_file(json_object *to_test, int single_section,
202*edee0a37SEd Tanous int all_valid_bits)
203*edee0a37SEd Tanous {
204*edee0a37SEd Tanous const char *schema_file;
205*edee0a37SEd Tanous if (single_section) {
206*edee0a37SEd Tanous schema_file = "cper-json-section-log.json";
207*edee0a37SEd Tanous } else {
208*edee0a37SEd Tanous schema_file = "cper-json-full-log.json";
209*edee0a37SEd Tanous }
210*edee0a37SEd Tanous int size = strlen(schema_file) + 1 + strlen(LIBCPER_JSON_SPEC) + 1;
211*edee0a37SEd Tanous char *schema_path = malloc(size);
212*edee0a37SEd Tanous snprintf(schema_path, size, "%s/%s", LIBCPER_JSON_SPEC, schema_file);
213*edee0a37SEd Tanous
214*edee0a37SEd Tanous json_object *schema = json_object_from_file(schema_path);
215*edee0a37SEd Tanous
216*edee0a37SEd Tanous if (schema == NULL) {
217*edee0a37SEd Tanous cper_print_log("Could not parse schema file: %s", schema_path);
218*edee0a37SEd Tanous free(schema_path);
219*edee0a37SEd Tanous return 0;
220*edee0a37SEd Tanous }
221*edee0a37SEd Tanous
222*edee0a37SEd Tanous if (iterate_make_required_props(schema, all_valid_bits) < 0) {
223*edee0a37SEd Tanous cper_print_log("Failed to make required props\n");
224*edee0a37SEd Tanous json_object_put(schema);
225*edee0a37SEd Tanous free(schema_path);
226*edee0a37SEd Tanous return -1;
227*edee0a37SEd Tanous }
228*edee0a37SEd Tanous
229*edee0a37SEd Tanous int err = jdac_validate(to_test, schema);
230*edee0a37SEd Tanous if (err == JDAC_ERR_VALID) {
231*edee0a37SEd Tanous cper_print_log("validation ok\n");
232*edee0a37SEd Tanous json_object_put(schema);
233*edee0a37SEd Tanous free(schema_path);
234*edee0a37SEd Tanous return 1;
235*edee0a37SEd Tanous }
236*edee0a37SEd Tanous
237*edee0a37SEd Tanous cper_print_log("validate failed %d: %s\n", err, jdac_errorstr(err));
238*edee0a37SEd Tanous
239*edee0a37SEd Tanous cper_print_log("schema: \n%s\n",
240*edee0a37SEd Tanous json_object_to_json_string_ext(schema,
241*edee0a37SEd Tanous JSON_C_TO_STRING_PRETTY));
242*edee0a37SEd Tanous cper_print_log("to_test: \n%s\n",
243*edee0a37SEd Tanous json_object_to_json_string_ext(to_test,
244*edee0a37SEd Tanous JSON_C_TO_STRING_PRETTY));
245*edee0a37SEd Tanous json_object_put(schema);
246*edee0a37SEd Tanous free(schema_path);
247*edee0a37SEd Tanous return 0;
248*edee0a37SEd Tanous }
249