pact 0.1.28 → 0.1.35
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +5 -5
- data/README.md +52 -53
- data/example/zoo-app/Gemfile +15 -0
- data/example/zoo-app/Gemfile.lock +77 -0
- data/example/zoo-app/lib/zoo_app/animal_service_client.rb +36 -0
- data/example/zoo-app/lib/zoo_app/models/alligator.rb +15 -0
- data/example/zoo-app/spec/pacts/zoo_app-animal_service.json +100 -0
- data/example/zoo-app/spec/service_providers/animal_service_spec.rb +92 -0
- data/example/zoo-app/spec/service_providers/pact_helper.rb +11 -0
- data/example/zoo-app/spec/spec_helper.rb +8 -0
- data/lib/pact/consumer/configuration_dsl.rb +2 -0
- data/lib/pact/consumer/consumer_contract_builder.rb +13 -12
- data/lib/pact/consumer/dsl.rb +51 -2
- data/lib/pact/consumer/interaction.rb +15 -12
- data/lib/pact/consumer/mock_service.rb +31 -9
- data/lib/pact/consumer/mock_service_client.rb +47 -0
- data/lib/pact/consumer/rspec.rb +2 -1
- data/lib/pact/consumer_contract.rb +2 -1
- data/lib/pact/matchers/matchers.rb +59 -18
- data/lib/pact/producer/dsl.rb +61 -0
- data/lib/pact/producer/producer_state.rb +7 -0
- data/lib/pact/producer/rspec.rb +2 -0
- data/lib/pact/provider/rspec.rb +1 -0
- data/lib/pact/request.rb +42 -6
- data/lib/pact/verification_task.rb +2 -5
- data/lib/pact/version.rb +1 -1
- data/spec/features/consumption_spec.rb +56 -18
- data/spec/features/production_spec.rb +7 -16
- data/spec/integration/pact/consumer_configuration_spec.rb +144 -0
- data/spec/integration/pact/provider_configuration_spec.rb +24 -0
- data/spec/lib/pact/consumer/consumer_contract_builder_spec.rb +13 -13
- data/spec/lib/pact/consumer/dsl_spec.rb +1 -0
- data/spec/lib/pact/consumer/interaction_spec.rb +34 -0
- data/spec/lib/pact/consumer_contract_spec.rb +13 -2
- data/spec/lib/pact/matchers/matchers_spec.rb +32 -12
- data/spec/lib/pact/producer/rspec_spec.rb +1 -1
- data/spec/lib/pact/request_spec.rb +43 -1
- data/spec/support/pact_rake_support.rb +5 -8
- metadata +17 -10
- data/spec/integration/pact/configuration_spec.rb +0 -65
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pact (0.1.
|
4
|
+
pact (0.1.35)
|
5
5
|
awesome_print (~> 1.1.0)
|
6
6
|
capybara (~> 2.1.0)
|
7
7
|
find_a_port (~> 1.0.1)
|
@@ -37,7 +37,7 @@ GEM
|
|
37
37
|
hashie (2.0.5)
|
38
38
|
json (1.8.0)
|
39
39
|
method_source (0.8.1)
|
40
|
-
mime-types (1.
|
40
|
+
mime-types (1.24)
|
41
41
|
mini_portile (0.5.1)
|
42
42
|
multipart-post (1.2.0)
|
43
43
|
nokogiri (1.6.0)
|
@@ -55,10 +55,10 @@ GEM
|
|
55
55
|
rspec-core (~> 2.14.0)
|
56
56
|
rspec-expectations (~> 2.14.0)
|
57
57
|
rspec-mocks (~> 2.14.0)
|
58
|
-
rspec-core (2.14.
|
59
|
-
rspec-expectations (2.14.
|
58
|
+
rspec-core (2.14.5)
|
59
|
+
rspec-expectations (2.14.2)
|
60
60
|
diff-lcs (>= 1.1.3, < 2.0)
|
61
|
-
rspec-mocks (2.14.
|
61
|
+
rspec-mocks (2.14.3)
|
62
62
|
safe_yaml (0.9.4)
|
63
63
|
slop (3.4.5)
|
64
64
|
thin (1.5.1)
|
data/README.md
CHANGED
@@ -3,28 +3,37 @@
|
|
3
3
|
Define a pact between service consumers and providers.
|
4
4
|
|
5
5
|
|
6
|
-
Pact provides an RSpec DSL for service consumers to define the request they will make to a service
|
7
|
-
response they expect back. This expectation is used in the consumers specs to provide a mock
|
8
|
-
played back in the
|
6
|
+
Pact provides an RSpec DSL for service consumers to define the request they will make to a service service provider and the
|
7
|
+
response they expect back. This expectation is used in the consumers specs to provide a mock service provider, and is also
|
8
|
+
played back in the service provider specs to ensure the service provider actually does provide the response the consumer expects.
|
9
9
|
|
10
10
|
This allows you to test both sides of an integration point using fast unit tests.
|
11
11
|
|
12
|
+
This gem is inspired by the concept of "Consumer driven contracts". See http://martinfowler.com/articles/consumerDrivenContracts.html for more information.
|
13
|
+
|
12
14
|
## Installation
|
13
15
|
|
14
16
|
Put it in your Gemfile. You know how.
|
15
17
|
|
16
18
|
## Usage
|
17
19
|
|
18
|
-
### Consumer project
|
20
|
+
### Service Consumer project
|
19
21
|
|
20
22
|
#### Configuration
|
21
23
|
|
24
|
+
```ruby
|
22
25
|
Pact.configure do | config |
|
23
26
|
config.pact_dir = "???" # Optional, default is ./spec/pacts
|
24
27
|
config.log_dir = "???" # Optional, default is ./log
|
25
|
-
config.logger = "??"
|
28
|
+
config.logger = "??" # Optional, defaults to a file logger to the configured log_dir.
|
26
29
|
config.logger.level = Logger::DEBUG #By default this is INFO, bump this up to debug for more detailed logs
|
30
|
+
# Optional.
|
31
|
+
# The default pactfile_write_mode is "defined?(Rake) ? :overwrite : :update"
|
32
|
+
# This allows it to create a clean file when running rake, but only update the executed interactions when running a specific test using "rspec spec/...".
|
33
|
+
# This is the recommended setting.
|
34
|
+
config.pactfile_write_mode = :ovewrite / :update
|
27
35
|
end
|
36
|
+
```
|
28
37
|
|
29
38
|
#### Create a Consumer (Driven) Contract
|
30
39
|
|
@@ -41,26 +50,23 @@ class SomeServiceClient
|
|
41
50
|
end
|
42
51
|
end
|
43
52
|
|
44
|
-
Pact.
|
45
|
-
|
46
|
-
|
53
|
+
Pact.service_consumer "My Consumer" do
|
54
|
+
has_pact_with "My Provider" do
|
55
|
+
mock_service :my_service_provider do
|
56
|
+
port 1234
|
57
|
+
end
|
47
58
|
end
|
48
59
|
end
|
49
60
|
|
50
61
|
# The following block creates a service on localhost:1234 which will respond to your application's queries
|
51
|
-
# over HTTP as if it were the real "My
|
52
|
-
# which you will use to set up your expectations. The method name to access the mock
|
53
|
-
# will be what ever name you give as the service argument - in this case "
|
62
|
+
# over HTTP as if it were the real "My Provider" app. It also creats a mock service provider object
|
63
|
+
# which you will use to set up your expectations. The method name to access the mock service provider
|
64
|
+
# will be what ever name you give as the service argument - in this case "my_service_provider"
|
54
65
|
|
55
|
-
Pact.with_producer "My Producer" do
|
56
|
-
mock_service :my_producer do
|
57
|
-
port 1234
|
58
|
-
end
|
59
|
-
end
|
60
66
|
|
61
67
|
# Use the :pact => true describe metadata to include all the pact generation functionality in your spec.
|
62
68
|
|
63
|
-
describe "a pact with My
|
69
|
+
describe "a pact with My Provider", :pact => true do
|
64
70
|
|
65
71
|
before do
|
66
72
|
# Configure your client to point to the stub service on localhost using the port you have specified
|
@@ -68,7 +74,7 @@ describe "a pact with My Producer", :pact => true do
|
|
68
74
|
end
|
69
75
|
|
70
76
|
it "returns something when requested" do
|
71
|
-
|
77
|
+
my_service_provider.
|
72
78
|
given("something exists").
|
73
79
|
upon_receiving("a request for something").
|
74
80
|
with({ method: :get, path: '/something' }).
|
@@ -93,32 +99,26 @@ Logs will be output to the configured log dir that can be useful when diagnosing
|
|
93
99
|
To run your consumer app as a process during your test (eg for a Capybara test):
|
94
100
|
|
95
101
|
```ruby
|
96
|
-
Pact.
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
port 4321
|
101
|
-
end
|
102
|
+
Pact.service_consumer "My Consumer" do
|
103
|
+
app my_consumer_rack_app
|
104
|
+
port 4321
|
105
|
+
end
|
102
106
|
```
|
103
107
|
|
104
|
-
###
|
108
|
+
### Service Provider project
|
105
109
|
|
106
|
-
#### Configure your
|
110
|
+
#### Configure your service provider rack app
|
107
111
|
|
108
112
|
```ruby
|
109
|
-
|
110
|
-
|
111
|
-
config.producer do
|
112
|
-
name "My Producer"
|
113
|
-
app { MyApp.new }
|
114
|
-
end
|
113
|
+
Pact.service_provider "My Provider" do
|
114
|
+
app { MyApp.new }
|
115
115
|
end
|
116
116
|
|
117
117
|
```
|
118
118
|
|
119
|
-
#### Set up the
|
119
|
+
#### Set up the service provider states
|
120
120
|
|
121
|
-
Having different
|
121
|
+
Having different service provider states allows you to test the same request with different expected responses.
|
122
122
|
|
123
123
|
For example, some code that creates the pact in a consumer project might look like this:
|
124
124
|
|
@@ -136,16 +136,16 @@ my_service.
|
|
136
136
|
will_respond_with({status: 404, :body => {error: "There is no thing :("} })
|
137
137
|
```
|
138
138
|
|
139
|
-
To define
|
140
|
-
Note that these states have been defined only for the 'My Consumer' consumer by using the Pact.
|
139
|
+
To define service provider states that create the right data for "a thing exists" and "a thing does not exist", write the following in the service provider project.
|
140
|
+
Note that these states have been defined only for the 'My Consumer' consumer by using the Pact.provider_states_for block.
|
141
141
|
|
142
142
|
|
143
143
|
```ruby
|
144
144
|
# The consumer name here must match the name of the consumer configured in your consumer project
|
145
145
|
# for it to use these states.
|
146
146
|
|
147
|
-
Pact.
|
148
|
-
|
147
|
+
Pact.provider_states_for 'My Consumer' do
|
148
|
+
provider_state "a thing exists" do
|
149
149
|
set_up do
|
150
150
|
# Create a thing here using your factory of choice
|
151
151
|
end
|
@@ -155,7 +155,7 @@ Pact.with_consumer 'My Consumer' do
|
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
158
|
-
|
158
|
+
provider_state "a thing does not exist" do
|
159
159
|
set_up do
|
160
160
|
# Well, probably not much to do here, but you get the picture.
|
161
161
|
end
|
@@ -164,17 +164,17 @@ end
|
|
164
164
|
|
165
165
|
```
|
166
166
|
|
167
|
-
If a state should be used for all consumers, the top level Pact.with_consumer can be skipped, and a global Pact.
|
167
|
+
If a state should be used for all consumers, the top level Pact.with_consumer can be skipped, and a global Pact.provider_state can be defined on its own.
|
168
168
|
|
169
|
-
#### Create a rake task to verify that the
|
169
|
+
#### Create a rake task to verify that the service provider honours the pact
|
170
170
|
|
171
|
-
You'll need to create one or more pact:verify:xxx tasks, that allow the currently checked out
|
171
|
+
You'll need to create one or more pact:verify:xxx tasks, that allow the currently checked out service provider to be tested against other versions of its consumers - most importantly, head and production.
|
172
172
|
|
173
173
|
Here is an example pact:verify:head task, pointing the the pact file for "some_consumer", found in the build artifacts of the latest successful build of "MY-CONSUMER" project.
|
174
174
|
|
175
175
|
```ruby
|
176
176
|
Pact::VerificationTask.new(:head) do | pact |
|
177
|
-
pact.uri 'http://our_build_server/MY-CONSUMER-BUILD/latestSuccessful/artifact/Pacts/some_consumer-
|
177
|
+
pact.uri 'http://our_build_server/MY-CONSUMER-BUILD/latestSuccessful/artifact/Pacts/some_consumer-this_service provider.json',
|
178
178
|
support_file: './spec/consumers/pact_helper'
|
179
179
|
end
|
180
180
|
```
|
@@ -182,20 +182,18 @@ end
|
|
182
182
|
```ruby
|
183
183
|
# Ideally we'd like to be able to create a production task like this, but firewalls are making this tricky right now.
|
184
184
|
Pact::VerificationTask.new(:production) do | pact |
|
185
|
-
pact.uri 'http://our_prod_server/pacts/some_consumer-
|
186
|
-
support_file: './spec/consumers/pact_helper'
|
185
|
+
pact.uri 'http://our_prod_server/pacts/some_consumer-this_service_provider.json',
|
186
|
+
support_file: './spec/consumers/pact_helper'
|
187
187
|
end
|
188
188
|
```
|
189
189
|
|
190
190
|
The pact.uri may be a local file system path or a remote URL.
|
191
191
|
|
192
|
-
The consumer is optional, and specifies which consumer namespace to use when looking up the producer states, if consumer namespaces have been used.
|
193
|
-
|
194
192
|
The support_file should include the code that makes your rack app available for the rack testing framework, and should load all its dependencies (eg include spec_helper)
|
195
193
|
|
196
|
-
Multiple pact.uri may be defined in the same rake task if a
|
194
|
+
Multiple pact.uri may be defined in the same rake task if a service provider has more than one consumer.
|
197
195
|
|
198
|
-
#### Verify that the
|
196
|
+
#### Verify that the service provider honours the pact
|
199
197
|
|
200
198
|
rake pact:verify:head
|
201
199
|
rake pact:verify # will run all verify tasks
|
@@ -212,18 +210,19 @@ when diagnosing issues with pacts.
|
|
212
210
|
## TODO
|
213
211
|
|
214
212
|
Short term:
|
215
|
-
- Rename
|
213
|
+
- Rename Pact to ConsumerContract (Done)
|
216
214
|
- Simplify set up for consumer (Done)
|
217
215
|
- Move server spawning into to the "at" method (Done)
|
218
216
|
- automatically register before and after hooks in consumer (Done)
|
219
|
-
- Provide before and after hooks and a place to define the app for Pact configuration in
|
217
|
+
- Provide before and after hooks and a place to define the app for Pact configuration in service provider (remove Rspc from interface of Pact setup) (Done)
|
220
218
|
- Set_up for state
|
221
219
|
- Tear_down for state
|
222
220
|
- Before hook for all
|
223
221
|
- After hook for all
|
224
|
-
- Make
|
225
|
-
- Put
|
222
|
+
- Make service provider state lookup try consumer defined state first, then fall back to global one (Done)
|
223
|
+
- Put service provider and consumer name into pact file (Done)
|
226
224
|
- Remove consumer name from the rake task, as it should now be able to be determined from the pact file. (Done)
|
225
|
+
- Provide more flexible matching (eg the keys should match, and the classes of the values should match, but the values of each key do not need to be equal). This is to make the pact verification less brittle.
|
227
226
|
|
228
227
|
Long term:
|
229
228
|
- Decouple Rspec from Pact and make rspec-pact gem for easy integration
|
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
source 'http://rea-rubygems/'
|
3
|
+
|
4
|
+
gem 'bundler', '~> 1.3.0'
|
5
|
+
|
6
|
+
group :development, :test do
|
7
|
+
gem 'rspec'
|
8
|
+
gem 'pact'
|
9
|
+
gem 'pry'
|
10
|
+
end
|
11
|
+
|
12
|
+
gem 'rake'
|
13
|
+
gem 'rack', '~>1.5.2'
|
14
|
+
gem 'json', '~>1.6.8'
|
15
|
+
gem 'httparty'
|
@@ -0,0 +1,77 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
remote: http://rea-rubygems/
|
4
|
+
specs:
|
5
|
+
awesome_print (1.1.0)
|
6
|
+
capybara (2.1.0)
|
7
|
+
mime-types (>= 1.16)
|
8
|
+
nokogiri (>= 1.3.3)
|
9
|
+
rack (>= 1.0.0)
|
10
|
+
rack-test (>= 0.5.4)
|
11
|
+
xpath (~> 2.0)
|
12
|
+
coderay (1.0.9)
|
13
|
+
daemons (1.1.9)
|
14
|
+
diff-lcs (1.2.4)
|
15
|
+
eventmachine (1.0.3)
|
16
|
+
find_a_port (1.0.1)
|
17
|
+
hashie (2.0.5)
|
18
|
+
httparty (0.11.0)
|
19
|
+
multi_json (~> 1.0)
|
20
|
+
multi_xml (>= 0.5.2)
|
21
|
+
json (1.6.8)
|
22
|
+
method_source (0.8.2)
|
23
|
+
mime-types (1.24)
|
24
|
+
mini_portile (0.5.1)
|
25
|
+
multi_json (1.7.9)
|
26
|
+
multi_xml (0.5.5)
|
27
|
+
nokogiri (1.6.0)
|
28
|
+
mini_portile (~> 0.5.0)
|
29
|
+
pact (0.1.32)
|
30
|
+
awesome_print (~> 1.1.0)
|
31
|
+
capybara (~> 2.1.0)
|
32
|
+
find_a_port (~> 1.0.1)
|
33
|
+
hashie (~> 2.0.5)
|
34
|
+
json
|
35
|
+
rack-test (~> 0.6.2)
|
36
|
+
randexp (~> 0.1.7)
|
37
|
+
rspec (~> 2.12)
|
38
|
+
thin
|
39
|
+
thor
|
40
|
+
pry (0.9.12.2)
|
41
|
+
coderay (~> 1.0.5)
|
42
|
+
method_source (~> 0.8)
|
43
|
+
slop (~> 3.4)
|
44
|
+
rack (1.5.2)
|
45
|
+
rack-test (0.6.2)
|
46
|
+
rack (>= 1.0)
|
47
|
+
rake (10.1.0)
|
48
|
+
randexp (0.1.7)
|
49
|
+
rspec (2.14.1)
|
50
|
+
rspec-core (~> 2.14.0)
|
51
|
+
rspec-expectations (~> 2.14.0)
|
52
|
+
rspec-mocks (~> 2.14.0)
|
53
|
+
rspec-core (2.14.5)
|
54
|
+
rspec-expectations (2.14.2)
|
55
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
56
|
+
rspec-mocks (2.14.3)
|
57
|
+
slop (3.4.6)
|
58
|
+
thin (1.5.1)
|
59
|
+
daemons (>= 1.0.9)
|
60
|
+
eventmachine (>= 0.12.6)
|
61
|
+
rack (>= 1.0.0)
|
62
|
+
thor (0.18.1)
|
63
|
+
xpath (2.0.0)
|
64
|
+
nokogiri (~> 1.3)
|
65
|
+
|
66
|
+
PLATFORMS
|
67
|
+
ruby
|
68
|
+
|
69
|
+
DEPENDENCIES
|
70
|
+
bundler (~> 1.3.0)
|
71
|
+
httparty
|
72
|
+
json (~> 1.6.8)
|
73
|
+
pact
|
74
|
+
pry
|
75
|
+
rack (~> 1.5.2)
|
76
|
+
rake
|
77
|
+
rspec
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'zoo_app/models/alligator'
|
3
|
+
|
4
|
+
module ZooApp
|
5
|
+
class AnimalServiceClient
|
6
|
+
|
7
|
+
include HTTParty
|
8
|
+
base_uri 'animal-service.com'
|
9
|
+
|
10
|
+
def self.find_alligators
|
11
|
+
response = get("/alligators", :headers => {'Accept' => 'application/json'})
|
12
|
+
if response.success?
|
13
|
+
parse_body(response).collect do | hash |
|
14
|
+
ZooApp::Animals::Alligator.new(hash)
|
15
|
+
end
|
16
|
+
else
|
17
|
+
raise response.body
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.find_alligator_by_name name
|
22
|
+
response = get("/alligators/#{name}", :headers => {'Accept' => 'application/json'})
|
23
|
+
if response.success?
|
24
|
+
ZooApp::Animals::Alligator.new(parse_body(response))
|
25
|
+
elsif response.code == 404
|
26
|
+
nil
|
27
|
+
else
|
28
|
+
raise response.body
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.parse_body response
|
33
|
+
JSON.parse(response.body, {:symbolize_names => true})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
{
|
2
|
+
"producer": {
|
3
|
+
"name": "Animal Service"
|
4
|
+
},
|
5
|
+
"consumer": {
|
6
|
+
"name": "Zoo App"
|
7
|
+
},
|
8
|
+
"interactions": [
|
9
|
+
{
|
10
|
+
"description": "a request for animals",
|
11
|
+
"request": {
|
12
|
+
"method": "get",
|
13
|
+
"path": "/animals"
|
14
|
+
},
|
15
|
+
"response": {
|
16
|
+
"status": 200,
|
17
|
+
"headers": {
|
18
|
+
"Content-Type": "application/json"
|
19
|
+
},
|
20
|
+
"body": {
|
21
|
+
"alligators": [
|
22
|
+
{
|
23
|
+
"name": "Bob"
|
24
|
+
}
|
25
|
+
]
|
26
|
+
}
|
27
|
+
},
|
28
|
+
"producer_state": "there are alligators"
|
29
|
+
},
|
30
|
+
{
|
31
|
+
"description": "a request for alligators",
|
32
|
+
"request": {
|
33
|
+
"method": "get",
|
34
|
+
"path": "/alligators",
|
35
|
+
"headers": {
|
36
|
+
"Accept": "application/json"
|
37
|
+
}
|
38
|
+
},
|
39
|
+
"response": {
|
40
|
+
"status": 200,
|
41
|
+
"headers": {
|
42
|
+
"Content-Type": "application/json"
|
43
|
+
},
|
44
|
+
"body": [
|
45
|
+
{
|
46
|
+
"name": "Bob"
|
47
|
+
}
|
48
|
+
]
|
49
|
+
},
|
50
|
+
"producer_state": "there are alligators"
|
51
|
+
},
|
52
|
+
{
|
53
|
+
"description": "a request for alligator Mary",
|
54
|
+
"request": {
|
55
|
+
"method": "get",
|
56
|
+
"path": "/alligators/Mary",
|
57
|
+
"headers": {
|
58
|
+
"Accept": "application/json"
|
59
|
+
}
|
60
|
+
},
|
61
|
+
"response": {
|
62
|
+
"status": 200,
|
63
|
+
"headers": {
|
64
|
+
"Content-Type": "application/json"
|
65
|
+
},
|
66
|
+
"body": [
|
67
|
+
{
|
68
|
+
"name": "Mary"
|
69
|
+
}
|
70
|
+
]
|
71
|
+
},
|
72
|
+
"producer_state": "there is an alligator named Mary"
|
73
|
+
},
|
74
|
+
{
|
75
|
+
"description": "a request for alligators",
|
76
|
+
"request": {
|
77
|
+
"method": "get",
|
78
|
+
"path": "/alligators",
|
79
|
+
"headers": {
|
80
|
+
"Accept": "application/json"
|
81
|
+
}
|
82
|
+
},
|
83
|
+
"response": {
|
84
|
+
"status": 500,
|
85
|
+
"headers": {
|
86
|
+
"Content-Type": "application/json"
|
87
|
+
},
|
88
|
+
"body": {
|
89
|
+
"error": "Argh!!!"
|
90
|
+
}
|
91
|
+
},
|
92
|
+
"producer_state": "an error has occurred"
|
93
|
+
}
|
94
|
+
],
|
95
|
+
"metadata": {
|
96
|
+
"pact_gem": {
|
97
|
+
"version": "0.1.32"
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require_relative 'pact_helper'
|
2
|
+
|
3
|
+
module ZooApp
|
4
|
+
describe "A pact with Animal Service", :pact => true do
|
5
|
+
|
6
|
+
before do
|
7
|
+
AnimalServiceClient.base_uri 'localhost:1234'
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "a call to get alligators" do
|
11
|
+
|
12
|
+
context "when valid response is received" do
|
13
|
+
before do
|
14
|
+
animal_service.
|
15
|
+
given("there are alligators").
|
16
|
+
upon_receiving("a request for alligators").
|
17
|
+
with({ method: :get, path: '/alligators', :headers => {'Accept' => 'application/json'} }).
|
18
|
+
will_respond_with({
|
19
|
+
status: 200,
|
20
|
+
headers: { 'Content-Type' => 'application/json' },
|
21
|
+
body: [{:name => 'Bob'}]
|
22
|
+
})
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns a list of alligators" do
|
26
|
+
expect(AnimalServiceClient.find_alligators).to eq [ZooApp::Animals::Alligator.new(:name => 'Bob')]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when an error response is returned" do
|
32
|
+
before do
|
33
|
+
animal_service.
|
34
|
+
given("an error has occurred").
|
35
|
+
upon_receiving("a request for alligators").
|
36
|
+
with({ method: :get, path: '/alligators', :headers => {'Accept' => 'application/json'} }).
|
37
|
+
will_respond_with({
|
38
|
+
status: 500,
|
39
|
+
headers: { 'Content-Type' => 'application/json' },
|
40
|
+
body: {:error => 'Argh!!!'}
|
41
|
+
})
|
42
|
+
end
|
43
|
+
|
44
|
+
it "raises an error" do
|
45
|
+
expect{ AnimalServiceClient.find_alligators }.to raise_error /Argh/
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "a call to get an alligator by name" do
|
52
|
+
context "when an alligator by the given name exists" do
|
53
|
+
|
54
|
+
before do
|
55
|
+
animal_service.
|
56
|
+
given("there is an alligator named Mary").
|
57
|
+
upon_receiving("a request for alligator Mary").
|
58
|
+
with({ method: :get, path: '/alligators/Mary', :headers => {'Accept' => 'application/json'} }).
|
59
|
+
will_respond_with({
|
60
|
+
status: 200,
|
61
|
+
headers: { 'Content-Type' => 'application/json' },
|
62
|
+
body: {:name => 'Mary'}
|
63
|
+
})
|
64
|
+
end
|
65
|
+
|
66
|
+
it "returns the alligator" do
|
67
|
+
expect(AnimalServiceClient.find_alligator_by_name("Mary")).to eq ZooApp::Animals::Alligator.new(:name => 'Mary')
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when an alligator by the given name does not exist" do
|
73
|
+
|
74
|
+
before do
|
75
|
+
animal_service.
|
76
|
+
given("there is an alligator named Mary").
|
77
|
+
upon_receiving("a request for alligator Mary").
|
78
|
+
with({ method: :get, path: '/alligators/Mary', :headers => {'Accept' => 'application/json'} }).
|
79
|
+
will_respond_with({
|
80
|
+
status: 404,
|
81
|
+
headers: { 'Content-Type' => 'application/json' }
|
82
|
+
})
|
83
|
+
end
|
84
|
+
|
85
|
+
it "returns nil" do
|
86
|
+
expect(AnimalServiceClient.find_alligator_by_name("Mary")).to be_nil
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|