pact 1.0.9 → 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/CHANGELOG.md +20 -0
  2. data/Gemfile.lock +3 -3
  3. data/example/animal-service/Gemfile +14 -0
  4. data/example/animal-service/Gemfile.lock +67 -0
  5. data/example/animal-service/Rakefile +3 -0
  6. data/example/animal-service/spec/service_consumers/pact_helper.rb +24 -0
  7. data/example/animal-service/spec/service_consumers/provider_states_for_zoo_app.rb +9 -0
  8. data/example/zoo-app/Gemfile.lock +2 -15
  9. data/example/zoo-app/spec/pacts/zoo_app-animal_service.json +21 -6
  10. data/example/zoo-app/spec/service_providers/animal_service_spec.rb +1 -1
  11. data/lib/pact/consumer.rb +10 -11
  12. data/lib/pact/consumer/app_manager.rb +1 -0
  13. data/lib/pact/consumer/configuration.rb +179 -0
  14. data/lib/pact/consumer/interaction_builder.rb +1 -2
  15. data/lib/pact/consumer/mock_service.rb +1 -370
  16. data/lib/pact/consumer/mock_service/app.rb +70 -0
  17. data/lib/pact/consumer/mock_service/interaction_delete.rb +28 -0
  18. data/lib/pact/consumer/mock_service/interaction_list.rb +57 -0
  19. data/lib/pact/consumer/mock_service/interaction_post.rb +25 -0
  20. data/lib/pact/consumer/mock_service/interaction_replay.rb +126 -0
  21. data/lib/pact/consumer/mock_service/missing_interactions_get.rb +26 -0
  22. data/lib/pact/consumer/mock_service/rack_request_helper.rb +51 -0
  23. data/lib/pact/consumer/mock_service/startup_poll.rb +22 -0
  24. data/lib/pact/consumer/mock_service/verification_get.rb +35 -0
  25. data/lib/pact/consumer/mock_service_client.rb +3 -1
  26. data/lib/pact/consumer/mock_service_interaction_expectation.rb +33 -0
  27. data/lib/pact/consumer/request.rb +27 -0
  28. data/lib/pact/consumer/rspec.rb +1 -4
  29. data/lib/pact/consumer_contract/consumer_contract.rb +11 -8
  30. data/lib/pact/consumer_contract/interaction.rb +9 -22
  31. data/lib/pact/consumer_contract/request.rb +68 -0
  32. data/lib/pact/consumer_contract/service_consumer.rb +6 -2
  33. data/lib/pact/consumer_contract/service_provider.rb +6 -2
  34. data/lib/pact/matchers/index_not_found.rb +20 -0
  35. data/lib/pact/matchers/matchers.rb +14 -28
  36. data/lib/pact/matchers/unexpected_index.rb +17 -0
  37. data/lib/pact/matchers/unexpected_key.rb +17 -0
  38. data/lib/pact/provider.rb +1 -1
  39. data/lib/pact/provider/configuration.rb +129 -0
  40. data/lib/pact/provider/request.rb +59 -0
  41. data/lib/pact/provider/rspec.rb +4 -5
  42. data/lib/pact/provider/test_methods.rb +14 -52
  43. data/lib/pact/shared/dsl.rb +20 -0
  44. data/lib/pact/shared/key_not_found.rb +24 -0
  45. data/lib/pact/shared/null_expectation.rb +31 -0
  46. data/lib/pact/shared/request.rb +68 -0
  47. data/lib/pact/something_like.rb +7 -1
  48. data/lib/pact/symbolize_keys.rb +12 -0
  49. data/lib/pact/tasks.rb +1 -1
  50. data/lib/pact/tasks/task_helper.rb +23 -0
  51. data/lib/pact/{verification_task.rb → tasks/verification_task.rb} +4 -4
  52. data/lib/pact/version.rb +1 -1
  53. data/lib/tasks/pact.rake +5 -4
  54. data/pact.gemspec +1 -1
  55. data/spec/features/consumption_spec.rb +1 -73
  56. data/spec/features/production_spec.rb +3 -0
  57. data/spec/integration/consumer_spec.rb +170 -0
  58. data/spec/integration/pact/consumer_configuration_spec.rb +1 -1
  59. data/spec/lib/pact/consumer/{dsl_spec.rb → configuration_spec.rb} +10 -9
  60. data/spec/lib/pact/consumer/consumer_contract_builder_spec.rb +2 -2
  61. data/spec/lib/pact/consumer/interaction_builder_spec.rb +1 -1
  62. data/spec/lib/pact/consumer/mock_service/interaction_list_spec.rb +66 -0
  63. data/spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb +82 -0
  64. data/spec/lib/pact/consumer/mock_service_interaction_expectation_spec.rb +54 -0
  65. data/spec/lib/pact/consumer/request_spec.rb +24 -0
  66. data/spec/lib/pact/consumer_contract/consumer_contract_spec.rb +1 -1
  67. data/spec/lib/pact/consumer_contract/interaction_spec.rb +0 -34
  68. data/spec/lib/pact/{request_spec.rb → consumer_contract/request_spec.rb} +45 -121
  69. data/spec/lib/pact/matchers/matchers_spec.rb +29 -13
  70. data/spec/lib/pact/provider/configuration_spec.rb +163 -0
  71. data/spec/lib/pact/provider/request_spec.rb +78 -0
  72. data/spec/lib/pact/provider/test_methods_spec.rb +0 -30
  73. data/spec/lib/pact/verification_task_spec.rb +1 -1
  74. data/spec/spec_helper.rb +3 -0
  75. data/spec/support/factories.rb +5 -1
  76. data/spec/support/pact_helper.rb +6 -0
  77. data/spec/support/shared_examples_for_request.rb +83 -0
  78. data/spec/support/test_app_fail.json +3 -0
  79. data/spec/support/test_app_pass.json +18 -1
  80. metadata +68 -31
  81. data/lib/pact/consumer/dsl.rb +0 -157
  82. data/lib/pact/pact_task_helper.rb +0 -21
  83. data/lib/pact/provider/dsl.rb +0 -115
  84. data/lib/pact/request.rb +0 -167
  85. data/spec/lib/pact/consumer/mock_service_spec.rb +0 -143
  86. data/spec/lib/pact/provider/dsl_spec.rb +0 -179
data/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ### 1.0.10 (24 September 2014)
2
+ * Removing unused requires [Beth Skurrie, 20 hours ago]
3
+ * Adding example changes [Beth Skurrie, 20 hours ago]
4
+ * Cleaning up provider configuration DSL. [Beth Skurrie, 6 days ago]
5
+ * Cleaned up consumer configuration DSL. [Beth Skurrie, 6 days ago]
6
+ * Splitting MockService request handlers into their own separate files. Divide and conquer... [Beth Skurrie, 6 days ago]
7
+ * Improving logging in mock service. [Beth Skurrie, 6 days ago]
8
+ * Cleaned up interaction list test. [Beth Skurrie, 6 days ago]
9
+ * Added better messages for matching when arrays are of different lengths. [Beth Skurrie, 6 days ago]
10
+ * Refactoring the Request world. Put each sub class of Request into it's relevant module. [Beth Skurrie, 6 days ago]
11
+ * Renaming request.match to request.matches? [Beth Skurrie, 7 days ago]
12
+ * Commenting and cleaning code. [Beth Skurrie, 7 days ago]
13
+ * Removed horrible as_json_for_mock_service method and created new class to do the same thing. [Beth Skurrie, 7 days ago]
14
+ * Moving rake task files into tasks directory. [Beth Skurrie, 7 days ago]
15
+ * Moving request file into consumer_contract folder. [Beth Skurrie, 7 days ago]
16
+ * Symbolizing keys so from_hash does not have to duplicate so much of the constructor methods. Service provider is now mandatory. [Beth Skurrie, 7 days ago]
17
+ * Removed Hashie from run time dependencies. [Beth Skurrie, 7 days ago]
18
+ * Starting to clean up mock service. Adding integration tests for failure scenarios. (Beth Skurrie, 7 days ago]
19
+ * Added RSpec fire to ensure stubbed methods exist. Pulled the recreation of a repayable request from an expected request out of the TestHelper into its own class. [Beth Skurrie, 7 days ago]
20
+
1
21
  ### 1.0.9 (16 September 2013)
2
22
 
3
23
  * Fixing pretty generate of json [Beth Skurrie]
data/Gemfile.lock CHANGED
@@ -1,10 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pact (1.0.9)
4
+ pact (1.0.10)
5
5
  awesome_print (~> 1.1.0)
6
6
  find_a_port (~> 1.0.1)
7
- hashie (~> 2.0)
8
7
  json
9
8
  rack-test (~> 0.6.2)
10
9
  randexp (~> 0.1.7)
@@ -46,7 +45,7 @@ GEM
46
45
  rspec-expectations (~> 2.14.0)
47
46
  rspec-mocks (~> 2.14.0)
48
47
  rspec-core (2.14.5)
49
- rspec-expectations (2.14.2)
48
+ rspec-expectations (2.14.3)
50
49
  diff-lcs (>= 1.1.3, < 2.0)
51
50
  rspec-mocks (2.14.3)
52
51
  safe_yaml (0.9.5)
@@ -66,6 +65,7 @@ PLATFORMS
66
65
  DEPENDENCIES
67
66
  fakefs (~> 0.4)
68
67
  geminabox-client
68
+ hashie (~> 2.0)
69
69
  pact!
70
70
  pry
71
71
  rake (~> 10.0.3)
@@ -0,0 +1,14 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'bundler', '~> 1.3.0'
4
+
5
+ group :development, :test do
6
+ gem 'rspec'
7
+ gem 'pact', path: '../../'
8
+ gem 'pry'
9
+ end
10
+
11
+ gem 'rake'
12
+ gem 'rack', '~>1.5.2'
13
+ gem 'json', '~>1.6.8'
14
+ gem 'httparty'
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: ../../
3
+ specs:
4
+ pact (1.0.9)
5
+ awesome_print (~> 1.1.0)
6
+ find_a_port (~> 1.0.1)
7
+ hashie (~> 2.0)
8
+ json
9
+ rack-test (~> 0.6.2)
10
+ randexp (~> 0.1.7)
11
+ rspec (~> 2.12)
12
+ thin
13
+ thor
14
+
15
+ GEM
16
+ remote: https://rubygems.org/
17
+ specs:
18
+ awesome_print (1.1.0)
19
+ coderay (1.0.9)
20
+ daemons (1.1.9)
21
+ diff-lcs (1.2.4)
22
+ eventmachine (1.0.3)
23
+ find_a_port (1.0.1)
24
+ hashie (2.0.5)
25
+ httparty (0.11.0)
26
+ multi_json (~> 1.0)
27
+ multi_xml (>= 0.5.2)
28
+ json (1.6.8)
29
+ method_source (0.8.2)
30
+ multi_json (1.8.0)
31
+ multi_xml (0.5.5)
32
+ pry (0.9.12.2)
33
+ coderay (~> 1.0.5)
34
+ method_source (~> 0.8)
35
+ slop (~> 3.4)
36
+ rack (1.5.2)
37
+ rack-test (0.6.2)
38
+ rack (>= 1.0)
39
+ rake (10.1.0)
40
+ randexp (0.1.7)
41
+ rspec (2.14.1)
42
+ rspec-core (~> 2.14.0)
43
+ rspec-expectations (~> 2.14.0)
44
+ rspec-mocks (~> 2.14.0)
45
+ rspec-core (2.14.5)
46
+ rspec-expectations (2.14.2)
47
+ diff-lcs (>= 1.1.3, < 2.0)
48
+ rspec-mocks (2.14.3)
49
+ slop (3.4.6)
50
+ thin (1.5.1)
51
+ daemons (>= 1.0.9)
52
+ eventmachine (>= 0.12.6)
53
+ rack (>= 1.0.0)
54
+ thor (0.18.1)
55
+
56
+ PLATFORMS
57
+ ruby
58
+
59
+ DEPENDENCIES
60
+ bundler (~> 1.3.0)
61
+ httparty
62
+ json (~> 1.6.8)
63
+ pact!
64
+ pry
65
+ rack (~> 1.5.2)
66
+ rake
67
+ rspec
@@ -0,0 +1,3 @@
1
+ require 'pact/tasks'
2
+
3
+ :default => ['pact:verify']
@@ -0,0 +1,24 @@
1
+ require 'pact/provider/rspec'
2
+ require_relative "provider_states_for_zoo_app"
3
+
4
+
5
+ class AnimalService
6
+
7
+ def call env
8
+ response_body = {}
9
+ if env['PATH_INFO'] == '/alligators'
10
+ response_body = {'name' => 'Bob'}.to_json
11
+ end
12
+ [200, {'Content-Type' => 'application/json'}, [response_body]]
13
+ end
14
+ end
15
+
16
+ Pact.service_provider 'Animal Service' do
17
+ app do
18
+ AnimalService.new
19
+ end
20
+
21
+ honours_pact_with "Zoo App" do
22
+ pact_uri '../zoo-app/spec/pacts/zoo_app-animal_service.json'
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ Pact.provider_states_for "Zoo App" do
2
+ provider_state "there are alligators" do
3
+ #AlligatorRepo.save(Alligator.name("Mary"))
4
+ end
5
+
6
+ provider_state "there is not an alligator named Mary" do
7
+
8
+ end
9
+ end
@@ -1,11 +1,10 @@
1
1
  PATH
2
2
  remote: ../../
3
3
  specs:
4
- pact (0.1.37)
4
+ pact (1.0.9)
5
5
  awesome_print (~> 1.1.0)
6
- capybara (~> 2.1.0)
7
6
  find_a_port (~> 1.0.1)
8
- hashie (~> 2.0.5)
7
+ hashie (~> 2.0)
9
8
  json
10
9
  rack-test (~> 0.6.2)
11
10
  randexp (~> 0.1.7)
@@ -17,12 +16,6 @@ GEM
17
16
  remote: https://rubygems.org/
18
17
  specs:
19
18
  awesome_print (1.1.0)
20
- capybara (2.1.0)
21
- mime-types (>= 1.16)
22
- nokogiri (>= 1.3.3)
23
- rack (>= 1.0.0)
24
- rack-test (>= 0.5.4)
25
- xpath (~> 2.0)
26
19
  coderay (1.0.9)
27
20
  daemons (1.1.9)
28
21
  diff-lcs (1.2.4)
@@ -34,12 +27,8 @@ GEM
34
27
  multi_xml (>= 0.5.2)
35
28
  json (1.6.8)
36
29
  method_source (0.8.2)
37
- mime-types (1.24)
38
- mini_portile (0.5.1)
39
30
  multi_json (1.7.9)
40
31
  multi_xml (0.5.5)
41
- nokogiri (1.6.0)
42
- mini_portile (~> 0.5.0)
43
32
  pry (0.9.12.2)
44
33
  coderay (~> 1.0.5)
45
34
  method_source (~> 0.8)
@@ -63,8 +52,6 @@ GEM
63
52
  eventmachine (>= 0.12.6)
64
53
  rack (>= 1.0.0)
65
54
  thor (0.18.1)
66
- xpath (2.0.0)
67
- nokogiri (~> 1.3)
68
55
 
69
56
  PLATFORMS
70
57
  ruby
@@ -63,11 +63,9 @@
63
63
  "headers": {
64
64
  "Content-Type": "application/json"
65
65
  },
66
- "body": [
67
- {
68
- "name": "Mary"
69
- }
70
- ]
66
+ "body": {
67
+ "name": "Mary"
68
+ }
71
69
  },
72
70
  "provider_state": "there is an alligator named Mary"
73
71
  },
@@ -90,11 +88,28 @@
90
88
  }
91
89
  },
92
90
  "provider_state": "an error has occurred"
91
+ },
92
+ {
93
+ "description": "a request for alligator Mary",
94
+ "request": {
95
+ "method": "get",
96
+ "path": "/alligators/Mary",
97
+ "headers": {
98
+ "Accept": "application/json"
99
+ }
100
+ },
101
+ "response": {
102
+ "status": 404,
103
+ "headers": {
104
+ "Content-Type": "application/json"
105
+ }
106
+ },
107
+ "provider_state": "there is not an alligator named Mary"
93
108
  }
94
109
  ],
95
110
  "metadata": {
96
111
  "pact_gem": {
97
- "version": "0.1.37"
112
+ "version": "1.0.9"
98
113
  }
99
114
  }
100
115
  }
@@ -73,7 +73,7 @@ module ZooApp
73
73
 
74
74
  before do
75
75
  animal_service.
76
- given("there is an alligator named Mary").
76
+ given("there is not an alligator named Mary").
77
77
  upon_receiving("a request for alligator Mary").
78
78
  with({ method: :get, path: '/alligators/Mary', :headers => {'Accept' => 'application/json'} }).
79
79
  will_respond_with({
data/lib/pact/consumer.rb CHANGED
@@ -1,11 +1,10 @@
1
- require_relative 'consumer_contract'
2
- require_relative 'consumer/consumer_contract_builder'
3
- require_relative 'consumer/consumer_contract_builders'
4
- require_relative 'consumer/dsl'
5
- require_relative 'consumer/interaction_builder'
6
- require_relative 'consumer/mock_service'
7
- require_relative 'consumer/mock_service_client'
8
- require_relative 'consumer/app_manager'
9
- require_relative 'term'
10
- require_relative 'something_like'
11
- require_relative 'request'
1
+ require 'pact/consumer_contract'
2
+ require 'pact/consumer/configuration'
3
+ require 'pact/consumer/consumer_contract_builder'
4
+ require 'pact/consumer/consumer_contract_builders'
5
+ require 'pact/consumer/interaction_builder'
6
+ require 'pact/consumer/mock_service'
7
+ require 'pact/consumer/mock_service_client'
8
+ require 'pact/consumer/app_manager'
9
+ require 'pact/term'
10
+ require 'pact/something_like'
@@ -5,6 +5,7 @@ require 'uri'
5
5
  require 'find_a_port'
6
6
  require 'pact/logging'
7
7
  require 'pact/consumer/server'
8
+ require 'singleton'
8
9
 
9
10
  module Pact
10
11
  module Consumer
@@ -0,0 +1,179 @@
1
+ require 'pact/configuration'
2
+ require 'pact/consumer/consumer_contract_builders'
3
+ require 'pact/consumer/consumer_contract_builder'
4
+ require 'pact/shared/dsl'
5
+
6
+ module Pact::Consumer
7
+
8
+ module DSL
9
+ def service_consumer name, &block
10
+ Configuration::ServiceConsumer.build(name, &block)
11
+ end
12
+ end
13
+
14
+ module Configuration
15
+
16
+ module ConfigurationExtensions
17
+ def add_provider_verification &block
18
+ provider_verifications << block
19
+ end
20
+ def provider_verifications
21
+ @provider_verifications ||= []
22
+ end
23
+ end
24
+
25
+ class ServiceConsumer
26
+ extend Pact::DSL
27
+ attr_accessor :app, :port, :name
28
+
29
+ def initialize name
30
+ @name = name
31
+ @app = nil
32
+ @port = nil
33
+ end
34
+
35
+ dsl do
36
+ def app app
37
+ self.app = app
38
+ end
39
+
40
+ def port port
41
+ self.port = port
42
+ end
43
+
44
+ def has_pact_with service_provider_name, &block
45
+ ServiceProvider.build(service_provider_name, name, &block)
46
+ end
47
+ end
48
+
49
+ def finalize
50
+ validate
51
+ register_consumer_app if @app
52
+ end
53
+
54
+ private
55
+
56
+ def validate
57
+ raise "Please provide a consumer name" unless (name && !name.empty?)
58
+ raise "Please provide a port for the consumer app" if app && !port
59
+ end
60
+
61
+
62
+ def register_consumer_app
63
+ Pact::Consumer::AppManager.instance.register app, port
64
+ end
65
+ end
66
+
67
+
68
+ class ServiceProvider
69
+ extend Pact::DSL
70
+
71
+ attr_accessor :service, :consumer_name, :name
72
+
73
+ def initialize name, consumer_name
74
+ @name = name
75
+ @service = nil
76
+ @consumer_name = consumer_name
77
+ end
78
+
79
+ dsl do
80
+ def mock_service name, &block
81
+ self.service = MockService.build(name, consumer_name, self.name, &block)
82
+ end
83
+ end
84
+
85
+ def finalize
86
+ validate
87
+ end
88
+
89
+ private
90
+
91
+ def validate
92
+ raise "Please configure a service for #{name}" unless service
93
+ end
94
+
95
+ end
96
+
97
+ class MockService
98
+ extend Pact::DSL
99
+
100
+ attr_accessor :port, :standalone, :verify, :provider_name, :consumer_name
101
+
102
+ def initialize name, consumer_name, provider_name
103
+ @name = name
104
+ @consumer_name = consumer_name
105
+ @provider_name = provider_name
106
+ @port = nil
107
+ @standalone = false
108
+ @verify = true
109
+ end
110
+
111
+ dsl do
112
+ def port port
113
+ self.port = port
114
+ end
115
+
116
+ def standalone standalone
117
+ self.standalone = standalone
118
+ end
119
+
120
+ def verify verify
121
+ self.verify = verify
122
+ end
123
+ end
124
+
125
+ def finalize
126
+ validate
127
+ register_mock_service
128
+ configure_consumer_contract_builder
129
+ end
130
+
131
+ private
132
+
133
+ def register_mock_service
134
+ unless standalone
135
+ AppManager.instance.register_mock_service_for provider_name, "http://localhost:#{port}"
136
+ end
137
+ end
138
+
139
+ def configure_consumer_contract_builder
140
+ consumer_contract_builder = create_consumer_contract_builder
141
+ create_consumer_contract_builders_method consumer_contract_builder
142
+ setup_verification(consumer_contract_builder) if verify
143
+ consumer_contract_builder
144
+ end
145
+
146
+ def create_consumer_contract_builder
147
+ consumer_contract_builder_fields = {
148
+ :consumer_name => consumer_name,
149
+ :provider_name => provider_name,
150
+ :pactfile_write_mode => Pact.configuration.pactfile_write_mode,
151
+ :port => port
152
+ }
153
+ Pact::Consumer::ConsumerContractBuilder.new consumer_contract_builder_fields
154
+ end
155
+
156
+ def setup_verification consumer_contract_builder
157
+ Pact.configuration.add_provider_verification do | example_description |
158
+ consumer_contract_builder.verify example_description
159
+ end
160
+ end
161
+
162
+ # This makes the consumer_contract_builder available via a module method with the given identifier
163
+ # as the method name.
164
+ # I feel this should be defined somewhere else, but I'm not sure where
165
+ def create_consumer_contract_builders_method consumer_contract_builder
166
+ Pact::Consumer::ConsumerContractBuilders.send(:define_method, @name.to_sym) do
167
+ consumer_contract_builder
168
+ end
169
+ end
170
+
171
+ def validate
172
+ raise "Please provide a port for service #{name}" unless port
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ Pact.send(:extend, Pact::Consumer::DSL)
179
+ Pact::Configuration.send(:include, Pact::Consumer::Configuration::ConfigurationExtensions)