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