pact 1.0.20 → 1.0.21

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - jruby-19mode
6
+ - jruby-20mode
7
+ - ruby-head
8
+ - jruby-head
@@ -2,6 +2,28 @@ Do this to generate your change history
2
2
 
3
3
  git log --date=relative --pretty=format:' * %h - %s (%an, %ad)'
4
4
 
5
+ ### 1.0.21 (25 November 2013)
6
+
7
+ * f810795 - add jruby 2.0 to travis (Ronald Holshausen, 4 days ago)
8
+ * 65e0ea2 - dropped rbx as it was failing in a crazy way (Ronald Holshausen, 4 days ago)
9
+ * 1403594 - added ruby 2 to travis (Ronald Holshausen, 4 days ago)
10
+ * c72662e - rbx requires the rubysl-thwait gem (Ronald Holshausen, 4 days ago)
11
+ * 70745dc - require webrick (Ronald Holshausen, 4 days ago)
12
+ * 43110ad - removed thin as a runtime dependancy as it is not supported on all rubies (Ronald Holshausen, 4 days ago)
13
+ * d4eea58 - dropped all rubies < 1.9.3 (Ronald Holshausen, 4 days ago)
14
+ * cb312b5 - removed debugger as a development dependancy as it will not build on all rubies (Ronald Holshausen, 4 days ago)
15
+ * 872c649 - removed ruby 1.9.2 as active support does not active support it (Ronald Holshausen, 4 days ago)
16
+ * 1930269 - added travis CI for the uglyog repo (Ronald Holshausen, 4 days ago)
17
+ * 7750ee1 - added travis build status image (Ronald Holshausen, 5 days ago)
18
+ * 9f72b31 - added travis build status image (Ronald Holshausen, 5 days ago)
19
+ * d9be65b - Added .travis.yml (Beth, 6 days ago)
20
+ * e7a7e7b - Refactoring pact_helper loading. (Beth, 6 days ago)
21
+ * 0224d36 - Only log loading of pact_helper once https://github.com/uglyog/pact/issues/8 (Beth, 6 days ago)
22
+ * 0123207 - Updating gemspec description (Beth, 7 days ago)
23
+ * 697cbdc - Updating README.md (Beth, 4 weeks ago)
24
+ * ca79968 - Investigating Rack and HTTP headers in response to https://github.com/uglyog/pact/issues/6. Updated tests and README with info on multiple headers with the same name. (B
25
+ * 01f0b9a - Updating README (Beth, 4 weeks ago)
26
+
5
27
  ### 1.0.20 (29 October 2013)
6
28
 
7
29
  * c03f34f - Fixed the pretty generation of JSON when active support is loaded. It is both a sad and a happy moment. (Beth, 7 minutes ago)
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in pact.gemspec
4
4
  gemspec
5
+
6
+ gem 'geminabox-client'
@@ -1,15 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pact (1.0.20)
4
+ pact (1.0.21)
5
5
  awesome_print (~> 1.1.0)
6
6
  find_a_port (~> 1.0.1)
7
7
  json
8
8
  rack-test (~> 0.6.2)
9
9
  randexp (~> 0.1.7)
10
10
  rspec (~> 2.12)
11
- thin
12
11
  thor
12
+ webrick
13
13
 
14
14
  GEM
15
15
  remote: https://rubygems.org/
@@ -24,18 +24,9 @@ GEM
24
24
  atomic (1.1.14)
25
25
  awesome_print (1.1.0)
26
26
  coderay (1.0.9)
27
- columnize (0.3.6)
28
27
  crack (0.4.1)
29
28
  safe_yaml (~> 0.9.0)
30
- daemons (1.1.9)
31
- debugger (1.6.2)
32
- columnize (>= 0.3.1)
33
- debugger-linecache (~> 1.2.0)
34
- debugger-ruby_core_source (~> 1.2.3)
35
- debugger-linecache (1.2.0)
36
- debugger-ruby_core_source (1.2.3)
37
29
  diff-lcs (1.2.4)
38
- eventmachine (1.0.3)
39
30
  fakefs (0.4.2)
40
31
  find_a_port (1.0.1)
41
32
  geminabox-client (0.0.2)
@@ -68,10 +59,6 @@ GEM
68
59
  rspec-mocks (2.14.3)
69
60
  safe_yaml (0.9.5)
70
61
  slop (3.4.6)
71
- thin (1.6.0)
72
- daemons (>= 1.0.9)
73
- eventmachine (>= 1.0.0)
74
- rack (>= 1.5.0)
75
62
  thor (0.18.1)
76
63
  thread_safe (0.1.3)
77
64
  atomic
@@ -79,13 +66,13 @@ GEM
79
66
  webmock (1.9.3)
80
67
  addressable (>= 2.2.7)
81
68
  crack (>= 0.3.2)
69
+ webrick (1.3.1)
82
70
 
83
71
  PLATFORMS
84
72
  ruby
85
73
 
86
74
  DEPENDENCIES
87
75
  activesupport
88
- debugger
89
76
  fakefs (~> 0.4)
90
77
  geminabox-client
91
78
  hashie (~> 2.0)
data/README.md CHANGED
@@ -9,6 +9,8 @@ This allows you to test both sides of an integration point using fast unit tests
9
9
 
10
10
  This gem is inspired by the concept of "Consumer driven contracts". See http://martinfowler.com/articles/consumerDrivenContracts.html for more information.
11
11
 
12
+ Travis CI Status: [![travis-ci.org Build Status](https://travis-ci.org/uglyog/pact.png)](https://travis-ci.org/uglyog/pact)
13
+
12
14
  ## Features
13
15
  * A services is mocked using an actual process running on a specified port, so javascript clients can be tested as easily as backend clients.
14
16
  * "Provider states" (similar to fixtures) allow the same request to be made with a different expected response.
@@ -23,53 +25,49 @@ Put it in your Gemfile. You know how.
23
25
 
24
26
  ## Usage
25
27
 
26
- ### Configuration
28
+ ### Service Consumer project
29
+
30
+ #### 1. Start with you model
31
+
32
+ Imagine a model class that looks something like this. The attributes for a SomethingModel live on a remote server, and will need to be retrieved by an HTTP call.
27
33
 
28
34
  ```ruby
29
- Pact.configure do | config |
30
- config.pact_dir = "???" # Optional, default is ./spec/pacts
31
- config.log_dir = "???" # Optional, default is ./log
32
- config.logger = "??" # Optional, defaults to a file logger to the configured log_dir.
33
- config.logger.level = Logger::DEBUG #By default this is INFO, bump this up to debug for more detailed logs
34
- config.pactfile_write_mode = :ovewrite / :update / :smart # Optional. The default pactfile_write_mode is :overwrite. See notes in Advanced section for further information.
35
+ class SomethingModel
36
+ attr_reader :name
37
+
38
+ def intialize name
39
+ @name = name
40
+ end
41
+
42
+ def == other
43
+ other.is_a?(Something) && other.name == name
44
+ end
35
45
  end
36
46
  ```
37
47
 
38
- ### Service Consumer project
48
+ #### 2. Create a skeleton client class
39
49
 
40
- #### Create a Consumer Driven Contract (pact file) using the spec for your client class
50
+ Imagine a service provider client class that looks something like this.
41
51
 
42
52
  ```ruby
43
53
 
44
- # Imagine a service provider client class that looks something like this
45
-
46
54
  class MyServiceProviderClient
47
55
  include HTTParty
48
56
  base_uri 'http://my-service'
49
57
 
50
58
  def get_something
51
- name = JSON.parse(self.class.get("/something").body)['name']
52
- Something.new(name)
59
+ # Yet to be implemented because we're doing Test First Development...
53
60
  end
54
61
  end
55
62
 
56
- class Something
57
- attr_reader :name
58
-
59
- def intialize name
60
- @name = name
61
- end
63
+ ```
64
+ #### 3. Configure the mock server
62
65
 
63
- def == other
64
- other.is_a?(Something) && other.name == name
65
- end
66
- end
66
+ The following code will create a mock service on localhost:1234 which will respond to your application's queries over HTTP as if it were the real "My Service Provider" app. It also creats a mock service provider object which you will use to set up your expectations. The method name to access the mock service provider will be what ever name you give as the service argument - in this case "my_service_provider"
67
67
 
68
68
 
69
- # The following code creates a service on localhost:1234 which will respond to your application's queries
70
- # over HTTP as if it were the real "My Service Provider" app. It also creats a mock service provider object
71
- # which you will use to set up your expectations. The method name to access the mock service provider
72
- # will be what ever name you give as the service argument - in this case "my_service_provider"
69
+ ```ruby
70
+ # In /spec/service_providers/pact_helper.rb
73
71
 
74
72
  require 'pact/consumer/rspec'
75
73
 
@@ -80,9 +78,14 @@ Pact.service_consumer "My Service Consumer" do
80
78
  end
81
79
  end
82
80
  end
81
+ ```
83
82
 
84
- # Use the :pact => true describe metadata to include all the pact generation functionality in your spec.
83
+ #### 4. Write a failing spec for the client
84
+
85
+ ```ruby
86
+ # In /spec/service_providers/my_service_provider_client_spec.rb
85
87
 
88
+ # Use the :pact => true describe metadata to include all the pact generation functionality in your spec.
86
89
  describe MyServiceProviderClient, :pact => true do
87
90
 
88
91
  before do
@@ -104,7 +107,7 @@ describe MyServiceProviderClient, :pact => true do
104
107
  end
105
108
 
106
109
  it "returns a Something" do
107
- expect(MyServiceProviderClient.get_something).to eq(Something.new('A small something'))
110
+ expect(MyServiceProviderClient.get_something).to eq(SomethingModel.new('A small something'))
108
111
  end
109
112
 
110
113
  end
@@ -113,27 +116,45 @@ end
113
116
 
114
117
  ```
115
118
 
119
+ #### 5. Run the specs
120
+
116
121
  Running the consumer spec will generate a pact file in the configured pact dir (spec/pacts by default).
117
122
  Logs will be output to the configured log dir that can be useful when diagnosing problems.
118
123
 
119
- To run your consumer app as a process during your test (eg for a Capybara test):
124
+ Of course, the above specs will fail because the client method is not implemented, so next, implement your client methods.
125
+
126
+ #### 6. Implement the client methods
120
127
 
121
128
  ```ruby
122
- Pact.service_consumer "My Consumer" do
123
- app my_consumer_rack_app
124
- port 4321
129
+
130
+ class MyServiceProviderClient
131
+ include HTTParty
132
+ base_uri 'http://my-service'
133
+
134
+ def get_something
135
+ name = JSON.parse(self.class.get("/something").body)['name']
136
+ SomethingModel.new(name)
137
+ end
125
138
  end
139
+
126
140
  ```
127
141
 
142
+ #### 7. Run the specs again.
143
+
144
+ Green! You now have a pact file that can be used to verify your expectations in the provider project.
145
+
128
146
  ### Service Provider project
129
147
 
130
- #### Configure your service provider
148
+ #### 1. Create the skeleton API classes
149
+
150
+ Create your API class using the framework of your choice (e.g. Sinatra, Grape) - leave the methods unimplemented, we're doing Test First Develoment, remember?
131
151
 
132
- Create a `pact_helper.rb` in your service provider project. The file must be called pact_helper.rb, however there is some flexibility in where it can be stored. The recommended place is `specs/service_providers/pact_helper.rb`.
152
+ #### 2. Tell your provider that it needs to honour the pact file you made earlier
153
+
154
+ Create a `pact_helper.rb` in your service provider project. The file must be called pact_helper.rb, however there is some flexibility in where it can be stored. The recommended place is `specs/service_consumers/pact_helper.rb`.
133
155
 
134
156
  ```ruby
135
157
  require 'my_app' # Require the boot files for your app
136
- require 'provider_states_for_my_consumer' # See next section on setting up provider states
137
158
 
138
159
  Pact.service_provider "My Service Provider" do
139
160
  app { MyApp.new }
@@ -147,8 +168,31 @@ Pact.service_provider "My Service Provider" do
147
168
  end
148
169
 
149
170
  ```
171
+ Require "pact/tasks" in your Rakefile. If the pact gem is in the test/development section of your Gemfile, you may want to put an env check around this so it doesn't load the pact tasks in prod.
172
+
173
+ ```ruby
174
+ # In Rakefile
175
+
176
+ require 'pact/tasks'
177
+ ```
178
+
179
+ #### 3. Run your failing specs
180
+
181
+ $ rake pact:verify
182
+
183
+ Congratulations! You now have a failing spec to develop against.
184
+
185
+ #### 4. Implement your service provider
186
+
187
+ At this stage, you'll probably want to be able to run your specs one at a time while you implement. Define the environment variables PACT_DESCRIPTION and/or PACT_PROVIDER_STATE as so:
188
+
189
+ $ PACT_DESCRIPTION="a request for something" PACT_PROVIDER_STATE="something exists" rake pact:verify
150
190
 
151
- #### Set up the service provider states
191
+ #### 5. Keep going til you're green
192
+
193
+ Yay! Your provider now honours the pact it has with your consumer. You can now have confidence that your consumer and provider will play nicely together.
194
+
195
+ ### Using provider states
152
196
 
153
197
  Having different service provider states allows you to test the same request with different expected responses.
154
198
 
@@ -161,6 +205,8 @@ my_service.
161
205
  with(method: 'get', path: '/thing').
162
206
  will_respond_with(status: 200, :body => {thing: "yay!"} )
163
207
 
208
+ ...
209
+
164
210
  my_service.
165
211
  given("a thing does not exist").
166
212
  upon_receiving("a request for a thing").
@@ -168,13 +214,11 @@ my_service.
168
214
  will_respond_with(status: 404, :body => {error: "There is no thing :("} )
169
215
  ```
170
216
 
171
- 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.
217
+ 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. (The consumer name here must match the name of the consumer configured in your consumer project for it to correctly find these provider states.)
172
218
 
173
219
 
174
220
  ```ruby
175
- # The consumer name here must match the name of the consumer configured in your consumer project
176
- # for it to correctly find these provider states.
177
- # Make sure the provider states are included in or required by your pact_helper.rb file.
221
+ # In /spec/service_consumers/provider_states_for_my_service_consumer.rb
178
222
 
179
223
  Pact.provider_states_for 'My Service Consumer' do
180
224
  provider_state "a thing exists" do
@@ -194,45 +238,46 @@ end
194
238
 
195
239
  ```
196
240
 
197
- 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.
198
-
199
- #### Verify that the service provider honours the pact
200
-
201
241
  ```ruby
202
- # In your Rakefile
203
- # If the pact gem is in the test/development section of your Gemfile, you may want to put an env check around this so it doesn't load the pact tasks in prod.
204
- require 'pact/tasks'
205
- ```
242
+ # In /spec/service_consumers/pact_helper.rb
206
243
 
207
- ```
208
- $ rake -T
209
- rake pact:verify # Verifies the pact files configured in the pact_helper.rb against this service provider.
210
- rake pact:verify:at[pact_uri] # Verifies the pact at the given URI against this service provider.
211
- $ rake pact:verify
244
+ require_relative 'provider_states_for_my_service_consumer.rb'
212
245
  ```
213
246
 
214
- #### Verification using arbitrary pact files
247
+ 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.
215
248
 
216
- ```
217
- # Local URI
218
- $ rake pact:verify:at[../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json]
219
249
 
220
- # Remote URI
221
- $ rake pact:verify:at[http://build-box/MyConsumerBuild/latestSuccessful/artifacts/my_consumer-my_provider.json]
222
- ```
250
+ ### Verifying pacts
251
+
252
+ You can verify a pact at an arbitrary local or remote URL
253
+
254
+ $ rake pact:verify:at[../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json]
255
+ $ rake pact:verify:at[http://build-box/MyConsumerBuild/latestSuccessful/artifacts/my_consumer-my_provider.json]
223
256
 
224
- To make a shortcut task for pact at an arbitrary URI, add the following to your Rakefile.
257
+ To make a shortcut task for pact at an arbitrary URL, add the following to your Rakefile. The pact.uri may be a local file system path or a remote URL.
225
258
 
226
259
  ```ruby
260
+ # In Rakefile or /tasks/pact.rake
261
+
227
262
  # This creates a rake task that can be executed by running
228
- # $rake pact:verify:dev
263
+ # $ rake pact:verify:dev
264
+
229
265
  Pact::VerificationTask.new(:dev) do | pact |
230
266
  pact.uri '../path-to-your-consumer-project/specs/pacts/my_consumer-my_provider.json'
231
267
  end
232
268
  ```
233
269
 
234
- The pact.uri may be a local file system path or a remote URL.
270
+ ### Configuration
235
271
 
272
+ ```ruby
273
+ Pact.configure do | config |
274
+ config.pact_dir = "???" # Optional, default is ./spec/pacts
275
+ config.log_dir = "???" # Optional, default is ./log
276
+ config.logger = "??" # Optional, defaults to a file logger to the configured log_dir.
277
+ config.logger.level = Logger::DEBUG #By default this is INFO, bump this up to debug for more detailed logs
278
+ config.pactfile_write_mode = :ovewrite / :update / :smart # Optional. The default pactfile_write_mode is :overwrite. See notes in Advanced section for further information.
279
+ end
280
+ ```
236
281
 
237
282
  ## Pact best practices
238
283
 
@@ -305,6 +350,32 @@ A pact service can be run locally and is really useful for debugging purposes.
305
350
  The service prints messages it recieves to stdout which can be really useful
306
351
  when diagnosing issues with pacts.
307
352
 
353
+ ### To run your consumer app as a process during your consumer specs
354
+
355
+ Eg. for Capybara tests
356
+
357
+ ```ruby
358
+ Pact.service_consumer "My Consumer" do
359
+ app my_consumer_rack_app
360
+ port 4321
361
+ end
362
+ ```
363
+
364
+ ### Handling multiple headers with the same name
365
+
366
+ RFC 2616 states that two headers with the same name can interpreted as a single header with two comma-separated values. This is the safest way to specify multiple headers with the same name, as Rack will only pass the last value through when they are defined separately (see https://github.com/rack/rack/issues/436).
367
+
368
+ ```ruby
369
+ my_service_provider.
370
+ .given("it is RFC 2616 compliant")
371
+ .upon_receiving("a request with a header with commas separated values")
372
+ .with( method: :get, path: '/', headers: {'X-Request-Multival' => "A, B"} )
373
+ .will_respond_with(
374
+ status: 200, headers: {'X-Response-Multival' => "C, D"}
375
+ )
376
+
377
+ ```
378
+
308
379
  ### Pact file write mode
309
380
 
310
381
  By default, the pact file will be overwritten (started from scratch) every time any rspec runs any spec using pacts. This means that if there are interactions that haven't been executed in the most recent rspec run, they are effectively removed from the pact file. If you have long running pact specs (e.g. they are generated using the browser with Capybara) and you are developing both consumer and provider in parallel, or trying to fix a broken interaction, it can be tedius to run all the specs at once. In this scenario, you can set the pactfile_write_mode to :update. This will keep all existing interactions, and update only the changed ones, identified by description and provider state. The down side of this is that if either of those fields change, the old interactions will not be removed from the pact file. As a middle path, you can set pactfile_write_mode to :smart. This will use :overwrite mode when running rake (as determined by a call to system using 'ps') and :update when running an individual spec.
@@ -36,7 +36,7 @@ module Pact
36
36
  private
37
37
 
38
38
  def headers_from env
39
- headers = env.reject{ |key, value| !(key.start_with?("HTTP") || key == 'CONTENT_TYPE')}
39
+ headers = env.reject{ |key, value| !(key.start_with?("HTTP") || key == 'CONTENT_TYPE' || key == 'CONTENT_LENGTH')}
40
40
  headers.inject({}) do | hash, header |
41
41
  hash[standardise_header(header.first)] = header.last
42
42
  hash
@@ -1,2 +1,4 @@
1
1
  require 'pact/provider/pact_helper_locator'
2
- load Pact::Provider::PactHelperLocater.pact_helper_path
2
+ pact_helper_path = Pact::Provider::PactHelperLocater.pact_helper_path
3
+ load pact_helper_path
4
+ puts "Using #{pact_helper_path}"
@@ -42,14 +42,13 @@ module Pact
42
42
 
43
43
  def require_pact_helper spec_definition
44
44
  if spec_definition[:pact_helper]
45
- puts "Requiring #{spec_definition[:pact_helper]}"
45
+ puts "Using #{spec_definition[:pact_helper]}"
46
46
  require spec_definition[:pact_helper]
47
47
  elsif spec_definition[:support_file]
48
- puts "Requiring #{spec_definition[:support_file]}"
48
+ puts "Using #{spec_definition[:support_file]}"
49
49
  $stderr.puts SUPPORT_FILE_DEPRECATION_MESSAGE
50
50
  require spec_definition[:support_file]
51
51
  else
52
- puts "Requiring #{Pact::Provider::PactHelperLocater.pact_helper_path}"
53
52
  require 'pact/provider/client_project_pact_helper'
54
53
  end
55
54
  end
@@ -7,6 +7,9 @@ module Pact
7
7
  module Request
8
8
  class Replayable
9
9
 
10
+ # See https://github.com/rack/rack/blob/e7d741c6282ca4cf4e01506f5681e6e6b14c0b32/SPEC#L87-89
11
+ NO_HTTP_PREFIX = ["CONTENT-TYPE", "CONTENT-LENGTH"]
12
+
10
13
  def initialize expected_request
11
14
  @expected_request = expected_request
12
15
  end
@@ -32,12 +35,7 @@ module Pact
32
35
  request_headers = {}
33
36
  return request_headers if expected_request.headers.is_a?(Pact::NullExpectation)
34
37
  expected_request.headers.each do |key, value|
35
- key = key.upcase
36
- if key.match(/CONTENT.TYPE/)
37
- request_headers['CONTENT_TYPE'] = value
38
- else
39
- request_headers[formatted_request_header_key(key)] = value
40
- end
38
+ request_headers[rack_request_header_for(key)] = value
41
39
  end
42
40
  request_headers
43
41
  end
@@ -54,10 +52,19 @@ module Pact
54
52
  end
55
53
  end
56
54
 
57
- def formatted_request_header_key(key)
58
- 'HTTP_' + key.to_s.gsub('-', '_')
55
+ def rack_request_header_for header
56
+ with_http_prefix(header.to_s.upcase).gsub('-', '_')
57
+ end
58
+
59
+ def rack_request_value_for value
60
+ Array(value).join("\n")
59
61
  end
60
- end
62
+
63
+ def with_http_prefix header
64
+ NO_HTTP_PREFIX.include?(header) ? header : "HTTP_#{header}"
65
+ end
66
+
67
+ end
61
68
  end
62
69
  end
63
70
  end
@@ -1,3 +1,3 @@
1
1
  module Pact
2
- VERSION = "1.0.20"
2
+ VERSION = "1.0.21"
3
3
  end
@@ -8,8 +8,8 @@ Gem::Specification.new do |gem|
8
8
  gem.version = Pact::VERSION
9
9
  gem.authors = ["James Fraser", "Sergei Matheson", "Brent Snook", "Ronald Holshausen", "Bethany 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
- gem.description = %q{Define a pact between service consumers and providers}
12
- gem.summary = %q{Define a pact between service consumers and providers}
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
+ 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.}
13
13
  gem.homepage = "https://github.com/uglyog/pact.git"
14
14
 
15
15
  gem.files = `git ls-files`.split($/)
@@ -24,8 +24,8 @@ Gem::Specification.new do |gem|
24
24
  gem.add_runtime_dependency 'rack-test', '~> 0.6.2'
25
25
  gem.add_runtime_dependency 'awesome_print', '~> 1.1.0'
26
26
  gem.add_runtime_dependency 'thor'
27
- gem.add_runtime_dependency 'thin'
28
27
  gem.add_runtime_dependency 'json' #Not locking down a version because buncher gem requires 1.6, while other projects use 1.7.
28
+ gem.add_runtime_dependency 'webrick'
29
29
 
30
30
  gem.add_development_dependency 'rake', '~> 10.0.3'
31
31
  gem.add_development_dependency 'webmock', '~> 1.9.3'
@@ -34,6 +34,4 @@ Gem::Specification.new do |gem|
34
34
  gem.add_development_dependency 'hashie', '~> 2.0'
35
35
  gem.add_development_dependency 'rspec-fire'
36
36
  gem.add_development_dependency 'activesupport'
37
- gem.add_development_dependency 'debugger'
38
- gem.add_development_dependency 'geminabox-client'
39
37
  end
@@ -129,6 +129,40 @@ describe "A service consumer side of a pact", :pact => true do
129
129
  end
130
130
  end
131
131
 
132
+ context "with multiple headers" do
133
+ before do
134
+ Pact.clear_configuration
135
+ Pact.service_consumer "Consumer" do
136
+ has_pact_with "Multi Headers Service" do
137
+ mock_service :multi_headers_service do
138
+ verify true
139
+ port 1240
140
+ end
141
+ end
142
+ end
143
+
144
+ multi_headers_service.
145
+ given("there are multiple headers").
146
+ upon_receiving("a request with multiple headers").
147
+ with(method: :get, path: '/something', headers: {'X-Something' => "1, 2"}).
148
+ will_respond_with(status: 200)
149
+ end
150
+
151
+ it "handles multiple headers with the same name in a comma separated list" do
152
+ interactions = Pact::ConsumerContract.from_json(File.read(multi_headers_service.consumer_contract.pactfile_path)).interactions
153
+ expect(interactions.first.request.headers['X-Something']).to eq("1, 2")
154
+
155
+ uri = URI('http://localhost:1240/something')
156
+ post_req = Net::HTTP::Get.new(uri.path)
157
+ post_req.add_field('X-Something', '1')
158
+ post_req.add_field('X-Something', '2')
159
+ response = Net::HTTP.start(uri.hostname, uri.port) do |http|
160
+ http.request post_req
161
+ end
162
+ end
163
+
164
+ end
165
+
132
166
  context "with a async interaction with provider" do
133
167
  before do
134
168
  Pact.clear_configuration
@@ -27,6 +27,7 @@ module Pact::Consumer
27
27
  "HTTP_ACCEPT" => "text/plain",
28
28
  "HTTP_USER_AGENT" => "Ruby",
29
29
  "HTTP_HOST" => "localhost:4321",
30
+ "HTTP_X_SOMETHING" => "1, 2",
30
31
  "rack.version" => [1, 2 ],
31
32
  "rack.input" => StringIO.new(body),
32
33
  "rack.errors" => nil,
@@ -39,6 +40,9 @@ module Pact::Consumer
39
40
  }
40
41
  }
41
42
 
43
+ let(:content_type) { "" }
44
+ let(:body) { '' }
45
+
42
46
  subject { TestSubject.new }
43
47
 
44
48
  let(:expected_request) {
@@ -49,10 +53,12 @@ module Pact::Consumer
49
53
  :path => "/donuts",
50
54
  :headers => {
51
55
  "Content-Type" => content_type,
56
+ "Content-Length" => "16",
52
57
  "Accept" => "text/plain",
53
58
  "User-Agent" => "Ruby",
54
59
  "Host" => "localhost:4321",
55
- "Version" => "HTTP/1.1"
60
+ "Version" => "HTTP/1.1",
61
+ "X-Something" => "1, 2"
56
62
  }
57
63
  }
58
64
  }
@@ -6,10 +6,10 @@ describe Pact::Provider::Request::Replayable do
6
6
  let(:path) { '/path?something' }
7
7
  let(:body) { {a: 'body'} }
8
8
  let(:headers) { {} }
9
- let(:expected_request) do
10
- instance_double('Pact::Request::Expected',
11
- :method => 'post',
12
- :full_path => path,
9
+ let(:expected_request) do
10
+ instance_double('Pact::Request::Expected',
11
+ :method => 'post',
12
+ :full_path => path,
13
13
  :body => body,
14
14
  :headers => headers)
15
15
  end
@@ -62,8 +62,8 @@ describe Pact::Provider::Request::Replayable do
62
62
 
63
63
  describe "headers" do
64
64
  context "when headers are expected" do
65
- let(:headers) { {"Content-Type" => "text/plain", "Accept" => "application/json", "Access-Control-Request-Method" => "POST"} }
66
- let(:expected_headers) { {"CONTENT_TYPE" => "text/plain", "HTTP_ACCEPT" => "application/json", "HTTP_ACCESS_CONTROL_REQUEST_METHOD" => "POST"} }
65
+ let(:headers) { {"Content-Type" => "text/plain", "Content-Length" => "123", "X-Content-Type" => "special", "Access-Control-Request-Method" => "POST"} }
66
+ let(:expected_headers) { {"CONTENT_TYPE" => "text/plain", "CONTENT_LENGTH" => "123", "HTTP_ACCESS_CONTROL_REQUEST_METHOD" => "POST", "HTTP_X_CONTENT_TYPE" => "special"} }
67
67
  it "transforms the headers into Rack format" do
68
68
  expect(subject.headers).to eq( expected_headers )
69
69
  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.0.20
4
+ version: 1.0.21
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2013-10-30 00:00:00.000000000 Z
16
+ date: 2013-11-25 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: randexp
@@ -112,7 +112,7 @@ dependencies:
112
112
  - !ruby/object:Gem::Version
113
113
  version: '0'
114
114
  - !ruby/object:Gem::Dependency
115
- name: thin
115
+ name: json
116
116
  requirement: !ruby/object:Gem::Requirement
117
117
  none: false
118
118
  requirements:
@@ -128,7 +128,7 @@ dependencies:
128
128
  - !ruby/object:Gem::Version
129
129
  version: '0'
130
130
  - !ruby/object:Gem::Dependency
131
- name: json
131
+ name: webrick
132
132
  requirement: !ruby/object:Gem::Requirement
133
133
  none: false
134
134
  requirements:
@@ -255,39 +255,9 @@ dependencies:
255
255
  - - ! '>='
256
256
  - !ruby/object:Gem::Version
257
257
  version: '0'
258
- - !ruby/object:Gem::Dependency
259
- name: debugger
260
- requirement: !ruby/object:Gem::Requirement
261
- none: false
262
- requirements:
263
- - - ! '>='
264
- - !ruby/object:Gem::Version
265
- version: '0'
266
- type: :development
267
- prerelease: false
268
- version_requirements: !ruby/object:Gem::Requirement
269
- none: false
270
- requirements:
271
- - - ! '>='
272
- - !ruby/object:Gem::Version
273
- version: '0'
274
- - !ruby/object:Gem::Dependency
275
- name: geminabox-client
276
- requirement: !ruby/object:Gem::Requirement
277
- none: false
278
- requirements:
279
- - - ! '>='
280
- - !ruby/object:Gem::Version
281
- version: '0'
282
- type: :development
283
- prerelease: false
284
- version_requirements: !ruby/object:Gem::Requirement
285
- none: false
286
- requirements:
287
- - - ! '>='
288
- - !ruby/object:Gem::Version
289
- version: '0'
290
- description: Define a pact between service consumers and providers
258
+ description: Enables consumer driven contract testing, providing a mock service and
259
+ DSL for the consumer project, and interaction playback and verification for the
260
+ service provider project.
291
261
  email:
292
262
  - james.fraser@alumni.swinburne.edu
293
263
  - sergei.matheson@gmail.com
@@ -301,6 +271,7 @@ extra_rdoc_files: []
301
271
  files:
302
272
  - .gitignore
303
273
  - .rspec
274
+ - .travis.yml
304
275
  - CHANGELOG.md
305
276
  - Gemfile
306
277
  - Gemfile.lock
@@ -448,7 +419,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
448
419
  version: '0'
449
420
  segments:
450
421
  - 0
451
- hash: -2921179149528665156
422
+ hash: -2335732393810580306
452
423
  required_rubygems_version: !ruby/object:Gem::Requirement
453
424
  none: false
454
425
  requirements:
@@ -457,13 +428,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
457
428
  version: '0'
458
429
  segments:
459
430
  - 0
460
- hash: -2921179149528665156
431
+ hash: -2335732393810580306
461
432
  requirements: []
462
433
  rubyforge_project:
463
434
  rubygems_version: 1.8.23
464
435
  signing_key:
465
436
  specification_version: 3
466
- summary: Define a pact between service consumers and providers
437
+ summary: Enables consumer driven contract testing, providing a mock service and DSL
438
+ for the consumer project, and interaction playback and verification for the service
439
+ provider project.
467
440
  test_files:
468
441
  - spec/features/consumption_spec.rb
469
442
  - spec/features/production_spec.rb