test(harness): reorganize regression suites and preserve contract coverage

This commit is contained in:
2026-10-16 07:24:49 +00:00
parent b6f87db623
commit 33709ab873
108 changed files with 5869 additions and 5328 deletions
@@ -0,0 +1,213 @@
import copy
import importlib.util
import json
import os
import subprocess
import sys
import tempfile
import time
import unittest
from pathlib import Path
from harness.tests._support.paths import ROOT
SCRIPT = ROOT / 'harness/agents/review/skills/gitea-code-review/scripts/native_review.py'
def load(path, name):
spec = importlib.util.spec_from_file_location(name, path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
from harness.tests._support.review import (
FakeAPI,
FakeLease,
plan_fixture,
publication_fixture,
support,
)
class TestNativeTransport(unittest.TestCase):
def module(self):
self.assertTrue(SCRIPT.is_file(), 'shared native review adapter is missing')
m = load(SCRIPT, 'native_review_test_' + str(id(self)))
# Every test gets a private registry root; production has no test-only
# root override, so isolate through the journal module seam.
private_root = tempfile.TemporaryDirectory()
self.addCleanup(private_root.cleanup)
root = Path(private_root.name) / 'native-review-journals'
m._journal.root_for = lambda anchor, root=root: root
return m
@staticmethod
def canonical(m, plan):
return m.canonical_journal_path(plan)
def test_api_adapter_empty_comments_without_header_verifies_publication(self):
m = self.module()
p, before, after, exact = publication_fixture()
def collect(source, comments=None, headers=None):
calls = []
def request(path, payload=None):
self.assertIsNone(payload, 'readback regression must be GET-only')
calls.append(path)
direct = {'/user': p['reviewer'], '/users/gitea-spec-agent': p['spec_reviewer'],
'/repos/acme/repo': source['repository'],
'/repos/acme/repo/issues/3': source['issue'],
'/repos/acme/repo/pulls/7': source['pr'],
'/repos/acme/repo/pulls/7/reviews/10': exact}
if path in direct:
return direct[path], {}, 200
from urllib.parse import urlsplit
endpoint = urlsplit(path).path
for name, suffix in [('files', '/pulls/7/files'), ('commits', '/pulls/7/commits'),
('reviews', '/pulls/7/reviews'), ('issue_comments', '/issues/3/comments'),
('pr_comments', '/issues/7/comments'),
('statuses', '/statuses/' + p['target']['head'])]:
if endpoint == '/repos/acme/repo' + suffix:
return copy.deepcopy(source[name]), {'X-Total-Count': str(len(source[name]))}, 200
if '/reviews/' in endpoint and endpoint.endswith('/comments'):
return ([] if comments is None else comments), ({} if headers is None else headers), 200
raise AssertionError('unexpected synthetic readback endpoint')
api = m.ApiAdapter(request, origin=m.ORIGIN + '/api/v1',
credential_source='$HERMES_HOME/.env:GITEA_TOKEN')
snapshot = api.snapshot(p['target'])
self.assertEqual(calls[0], '/user')
self.assertTrue(any('/reviews/' in path and '/comments?' in path for path in calls))
return api, snapshot
_, initial = collect(before)
api, final = collect(after)
m.validate_snapshot(p, initial)
m.validate_snapshot(p, final)
authoritative = api.read_review(p['target'], exact['id'])
m.verify_publication(p, initial, final, authoritative)
for snapshot in [initial, final]:
for rid in snapshot['review_comments']:
self.assertEqual(snapshot['review_comments'][rid], [])
self.assertEqual(snapshot['pagination']['review_comments_' + rid],
[{'page': 1, 'count': 0, 'declared_total': None, 'link': None}])
# The admitted control above distinguishes intentional rejection from
# a broken fixture. Missing headers never waive the review count or
# the complete-collection and newly-created no-inline-comment checks.
for count in [1, None, True]:
with self.subTest(count=count):
drift = copy.deepcopy(final)
drift['reviews'][-1]['comments_count'] = count
with self.assertRaisesRegex(m.ValidationError, 'review comment cardinality mismatch'):
m.validate_snapshot(p, drift)
_, unexpected = collect(after, comments=[{'id': 999}])
for review in unexpected['reviews']:
review['comments_count'] = 1
m.validate_snapshot(p, unexpected)
exact_with_inline = copy.deepcopy(authoritative)
exact_with_inline['comments_count'] = 1
with self.assertRaisesRegex(m.ValidationError, 'exact review binding mismatch'):
m.verify_publication(p, initial, unexpected, exact_with_inline)
with self.assertRaisesRegex(m.ValidationError, 'truncated pages'):
collect(after, headers={'X-Total-Count': '1'})
truncated = copy.deepcopy(final)
truncated['pagination']['review_comments_' + str(exact['id'])][0]['link'] = '<next>; rel=next'
with self.assertRaisesRegex(m.ValidationError, 'truncated pagination'):
m.validate_snapshot(p, truncated)
with self.assertRaisesRegex(m.ValidationError, 'truncated pagination'):
m.check_pages([{'id': i + 1} for i in range(50)],
[{'page': 1, 'count': 50, 'declared_total': None, 'link': None}])
def test_api_adapter_checks_identity_first_and_collects_all_pages(self):
m = self.module()
self.assertTrue(callable(getattr(m, 'ApiAdapter', None)), 'REST bridge is missing')
p, before, after, exact = publication_fixture()
calls = []
def request(path, payload=None):
calls.append((path, payload))
if path == '/user': return p['reviewer'], {}, 200
if path == '/users/gitea-spec-agent': return p['spec_reviewer'], {}, 200
if path == '/repos/acme/repo': return before['repository'], {}, 200
if path == '/repos/acme/repo/issues/3': return before['issue'], {}, 200
if path == '/repos/acme/repo/pulls/7': return before['pr'], {}, 200
from urllib.parse import parse_qs, urlsplit
parsed = urlsplit(path); page = int(parse_qs(parsed.query).get('page', ['1'])[0])
for name, suffix in [('files', '/pulls/7/files'), ('commits', '/pulls/7/commits'),
('reviews', '/pulls/7/reviews'), ('issue_comments', '/issues/3/comments'),
('pr_comments', '/issues/7/comments'), ('statuses', '/statuses/' + p['target']['head'])]:
if parsed.path == '/repos/acme/repo' + suffix:
if name == 'reviews' and payload is not None: return exact, {}, 201
return before[name], {'x-total-count': str(len(before[name]))}, 200
if parsed.path.endswith('/comments'): return [], {'X-Total-Count': '0'}, 200
raise AssertionError('unexpected request')
adapter = m.ApiAdapter(request, origin=m.ORIGIN + '/api/v1',
credential_source='$HERMES_HOME/.env:GITEA_TOKEN')
snapshot = adapter.snapshot(p['target'])
m.validate_snapshot(p, snapshot)
self.assertEqual(calls[0][0], '/user')
self.assertEqual(adapter.create_review(p['target'], m.build_payload(p))['id'], 10)
self.assertEqual(calls[-1][1]['comments'], [])
with self.assertRaises(m.ValidationError):
m.ApiAdapter(request, origin='https://other.test/api/v1', credential_source='unknown')
def test_transport_origin_credential_source_and_exception_text_are_guarded(self):
m = self.module()
with self.assertRaises(m.ValidationError): m.ApiAdapter(lambda *args: None, origin='https://other/api/v1', credential_source='$HERMES_HOME/.env:GITEA_TOKEN')
with self.assertRaises(m.ValidationError): m.ApiAdapter(lambda *args: None, origin=m.ORIGIN + '/api/v1', credential_source='other-profile')
def bad(*args): raise TimeoutError('DO_NOT_ECHO_TRANSPORT_SECRET')
api = m.ApiAdapter(bad, origin=m.ORIGIN + '/api/v1', credential_source='$HERMES_HOME/.env:GITEA_TOKEN')
with self.assertRaises(m.ValidationError) as raised: api.identity()
self.assertNotIn('DO_NOT_ECHO_TRANSPORT_SECRET', str(raised.exception))
self.assertTrue(raised.exception.__suppress_context__)
def test_live_rest_bridge_over_loopback_publishes_once_then_no_ops(self):
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.request import Request, urlopen
m = self.module(); p, before, after, exact = publication_fixture()
after['reviews'][0].update(official=False, dismissed=True, updated_at=exact['submitted_at'])
after['commits'][0]['files'].reverse()
state = {'posted': False, 'posts': 0}
class Handler(BaseHTTPRequestHandler):
def log_message(self, *args): pass
def respond(self, value, status=200, total=None):
body = json.dumps(value, ensure_ascii=False).encode()
self.send_response(status); self.send_header('Content-Type', 'application/json')
if total is not None: self.send_header('X-Total-Count', str(total))
self.send_header('Content-Length', str(len(body))); self.end_headers(); self.wfile.write(body)
def do_GET(self):
path = self.path.split('?')[0]; s = after if state['posted'] else before
if path == '/user': return self.respond(p['reviewer'])
if path == '/users/gitea-spec-agent': return self.respond(p['spec_reviewer'])
prefix = '/repos/acme/repo'; pull = prefix + '/pulls/7'
singles = {prefix: s['repository'], prefix + '/issues/3': s['issue'], pull: s['pr']}
if path in singles: return self.respond(singles[path])
if path == pull + '/reviews/10': return self.respond(exact)
arrays = {pull + '/files': s['files'], pull + '/commits': s['commits'], pull + '/reviews': s['reviews'],
prefix + '/issues/3/comments': s['issue_comments'], prefix + '/issues/7/comments': s['pr_comments'],
prefix + '/statuses/' + p['target']['head']: s['statuses']}
for rid, comments in s['review_comments'].items(): arrays[pull + '/reviews/' + rid + '/comments'] = comments
if path in arrays: return self.respond(arrays[path], total=len(arrays[path]))
self.respond({}, 404)
def do_POST(self):
self.server.received = json.loads(self.rfile.read(int(self.headers['Content-Length'])))
state['posts'] += 1; state['posted'] = True
self.respond(exact, 201)
server = HTTPServer(('127.0.0.1', 0), Handler)
thread = threading.Thread(target=server.serve_forever, daemon=True); thread.start()
def request(path, payload=None):
wire = None if payload is None else json.dumps(payload, ensure_ascii=False).encode()
req = Request('http://127.0.0.1:' + str(server.server_port) + path, data=wire,
headers={'Content-Type': 'application/json'})
with urlopen(req, timeout=5) as response:
return json.loads(response.read()), dict(response.headers), response.status
try:
# Controlled local fixture transport, not a real role credential/origin assertion.
api = m.ApiAdapter(request, origin=m.ORIGIN + '/api/v1', credential_source='$HERMES_HOME/.env:GITEA_TOKEN')
baseline = api.snapshot(p['target'])
with tempfile.TemporaryDirectory() as td:
result = m.publish(p, baseline, api, FakeLease(), self.canonical(m, p), declaration={'mode': 'none'})
self.assertEqual(result['mode'], 'created'); self.assertEqual(result['projected_review_ids'], [8])
self.assertTrue(result['commit_file_order_normalized'])
second = m.publish(p, baseline, api, FakeLease(), self.canonical(m, p), declaration={'mode': 'none'})
self.assertEqual(second['mode'], 'no_op'); self.assertFalse(second['wrote'])
self.assertEqual(state['posts'], 1); self.assertEqual(server.received, m.build_payload(p))
finally:
server.shutdown(); server.server_close(); thread.join(timeout=5)
self.assertFalse(thread.is_alive())
if __name__ == '__main__':
unittest.main()