xref: /openbmc/libcper/tests/test-utils.c (revision edee0a37f42ce7c9444b3b470b0c5df407caf629)
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