Skip to content

Commit c6f0358

Browse files
valkolovosJP-Ellis
authored andcommitted
adding http_matcher.feature v3 compatibility test
1 parent 47143aa commit c6f0358

File tree

2 files changed

+223
-1
lines changed

2 files changed

+223
-1
lines changed
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
"""Matching HTTP parts (request or response) feature tests."""
2+
3+
import pickle
4+
import re
5+
import sys
6+
from pathlib import Path
7+
from typing import Generator
8+
9+
import pytest
10+
from pytest_bdd import (
11+
given,
12+
parsers,
13+
scenario,
14+
then,
15+
when,
16+
)
17+
from yarl import URL
18+
19+
from pact.v3 import Pact
20+
from pact.v3.verifier import Verifier
21+
from tests.v3.compatibility_suite.util.interaction_definition import (
22+
InteractionDefinition,
23+
)
24+
from tests.v3.compatibility_suite.util.provider import start_provider
25+
26+
################################################################################
27+
## Scenarios
28+
################################################################################
29+
30+
31+
@pytest.mark.skipif(
32+
sys.platform.startswith("win"),
33+
reason="See pact-foundation/pact-python#639",
34+
)
35+
@scenario(
36+
"definition/features/V3/http_matching.feature",
37+
"Comparing accept headers where the actual has additional parameters",
38+
)
39+
def test_comparing_accept_headers_where_the_actual_has_additional_parameters() -> None:
40+
"""Comparing accept headers where the actual has additional parameters."""
41+
42+
43+
@pytest.mark.skipif(
44+
sys.platform.startswith("win"),
45+
reason="See pact-foundation/pact-python#639",
46+
)
47+
@scenario(
48+
"definition/features/V3/http_matching.feature",
49+
"Comparing accept headers where the actual has is missing a value",
50+
)
51+
def test_comparing_accept_headers_where_the_actual_has_is_missing_a_value() -> None:
52+
"""Comparing accept headers where the actual has is missing a value."""
53+
54+
55+
@pytest.mark.skipif(
56+
sys.platform.startswith("win"),
57+
reason="See pact-foundation/pact-python#639",
58+
)
59+
@scenario(
60+
"definition/features/V3/http_matching.feature",
61+
"Comparing content type headers where the actual has a charset",
62+
)
63+
def test_comparing_content_type_headers_where_the_actual_has_a_charset() -> None:
64+
"""Comparing content type headers where the actual has a charset."""
65+
66+
67+
@pytest.mark.skipif(
68+
sys.platform.startswith("win"),
69+
reason="See pact-foundation/pact-python#639",
70+
)
71+
@scenario(
72+
"definition/features/V3/http_matching.feature",
73+
"Comparing content type headers where the actual has a different charset",
74+
)
75+
def test_comparing_content_type_headers_where_the_actual_has_a_different_charset() -> (
76+
None
77+
):
78+
"""Comparing content type headers where the actual has a different charset."""
79+
80+
81+
@pytest.mark.skipif(
82+
sys.platform.startswith("win"),
83+
reason="See pact-foundation/pact-python#639",
84+
)
85+
@scenario(
86+
"definition/features/V3/http_matching.feature",
87+
"Comparing content type headers where the actual is missing a charset",
88+
)
89+
def test_comparing_content_type_headers_where_the_actual_is_missing_a_charset() -> None:
90+
"""Comparing content type headers where the actual is missing a charset."""
91+
92+
93+
@pytest.mark.skipif(
94+
sys.platform.startswith("win"),
95+
reason="See pact-foundation/pact-python#639",
96+
)
97+
@scenario(
98+
"definition/features/V3/http_matching.feature",
99+
"Comparing content type headers where they have the same charset",
100+
)
101+
def test_comparing_content_type_headers_where_they_have_the_same_charset() -> None:
102+
"""Comparing content type headers where they have the same charset."""
103+
104+
105+
@pytest.mark.skipif(
106+
sys.platform.startswith("win"),
107+
reason="See pact-foundation/pact-python#639",
108+
)
109+
@scenario(
110+
"definition/features/V3/http_matching.feature",
111+
"Comparing content type headers which are equal",
112+
)
113+
def test_comparing_content_type_headers_which_are_equal() -> None:
114+
"""Comparing content type headers which are equal."""
115+
116+
117+
################################################################################
118+
## Given
119+
################################################################################
120+
121+
122+
@given(
123+
parsers.re(
124+
r'a request is received with an? "(?P<name>[^"]+)" header of "(?P<value>[^"]+)"'
125+
)
126+
)
127+
def a_request_is_received_with_header(name: str, value: str, temp_dir: Path) -> None:
128+
"""A request is received with a "content-type" header of "application/json"."""
129+
interaction_definition = InteractionDefinition(method="GET", path="/", type="HTTP")
130+
interaction_definition.response_headers.update({name: value})
131+
with (temp_dir / "interactions.pkl").open("wb") as pkl_file:
132+
pickle.dump([interaction_definition], pkl_file)
133+
134+
135+
@given(
136+
parsers.re(
137+
r'an expected request with an? "(?P<name>[^"]+)" header of "(?P<value>[^"]+)"'
138+
),
139+
)
140+
def an_expected_request_with_header(name: str, value: str, temp_dir: Path) -> None:
141+
"""An expected request with a "content-type" header of "application/json"."""
142+
pact = Pact("consumer", "provider")
143+
pact.with_specification("V3")
144+
interaction_definition = InteractionDefinition(method="GET", path="/", type="HTTP")
145+
interaction_definition.response_headers.update({name: value})
146+
interaction_definition.add_to_pact(pact, name)
147+
(temp_dir / "pacts").mkdir(exist_ok=True, parents=True)
148+
pact.write_file(temp_dir / "pacts")
149+
150+
151+
################################################################################
152+
## When
153+
################################################################################
154+
155+
156+
@when("the request is compared to the expected one", target_fixture="provider_url")
157+
def the_request_is_compared_to_the_expected_one(
158+
temp_dir: Path,
159+
) -> Generator[URL, None, None]:
160+
"""The request is compared to the expected one."""
161+
yield from start_provider(temp_dir)
162+
163+
164+
################################################################################
165+
## Then
166+
################################################################################
167+
168+
169+
@then(
170+
parsers.re("the comparison should(?P<negated>( NOT)?) be OK"),
171+
converters={"negated": lambda x: x == " NOT"},
172+
target_fixture="verifier_result",
173+
)
174+
def the_comparison_should_not_be_ok(
175+
provider_url: URL,
176+
verifier: Verifier,
177+
temp_dir: Path,
178+
negated: bool, # noqa: FBT001
179+
) -> Verifier:
180+
"""The comparison should NOT be OK."""
181+
verifier.set_info("provider", url=provider_url)
182+
verifier.add_transport(
183+
protocol="http",
184+
port=provider_url.port,
185+
path="/",
186+
)
187+
verifier.add_source(temp_dir / "pacts")
188+
if negated:
189+
with pytest.raises(RuntimeError):
190+
verifier.verify()
191+
else:
192+
verifier.verify()
193+
return verifier
194+
195+
196+
@then(
197+
parsers.parse(
198+
'the mismatches will contain a mismatch with error "{mismatch_key}" '
199+
"-> \"Expected header '{header_name}' to have value '{expected_value}' "
200+
"but was '{actual_value}'\""
201+
)
202+
)
203+
def the_mismatches_will_contain_a_mismatch_with_error(
204+
verifier_result: Verifier,
205+
mismatch_key: str,
206+
header_name: str,
207+
expected_value: str,
208+
actual_value: str,
209+
) -> None:
210+
"""Mismatches will contain a mismatch with error."""
211+
expected_value_matcher = re.compile(expected_value)
212+
actual_value_matcher = re.compile(actual_value)
213+
expected_error_matcher = re.compile(
214+
rf"Mismatch with header \'{mismatch_key}\': Expected header \'{header_name}\' "
215+
rf"to have value \'{expected_value}\' but was \'{actual_value}\'"
216+
)
217+
mismatch = verifier_result.results["errors"][0]["mismatch"]["mismatches"][0]
218+
assert mismatch["key"] == mismatch_key
219+
assert mismatch["type"] == "HeaderMismatch"
220+
assert expected_value_matcher.match(mismatch["expected"]) is not None
221+
assert actual_value_matcher.match(mismatch["actual"]) is not None
222+
assert expected_error_matcher.match(mismatch["mismatch"]) is not None

tests/v3/compatibility_suite/util/interaction_definition.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ def add_to_pact( # noqa: C901, PLR0912, PLR0915
576576
interaction, HttpInteraction
577577
), "Response headers require an HTTP interaction"
578578
logger.info("with_headers(%r)", self.response_headers)
579-
interaction.with_headers(self.response_headers.items())
579+
interaction.with_headers(self.response_headers.items(), "Response")
580580

581581
if self.response_body:
582582
assert isinstance(

0 commit comments

Comments
 (0)