f607ee7502
AvevaGatewayHistoryLiveGateTests boots the server in-process, wires the production Gateway backend (HistorianBackendRegistry -> GatewayHistorianDataSource) to a real HistorianGateway and drives HistoryRead over a real SDK session: raw (all, paged, reverse, bounds), modified, the ten served aggregates and seven refused ones, AtTime, events (all, 1-event pages, reverse), a missing tag, HistoryServerCapabilities and node metadata, and a HistoryUpdate that must be refused (sandbox-bound node only). Every wire answer is compared with the backend's direct answer; the run is dumped as JSON for cross-SDK and SQL comparison. Skips unless HISTGW_GATEWAY_ENDPOINT and HISTGW_GATEWAY_APIKEY are set; read-only by construction. scripts/validation/aveva-history-801: run/compare instructions, the SDK 1.5.378 baseline port patch (API spelling only), and the diff / SQL / aggregate / histgw-cli comparison scripts. Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi
29 lines
1.7 KiB
Python
29 lines
1.7 KiB
Python
import json, sys, re
|
|
a = json.load(open(sys.argv[1])); b = json.load(open(sys.argv[2]))
|
|
def key(c): return (c['Name'], c['Tag'], c['Window'], c['Path'])
|
|
A = {key(c): c for c in a['Cases']}; B = {key(c): c for c in b['Cases']}
|
|
print(f"A={a['Label']} sdk={a['SdkServerAssembly']} cases={len(A)} failures={len(a['Failures'])}")
|
|
print(f"B={b['Label']} sdk={b['SdkServerAssembly']} cases={len(B)} failures={len(b['Failures'])}")
|
|
only = set(A) ^ set(B)
|
|
if only: print("cases only in one run:", sorted(only, key=str))
|
|
diffs = 0; rows = 0; events = 0; same = 0
|
|
def norm_note(n): return re.sub(r'elapsedMs=\d+', 'elapsedMs=*', n or '')
|
|
for k in sorted(set(A) & set(B), key=str):
|
|
x, y = A[k], B[k]; d = []
|
|
if x['Status'] != y['Status']: d.append(f"status {x['Status']} vs {y['Status']}")
|
|
if norm_note(x['Note']) != norm_note(y['Note']): d.append(f"note {x['Note']} vs {y['Note']}")
|
|
if (x['Attributes'] or {}) != (y['Attributes'] or {}): d.append(f"attrs {x['Attributes']} vs {y['Attributes']}")
|
|
xr, yr = x['Rows'] or [], y['Rows'] or []
|
|
rows += len(xr)
|
|
if len(xr) != len(yr): d.append(f"rows {len(xr)} vs {len(yr)}")
|
|
else:
|
|
for i, (p, q) in enumerate(zip(xr, yr)):
|
|
if (p['V'], p['Status'], p['Src'], p['Srv'] is None) != (q['V'], q['Status'], q['Src'], q['Srv'] is None):
|
|
d.append(f"row[{i}] {p} vs {q}"); break
|
|
xe, ye = x['Events'] or [], y['Events'] or []
|
|
events += len(xe)
|
|
if xe != ye: d.append(f"events {len(xe)} vs {len(ye)}")
|
|
if d: diffs += 1; print("DIFF", k, "; ".join(d)[:500])
|
|
else: same += 1
|
|
print(f"compared {same+diffs} cases: identical={same} differing={diffs}; rows compared={rows}, events compared={events} (ServerTimestamp compared for presence only: it is the read time)")
|