1# Expected JSON Checker tool
2
3A tool that cross checks an expected set of JSON entries, by a given index, with
4a given input set of JSON entries. In addition, there's an ability to filter
5expected entries by using logical operations against entries within another file
6contain JSON entries. This filtering functionality on cross checking expected
7entries with a set of input is optional
8
9Expected entries that only want to be found within the input JSON should use a
10value of `{}`. This denotes the value for the given property should be treated
11as a `don't care` and ignored during the cross-check.
12
13## Intention
14
15The intention for this tool's creation was to provide an ability to cross check
16entries within the BMC's enumerated sensor JSON output against an expected set
17of entries for a specific machine. In addition, the expected set of entries are
18different based on specific entries within inventory. So given a dump of a
19machine's enumerated sensor data and inventory data to separate JSON files, an
20expected set of entries that should be contained within the sensor data is
21created for this machine. These JSON files are then fed into this tool to
22determine if all the expected set of entries are found within the sensor data.
23The machine's name was used as the index into the expected JSON to allow the
24same expected JSON file to be used across multiple machines instead of having
25separate expected JSON files per machine(since what's expected will likely be
26different across different machines).
27
28## (OPTIONAL) Filtering
29
30Filters can be used for whether or not a set of entries within the expected JSON
31file should be included when cross checking with the input set of JSON entries.
32This is useful in allowing a single set of expected entries to be used and
33add/remove entries based on some other JSON file's contents.
34
35### Supported logical operations
36
37- \$and : Performs an AND operation on an array with at least two expressions
38  and returns the document that meets all the expressions. i.e.) {"$and":
39  [{"age": 5}, {"name": "Joe"}]}
40- \$or : Performs an OR operation on an array with at least two expressions and
41  returns the documents that meet at least one of the expressions. i.e.) {"$or":
42  [{"age": 4}, {"name": "Joe"}]}
43- \$nor : Performs a NOR operation on an array with at least two expressions and
44  returns the documents that do not meet any of the expressions. i.e.) {"$nor":
45  [{"age": 3}, {"name": "Moe"}]}
46- \$not : Performs a NOT operation on the specified expression and returns the
47  documents that do not meet the expression. i.e.) {"$not": {"age": 4}}
48
49## Example Usage
50
51Expected JSON set of entries for a `witherspoon` index(expected.json):
52
53```json
54{
55  "witherspoon": {
56    "/xyz/openbmc_project/sensors/fan_tach/fan0_0": {
57      "Functional": true,
58      "Target": {},
59      "Value": {}
60    },
61    "/xyz/openbmc_project/sensors/fan_tach/fan0_1": {
62      "Functional": true,
63      "Value": {}
64    },
65    "$op": {
66      "$and": [
67        {
68          "/xyz/openbmc_project/inventory/system/chassis": {
69            "WaterCooled": false
70          }
71        }
72      ],
73      "$input": [
74        {
75          "/xyz/openbmc_project/sensors/fan_tach/fan1_0": {
76            "Functional": true,
77            "Target": {},
78            "Value": {}
79          },
80          "/xyz/openbmc_project/sensors/fan_tach/fan1_1": {
81            "Functional": true,
82            "Value": {}
83          }
84        }
85      ]
86    }
87  }
88}
89```
90
91Input JSON set of entries(input.json):
92
93```json
94{
95  "data": {
96    "/xyz/openbmc_project/sensors/fan_tach/fan0_0": {
97      "CriticalAlarmHigh": false,
98      "CriticalAlarmLow": true,
99      "CriticalHigh": 12076,
100      "CriticalLow": 2974,
101      "Functional": true,
102      "MaxValue": 0,
103      "MinValue": 0,
104      "Scale": 0,
105      "Target": 10500,
106      "Unit": "xyz.openbmc_project.Sensor.Value.Unit.RPMS",
107      "Value": 0
108    },
109    "/xyz/openbmc_project/sensors/fan_tach/fan0_0/chassis": {
110      "endpoints": ["/xyz/openbmc_project/inventory/system/chassis"]
111    },
112    "/xyz/openbmc_project/sensors/fan_tach/fan0_0/inventory": {
113      "endpoints": [
114        "/xyz/openbmc_project/inventory/system/chassis/motherboard/fan0"
115      ]
116    },
117    "/xyz/openbmc_project/sensors/fan_tach/fan0_1": {
118      "CriticalAlarmHigh": false,
119      "CriticalAlarmLow": false,
120      "CriticalHigh": 12076,
121      "CriticalLow": 2974,
122      "Functional": true,
123      "MaxValue": 0,
124      "MinValue": 0,
125      "Scale": 0,
126      "Unit": "xyz.openbmc_project.Sensor.Value.Unit.RPMS",
127      "Value": 3393
128    },
129    "/xyz/openbmc_project/sensors/fan_tach/fan0_1/chassis": {
130      "endpoints": ["/xyz/openbmc_project/inventory/system/chassis"]
131    },
132    "/xyz/openbmc_project/sensors/fan_tach/fan0_1/inventory": {
133      "endpoints": [
134        "/xyz/openbmc_project/inventory/system/chassis/motherboard/fan0"
135      ]
136    },
137    "/xyz/openbmc_project/sensors/fan_tach/fan1_0": {
138      "CriticalAlarmHigh": false,
139      "CriticalAlarmLow": true,
140      "CriticalHigh": 12076,
141      "CriticalLow": 2974,
142      "Functional": true,
143      "MaxValue": 0,
144      "MinValue": 0,
145      "Scale": 0,
146      "Target": 10500,
147      "Unit": "xyz.openbmc_project.Sensor.Value.Unit.RPMS",
148      "Value": 0
149    },
150    "/xyz/openbmc_project/sensors/fan_tach/fan1_0/chassis": {
151      "endpoints": ["/xyz/openbmc_project/inventory/system/chassis"]
152    },
153    "/xyz/openbmc_project/sensors/fan_tach/fan1_0/inventory": {
154      "endpoints": [
155        "/xyz/openbmc_project/inventory/system/chassis/motherboard/fan1"
156      ]
157    },
158    "/xyz/openbmc_project/sensors/fan_tach/fan1_1": {
159      "CriticalAlarmHigh": false,
160      "CriticalAlarmLow": false,
161      "CriticalHigh": 12076,
162      "CriticalLow": 2974,
163      "Functional": true,
164      "MaxValue": 0,
165      "MinValue": 0,
166      "Scale": 0,
167      "Unit": "xyz.openbmc_project.Sensor.Value.Unit.RPMS",
168      "Value": 3409
169    },
170    "/xyz/openbmc_project/sensors/fan_tach/fan1_1/chassis": {
171      "endpoints": ["/xyz/openbmc_project/inventory/system/chassis"]
172    },
173    "/xyz/openbmc_project/sensors/fan_tach/fan1_1/inventory": {
174      "endpoints": [
175        "/xyz/openbmc_project/inventory/system/chassis/motherboard/fan1"
176      ]
177    },
178    "/xyz/openbmc_project/sensors/power/ps0_input_power": {
179      "CriticalAlarmHigh": false,
180      "CriticalAlarmLow": true,
181      "CriticalHigh": 2500000000,
182      "CriticalLow": 0,
183      "Functional": true,
184      "MaxValue": 0,
185      "MinValue": 0,
186      "Scale": -6,
187      "Unit": "xyz.openbmc_project.Sensor.Value.Unit.Watts",
188      "Value": 0,
189      "WarningAlarmHigh": false,
190      "WarningAlarmLow": true,
191      "WarningHigh": 2350000000,
192      "WarningLow": 0
193    },
194    "/xyz/openbmc_project/sensors/power/ps0_input_power/chassis": {
195      "endpoints": ["/xyz/openbmc_project/inventory/system/chassis"]
196    },
197    "/xyz/openbmc_project/sensors/power/ps0_input_power/inventory": {
198      "endpoints": [
199        "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0"
200      ]
201    },
202    "/xyz/openbmc_project/sensors/power/ps1_input_power": {
203      "CriticalAlarmHigh": false,
204      "CriticalAlarmLow": false,
205      "CriticalHigh": 2500000000,
206      "CriticalLow": 0,
207      "Functional": true,
208      "MaxValue": 0,
209      "MinValue": 0,
210      "Scale": -6,
211      "Unit": "xyz.openbmc_project.Sensor.Value.Unit.Watts",
212      "Value": 18000000,
213      "WarningAlarmHigh": false,
214      "WarningAlarmLow": false,
215      "WarningHigh": 2350000000,
216      "WarningLow": 0
217    },
218    "/xyz/openbmc_project/sensors/power/ps1_input_power/chassis": {
219      "endpoints": ["/xyz/openbmc_project/inventory/system/chassis"]
220    },
221    "/xyz/openbmc_project/sensors/power/ps1_input_power/inventory": {
222      "endpoints": [
223        "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1"
224      ]
225    },
226    "/xyz/openbmc_project/sensors/temperature/ambient": {
227      "CriticalAlarmHigh": false,
228      "CriticalAlarmLow": false,
229      "CriticalHigh": 35000,
230      "CriticalLow": 0,
231      "Functional": true,
232      "MaxValue": 0,
233      "MinValue": 0,
234      "Scale": -3,
235      "Unit": "xyz.openbmc_project.Sensor.Value.Unit.DegreesC",
236      "Value": 22420,
237      "WarningAlarmHigh": false,
238      "WarningAlarmLow": false,
239      "WarningHigh": 25000,
240      "WarningLow": 0
241    }
242  },
243  "message": "200 OK",
244  "status": "ok"
245}
246```
247
248Filter JSON set of entries(filter.json):
249
250```json
251{
252  "data": {
253    "/xyz/openbmc_project/inventory/system": {
254      "AssetTag": "",
255      "BuildDate": "",
256      "Cached": false,
257      "FieldReplaceable": false,
258      "Manufacturer": "",
259      "Model": "8335-GTA        ",
260      "PartNumber": "",
261      "Present": true,
262      "PrettyName": "",
263      "SerialNumber": "1234567         "
264    },
265    "/xyz/openbmc_project/inventory/system/chassis": {
266      "AirCooled": true,
267      "Type": "RackMount",
268      "WaterCooled": false
269    },
270    "/xyz/openbmc_project/inventory/system/chassis/activation": {
271      "endpoints": ["/xyz/openbmc_project/software/224cd310"]
272    },
273    "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0": {
274      "BuildDate": "1996-01-01 - 00:00:00",
275      "Cached": false,
276      "FieldReplaceable": true,
277      "Functional": true,
278      "Manufacturer": "IBM",
279      "Model": "",
280      "PartNumber": "02CY211",
281      "Present": true,
282      "PrettyName": "PROCESSOR MODULE",
283      "SerialNumber": "YA1934302447",
284      "Version": "22"
285    },
286    "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core0": {
287      "Associations": [
288        [
289          "sensors",
290          "inventory",
291          "/xyz/openbmc_project/sensors/temperature/p0_core0_temp"
292        ]
293      ],
294      "Functional": true,
295      "Present": true,
296      "PrettyName": ""
297    },
298    "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core1": {
299      "Associations": [
300        [
301          "sensors",
302          "inventory",
303          "/xyz/openbmc_project/sensors/temperature/p0_core1_temp"
304        ]
305      ],
306      "Functional": true,
307      "Present": true,
308      "PrettyName": ""
309    }
310  },
311  "message": "200 OK",
312  "status": "ok"
313}
314```
315
316Invoke the tool(with everything expected found):
317
318```sh
319expectedJsonChecker.py witherspoon expected.json input.json -f filter.json
320```
321
322Invoke the tool(with modified `fan1_0` `Functional` property to `False`):
323
324```sh
325> expectedJsonChecker.py witherspoon expected.json input.json -f filter.json
326NOT FOUND:
327/xyz/openbmc_project/sensors/fan_tach/fan1_0: {u'Functional': False}
328```
329