pacto 0.3.0.pre → 0.3.0

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 (111) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rubocop-todo.yml +0 -27
  4. data/.rubocop.yml +9 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +4 -5
  8. data/CONTRIBUTING.md +112 -0
  9. data/Gemfile +5 -0
  10. data/Guardfile +18 -13
  11. data/README.md +157 -101
  12. data/Rakefile +3 -3
  13. data/features/configuration/strict_matchers.feature +97 -0
  14. data/features/evolve/README.md +11 -0
  15. data/features/evolve/existing_services.feature +82 -0
  16. data/features/generate/README.md +5 -0
  17. data/features/generate/generation.feature +28 -0
  18. data/features/steps/pacto_steps.rb +75 -0
  19. data/features/stub/README.md +2 -0
  20. data/features/stub/templates.feature +46 -0
  21. data/features/support/env.rb +11 -5
  22. data/features/validate/README.md +1 -0
  23. data/features/validate/body_only.feature +85 -0
  24. data/features/{journeys/validation.feature → validate/meta_validation.feature} +41 -24
  25. data/features/validate/validation.feature +36 -0
  26. data/lib/pacto.rb +61 -33
  27. data/lib/pacto/contract.rb +18 -15
  28. data/lib/pacto/contract_factory.rb +14 -11
  29. data/lib/pacto/contract_files.rb +17 -0
  30. data/lib/pacto/contract_list.rb +17 -0
  31. data/lib/pacto/contract_validator.rb +29 -0
  32. data/lib/pacto/core/configuration.rb +19 -17
  33. data/lib/pacto/core/contract_registry.rb +43 -0
  34. data/lib/pacto/core/{callback.rb → hook.rb} +3 -3
  35. data/lib/pacto/core/modes.rb +33 -0
  36. data/lib/pacto/core/validation_registry.rb +45 -0
  37. data/lib/pacto/erb_processor.rb +0 -1
  38. data/lib/pacto/extensions.rb +18 -4
  39. data/lib/pacto/generator.rb +34 -49
  40. data/lib/pacto/generator/filters.rb +41 -0
  41. data/lib/pacto/hooks/erb_hook.rb +4 -3
  42. data/lib/pacto/logger.rb +4 -2
  43. data/lib/pacto/meta_schema.rb +4 -2
  44. data/lib/pacto/rake_task.rb +28 -25
  45. data/lib/pacto/request_clause.rb +43 -0
  46. data/lib/pacto/request_pattern.rb +8 -0
  47. data/lib/pacto/response_clause.rb +15 -0
  48. data/lib/pacto/rspec.rb +102 -0
  49. data/lib/pacto/stubs/uri_pattern.rb +23 -0
  50. data/lib/pacto/stubs/webmock_adapter.rb +69 -0
  51. data/lib/pacto/stubs/webmock_helper.rb +71 -0
  52. data/lib/pacto/ui.rb +7 -0
  53. data/lib/pacto/uri.rb +9 -0
  54. data/lib/pacto/validation.rb +57 -0
  55. data/lib/pacto/validators/body_validator.rb +41 -0
  56. data/lib/pacto/validators/request_body_validator.rb +23 -0
  57. data/lib/pacto/validators/response_body_validator.rb +23 -0
  58. data/lib/pacto/validators/response_header_validator.rb +49 -0
  59. data/lib/pacto/validators/response_status_validator.rb +24 -0
  60. data/lib/pacto/version.rb +1 -1
  61. data/pacto.gemspec +33 -29
  62. data/resources/contract_schema.json +8 -176
  63. data/resources/draft-03.json +174 -0
  64. data/spec/integration/data/strict_contract.json +2 -2
  65. data/spec/integration/e2e_spec.rb +22 -31
  66. data/spec/integration/rspec_spec.rb +94 -0
  67. data/spec/integration/templating_spec.rb +9 -12
  68. data/{lib → spec}/pacto/server.rb +0 -0
  69. data/{lib → spec}/pacto/server/dummy.rb +11 -8
  70. data/{lib → spec}/pacto/server/playback_servlet.rb +1 -1
  71. data/spec/spec_helper.rb +2 -0
  72. data/spec/unit/hooks/erb_hook_spec.rb +15 -15
  73. data/spec/unit/pacto/configuration_spec.rb +2 -10
  74. data/spec/unit/pacto/contract_factory_spec.rb +16 -13
  75. data/spec/unit/pacto/contract_files_spec.rb +42 -0
  76. data/spec/unit/pacto/contract_list_spec.rb +35 -0
  77. data/spec/unit/pacto/contract_spec.rb +43 -44
  78. data/spec/unit/pacto/contract_validator_spec.rb +85 -0
  79. data/spec/unit/pacto/core/configuration_spec.rb +4 -11
  80. data/spec/unit/pacto/core/contract_registry_spec.rb +119 -0
  81. data/spec/unit/pacto/core/modes_spec.rb +18 -0
  82. data/spec/unit/pacto/core/validation_registry_spec.rb +76 -0
  83. data/spec/unit/pacto/core/validation_spec.rb +60 -0
  84. data/spec/unit/pacto/extensions_spec.rb +14 -23
  85. data/spec/unit/pacto/generator/filters_spec.rb +99 -0
  86. data/spec/unit/pacto/generator_spec.rb +34 -73
  87. data/spec/unit/pacto/meta_schema_spec.rb +46 -6
  88. data/spec/unit/pacto/pacto_spec.rb +17 -15
  89. data/spec/unit/pacto/{request_spec.rb → request_clause_spec.rb} +32 -44
  90. data/spec/unit/pacto/request_pattern_spec.rb +22 -0
  91. data/spec/unit/pacto/response_clause_spec.rb +54 -0
  92. data/spec/unit/pacto/stubs/uri_pattern_spec.rb +28 -0
  93. data/spec/unit/pacto/stubs/webmock_adapter_spec.rb +205 -0
  94. data/spec/unit/pacto/stubs/webmock_helper_spec.rb +20 -0
  95. data/spec/unit/pacto/uri_spec.rb +20 -0
  96. data/spec/unit/pacto/validators/body_validator_spec.rb +105 -0
  97. data/spec/unit/pacto/validators/response_header_validator_spec.rb +94 -0
  98. data/spec/unit/pacto/validators/response_status_validator_spec.rb +20 -0
  99. metadata +230 -146
  100. data/features/generation/generation.feature +0 -25
  101. data/lib/pacto/core/contract_repository.rb +0 -44
  102. data/lib/pacto/hash_merge_processor.rb +0 -14
  103. data/lib/pacto/request.rb +0 -57
  104. data/lib/pacto/response.rb +0 -63
  105. data/lib/pacto/response_adapter.rb +0 -24
  106. data/lib/pacto/stubs/built_in.rb +0 -57
  107. data/spec/unit/pacto/core/contract_repository_spec.rb +0 -133
  108. data/spec/unit/pacto/hash_merge_processor_spec.rb +0 -20
  109. data/spec/unit/pacto/response_adapter_spec.rb +0 -25
  110. data/spec/unit/pacto/response_spec.rb +0 -201
  111. data/spec/unit/pacto/stubs/built_in_spec.rb +0 -168
@@ -1,25 +0,0 @@
1
- module Pacto
2
- describe ResponseAdapter do
3
- let(:response) do
4
- double(
5
- :code => 200,
6
- :headers => {'foo' => ['bar', 'baz'], 'hello' => ['world']},
7
- :body => double('body')
8
- )
9
- end
10
-
11
- subject(:response_adapter) { described_class.new response }
12
-
13
- it 'has a status' do
14
- expect(response_adapter.status).to eq response.code
15
- end
16
-
17
- it 'has a body' do
18
- expect(response_adapter.body).to eq response.body
19
- end
20
-
21
- it 'normalizes headers values according to RFC2616' do
22
- expect(response_adapter.headers).to eq({'foo' => 'bar,baz', 'hello' => 'world'})
23
- end
24
- end
25
- end
@@ -1,201 +0,0 @@
1
- module Pacto
2
- describe Response do
3
- let(:body_definition) do
4
- {:type => 'object', :required => true, :properties => double('body definition properties')}
5
- end
6
- let(:definition) do
7
- {
8
- 'status' => 200,
9
- 'headers' => {'Content-Type' => 'application/json'},
10
- 'body' => body_definition
11
- }
12
- end
13
-
14
- describe '#instantiate' do
15
- let(:generated_body) { double('generated body') }
16
-
17
- it 'instantiates a response with a body that matches the given definition' do
18
- JSON::Generator.should_receive(:generate).
19
- with(definition['body']).
20
- and_return(generated_body)
21
-
22
- response = described_class.new(definition).instantiate
23
- expect(response.status).to eq definition['status']
24
- expect(response.headers).to eq definition['headers']
25
- expect(response.body).to eq generated_body
26
- end
27
- end
28
-
29
- describe '#validate' do
30
- let(:status) { 200 }
31
- let(:headers) { {'Content-Type' => 'application/json', 'Age' => '60'} }
32
- let(:response_body) { {'message' => 'response'} }
33
- let(:fake_response) do
34
- double({
35
- :status => status,
36
- :headers => headers,
37
- :body => response_body
38
- })
39
- end
40
-
41
- context 'when status, headers and body match' do
42
- it 'does not return any errors' do
43
- JSON::Validator.should_receive(:fully_validate).
44
- with(definition['body'], fake_response.body, :version => :draft3).
45
- and_return([])
46
-
47
- response = described_class.new(definition)
48
- expect(response.validate(fake_response)).to be_empty
49
- end
50
- end
51
-
52
- context 'when body is a pure string and matches the description' do
53
- let(:string_required) { true }
54
- let(:body_definition) do
55
- { 'type' => 'string', 'required' => string_required }
56
- end
57
- let(:response_body) { 'a simple string' }
58
-
59
- it 'does not validate using JSON Schema' do
60
- response = described_class.new(definition)
61
-
62
- JSON::Validator.should_not_receive(:fully_validate)
63
- response.validate(fake_response)
64
- end
65
-
66
- context 'if required' do
67
- it 'does not return an error when body is a string' do
68
- response = described_class.new(definition)
69
-
70
- expect(response.validate(fake_response)).to be_empty
71
- end
72
-
73
- it 'returns an error when body is nil' do
74
- response = described_class.new(definition)
75
-
76
- fake_response.stub(:body).and_return(nil)
77
- expect(response.validate(fake_response).size).to eq 1
78
- end
79
- end
80
-
81
- context 'if not required' do
82
- let(:string_required) { false }
83
-
84
- it 'does not return an error when body is a string' do
85
- response = described_class.new(definition)
86
-
87
- expect(response.validate(fake_response)).to be_empty
88
- end
89
-
90
- it 'does not return an error when body is nil' do
91
- response = described_class.new(definition)
92
-
93
- fake_response.stub(:body).and_return(nil)
94
- expect(response.validate(fake_response)).to be_empty
95
- end
96
- end
97
-
98
- context 'if contains pattern' do
99
- let(:body_definition) do
100
- { 'type' => 'string', 'required' => string_required, 'pattern' => 'a.c' }
101
- end
102
-
103
- context 'body matches pattern' do
104
- let(:response_body) { 'cabcd' }
105
-
106
- it 'does not return an error' do
107
- response = described_class.new(definition)
108
-
109
- expect(response.validate(fake_response)).to be_empty
110
- end
111
- end
112
-
113
- context 'body does not match pattern' do
114
- let(:response_body) { 'cabscd' }
115
-
116
- it 'returns an error' do
117
- response = described_class.new(definition)
118
-
119
- expect(response.validate(fake_response).size).to eq 1
120
- end
121
- end
122
-
123
- end
124
- end
125
-
126
- context 'when status does not match' do
127
- let(:status) { 500 }
128
-
129
- it 'returns a status error' do
130
- JSON::Validator.should_not_receive(:fully_validate)
131
-
132
- response = described_class.new(definition)
133
- expect(response.validate(fake_response)).to eq ["Invalid status: expected #{definition['status']} but got #{status}"]
134
- end
135
- end
136
-
137
- context 'when headers do not match' do
138
- let(:headers) { {'Content-Type' => 'text/html'} }
139
-
140
- it 'returns a header error' do
141
- JSON::Validator.should_not_receive(:fully_validate)
142
-
143
- response = described_class.new(definition)
144
- expect(response.validate(fake_response)).to eq ["Invalid headers: expected #{definition['headers'].inspect} to be a subset of #{headers.inspect}"]
145
- end
146
- end
147
-
148
- context 'when headers are a subset of expected headers' do
149
- let(:headers) { {'Content-Type' => 'application/json'} }
150
-
151
- it 'does not return any errors' do
152
- JSON::Validator.stub(:fully_validate).and_return([])
153
-
154
- response = described_class.new(definition)
155
- expect(response.validate(fake_response)).to be_empty
156
- end
157
- end
158
-
159
- context 'when headers values match but keys have different case' do
160
- let(:headers) { {'content-type' => 'application/json'} }
161
-
162
- it 'does not return any errors' do
163
- JSON::Validator.stub(:fully_validate).and_return([])
164
-
165
- response = described_class.new(definition)
166
- expect(response.validate(fake_response)).to be_empty
167
- end
168
- end
169
-
170
- context 'when body does not match' do
171
- let(:errors) { [double('error1'), double('error2')] }
172
-
173
- it 'returns a list of errors' do
174
- JSON::Validator.stub(:fully_validate).and_return(errors)
175
-
176
- response = described_class.new(definition)
177
- expect(response.validate(fake_response)).to eq errors
178
- end
179
- end
180
-
181
- context 'when body not specified' do
182
- let(:definition) do
183
- {
184
- 'status' => status,
185
- 'headers' => headers
186
- }
187
- end
188
-
189
- it 'does not validate body' do
190
- JSON::Validator.should_not_receive(:fully_validate)
191
- described_class.new(definition)
192
- end
193
-
194
- it 'gives no errors' do
195
- response = described_class.new(definition)
196
- expect(response.validate(fake_response)).to be_empty
197
- end
198
- end
199
- end
200
- end
201
- end
@@ -1,168 +0,0 @@
1
- module Pacto
2
- module Stubs
3
- describe BuiltIn do
4
- let(:request) do
5
- double({
6
- :host => 'http://localhost',
7
- :method => method,
8
- :path => '/hello_world',
9
- :headers => {'Accept' => 'application/json'},
10
- :params => {'foo' => 'bar'}
11
- })
12
- end
13
-
14
- let(:method) { :get }
15
-
16
- let(:response) do
17
- double({
18
- :status => 200,
19
- :headers => {},
20
- :body => body
21
- })
22
- end
23
-
24
- let(:body) do
25
- {'message' => 'foo'}
26
- end
27
-
28
- let(:stubbed_request) { double('stubbed request') }
29
- let(:processor) { double('processor') }
30
-
31
- describe '#initialize' do
32
- it 'sets up a callback' do
33
- WebMock.should_receive(:after_request) do | arg, &block |
34
- expect(block.parameters).to have(2).items
35
- end
36
-
37
- described_class.new
38
- end
39
- end
40
-
41
- describe '#stub_request!' do
42
- before do
43
- WebMock.should_receive(:stub_request).
44
- with(request.method, "#{request.host}#{request.path}").
45
- and_return(stubbed_request)
46
-
47
- stubbed_request.stub(:to_return).with({
48
- :status => response.status,
49
- :headers => response.headers,
50
- :body => response.body.to_json
51
- })
52
- end
53
-
54
- context 'when the response body is an object' do
55
- let(:body) do
56
- {'message' => 'foo'}
57
- end
58
-
59
- it 'stubs the response body with a json representation' do
60
- stubbed_request.should_receive(:to_return).with({
61
- :status => response.status,
62
- :headers => response.headers,
63
- :body => response.body.to_json
64
- })
65
-
66
- stubbed_request.stub(:with).and_return(stubbed_request)
67
-
68
- described_class.new.stub_request! request, response
69
- end
70
- end
71
-
72
- context 'when the response body is an array' do
73
- let(:body) do
74
- [1, 2, 3]
75
- end
76
-
77
- it 'stubs the response body with a json representation' do
78
- stubbed_request.should_receive(:to_return).with({
79
- :status => response.status,
80
- :headers => response.headers,
81
- :body => response.body.to_json
82
- })
83
-
84
- stubbed_request.stub(:with).and_return(stubbed_request)
85
-
86
- described_class.new.stub_request! request, response
87
- end
88
- end
89
-
90
- context 'when the response body is not an object or an array' do
91
- let(:body) { nil }
92
-
93
- it 'stubs the response body with the original body' do
94
- stubbed_request.should_receive(:to_return).with({
95
- :status => response.status,
96
- :headers => response.headers,
97
- :body => response.body
98
- })
99
-
100
- stubbed_request.stub(:with).and_return(stubbed_request)
101
-
102
- described_class.new.stub_request! request, response
103
- end
104
- end
105
-
106
- context 'a GET request' do
107
- let(:method) { :get }
108
-
109
- it 'uses WebMock to stub the request' do
110
- stubbed_request.should_receive(:with).
111
- with({:headers => request.headers, :query => request.params}).
112
- and_return(stubbed_request)
113
- described_class.new.stub_request! request, response
114
- end
115
- end
116
-
117
- context 'a POST request' do
118
- let(:method) { :post }
119
-
120
- it 'uses WebMock to stub the request' do
121
- stubbed_request.should_receive(:with).
122
- with({:headers => request.headers, :body => request.params}).
123
- and_return(stubbed_request)
124
- described_class.new.stub_request! request, response
125
- end
126
- end
127
-
128
- context 'a request with no headers' do
129
- let(:request) do
130
- double({
131
- :host => 'http://localhost',
132
- :method => :get,
133
- :path => '/hello_world',
134
- :headers => {},
135
- :params => {'foo' => 'bar'}
136
- })
137
- end
138
-
139
- it 'uses WebMock to stub the request' do
140
- stubbed_request.should_receive(:with).
141
- with({:query => request.params}).
142
- and_return(stubbed_request)
143
- described_class.new.stub_request! request, response
144
- end
145
- end
146
-
147
- context 'a request with no params' do
148
- let(:request) do
149
- double({
150
- :host => 'http://localhost',
151
- :method => :get,
152
- :path => '/hello_world',
153
- :headers => {},
154
- :params => {}
155
- })
156
- end
157
-
158
- it 'uses WebMock to stub the request' do
159
- stubbed_request.should_receive(:with).
160
- with({}).
161
- and_return(stubbed_request)
162
- described_class.new.stub_request! request, response
163
- end
164
- end
165
- end
166
- end
167
- end
168
- end