Coverage for suhteita/store.py: 95.35%
39 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-03 13:32:01 +00:00
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-03 13:32:01 +00:00
1"""Provide a simple JSON store for event records."""
3import copy
4import datetime as dti
5import json
6import pathlib
7from typing import Dict, Union, no_type_check
9from suhteita import ENCODING, NODE_INDICATOR, STORE, TS_FORMAT_PAYLOADS, Clocking
11TS_FORMAT_STORE = '%Y%m%dT%H%M%S.%fZ'
12Context = Dict[str, Union[str, dti.datetime]]
15@no_type_check
16class Store:
17 @no_type_check
18 def __init__(self, context: Context, setup: object, folder_path: Union[pathlib.Path, str] = STORE):
19 self.store = pathlib.Path(folder_path)
20 self.identity = context['identity']
21 self.start_time = context['start_time']
22 self.end_ts = None
23 self.total_secs = 0.0
24 self.node_indicator = NODE_INDICATOR
25 self.store.mkdir(parents=True, exist_ok=True)
26 self.db_name = f'{self.identity}-{self.start_time.strftime(TS_FORMAT_STORE)}-{self.node_indicator}.json'
27 self.rank = 0
28 self.db = {
29 '_meta': {
30 'scenario': context.get('scenario', 'unknown'),
31 'identity': self.identity,
32 'node_indicator': str(self.node_indicator),
33 'target': context.get('target', 'unknown'),
34 'mode': context.get('mode', 'unknown'),
35 'project': context.get('project', 'unknown'),
36 'db_name': self.db_name,
37 'db_path': str(self.store / self.db_name),
38 'start_ts': self.start_time.strftime(TS_FORMAT_PAYLOADS),
39 'total_secs': self.total_secs,
40 'end_ts': self.end_ts,
41 'has_failures_declared': None,
42 'has_failures_detected': None,
43 'setup': copy.deepcopy(setup.__dict__),
44 },
45 'events': [],
46 }
48 @no_type_check
49 def add(self, label: str, ok: bool, clk: Clocking, comment: str = ''):
50 self.rank += 1
51 self.db['events'].append(
52 {
53 'rank': self.rank,
54 'label': label,
55 'ok': ok,
56 'start_ts': clk[0],
57 'duration_usecs': clk[1],
58 'end_ts': clk[2],
59 'comment': comment,
60 }
61 )
63 @no_type_check
64 def dump(self, end_time: dti.datetime, has_failures: bool = False):
65 self.end_time = end_time
66 self.db['_meta']['end_ts'] = self.end_time.strftime(TS_FORMAT_PAYLOADS)
67 self.db['_meta']['total_secs'] = (self.end_time - self.start_time).total_seconds()
68 self.db['_meta']['has_failures_declared'] = has_failures
69 detect_failures = False
70 for event in self.db['events']:
71 if not event['ok']: 71 ↛ 72line 71 didn't jump to line 72 because the condition on line 71 was never true
72 detect_failures = True
73 self.db['_meta']['has_failures_detected'] = detect_failures
74 with open(self.store / self.db_name, 'wt', encoding=ENCODING) as handle:
75 json.dump(self.db, handle)