Coverage for tests/test_livekit_coverage.py: 97.53%

61 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2026-09-27 04:08 +0000

1"""The LiveKit plugin registry has to stay joinable to the catalog. 

2 

3The coverage page is only worth reading if the join underneath it is sound, and every way it can 

4rot is silent: a provider gets renamed and a covered plugin quietly reads as a gap, a hand-edit 

5drops a `provides` list and the denominator shrinks, a skip reason gets a status nobody renders. 

6None of that fails a normal build, so it is pinned here instead. 

7""" 

8 

9from __future__ import annotations 

10 

11import json 

12from typing import Any, cast 

13 

14import pytest 

15 

16from prices.build_docs import CATEGORIES 

17from prices.livekit_coverage import ( 

18 CAPABILITY_TABS, 

19 OUT_OF_SCOPE, 

20 REGISTRY, 

21 STATUS_LABEL, 

22 build_coverage, 

23 load_registry, 

24 render_coverage_page, 

25) 

26from prices.utils import package_dir 

27 

28RAW, PLUGINS = load_registry() 

29DATA = cast('list[dict[str, Any]]', json.loads((package_dir / 'data.json').read_text())) 

30COVERAGE = build_coverage(PLUGINS, DATA) 

31 

32VALID_KINDS = {'inference', 'unknown'} | set(OUT_OF_SCOPE) 

33 

34 

35def test_registry_is_sorted_and_unique(): 

36 """Sorted by package, matching the house rule for the provider YAMLs, so diffs stay small.""" 

37 packages = [plugin.package for plugin in PLUGINS] 

38 assert packages == sorted(packages), 'plugins in livekit_plugins.json must be sorted by package' 

39 assert len(packages) == len(set(packages)), 'duplicate package in livekit_plugins.json' 

40 

41 

42def test_every_provider_id_resolves(): 

43 """A renamed provider must fail here rather than silently read as an uncovered plugin. 

44 

45 `build_coverage` raises on an unresolved id, so constructing COVERAGE at import time is the 

46 assertion. This test names the failure mode so the traceback is legible. 

47 """ 

48 known = {str(provider.get('id', '')) for provider in DATA} 

49 unresolved = [p.package for p in PLUGINS if p.provider_id is not None and p.provider_id not in known] 

50 assert not unresolved, f'registry names providers that are not in the catalog: {unresolved}' 

51 

52 

53@pytest.mark.parametrize('plugin', PLUGINS, ids=lambda p: p.package) 

54def test_plugin_entry_is_well_formed(plugin: Any): 

55 assert plugin.kind in VALID_KINDS, f'{plugin.package}: unknown kind {plugin.kind!r}' 

56 

57 if plugin.kind in OUT_OF_SCOPE: 

58 # Out-of-scope plugins are not priced by definition, so a price-shaped field on one means 

59 # somebody classified it wrong. 

60 assert not plugin.provides, f'{plugin.package}: out-of-scope plugins must not declare capabilities' 

61 assert plugin.provider_id is None, f'{plugin.package}: out-of-scope plugins must not name a provider' 

62 return 

63 

64 if plugin.kind == 'inference': 64 ↛ 66line 64 didn't jump to line 66 because the condition on line 64 was always true

65 assert plugin.provides, f'{plugin.package}: an inference plugin must declare what it provides' 

66 for capability in plugin.provides: 

67 assert capability in CAPABILITY_TABS, f'{plugin.package}: unknown capability {capability!r}' 

68 

69 # `provider_id` and `status` answer the same question and must not both be set: one says the 

70 # vendor is in the catalog, the other says why it is not. 

71 if plugin.provider_id is not None: 

72 assert plugin.status is None, f'{plugin.package}: has a provider_id, so it needs no status' 

73 elif plugin.status is not None: 73 ↛ exitline 73 didn't return from function 'test_plugin_entry_is_well_formed' because the condition on line 73 was always true

74 assert plugin.status in STATUS_LABEL, f'{plugin.package}: unrenderable status {plugin.status!r}' 

75 

76 

77def test_capability_tabs_are_real_categories(): 

78 """Every capability maps onto docs tabs that actually exist.""" 

79 for capability, tabs in CAPABILITY_TABS.items(): 

80 unknown = set(tabs) - set(CATEGORIES) 

81 assert not unknown, f'capability {capability!r} maps to non-existent tab(s) {unknown}' 

82 

83 

84def test_coverage_is_derived_not_recorded(): 

85 """A plugin counts as priced only when the catalog actually prices that modality. 

86 

87 This is the guard against the mistake the slot model exists to prevent: a vendor priced for 

88 the wrong thing reading as covered. `livekit-plugins-azure` is the live example, priced for 

89 LLM while the plugin calls Azure Speech. 

90 """ 

91 for c in COVERAGE: 

92 for capability in c.priced: 

93 assert set(CAPABILITY_TABS[capability]) & set(c.modalities), ( 

94 f'{c.plugin.package}: {capability} counted as priced but the catalog has no such tab for ' 

95 f'{c.plugin.provider_id}' 

96 ) 

97 for capability in c.unpriced: 

98 assert not (set(CAPABILITY_TABS[capability]) & set(c.modalities)), ( 

99 f'{c.plugin.package}: {capability} counted as unpriced but the catalog prices it' 

100 ) 

101 assert sorted((*c.priced, *c.unpriced)) == sorted(c.plugin.provides), ( 

102 f'{c.plugin.package}: priced + unpriced must partition what the plugin provides' 

103 ) 

104 

105 

106def test_page_is_up_to_date(): 

107 """The committed page matches what the current registry and catalog produce.""" 

108 from prices.livekit_coverage import COVERAGE_PAGE 

109 

110 expected = render_coverage_page(COVERAGE, str(RAW.get('checked', ''))) 

111 assert COVERAGE_PAGE.read_text() == expected, 'docs/livekit-coverage.mdx is stale; run `make livekit-coverage`' 

112 

113 

114def test_registry_records_when_it_was_checked(): 

115 checked = RAW.get('checked') 

116 assert isinstance(checked, str) and checked, f'{REGISTRY.name} must record when the plugin list was read' 

117 assert RAW.get('source_url'), f'{REGISTRY.name} must record where the plugin list came from' 

118 

119 

120def test_status_labels_inline_cleanly(): 

121 """A status label is folded into a comma-joined summary, so it must not contain a comma. 

122 

123 The failure is silent and structural: a label with a comma in it splits into two apparent 

124 entries on the page, the second with no count in front of it, and the numbers stop adding 

125 up to the total the same sentence just quoted. Nothing raises, the page still builds, and 

126 the docs still parse. `non_usd_currency` shipped with a comma and read as 

127 "1 publishes rates, but not in usd" before this test existed. 

128 """ 

129 for status, label in STATUS_LABEL.items(): 

130 assert ',' not in label, ( 

131 f'STATUS_LABEL[{status!r}] contains a comma, which splits the summary line into ' 

132 f'two apparent entries: {label!r}' 

133 ) 

134 assert label and label[0].isupper(), ( 

135 f'STATUS_LABEL[{status!r}] should read as a sentence-case label for the table cell; ' 

136 f'`_inline` lowers the first character for the summary line: {label!r}' 

137 ) 

138 

139 

140def test_inline_preserves_acronyms(): 

141 """`_inline` lowers only the leading character, so a currency code in a label survives.""" 

142 from prices.livekit_coverage import _inline 

143 

144 assert _inline('Publishes rates in a non-USD currency') == 'publishes rates in a non-USD currency' 

145 assert _inline('Not investigated yet') == 'not investigated yet'