"""Tests for the HTTP layer and file listing in web.py.""" import io import web def test_listing_is_ordered_by_the_filename_clock_not_mtime(tmp_path, write_wav): # mtime is the last write (≈ the end of the recording) and drifts from the # name on any copy or round-trip. Here the older recording is touched last. import os early, late = tmp_path / '20260523_080000.wav', tmp_path / '20260523_090000.wav' write_wav(early) write_wav(late) os.utime(late, (1000, 1000)) # newest recording, oldest mtime names = [f['name'] for f in web.list_files(str(tmp_path))] assert names == ['20260523_090000.wav', '20260523_080000.wav'] # --------------------------------------------------------------------------- # /api/clip error handling # --------------------------------------------------------------------------- class _OfflineHandler(web._Handler): """A _Handler with no socket, for driving handler methods directly.""" def __init__(self, recordings_dir): self.recordings_dir = str(recordings_dir) self.analyses_dir = str(recordings_dir) self.command = 'GET' # _send skips the body on HEAD self.wfile = io.BytesIO() self.close_connection = False self.codes = [] def send_response(self, code): self.codes.append(code) def send_header(self, key, value): pass def end_headers(self): pass def test_clip_failure_after_headers_closes_connection_instead_of_writing_json(tmp_path, write_wav): # Once the audio headers are out, an error body would be a second response # on a keep-alive connection that already promised audio/wav plus an exact # Content-Length — desyncing every later request on that connection. write_wav(tmp_path / 'rec.wav') h = _OfflineHandler(tmp_path) def boom(path, start, end): h._send_clip_headers(b'HDR', 10, 1, 2) raise RuntimeError('decode exploded') h._clip_wav = boom h._api_clip({'file': ['rec.wav'], 'start': ['0'], 'end': ['1']}) assert h.close_connection is True assert h.codes == [200] # no second status line assert b'error' not in h.wfile.getvalue() # no JSON body def test_clip_failure_before_headers_still_reports_json(tmp_path, write_wav): write_wav(tmp_path / 'rec.wav') h = _OfflineHandler(tmp_path) def boom(path, start, end): raise RuntimeError('could not open') h._clip_wav = boom h._api_clip({'file': ['rec.wav'], 'start': ['0'], 'end': ['1']}) assert h.close_connection is False assert h.codes == [500] assert b'could not open' in h.wfile.getvalue()