pact 1.3.2 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +23 -9
- data/lib/pact/consumer_contract/interaction.rb +1 -1
- data/lib/pact/matchers/differ.rb +10 -7
- data/lib/pact/matchers/unix_diff_formatter.rb +8 -1
- data/lib/pact/reification.rb +5 -5
- data/lib/pact/version.rb +1 -1
- data/pact.gemspec +1 -1
- data/spec/lib/pact/consumer_contract/interaction_spec.rb +14 -0
- data/spec/lib/pact/matchers/unix_diff_formatter_spec.rb +9 -8
- data/spec/lib/pact/reification_spec.rb +12 -0
- metadata +5 -5
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,13 @@ Do this to generate your change history
|
|
2
2
|
|
3
3
|
git log --pretty=format:' * %h - %s (%an, %ad)'
|
4
4
|
|
5
|
+
### 1.3.3 (23 September 2014)
|
6
|
+
|
7
|
+
* 9106aac - Fixed reification when using FactoryGirl. (bethesque, Tue Sep 23 08:23:51 2014 +1000)
|
8
|
+
* 2182803 - Added "query" to example. (bethesque, Fri Sep 19 14:29:36 2014 +1000)
|
9
|
+
* 0002014 - Added key to explain - and + in unix diff output. (bethesque, Mon Sep 8 15:21:37 2014 +1000)
|
10
|
+
* 34f1c9b - Adding forward compatibility for reading 'providerState' from pact. (bethesque, Mon Aug 25 16:09:57 2014 +1000)
|
11
|
+
|
5
12
|
### 1.3.2 (20 August 2014)
|
6
13
|
|
7
14
|
* 65e1e23 - Renamed memoised :options to :diff_options because it clashes with the HTTP options method (bethesque, Wed Aug 20 09:31:0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,17 +2,17 @@
|
|
2
2
|
|
3
3
|
Define a pact between service consumers and providers, enabling "consumer driven contract" testing.
|
4
4
|
|
5
|
-
Pact provides an
|
5
|
+
Pact provides an fluent API for service consumers to define the HTTP requests they will make to a service provider and the HTTP responses they expect back. These expectations are used in the consumer specs to provide a mock service provider. The interactions are recorded, and played back in the service provider specs to ensure the service provider actually does provide the response the consumer expects.
|
6
6
|
|
7
7
|
This allows testing of both sides of an integration point using fast unit tests.
|
8
8
|
|
9
|
-
This gem is inspired by the concept of "Consumer driven contracts". See http://martinfowler.com/articles/consumerDrivenContracts.html for more information.
|
9
|
+
This gem is inspired by the concept of "Consumer driven contracts". See [this article](http://martinfowler.com/articles/consumerDrivenContracts.html) by Martin Fowler for more information.
|
10
10
|
|
11
11
|
Travis CI Status: [](https://travis-ci.org/realestate-com-au/pact)
|
12
12
|
|
13
13
|
## What is it good for?
|
14
14
|
|
15
|
-
Pact is most valuable for designing and testing integrations where you (or your team/organisation/partner organisation) control the development of both the consumer and the provider. It is fantastic tool for intra-organsation microservices.
|
15
|
+
Pact is most valuable for designing and testing integrations where you (or your team/organisation/partner organisation) control the development of both the consumer and the provider. It is fantastic tool for testing intra-organsation microservices.
|
16
16
|
|
17
17
|
## What is it not good for?
|
18
18
|
|
@@ -25,10 +25,11 @@ Pact is most valuable for designing and testing integrations where you (or your
|
|
25
25
|
* A service is mocked using an actual process running on a specified port, so javascript clients can be tested as easily as backend clients.
|
26
26
|
* "Provider states" (similar to fixtures) allow the same request to be made with a different expected response.
|
27
27
|
* Consumers specify only the fields they are interested in, allowing a provider to return more fields without breaking the pact. This allows a provider to have a different pact with a different consumer, and know which fields each cares about in a given response.
|
28
|
+
* RSpec and Minitest support for the service consumer codebase.
|
28
29
|
* Rake tasks allow pacts to be verified against a service provider codebase.
|
29
30
|
* Different versions of a consumer/provider pairs can be easily tested against each other, allowing confidence when deploying new versions of each (see the pact_broker and pact_broker-client gems).
|
30
31
|
* Autogenerated API documentation - need we say more?
|
31
|
-
*
|
32
|
+
* Autogenerated network diagrams with the [Pact Broker](https://github.com/bethesque/pact_broker)
|
32
33
|
|
33
34
|
## How does it work?
|
34
35
|
|
@@ -81,6 +82,8 @@ end
|
|
81
82
|
Imagine a service provider client class that looks something like this.
|
82
83
|
|
83
84
|
```ruby
|
85
|
+
require 'httparty'
|
86
|
+
|
84
87
|
class MyServiceProviderClient
|
85
88
|
include HTTParty
|
86
89
|
base_uri 'http://my-service'
|
@@ -99,6 +102,7 @@ The following code will create a mock service on localhost:1234 which will respo
|
|
99
102
|
# In /spec/service_providers/pact_helper.rb
|
100
103
|
|
101
104
|
require 'pact/consumer/rspec'
|
105
|
+
# or require 'pact/consumer/minitest' if you are using Minitest
|
102
106
|
|
103
107
|
Pact.service_consumer "My Service Consumer" do
|
104
108
|
has_pact_with "My Service Provider" do
|
@@ -114,7 +118,9 @@ end
|
|
114
118
|
```ruby
|
115
119
|
# In /spec/service_providers/my_service_provider_client_spec.rb
|
116
120
|
|
117
|
-
#
|
121
|
+
# When using RSpec, use the metadata `:pact => true` to include all the pact functionality in your spec.
|
122
|
+
# When using Minitest, include Pact::Consumer::Minitest in your spec.
|
123
|
+
|
118
124
|
describe MyServiceProviderClient, :pact => true do
|
119
125
|
|
120
126
|
before do
|
@@ -128,7 +134,7 @@ describe MyServiceProviderClient, :pact => true do
|
|
128
134
|
|
129
135
|
before do
|
130
136
|
my_service_provider.given("something exists").
|
131
|
-
upon_receiving("a request for something").with(method: :get, path: '/something').
|
137
|
+
upon_receiving("a request for something").with(method: :get, path: '/something', query: '').
|
132
138
|
will_respond_with(
|
133
139
|
status: 200,
|
134
140
|
headers: {'Content-Type' => 'application/json'},
|
@@ -167,14 +173,18 @@ end
|
|
167
173
|
|
168
174
|
#### 7. Run the specs again.
|
169
175
|
|
170
|
-
Green! You now have a pact file that can be used to verify your expectations
|
171
|
-
|
176
|
+
Green! You now have a pact file that can be used to verify your expectations of the provider project.
|
177
|
+
|
178
|
+
Now, rinse and repeat for other likely status codes that may be returned. For example, consider how you want your client to respond to a:
|
179
|
+
* 404 (return null, or raise an error?)
|
180
|
+
* 500 (specifying that the response body should contain an error message, and ensuring that your client logs that error message will make your life much easier when things go wrong)
|
181
|
+
* 401/403 if there is authorisation.
|
172
182
|
|
173
183
|
### Service Provider project
|
174
184
|
|
175
185
|
#### 1. Create the skeleton API classes
|
176
186
|
|
177
|
-
Create your API class using the framework of your choice - leave the methods unimplemented, we're doing Test First Develoment, remember?
|
187
|
+
Create your API class using the framework of your choice (the Pact authors have a preference for [Webmachine][webmachine] and [Roar][roar]) - leave the methods unimplemented, we're doing Test First Develoment, remember?
|
178
188
|
|
179
189
|
#### 2. Tell your provider that it needs to honour the pact file you made earlier
|
180
190
|
|
@@ -245,6 +255,7 @@ As in all things, there are good ways to implement Pacts, and there are not so g
|
|
245
255
|
* [Terminology](https://github.com/realestate-com-au/pact/wiki/Terminology)
|
246
256
|
* [Provider States](https://github.com/realestate-com-au/pact/wiki/Provider-states)
|
247
257
|
* [Verifying pacts](https://github.com/realestate-com-au/pact/wiki/Verifying-pacts)
|
258
|
+
* [Sharing pacts between consumer and provider](https://github.com/realestate-com-au/pact/wiki/Sharing-pacts-between-consumer-and-provider)
|
248
259
|
* [Frequently asked questions](https://github.com/realestate-com-au/pact/wiki/FAQ)
|
249
260
|
* [Rarely asked questions](https://github.com/realestate-com-au/pact/wiki/RAQ)
|
250
261
|
* [Best practices](https://github.com/realestate-com-au/pact/wiki/Best-practices)
|
@@ -297,3 +308,6 @@ Long term:
|
|
297
308
|
|
298
309
|
If you would like to implement pact in another language, please check out the [Pact specification](https://github.com/bethesque/pact-specification) and have a chat to one of us on the [pact-dev Google group](https://groups.google.com/forum/#!forum/pact-dev). The vision is to have a compatible pact implementation in all the commonly used languages, your help would be greatly appreciated!
|
299
310
|
|
311
|
+
[webmachine]: https://github.com/seancribbs/webmachine-ruby
|
312
|
+
[roar]: https://github.com/apotonick/roar
|
313
|
+
|
@@ -13,7 +13,7 @@ module Pact
|
|
13
13
|
@description = attributes[:description]
|
14
14
|
@request = attributes[:request]
|
15
15
|
@response = attributes[:response]
|
16
|
-
@provider_state = attributes[:provider_state]
|
16
|
+
@provider_state = attributes[:provider_state] || attributes[:providerState]
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.from_hash hash
|
data/lib/pact/matchers/differ.rb
CHANGED
@@ -71,6 +71,16 @@ module Pact
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
def red(text)
|
75
|
+
return text unless @color
|
76
|
+
color(text, 31)
|
77
|
+
end
|
78
|
+
|
79
|
+
def green(text)
|
80
|
+
return text unless @color
|
81
|
+
color(text, 32)
|
82
|
+
end
|
83
|
+
|
74
84
|
protected
|
75
85
|
|
76
86
|
def format
|
@@ -85,13 +95,6 @@ module Pact
|
|
85
95
|
"\e[#{color_code}m#{text}\e[0m"
|
86
96
|
end
|
87
97
|
|
88
|
-
def red(text)
|
89
|
-
color(text, 31)
|
90
|
-
end
|
91
|
-
|
92
|
-
def green(text)
|
93
|
-
color(text, 32)
|
94
|
-
end
|
95
98
|
|
96
99
|
def blue(text)
|
97
100
|
color(text, 34)
|
@@ -11,6 +11,7 @@ module Pact
|
|
11
11
|
def initialize diff, options = {}
|
12
12
|
@diff = diff
|
13
13
|
@colour = options.fetch(:colour, false)
|
14
|
+
@differ = Pact::Matchers::Differ.new(@colour)
|
14
15
|
end
|
15
16
|
|
16
17
|
def self.call diff, options = {colour: Pact.configuration.color_enabled}
|
@@ -24,7 +25,7 @@ module Pact
|
|
24
25
|
def to_s
|
25
26
|
expected = generate_string(diff, :expected)
|
26
27
|
actual = generate_string(diff, :actual)
|
27
|
-
|
28
|
+
@differ.diff_as_string(actual, expected).lstrip + "\n" + key
|
28
29
|
end
|
29
30
|
|
30
31
|
private
|
@@ -85,6 +86,12 @@ module Pact
|
|
85
86
|
end
|
86
87
|
end
|
87
88
|
|
89
|
+
def key
|
90
|
+
"Key: " + @differ.red("-") + @differ.red(" means \"expected, but was not found\". \n") +
|
91
|
+
@differ.green(" +") + @differ.green(" means \"actual, should not be found\". \n") +
|
92
|
+
" Values where the expected matches the actual are not shown.\n"
|
93
|
+
end
|
94
|
+
|
88
95
|
class RegexpDecorator
|
89
96
|
|
90
97
|
def initialize regexp
|
data/lib/pact/reification.rb
CHANGED
@@ -4,20 +4,20 @@ module Pact
|
|
4
4
|
module Reification
|
5
5
|
|
6
6
|
def self.from_term(term)
|
7
|
-
case
|
8
|
-
when
|
7
|
+
case term
|
8
|
+
when Pact::Term, Regexp, Pact::SomethingLike
|
9
9
|
term.generate
|
10
|
-
when
|
10
|
+
when Hash
|
11
11
|
term.inject({}) do |mem, (key,term)|
|
12
12
|
mem[key] = from_term(term)
|
13
13
|
mem
|
14
14
|
end
|
15
|
-
when
|
15
|
+
when Array
|
16
16
|
term.inject([]) do |mem, term|
|
17
17
|
mem << from_term(term)
|
18
18
|
mem
|
19
19
|
end
|
20
|
-
when
|
20
|
+
when Pact::Request::Base
|
21
21
|
from_term(term.to_hash)
|
22
22
|
else
|
23
23
|
term
|
data/lib/pact/version.rb
CHANGED
data/pact.gemspec
CHANGED
@@ -6,7 +6,7 @@ require 'pact/version'
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.name = "pact"
|
8
8
|
gem.version = Pact::VERSION
|
9
|
-
gem.authors = ["James Fraser", "Sergei Matheson", "Brent Snook", "Ronald Holshausen", "
|
9
|
+
gem.authors = ["James Fraser", "Sergei Matheson", "Brent Snook", "Ronald Holshausen", "Beth Skurrie"]
|
10
10
|
gem.email = ["james.fraser@alumni.swinburne.edu", "sergei.matheson@gmail.com", "brent@fuglylogic.com", "uglyog@gmail.com", "bskurrie@dius.com.au"]
|
11
11
|
gem.description = %q{Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.}
|
12
12
|
gem.summary = %q{Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.}
|
@@ -7,6 +7,9 @@ module Pact
|
|
7
7
|
|
8
8
|
describe Interaction do
|
9
9
|
|
10
|
+
let(:request) { {method: 'get', path: 'path'} }
|
11
|
+
let(:response) { {} }
|
12
|
+
|
10
13
|
describe "==" do
|
11
14
|
subject { InteractionFactory.create }
|
12
15
|
context "when other is the same" do
|
@@ -39,6 +42,17 @@ module Pact
|
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
45
|
+
describe "from_hash" do
|
46
|
+
context "when providerState has been used instead of provider_state" do
|
47
|
+
|
48
|
+
subject { Interaction.from_hash('response' => response, 'request' => request, 'providerState' => 'some state') }
|
49
|
+
|
50
|
+
it "recognises the provider state" do
|
51
|
+
expect(subject.provider_state).to eq 'some state'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
42
56
|
describe "to JSON" do
|
43
57
|
let(:request) do
|
44
58
|
{
|
@@ -9,6 +9,7 @@ module Pact
|
|
9
9
|
|
10
10
|
describe ".call" do
|
11
11
|
|
12
|
+
let(:key_lines_count) { 4 }
|
12
13
|
let(:colour) { false }
|
13
14
|
subject { UnixDiffFormatter.call(diff, {colour: colour}) }
|
14
15
|
|
@@ -54,7 +55,7 @@ EOF
|
|
54
55
|
end
|
55
56
|
|
56
57
|
it "generates the right number of lines, even with ActiveSupport loaded" do
|
57
|
-
expect(line_count).to eq 9
|
58
|
+
expect(line_count).to eq 9 + key_lines_count
|
58
59
|
end
|
59
60
|
|
60
61
|
end
|
@@ -76,7 +77,7 @@ EOF
|
|
76
77
|
end
|
77
78
|
|
78
79
|
it "generates the right number of lines, even with ActiveSupport loaded" do
|
79
|
-
expect(line_count).to eq 9
|
80
|
+
expect(line_count).to eq 9 + key_lines_count
|
80
81
|
end
|
81
82
|
|
82
83
|
end
|
@@ -98,7 +99,7 @@ EOF
|
|
98
99
|
end
|
99
100
|
|
100
101
|
it "generates the right number of lines, even with ActiveSupport loaded" do
|
101
|
-
expect(line_count).to eq 5
|
102
|
+
expect(line_count).to eq 5 + key_lines_count
|
102
103
|
end
|
103
104
|
|
104
105
|
end
|
@@ -120,7 +121,7 @@ EOF
|
|
120
121
|
end
|
121
122
|
|
122
123
|
it "generates the right number of lines, even with ActiveSupport loaded" do
|
123
|
-
expect(line_count).to eq 8
|
124
|
+
expect(line_count).to eq 8 + key_lines_count
|
124
125
|
end
|
125
126
|
end
|
126
127
|
|
@@ -140,7 +141,7 @@ EOF
|
|
140
141
|
end
|
141
142
|
|
142
143
|
it "generates the right number of lines, even with ActiveSupport loaded" do
|
143
|
-
expect(line_count).to eq 8
|
144
|
+
expect(line_count).to eq 8 + key_lines_count
|
144
145
|
end
|
145
146
|
|
146
147
|
end
|
@@ -159,7 +160,7 @@ EOF
|
|
159
160
|
end
|
160
161
|
|
161
162
|
it "generates the right number of lines, even with ActiveSupport loaded" do
|
162
|
-
expect(line_count).to eq 8
|
163
|
+
expect(line_count).to eq 8 + key_lines_count
|
163
164
|
end
|
164
165
|
|
165
166
|
end
|
@@ -185,7 +186,7 @@ EOF
|
|
185
186
|
end
|
186
187
|
|
187
188
|
it "generates the right number of lines, even with ActiveSupport loaded" do
|
188
|
-
expect(line_count).to eq 8
|
189
|
+
expect(line_count).to eq 8 + key_lines_count
|
189
190
|
end
|
190
191
|
|
191
192
|
end
|
@@ -203,7 +204,7 @@ EOF
|
|
203
204
|
end
|
204
205
|
|
205
206
|
it "generates the right number of lines, even with ActiveSupport loaded" do
|
206
|
-
expect(line_count).to eq 11
|
207
|
+
expect(line_count).to eq 11 + key_lines_count
|
207
208
|
end
|
208
209
|
|
209
210
|
end
|
@@ -51,5 +51,17 @@ module Pact
|
|
51
51
|
|
52
52
|
end
|
53
53
|
|
54
|
+
context "when SomethingLike" do
|
55
|
+
|
56
|
+
let(:request) { Pact::SomethingLike.new({a: 'String'})}
|
57
|
+
|
58
|
+
subject { Reification.from_term(request)}
|
59
|
+
|
60
|
+
it "returns the contents of the SomethingLike" do
|
61
|
+
expect(subject).to eq({a: 'String'})
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
54
66
|
end
|
55
67
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pact
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
- Sergei Matheson
|
10
10
|
- Brent Snook
|
11
11
|
- Ronald Holshausen
|
12
|
-
-
|
12
|
+
- Beth Skurrie
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2014-
|
16
|
+
date: 2014-09-22 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: randexp
|
@@ -560,7 +560,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
560
560
|
version: '0'
|
561
561
|
segments:
|
562
562
|
- 0
|
563
|
-
hash:
|
563
|
+
hash: 3250914731854232740
|
564
564
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
565
565
|
none: false
|
566
566
|
requirements:
|
@@ -569,7 +569,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
569
569
|
version: '0'
|
570
570
|
segments:
|
571
571
|
- 0
|
572
|
-
hash:
|
572
|
+
hash: 3250914731854232740
|
573
573
|
requirements: []
|
574
574
|
rubyforge_project:
|
575
575
|
rubygems_version: 1.8.23
|