1
1
import os
2
2
3
3
import pytest as pytest
4
- from pact import Like , MessageConsumer , Provider , Term
5
-
4
+ import json
5
+ from pact .v3 .pact import Pact
6
+ from pact import matchers
7
+ from pathlib import Path
8
+ from typing import (
9
+ TYPE_CHECKING ,
10
+ Any ,
11
+ )
6
12
from src .product .product_service import receive_product_update
13
+ from src .product .product import Products
7
14
8
15
CONSUMER_NAME = "pactflow-example-consumer-python-sns"
9
16
PROVIDER_NAME = os .getenv ("PACT_PROVIDER" , "pactflow-example-provider-js-sns" )
10
17
PACT_DIR = os .path .join (os .path .dirname (os .path .realpath (__file__ )),".." ,".." , "pacts" )
11
18
12
- @pytest .fixture (scope = "session " )
13
- def consumer ():
19
+ @pytest .fixture (scope = "module " )
20
+ def handler ():
14
21
return receive_product_update
15
22
16
-
17
- @pytest .fixture (scope = "session" )
23
+ @pytest .fixture (scope = "module" )
18
24
def pact ():
19
- pact = MessageConsumer (
20
- CONSUMER_NAME ,
21
- ).has_pact_with (
22
- Provider (PROVIDER_NAME ),
23
- pact_dir = PACT_DIR ,
24
- )
25
+ pact_dir = Path (Path (__file__ ).parent .parent .parent / "pacts" )
26
+ pact = Pact (CONSUMER_NAME , PROVIDER_NAME )
27
+ yield pact .with_specification ("V3" )
28
+ pact .write_file (pact_dir , overwrite = True )
29
+
30
+ @pytest .fixture
31
+ def verifier (
32
+ handler ,
33
+ ):
34
+ """
35
+ Verifier function for the Pact.
25
36
26
- yield pact
37
+ This function is passed to the `verify` method of the Pact object. It is
38
+ responsible for taking in the messages (along with the context/metadata)
39
+ and ensuring that the consumer is able to process the message correctly.
40
+
41
+ In our case, we deserialize the message and pass it to our message
42
+ handler for processing.
43
+ """
44
+
45
+ def _verifier (msg : str | bytes | None , context : dict [str , Any ]) -> None :
46
+ assert msg is not None , "Message is None"
47
+ data = json .loads (msg )
48
+ print (
49
+ "Processing message: " ,
50
+ {"input" : msg , "processed_message" : data , "context" : context },
51
+ )
52
+ handler (data )
53
+ yield _verifier
27
54
28
55
@pytest .mark .asyncio
29
- async def test_receive_a_product_update (pact , consumer ):
56
+ async def test_receive_a_product_update (pact , handler , verifier ):
30
57
event = {
31
- "id" : Like ( "some-uuid-1234-5678" ) ,
32
- "type" : Like ( "Product Range" ) ,
33
- "name" : Like ( "Some Product" ) ,
34
- "event" : Term ( matcher = "^(CREATED| UPDATED|DELETED)$" , generate = "UPDATED" )
58
+ "id" : "some-uuid-1234-5678" ,
59
+ "type" : "Product Range" ,
60
+ "name" : "Some Product" ,
61
+ "event" : " UPDATED"
35
62
}
36
63
(
37
64
pact
38
- .expects_to_receive ("a product event update" )
39
- .with_content (event )
40
- .with_metadata ({"contentType" : "application/json" , 'topic' : 'products' })
65
+ .upon_receiving ("a product event update" , "Async" )
66
+ .with_body (json .dumps (event ),
67
+ "application/json" )
68
+ .with_matching_rules (
69
+ {
70
+ "body" : {
71
+ "$.event" : {
72
+ "combine" : "AND" ,
73
+ "matchers" : [
74
+ {
75
+ "match" : "regex" ,
76
+ "regex" : "^(CREATED|UPDATED|DELETED)$"
77
+ }
78
+ ]
79
+ },
80
+ "$.id" : {
81
+ "combine" : "AND" ,
82
+ "matchers" : [
83
+ {
84
+ "match" : "type"
85
+ }
86
+ ]
87
+ },
88
+ "$.name" : {
89
+ "combine" : "AND" ,
90
+ "matchers" : [
91
+ {
92
+ "match" : "type"
93
+ }
94
+ ]
95
+ },
96
+ "$.type" : {
97
+ "combine" : "AND" ,
98
+ "matchers" : [
99
+ {
100
+ "match" : "type"
101
+ }
102
+ ]
103
+ },
104
+ "$.version" : {
105
+ "combine" : "AND" ,
106
+ "matchers" : [
107
+ {
108
+ "match" : "type"
109
+ }
110
+ ]
111
+ }
112
+ }
113
+ }
114
+ )
115
+ .with_metadata ({"topic" : "products" })
41
116
)
42
-
43
- with pact :
44
- await consumer (event )
117
+ pact .verify (verifier , "Async" )
0 commit comments