# Copyright 2023 Greptime Team # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import importlib.util import json import sys import tempfile import unittest from pathlib import Path SCRIPT = Path(__file__).parents[2] / '.github/scripts/agent-observability-summary.py' sys.path.insert(0, str(SCRIPT.parent)) spec = importlib.util.spec_from_file_location('observability_summary', SCRIPT) summary = importlib.util.module_from_spec(spec) spec.loader.exec_module(summary) class SummaryTest(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.addCleanup(self.tmp.cleanup) self.root = Path(self.tmp.name) def write(self, path, data): path = self.root / path path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(data)) return path def measured(self, target, value=10, **overrides): data = dict(passed=True, contract_sha256='same', data_profile={'id':'S'}, query_window={'start':0,'end':1}, warmup_runs=1, measured_runs=5, per_query=[dict(query_id='Q01', p50_ms=value, p95_ms=value, p99_ms=value, result_fingerprint='same-result', success=5, errors=0, timeouts=0)]) data.update(overrides) return self.write(f'{target}-1/{target}-1/measured-summary.json', data) def test_duration_units_and_invalid(self): for value, expected in [(0.25,'250 µs'), (12.3,'12.3 ms'), (1250,'1.25 s'), (130000,'2m 10s'), (3661000,'1h 1m 1s'), (None,'—'), (-1,'—'), (float('nan'),'—')]: with self.subTest(value=value): self.assertEqual(summary.duration(value), expected) def test_relative_latency_and_measurement_counts(self): self.measured('greptimedb') self.measured('clickhouse',20) self.measured('victorialogs',5) text = summary.benchmark(self.root, summary.TARGETS) self.assertIn('| Q01 | Scan / index | greptimedb | 10.0 ms | — |', text) self.assertEqual(text.count('+100.0%'),3) self.assertEqual(text.count('-50.0%'),3) self.assertEqual(text.count('| 5 | 0 | 0 |'),3) def test_missing_failed_and_incompatible_baseline(self): self.measured('clickhouse',20) for base in [None, {'passed':False}, {'data_profile':{'id':'M'}}]: if base is not None: self.measured('greptimedb', **base) text = summary.benchmark(self.root, summary.TARGETS) self.assertNotIn('+100.0%',text) self.assertEqual(summary.delta(10,0),'—') self.assertEqual(summary.delta(None,10),'—') def test_mismatched_results_have_no_comparison(self): self.measured('greptimedb') path = self.measured('clickhouse', 20) data = json.loads(path.read_text()) data['per_query'][0]['result_fingerprint'] = 'different-result' path.write_text(json.dumps(data)) self.assertNotIn('+100.0%', summary.benchmark(self.root, summary.TARGETS)) def test_collapsed_explain_escaped_and_bounded(self): self.write('greptimedb-1/greptimedb-1/query-plans.json', {'capability':{'state':'supported'}, 'queries':[ {'query_name':'Q01','state':'passed','explain_sql':'SELECT ', 'raw_response':'