Files
harness-tools/services/dictate/tests/test_config.py
T

121 lines
4.6 KiB
Python

from __future__ import annotations
import json
import os
from pathlib import Path
import tempfile
import unittest
from unittest.mock import patch
from pi_dictate_service.config import (
ConfigError,
CredentialError,
load_config,
parse_config,
provider_keywords,
read_credential,
)
from pi_dictate_service.recorder import audio_level_window_bytes, pw_record_command
class ConfigTests(unittest.TestCase):
def test_recorder_supports_both_backend_sample_rates(self) -> None:
self.assertEqual(pw_record_command(16_000)[5], "16000")
self.assertEqual(pw_record_command(24_000)[5], "24000")
self.assertEqual(audio_level_window_bytes(24_000), 4_800)
def test_rejects_unknown_selected_fields_and_invalid_backend_values(self) -> None:
for invalid_backend in ([], {}, 1, True, None):
with self.subTest(backend=invalid_backend):
with self.assertRaisesRegex(ConfigError, "backend must be"):
parse_config({"version": 1, "backend": invalid_backend})
base = {
"version": 1,
"backend": "openai",
"openai": {
"model": "gpt-live-transcribe",
"apiKeyFile": "~/.config/pi-dictate/credentials/openai-api-key",
"termsPath": "/tmp/terms",
},
}
with patch.dict(os.environ, {"HOME": "/tmp/pi-dictate-test"}):
invalid = {**base, "openai": {**base["openai"], "endpoint": "https://bad"}}
with self.assertRaises(ConfigError):
parse_config(invalid)
with self.assertRaises(ConfigError):
parse_config({**base, "version": 2})
configured = parse_config(
{**base, "openai": {**base["openai"], "delay": "low"}}
)
self.assertEqual(configured.openai.delay, "low")
with self.assertRaises(ConfigError):
parse_config({**base, "openai": {**base["openai"], "delay": "fast"}})
with self.assertRaises(ConfigError):
parse_config({**base, "openai": {**base["openai"], "termsPath": "relative/terms"}})
def test_reads_only_one_trailing_newline_from_a_private_credential(self) -> None:
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / "key"
path.write_text("secret\n", encoding="utf-8")
path.chmod(0o600)
self.assertEqual(read_credential(path), "secret")
path.chmod(0o640)
with self.assertRaises(CredentialError):
read_credential(path)
path.chmod(0o600)
path.write_text("secret\nextra", encoding="utf-8")
with self.assertRaises(CredentialError):
read_credential(path)
def test_rejects_a_credential_reached_through_a_symlinked_directory(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
actual = root / "actual"
actual.mkdir()
key = actual / "key"
key.write_text("secret", encoding="utf-8")
key.chmod(0o600)
linked = root / "credentials"
linked.symlink_to(actual, target_is_directory=True)
with self.assertRaisesRegex(CredentialError, "ancestry"):
read_credential(linked / "key")
def test_config_file_is_regular_private_and_provider_terms_reject_cr(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
config_path = root / "config.json"
config_path.write_text(
json.dumps(
{
"version": 1,
"backend": "local",
"local": {
"adapter": "nemo-parakeet",
"modelPath": "/tmp/model.nemo",
"modelSha256": "0" * 64,
"termsPath": "/tmp/terms",
"boostAlpha": 1.0,
},
}
),
encoding="utf-8",
)
config_path.chmod(0o600)
self.assertEqual(load_config(config_path).backend, "local")
terms = root / "terms"
terms.write_bytes(b"bad\rterm")
with self.assertRaises(ConfigError):
provider_keywords(terms)
terms.write_bytes(b"safe\nbad\x00term\n")
with self.assertRaises(ConfigError):
provider_keywords(terms)
if __name__ == "__main__":
unittest.main()