main
py 99 lines 2.97 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 """Check the watermarking goldens still reproduce."""
5
6 import dataclasses
7 from pathlib import Path
8
9 import pytest
10
11 from tests.watermarking.golden_candidates import (
12 DETECTOR_FACTORIES,
13 GOLDEN_FLOAT_RTOL,
14 WATERMARK_CONFIG_FIELDS,
15 WATERMARKING_CANDIDATES,
16 compare_golden,
17 configured_algorithm_prf_combinations,
18 configured_algorithms,
19 read_goldens,
20 routing_boundary,
21 validate_golden_guards,
22 )
23 from vllm.config.watermarking import WatermarkConfig
24
25 GOLDENS_PATH = Path(__file__).with_name("watermarking_goldens.json")
26
27 CANDIDATES_BY_ID = {candidate.id: candidate for candidate in WATERMARKING_CANDIDATES}
28
29 NEGATIVE_CANDIDATE_ID = "gumbel-philox-key42-cw4-wrong-key"
30
31
32 @pytest.fixture(scope="module")
33 def goldens() -> dict[str, dict]:
34 return read_goldens(GOLDENS_PATH)
35
36
37 def test_goldens_cover_every_candidate(goldens: dict[str, dict]):
38 candidate_ids = set(CANDIDATES_BY_ID)
39
40 assert len(candidate_ids) == len(WATERMARKING_CANDIDATES)
41 assert set(goldens) == candidate_ids, "golden contract does not match candidates"
42 candidate_combinations = {
43 (candidate.scheme, candidate.prf) for candidate in WATERMARKING_CANDIDATES
44 }
45 assert candidate_combinations == configured_algorithm_prf_combinations()
46 assert set(DETECTOR_FACTORIES) == configured_algorithms()
47
48
49 def test_golden_fixture_guards(goldens: dict[str, dict]):
50 validate_golden_guards(goldens)
51
52
53 def test_resolved_records_every_watermark_config_field():
54 assert {field.name for field in dataclasses.fields(WatermarkConfig)} == (
55 set(WATERMARK_CONFIG_FIELDS) | {"key"}
56 )
57
58
59 @pytest.mark.parametrize(
60 "candidate",
61 WATERMARKING_CANDIDATES,
62 ids=lambda candidate: candidate.id,
63 )
64 def test_watermarking_candidate_golden(candidate, goldens: dict[str, dict]):
65 differences = compare_golden(candidate, goldens[candidate.id])
66
67 assert not differences, "\n".join(
68 [
69 f"{candidate.id}: golden drift "
70 f"(tolerance {GOLDEN_FLOAT_RTOL:g} on score and p_value)",
71 *differences,
72 ]
73 )
74
75
76 def test_negative_row_is_not_watermarked(goldens: dict[str, dict]):
77 candidate = CANDIDATES_BY_ID[NEGATIVE_CANDIDATE_ID]
78
79 assert candidate.detection_key != candidate.key
80 assert goldens[NEGATIVE_CANDIDATE_ID]["detection"]["is_watermarked"] is False
81
82
83 @pytest.mark.parametrize(
84 "candidate",
85 [
86 candidate
87 for candidate in WATERMARKING_CANDIDATES
88 if candidate.scheme == "dual_key_gumbel"
89 and 0 < candidate.scheme_config.generation_alpha < 1
90 ],
91 ids=lambda candidate: candidate.id,
92 )
93 def test_routing_sequence_resolves_alpha(candidate):
94 alpha = candidate.scheme_config.generation_alpha
95 uniforms = candidate.fixture.routing_uniforms
96 boundary = routing_boundary(alpha)
97 share = sum(1 for uniform in uniforms if boundary <= uniform) / len(uniforms)
98
99 assert abs(share - alpha) <= 0.03