blob: e4d79d33fa8069bdcf4cdab438e8d5fdeb13efa4 [file] [log] [blame]
Lawrence Tangd34f2b12022-07-19 15:36:31 +01001/**
2 * Defines utility functions for testing CPER-JSON IR output from the cper-parse library.
Ed Tanousfedd4572024-07-12 13:56:00 -07003 *
Lawrence Tangd34f2b12022-07-19 15:36:31 +01004 * Author: Lawrence.Tang@arm.com
5 **/
6
John Chungf8fc7052024-05-03 20:05:29 +08007#include <cstdio>
8#include <cstdlib>
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08009#include <fstream>
Ed Tanousa3663052025-03-16 12:54:36 -070010#include <map>
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080011#include <filesystem>
Ed Tanousa3663052025-03-16 12:54:36 -070012#include <vector>
13#include <algorithm>
Lawrence Tangd34f2b12022-07-19 15:36:31 +010014#include "test-utils.hpp"
Karthik Rajagopalan255bd812024-09-06 14:36:34 -070015
Thu Nguyene42fb482024-10-15 14:43:11 +000016#include <libcper/BaseTypes.h>
17#include <libcper/generator/cper-generate.h>
Lawrence Tangd34f2b12022-07-19 15:36:31 +010018
Ed Tanousa3663052025-03-16 12:54:36 -070019extern "C" {
20#include <jsoncdaccord.h>
21#include <json.h>
22#include <libcper/log.h>
23}
24
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080025namespace fs = std::filesystem;
26
Ed Tanous2c4d7b62025-03-16 12:22:02 -070027// Objects that have mutually exclusive fields (and thereforce can't have both
28// required at the same time) can be added to this list.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080029// Truly optional properties that shouldn't be added to "required" field for
30// validating the entire schema with validationbits=1
Ed Tanousa3663052025-03-16 12:54:36 -070031// In most cases making sure examples set all valid bits is preferable to adding to this list
32const static std::vector<std::string> optional_props = {
33 { // Some sections don't parse header correctly?
34 "header",
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080035
Ed Tanousa3663052025-03-16 12:54:36 -070036 // Each section is optional
37 "GenericProcessor", "Ia32x64Processor", "ArmProcessor", "Memory",
38 "Memory2", "Pcie", "PciBus", "PciComponent", "Firmware",
39 "GenericDmar", "VtdDmar", "IommuDmar", "CcixPer", "CxlProtocol",
40 "CxlComponent", "Nvidia", "Ampere", "Unknown",
41
42 // CXL? might have a bug?
43 "partitionID",
44
45 // CXL protocol
46 "capabilityStructure", "deviceSerial",
47
48 // CXL component
49 "cxlComponentEventLog", "addressSpace", "errorType",
50 "participationType", "timedOut", "level", "operation", "preciseIP",
51 "restartableIP", "overflow", "uncorrected", "transactionType",
52
53 // PCIe AER
54 "addressSpace", "errorType", "participationType", "timedOut", "level",
55 "operation", "preciseIP", "restartableIP", "overflow", "uncorrected",
56 "transactionType" }
57};
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080058
Lawrence Tangd34f2b12022-07-19 15:36:31 +010059//Returns a ready-for-use memory stream containing a CPER record with the given sections inside.
Lawrence Tange407b4c2022-07-21 13:54:01 +010060FILE *generate_record_memstream(const char **types, UINT16 num_types,
John Chungf8fc7052024-05-03 20:05:29 +080061 char **buf, size_t *buf_size,
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080062 int single_section,
63 GEN_VALID_BITS_TEST_TYPE validBitsType)
Lawrence Tangd34f2b12022-07-19 15:36:31 +010064{
Lawrence Tange407b4c2022-07-21 13:54:01 +010065 //Open a memory stream.
66 FILE *stream = open_memstream(buf, buf_size);
Lawrence Tangd34f2b12022-07-19 15:36:31 +010067
Lawrence Tange407b4c2022-07-21 13:54:01 +010068 //Generate a section to the stream, close & return.
John Chungf8fc7052024-05-03 20:05:29 +080069 if (!single_section) {
70 generate_cper_record(const_cast<char **>(types), num_types,
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080071 stream, validBitsType);
John Chungf8fc7052024-05-03 20:05:29 +080072 } else {
73 generate_single_section_record(const_cast<char *>(types[0]),
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080074 stream, validBitsType);
John Chungf8fc7052024-05-03 20:05:29 +080075 }
Lawrence Tange407b4c2022-07-21 13:54:01 +010076 fclose(stream);
Lawrence Tangd34f2b12022-07-19 15:36:31 +010077
Lawrence Tange407b4c2022-07-21 13:54:01 +010078 //Return fmemopen() buffer for reading.
79 return fmemopen(*buf, *buf_size, "r");
John Chungf8fc7052024-05-03 20:05:29 +080080}
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080081
Ed Tanousa3663052025-03-16 12:54:36 -070082int iterate_make_required_props(json_object *jsonSchema, bool all_valid_bits)
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080083{
Ed Tanousa3663052025-03-16 12:54:36 -070084 //properties
85 json_object *properties =
86 json_object_object_get(jsonSchema, "properties");
87
88 if (properties != nullptr) {
89 json_object *requrired_arr = json_object_new_array();
90
91 json_object_object_foreach(properties, property_name,
92 property_value)
93 {
94 bool add_to_required = true;
95 const auto it_find_opt_prop = std::ranges::find(
96 optional_props, property_name);
97 if (it_find_opt_prop != optional_props.end()) {
98 add_to_required = false;
99 }
100
101 if (add_to_required) {
102 //Add to list if property is not optional
103 json_object_array_add(
104 requrired_arr,
105 json_object_new_string(property_name));
106 }
107 }
108
109 json_object_object_foreach(properties, property_name2,
110 property_value2)
111 {
112 (void)property_name2;
113 if (iterate_make_required_props(property_value2,
114 all_valid_bits) < 0) {
115 return -1;
116 }
117 }
118
119 if (all_valid_bits) {
120 json_object_object_add(jsonSchema, "required",
121 requrired_arr);
122 }
123 //json_object_put(requrired_arr);
124 }
125
126 // ref
127 json_object *ref = json_object_object_get(jsonSchema, "$ref");
128 if (ref != nullptr) {
129 const char *ref_str = json_object_get_string(ref);
130 if (ref_str != nullptr) {
131 std::string ref_path = LIBCPER_JSON_SPEC;
132 // remove the leading .
133 ref_path += std::string(ref_str).substr(1);
134 json_object *ref_obj =
135 json_object_from_file(ref_path.c_str());
136 if (ref_obj == nullptr) {
137 printf("Failed to parse file: %s\n",
138 ref_path.c_str());
139 return -1;
140 }
141
142 if (iterate_make_required_props(ref_obj,
143 all_valid_bits) < 0) {
144 json_object_put(ref_obj);
145 return -1;
146 }
147
148 json_object_object_foreach(ref_obj, key, val)
149 {
150 json_object_object_add(jsonSchema, key,
151 json_object_get(val));
152 }
153 json_object_object_del(jsonSchema, "$ref");
154
155 json_object_put(ref_obj);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800156 }
157 }
Ed Tanousa3663052025-03-16 12:54:36 -0700158
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800159 //oneOf
Ed Tanousa3663052025-03-16 12:54:36 -0700160 const json_object *oneOf = json_object_object_get(jsonSchema, "oneOf");
161 if (oneOf != nullptr) {
162 size_t num_elements = json_object_array_length(oneOf);
163
164 for (size_t i = 0; i < num_elements; i++) {
165 json_object *obj = json_object_array_get_idx(oneOf, i);
166 if (iterate_make_required_props(obj, all_valid_bits) <
167 0) {
168 return -1;
169 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800170 }
171 }
172
173 //items
Ed Tanousa3663052025-03-16 12:54:36 -0700174 const json_object *items = json_object_object_get(jsonSchema, "items");
175 if (items != nullptr) {
176 json_object_object_foreach(items, key, val)
177 {
178 (void)key;
179 if (iterate_make_required_props(val, all_valid_bits) <
180 0) {
181 return -1;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800182 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800183 }
184 }
185
Ed Tanousa3663052025-03-16 12:54:36 -0700186 return 1;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800187}
188
Ed Tanousa3663052025-03-16 12:54:36 -0700189int schema_validate_from_file(json_object *to_test, int single_section,
190 int all_valid_bits)
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800191{
Ed Tanousa3663052025-03-16 12:54:36 -0700192 const char *schema_file;
Ed Tanousd6b62632025-03-14 15:30:07 -0700193 if (single_section) {
Ed Tanousa3663052025-03-16 12:54:36 -0700194 schema_file = "cper-json-section-log.json";
Ed Tanousd6b62632025-03-14 15:30:07 -0700195 } else {
Ed Tanousa3663052025-03-16 12:54:36 -0700196 schema_file = "cper-json-full-log.json";
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800197 }
198
Ed Tanousa3663052025-03-16 12:54:36 -0700199 std::string schema_path = LIBCPER_JSON_SPEC;
200 schema_path += "/";
201 schema_path += schema_file;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800202
Ed Tanousa3663052025-03-16 12:54:36 -0700203 json_object *schema = json_object_from_file(schema_path.c_str());
204 if (schema == nullptr) {
205 cper_print_log("Could not parse schema file: %s", schema_file);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800206 return 0;
207 }
208
Ed Tanousa3663052025-03-16 12:54:36 -0700209 if (iterate_make_required_props(schema, all_valid_bits) < 0) {
210 printf("Failed to make required props\n");
211 json_object_put(schema);
212 return -1;
213 }
214
215 int err = jdac_validate(to_test, schema);
216 if (err == JDAC_ERR_VALID) {
217 printf("validation ok\n");
218 json_object_put(schema);
219 return 1;
220 }
221 printf("validate failed %d: %s\n", err, jdac_errorstr(err));
222
223 printf("schema: \n%s\n",
224 json_object_to_json_string_ext(schema, JSON_C_TO_STRING_PRETTY));
225 printf("to_test: \n%s\n", json_object_to_json_string_ext(
226 to_test, JSON_C_TO_STRING_PRETTY));
227 json_object_put(schema);
228 return 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800229}