pacto 0.2.5 → 0.3.0.pre

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.
Files changed (70) hide show
  1. data/.gitignore +3 -0
  2. data/.rspec +0 -2
  3. data/.rubocop-todo.yml +51 -0
  4. data/.rubocop.yml +1 -0
  5. data/.travis.yml +4 -2
  6. data/Guardfile +28 -14
  7. data/README.md +81 -51
  8. data/Rakefile +24 -11
  9. data/features/generation/generation.feature +25 -0
  10. data/features/journeys/validation.feature +74 -0
  11. data/features/support/env.rb +16 -0
  12. data/lib/pacto.rb +63 -34
  13. data/lib/pacto/contract.rb +25 -11
  14. data/lib/pacto/contract_factory.rb +13 -44
  15. data/lib/pacto/core/callback.rb +11 -0
  16. data/lib/pacto/core/configuration.rb +34 -0
  17. data/lib/pacto/core/contract_repository.rb +44 -0
  18. data/lib/pacto/erb_processor.rb +18 -0
  19. data/lib/pacto/exceptions/invalid_contract.rb +10 -1
  20. data/lib/pacto/extensions.rb +2 -2
  21. data/lib/pacto/generator.rb +75 -0
  22. data/lib/pacto/hash_merge_processor.rb +14 -0
  23. data/lib/pacto/hooks/erb_hook.rb +17 -0
  24. data/lib/pacto/logger.rb +42 -0
  25. data/lib/pacto/meta_schema.rb +17 -0
  26. data/lib/pacto/rake_task.rb +75 -12
  27. data/lib/pacto/request.rb +3 -4
  28. data/lib/pacto/response.rb +27 -19
  29. data/lib/pacto/server.rb +2 -0
  30. data/lib/pacto/server/dummy.rb +45 -0
  31. data/lib/pacto/server/playback_servlet.rb +21 -0
  32. data/lib/pacto/stubs/built_in.rb +57 -0
  33. data/lib/pacto/version.rb +1 -1
  34. data/pacto.gemspec +8 -2
  35. data/resources/contract_schema.json +216 -0
  36. data/spec/coveralls_helper.rb +10 -0
  37. data/spec/integration/data/strict_contract.json +33 -0
  38. data/spec/integration/data/templating_contract.json +25 -0
  39. data/spec/integration/e2e_spec.rb +40 -7
  40. data/spec/integration/templating_spec.rb +55 -0
  41. data/spec/spec_helper.rb +17 -0
  42. data/spec/unit/data/simple_contract.json +22 -0
  43. data/spec/unit/hooks/erb_hook_spec.rb +51 -0
  44. data/spec/unit/pacto/configuration_spec.rb +51 -0
  45. data/spec/unit/pacto/contract_factory_spec.rb +4 -35
  46. data/spec/unit/pacto/contract_spec.rb +59 -31
  47. data/spec/unit/pacto/core/configuration_spec.rb +28 -0
  48. data/spec/unit/pacto/core/contract_repository_spec.rb +133 -0
  49. data/spec/unit/pacto/erb_processor_spec.rb +23 -0
  50. data/spec/unit/pacto/extensions_spec.rb +11 -11
  51. data/spec/unit/pacto/generator_spec.rb +142 -0
  52. data/spec/unit/pacto/hash_merge_processor_spec.rb +20 -0
  53. data/spec/unit/pacto/logger_spec.rb +44 -0
  54. data/spec/unit/pacto/meta_schema_spec.rb +70 -0
  55. data/spec/unit/pacto/pacto_spec.rb +32 -58
  56. data/spec/unit/pacto/request_spec.rb +83 -34
  57. data/spec/unit/pacto/response_adapter_spec.rb +9 -11
  58. data/spec/unit/pacto/response_spec.rb +68 -68
  59. data/spec/unit/pacto/server/playback_servlet_spec.rb +24 -0
  60. data/spec/unit/pacto/stubs/built_in_spec.rb +168 -0
  61. metadata +291 -147
  62. data/.rspec_integration +0 -4
  63. data/.rspec_unit +0 -4
  64. data/lib/pacto/file_pre_processor.rb +0 -12
  65. data/lib/pacto/instantiated_contract.rb +0 -62
  66. data/spec/integration/spec_helper.rb +0 -1
  67. data/spec/integration/utils/dummy_server.rb +0 -34
  68. data/spec/unit/pacto/file_pre_processor_spec.rb +0 -13
  69. data/spec/unit/pacto/instantiated_contract_spec.rb +0 -224
  70. data/spec/unit/spec_helper.rb +0 -5
data/.rspec_integration DELETED
@@ -1,4 +0,0 @@
1
- --colour
2
- --require spec_helper
3
- --require integration/spec_helper
4
- --pattern spec/integration/**/*_spec.rb
data/.rspec_unit DELETED
@@ -1,4 +0,0 @@
1
- --colour
2
- --require spec_helper
3
- --require unit/spec_helper
4
- --pattern spec/unit/**/*_spec.rb
@@ -1,12 +0,0 @@
1
- module Pacto
2
- class FilePreProcessor
3
- def process(file_string)
4
- erb = ERB.new file_string
5
- erb_result = erb.result binding
6
- if ENV["DEBUG_PACTO"]
7
- puts "[DEBUG] Processed contract: #{erb_result.inspect}"
8
- end
9
- erb_result
10
- end
11
- end
12
- end
@@ -1,62 +0,0 @@
1
- module Pacto
2
- class InstantiatedContract
3
- attr_reader :response_body
4
-
5
- def initialize(request, response)
6
- @request = request
7
- @response = response
8
- @response_body = response.body
9
- end
10
-
11
- def request_path
12
- @request.absolute_uri
13
- end
14
-
15
- def request_uri
16
- @request.full_uri
17
- end
18
-
19
- def replace!(values)
20
- if @response_body.respond_to?(:normalize_keys)
21
- @response_body = @response_body.normalize_keys.deep_merge(values.normalize_keys)
22
- else
23
- @response_body = values
24
- end
25
- end
26
-
27
- def stub!
28
- WebMock.stub_request(@request.method, "#{@request.host}#{@request.path}").
29
- with(request_details).
30
- to_return({
31
- :status => @response.status,
32
- :headers => @response.headers,
33
- :body => format_body(@response_body)
34
- })
35
- end
36
-
37
- private
38
-
39
- def format_body(body)
40
- if body.is_a?(Hash) or body.is_a?(Array)
41
- body.to_json
42
- else
43
- body
44
- end
45
- end
46
-
47
- def request_details
48
- details = {}
49
- unless @request.params.empty?
50
- details[webmock_params_key] = @request.params
51
- end
52
- unless @request.headers.empty?
53
- details[:headers] = @request.headers
54
- end
55
- details
56
- end
57
-
58
- def webmock_params_key
59
- @request.method == :get ? :query : :body
60
- end
61
- end
62
- end
@@ -1 +0,0 @@
1
- require_relative 'utils/dummy_server'
@@ -1,34 +0,0 @@
1
- require 'webrick'
2
-
3
- class Servlet < WEBrick::HTTPServlet::AbstractServlet
4
- def initialize(server, json)
5
- super(server)
6
- @json = json
7
- end
8
-
9
- def do_GET(request, response)
10
- response.status = 200
11
- response['Content-Type'] = 'application/json'
12
- response.body = @json
13
- end
14
- end
15
-
16
- class DummyServer
17
- def initialize port, path, response
18
- @server = WEBrick::HTTPServer.new :Port => port,
19
- :AccessLog => [],
20
- :Logger => WEBrick::Log::new("/dev/null", 7)
21
- @server.mount path, Servlet, response
22
- end
23
-
24
- def start
25
- @pid = fork do
26
- trap 'INT' do @server.shutdown end
27
- @server.start
28
- end
29
- end
30
-
31
- def terminate
32
- Process.kill('INT', @pid)
33
- end
34
- end
@@ -1,13 +0,0 @@
1
- module Pacto
2
- describe FilePreProcessor do
3
- describe "#process" do
4
- it "should return the result of ERB" do
5
- subject.process("2 + 2 = <%= 2 + 2 %>").should == "2 + 2 = 4"
6
- end
7
-
8
- it "should not mess with pure JSONs" do
9
- subject.process('{"property": ["one", "two, null"]}')
10
- end
11
- end
12
- end
13
- end
@@ -1,224 +0,0 @@
1
- module Pacto
2
- describe InstantiatedContract do
3
- describe '#replace!' do
4
- let(:body) { double('body') }
5
- let(:response) { double(:body => body) }
6
- let(:values) { double('values') }
7
-
8
- context 'when response body is a hash' do
9
- let(:normalized_values) { double('normalized values') }
10
- let(:normalized_body) { double('normalized body') }
11
- let(:merged_body) { double('merged body') }
12
-
13
- it 'should normalize keys and deep merge response body with given values' do
14
- values.should_receive(:normalize_keys).and_return(normalized_values)
15
- response.body.should_receive(:normalize_keys).and_return(normalized_body)
16
- normalized_body.should_receive(:deep_merge).with(normalized_values).and_return(merged_body)
17
-
18
- instantiated_contract = described_class.new(nil, response)
19
- instantiated_contract.replace!(values)
20
-
21
- instantiated_contract.response_body.should == merged_body
22
- end
23
- end
24
-
25
- context 'when response body is a string' do
26
- let(:body) { 'foo' }
27
-
28
- it 'should replace response body with given values' do
29
- instantiated_contract = described_class.new(nil, response)
30
- instantiated_contract.replace!(values)
31
- instantiated_contract.response_body.should == values
32
- end
33
- end
34
-
35
- context 'when response body is nil' do
36
- let(:body) { nil }
37
-
38
- it 'should replace response body with given values' do
39
- instantiated_contract = described_class.new(nil, response)
40
- instantiated_contract.replace!(values)
41
- instantiated_contract.response_body.should == values
42
- end
43
- end
44
- end
45
-
46
- describe '#response_body' do
47
- let(:response) { double(:body => double('body')) }
48
-
49
- it "should return response body" do
50
- described_class.new(nil, response).response_body.should == response.body
51
- end
52
- end
53
-
54
- describe '#request_path' do
55
- let(:request) { double('request', :absolute_uri => "http://dummy_link/hello_world") }
56
- let(:response) { double('response', :body => double('body')) }
57
-
58
- it "should return the request absolute uri" do
59
- described_class.new(request, response).request_path.should == "http://dummy_link/hello_world"
60
- end
61
- end
62
-
63
- describe '#request_uri' do
64
- let(:request) { double('request', :full_uri => "http://dummy_link/hello_world?param=value#fragment") }
65
- let(:response) { double('response', :body => double('body')) }
66
-
67
- it "should return request full uri" do
68
- described_class.new(request, response).request_uri.should == "http://dummy_link/hello_world?param=value#fragment"
69
- end
70
- end
71
-
72
- describe '#stub!' do
73
- let(:request) do
74
- double({
75
- :host => 'http://localhost',
76
- :method => method,
77
- :path => '/hello_world',
78
- :headers => {'Accept' => 'application/json'},
79
- :params => {'foo' => 'bar'}
80
- })
81
- end
82
-
83
- let(:method) { :get }
84
-
85
- let(:response) do
86
- double({
87
- :status => 200,
88
- :headers => {},
89
- :body => body
90
- })
91
- end
92
-
93
- let(:body) do
94
- {'message' => 'foo'}
95
- end
96
-
97
- let(:stubbed_request) { double('stubbed request') }
98
-
99
- before do
100
- WebMock.should_receive(:stub_request).
101
- with(request.method, "#{request.host}#{request.path}").
102
- and_return(stubbed_request)
103
-
104
- stubbed_request.stub(:to_return).with({
105
- :status => response.status,
106
- :headers => response.headers,
107
- :body => response.body.to_json
108
- })
109
- end
110
-
111
- context 'when the response body is an object' do
112
- let(:body) do
113
- {'message' => 'foo'}
114
- end
115
-
116
- it 'should stub the response body with a json representation' do
117
- stubbed_request.should_receive(:to_return).with({
118
- :status => response.status,
119
- :headers => response.headers,
120
- :body => response.body.to_json
121
- })
122
-
123
- stubbed_request.stub(:with).and_return(stubbed_request)
124
-
125
- described_class.new(request, response).stub!
126
- end
127
- end
128
-
129
- context 'when the response body is an array' do
130
- let(:body) do
131
- [1, 2, 3]
132
- end
133
-
134
- it 'should stub the response body with a json representation' do
135
- stubbed_request.should_receive(:to_return).with({
136
- :status => response.status,
137
- :headers => response.headers,
138
- :body => response.body.to_json
139
- })
140
-
141
- stubbed_request.stub(:with).and_return(stubbed_request)
142
-
143
- described_class.new(request, response).stub!
144
- end
145
- end
146
-
147
- context 'when the response body is not an object or an array' do
148
- let(:body) { nil }
149
-
150
- it 'should stub the response body with the original body' do
151
- stubbed_request.should_receive(:to_return).with({
152
- :status => response.status,
153
- :headers => response.headers,
154
- :body => response.body
155
- })
156
-
157
- stubbed_request.stub(:with).and_return(stubbed_request)
158
-
159
- described_class.new(request, response).stub!
160
- end
161
- end
162
-
163
- context 'a GET request' do
164
- let(:method) { :get }
165
-
166
- it 'should use WebMock to stub the request' do
167
- stubbed_request.should_receive(:with).
168
- with({:headers => request.headers, :query => request.params}).
169
- and_return(stubbed_request)
170
- described_class.new(request, response).stub!
171
- end
172
- end
173
-
174
- context 'a POST request' do
175
- let(:method) { :post }
176
-
177
- it 'should use WebMock to stub the request' do
178
- stubbed_request.should_receive(:with).
179
- with({:headers => request.headers, :body => request.params}).
180
- and_return(stubbed_request)
181
- described_class.new(request, response).stub!
182
- end
183
- end
184
-
185
- context 'a request with no headers' do
186
- let(:request) do
187
- double({
188
- :host => 'http://localhost',
189
- :method => :get,
190
- :path => '/hello_world',
191
- :headers => {},
192
- :params => {'foo' => 'bar'}
193
- })
194
- end
195
-
196
- it 'should use WebMock to stub the request' do
197
- stubbed_request.should_receive(:with).
198
- with({:query => request.params}).
199
- and_return(stubbed_request)
200
- described_class.new(request, response).stub!
201
- end
202
- end
203
-
204
- context 'a request with no params' do
205
- let(:request) do
206
- double({
207
- :host => 'http://localhost',
208
- :method => :get,
209
- :path => '/hello_world',
210
- :headers => {},
211
- :params => {}
212
- })
213
- end
214
-
215
- it 'should use WebMock to stub the request' do
216
- stubbed_request.should_receive(:with).
217
- with({}).
218
- and_return(stubbed_request)
219
- described_class.new(request, response).stub!
220
- end
221
- end
222
- end
223
- end
224
- end
@@ -1,5 +0,0 @@
1
- # Enable Coveralls only on the CI environment
2
- if ENV['CI']
3
- require 'coveralls'
4
- Coveralls.wear!
5
- end