Skip to content

Commit 18aeb4e

Browse files
committed
chore(tests): significant refactor of InteractionDefinition
The `InteractionDefinition` class and the way it works with the `Provider` class during testing has been fairly signifcantly refactored. This should hopefully make it clearer and easier to maintaing going forward. Signed-off-by: JP-Ellis <[email protected]>
1 parent 941d6bb commit 18aeb4e

File tree

3 files changed

+392
-193
lines changed

3 files changed

+392
-193
lines changed

tests/v3/compatibility_suite/test_v3_message_producer.py

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import pickle
88
import re
99
from pathlib import Path
10-
from typing import TYPE_CHECKING
10+
from typing import TYPE_CHECKING, Generator
1111

1212
import pytest
1313
from pytest_bdd import (
@@ -24,15 +24,19 @@
2424
)
2525
from tests.v3.compatibility_suite.util.provider import (
2626
a_provider_is_started_that_can_generate_the_message,
27+
a_provider_state_callback_is_configured,
28+
start_provider,
2729
the_provider_state_callback_will_be_called_after_the_verification_is_run,
2830
the_provider_state_callback_will_be_called_before_the_verification_is_run,
2931
the_provider_state_callback_will_receive_a_setup_call,
30-
the_verification_is_run_with_start_context,
32+
the_verification_is_run,
3133
the_verification_results_will_contain_a_error,
3234
the_verification_will_be_successful,
3335
)
3436

3537
if TYPE_CHECKING:
38+
from yarl import URL
39+
3640
from pact.v3.verifier import Verifier
3741

3842
TEST_PACT_FILE_DIRECTORY = Path(Path(__file__).parent / "pacts")
@@ -191,6 +195,7 @@ def test_verifying_multiple_pact_files() -> None:
191195

192196

193197
a_provider_is_started_that_can_generate_the_message()
198+
a_provider_state_callback_is_configured()
194199

195200

196201
@given(
@@ -205,57 +210,63 @@ def a_pact_file_for_is_to_be_verified_with_the_following(
205210
verifier: Verifier,
206211
temp_dir: Path,
207212
name: str,
208-
table: dict[str, str],
213+
table: dict[str, str | dict[str, str]],
209214
) -> None:
210-
"""A Pact file for "basic" is to be verified with the following."""
211-
metadata = {}
212-
if table.get("metadata"):
213-
214-
def _repl(x: str) -> tuple[str, str]:
215-
return (z.replace("JSON: ", "") for z in x.split("="))
216-
217-
metadata = dict(_repl(x) for x in table["metadata"].split("; "))
215+
"""
216+
A Pact file for "basic" is to be verified with the following.
217+
"""
218218
pact = Pact("consumer", "provider")
219219
pact.with_specification("V3")
220+
221+
if "metadata" in table:
222+
assert isinstance(table["metadata"], str)
223+
metadata = {
224+
k: json.loads(v.replace("JSON: ", "")) if v.startswith("JSON: ") else v
225+
for k, _, v in (s.partition("=") for s in table["metadata"].split("; "))
226+
}
227+
table["metadata"] = metadata
228+
220229
interaction_definition = InteractionDefinition(
221-
method="POST",
222-
path=f"/{name}",
223-
metadata=metadata,
224-
response_body=table["body"],
225-
matching_rules=table.get("matching rules"),
226230
type="Async",
231+
description=name,
232+
**table,
227233
)
228234
interaction_definition.add_to_pact(pact, name)
229235
(temp_dir / "pacts").mkdir(exist_ok=True, parents=True)
230236
pact.write_file(temp_dir / "pacts")
231237
verifier.add_source(temp_dir / "pacts")
232238

233239

234-
@given(parsers.parse('a Pact file for "{name}":"{fixture}" is to be verified'))
240+
@given(
241+
parsers.re(
242+
r'a Pact file for "(?P<name>[^"]+)":"(?P<fixture>[^"]+)" is to be verified'
243+
)
244+
)
235245
def a_pact_file_for_is_to_be_verified(
236-
verifier: Verifier, temp_dir: Path, name: str, fixture: str
246+
verifier: Verifier,
247+
temp_dir: Path,
248+
name: str,
249+
fixture: str,
237250
) -> None:
238251
pact = Pact("consumer", "provider")
239252
pact.with_specification("V3")
240253
interaction_definition = InteractionDefinition(
241-
method="POST",
242-
path=f"/{name}",
243-
response_body=fixture,
244254
type="Async",
255+
description=name,
256+
body=fixture,
245257
)
246-
# for plain text message, the mime type needs to be set
247-
if not re.match(r"^(file:|JSON:)", fixture):
248-
interaction_definition.response_body.mime_type = "text/html;charset=utf-8"
249258
interaction_definition.add_to_pact(pact, name)
250259
(temp_dir / "pacts").mkdir(exist_ok=True, parents=True)
251260
pact.write_file(temp_dir / "pacts")
261+
with (temp_dir / "pacts" / "consumer-provider.json").open() as f:
262+
logger.debug("Pact file contents: %s", f.read())
252263
verifier.add_source(temp_dir / "pacts")
253264

254265

255266
@given(
256-
parsers.parse(
257-
'a Pact file for "{name}":"{fixture}" is to be '
258-
'verified with provider state "{provider_state}"'
267+
parsers.re(
268+
r'a Pact file for "(?P<name>[^"]+)":"(?P<fixture>[^"]+)"'
269+
r' is to be verified with provider state "(?P<provider_state>[^"]+)"'
259270
)
260271
)
261272
def a_pact_file_for_is_to_be_verified_with_provider_state(
@@ -269,13 +280,11 @@ def a_pact_file_for_is_to_be_verified_with_provider_state(
269280
pact = Pact("consumer", "provider")
270281
pact.with_specification("V3")
271282
interaction_definition = InteractionDefinition(
272-
method="POST",
273-
path=f"/{name}",
274-
response_body=fixture,
275283
type="Async",
284+
description=name,
285+
body=fixture,
276286
)
277-
states = [InteractionDefinition.State(provider_state)]
278-
interaction_definition.states = states
287+
interaction_definition.states = [InteractionDefinition.State(provider_state)]
279288
interaction_definition.add_to_pact(pact, name)
280289
(temp_dir / "pacts").mkdir(exist_ok=True, parents=True)
281290
pact.write_file(temp_dir / "pacts")
@@ -301,17 +310,21 @@ def a_pact_file_for_is_to_be_verified_with_the_following_metadata(
301310
verifier: Verifier,
302311
name: str,
303312
fixture: str,
304-
metadata: dict[str, str],
313+
metadata: list[dict[str, str]],
305314
) -> None:
306315
"""A Pact file is to be verified with the following metadata."""
307316
pact = Pact("consumer", "provider")
308317
pact.with_specification("V3")
309318
interaction_definition = InteractionDefinition(
310-
method="POST",
311-
path=f"/{name}",
312-
metadata={h["key"]: h["value"].replace("JSON: ", "") for h in metadata},
313-
response_body=fixture,
314319
type="Async",
320+
description=name,
321+
body=fixture,
322+
metadata={
323+
row["key"]: json.loads(row["value"].replace("JSON: ", ""))
324+
if row["value"].startswith("JSON: ")
325+
else row["value"]
326+
for row in metadata
327+
},
315328
)
316329
interaction_definition.add_to_pact(pact, name)
317330
(temp_dir / "pacts").mkdir(exist_ok=True, parents=True)
@@ -327,49 +340,45 @@ def a_pact_file_for_is_to_be_verified_with_the_following_metadata(
327340
re.DOTALL,
328341
),
329342
converters={"metadata": parse_markdown_table},
343+
target_fixture="provider_url",
330344
)
331345
def a_provider_is_started_that_can_generate_the_message_with_the_following_metadata(
332346
temp_dir: Path,
333347
name: str,
334348
fixture: str,
335-
metadata: dict[str, str],
336-
) -> None:
349+
metadata: list[dict[str, str]],
350+
) -> Generator[URL, None, None]:
337351
"""A provider is started that can generate the message with the following metadata.""" # noqa: E501
338-
interaction_definitions = []
352+
interaction_definitions: list[InteractionDefinition] = []
339353
if (temp_dir / "interactions.pkl").exists():
340354
with (temp_dir / "interactions.pkl").open("rb") as pkl_file:
341355
interaction_definitions = pickle.load(pkl_file) # noqa: S301
342356

343-
def parse_metadata_value(value: str) -> str:
344-
return (
345-
json.loads(value.replace("JSON: ", ""))
346-
if value.startswith("JSON: ")
347-
else value
348-
)
349-
350357
interaction_definition = InteractionDefinition(
351-
method="POST",
352-
path=f"/{name}",
353-
metadata={m["key"]: parse_metadata_value(m["value"]) for m in metadata},
354-
response_body=fixture,
355358
type="Async",
359+
description=name,
360+
body=fixture,
361+
metadata={
362+
row["key"]: json.loads(row["value"].replace("JSON: ", ""))
363+
if row["value"].startswith("JSON: ")
364+
else row["value"]
365+
for row in metadata
366+
},
356367
)
357368
interaction_definitions.append(interaction_definition)
369+
358370
with (temp_dir / "interactions.pkl").open("wb") as pkl_file:
359371
pickle.dump(interaction_definitions, pkl_file)
360372

361-
362-
@given("a provider state callback is configured", target_fixture="callback")
363-
def a_provider_state_callback_is_configured() -> None:
364-
"""A provider state callback is configured."""
373+
yield from start_provider(temp_dir)
365374

366375

367376
################################################################################
368377
## When
369378
################################################################################
370379

371380

372-
the_verification_is_run_with_start_context()
381+
the_verification_is_run()
373382

374383

375384
################################################################################

0 commit comments

Comments
 (0)