pacto 0.3.0.pre → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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