1 /** 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 24 static 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. 52 FILE *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 74 int 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 201 int 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 } 249