pacto 0.3.1 → 0.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.rubocop.yml +29 -7
  4. data/.travis.yml +8 -1
  5. data/CONTRIBUTING.md +3 -6
  6. data/Gemfile +13 -2
  7. data/Guardfile +4 -4
  8. data/Procfile +1 -0
  9. data/README.md +47 -13
  10. data/Rakefile +66 -19
  11. data/TODO.md +33 -10
  12. data/bin/pacto +4 -0
  13. data/changelog.md +30 -0
  14. data/docs/configuration.md +69 -0
  15. data/docs/consumer.md +18 -0
  16. data/docs/cops.md +39 -0
  17. data/docs/forensics.md +66 -0
  18. data/docs/generation.md +65 -0
  19. data/docs/rake_tasks.md +10 -0
  20. data/docs/rspec.md +0 -0
  21. data/docs/samples.md +133 -0
  22. data/docs/server.md +34 -0
  23. data/docs/server_cli.md +18 -0
  24. data/docs/stenographer.md +20 -0
  25. data/features/configuration/strict_matchers.feature +10 -10
  26. data/features/evolve/existing_services.feature +12 -10
  27. data/features/generate/generation.feature +11 -11
  28. data/features/steps/pacto_steps.rb +17 -12
  29. data/features/stub/templates.feature +4 -4
  30. data/features/support/env.rb +21 -9
  31. data/features/validate/meta_validation.feature +9 -17
  32. data/features/validate/validation.feature +5 -6
  33. data/lib/pacto.rb +41 -33
  34. data/lib/pacto/actor.rb +5 -0
  35. data/lib/pacto/actors/from_examples.rb +67 -0
  36. data/lib/pacto/actors/json_generator.rb +20 -0
  37. data/lib/pacto/cli.rb +75 -0
  38. data/lib/pacto/cli/helpers.rb +20 -0
  39. data/lib/pacto/consumer.rb +80 -0
  40. data/lib/pacto/consumer/faraday_driver.rb +34 -0
  41. data/lib/pacto/contract.rb +48 -20
  42. data/lib/pacto/contract_builder.rb +125 -0
  43. data/lib/pacto/contract_factory.rb +31 -12
  44. data/lib/pacto/contract_files.rb +1 -0
  45. data/lib/pacto/contract_set.rb +12 -0
  46. data/lib/pacto/cops.rb +46 -0
  47. data/lib/pacto/cops/body_cop.rb +23 -0
  48. data/lib/pacto/cops/request_body_cop.rb +10 -0
  49. data/lib/pacto/cops/response_body_cop.rb +10 -0
  50. data/lib/pacto/{validators/response_header_validator.rb → cops/response_header_cop.rb} +9 -15
  51. data/lib/pacto/cops/response_status_cop.rb +18 -0
  52. data/lib/pacto/core/configuration.rb +16 -5
  53. data/lib/pacto/core/contract_registry.rb +13 -32
  54. data/lib/pacto/core/hook.rb +1 -0
  55. data/lib/pacto/core/http_middleware.rb +23 -0
  56. data/lib/pacto/core/investigation_registry.rb +60 -0
  57. data/lib/pacto/core/modes.rb +1 -0
  58. data/lib/pacto/core/pacto_request.rb +59 -0
  59. data/lib/pacto/core/pacto_response.rb +41 -0
  60. data/lib/pacto/dash.rb +9 -0
  61. data/lib/pacto/erb_processor.rb +1 -0
  62. data/lib/pacto/exceptions/invalid_contract.rb +1 -0
  63. data/lib/pacto/extensions.rb +3 -16
  64. data/lib/pacto/forensics/investigation_filter.rb +90 -0
  65. data/lib/pacto/forensics/investigation_matcher.rb +80 -0
  66. data/lib/pacto/generator.rb +31 -53
  67. data/lib/pacto/generator/filters.rb +8 -7
  68. data/lib/pacto/generator/hint.rb +26 -0
  69. data/lib/pacto/generator/native_contract_generator.rb +74 -0
  70. data/lib/pacto/hooks/erb_hook.rb +2 -1
  71. data/lib/pacto/investigation.rb +49 -0
  72. data/lib/pacto/logger.rb +1 -0
  73. data/lib/pacto/meta_schema.rb +12 -6
  74. data/lib/pacto/native_contract_factory.rb +60 -0
  75. data/lib/pacto/observers/stenographer.rb +42 -0
  76. data/lib/pacto/provider.rb +27 -0
  77. data/lib/pacto/rake_task.rb +25 -70
  78. data/lib/pacto/request_clause.rb +31 -29
  79. data/lib/pacto/request_pattern.rb +20 -3
  80. data/lib/pacto/resettable.rb +22 -0
  81. data/lib/pacto/response_clause.rb +5 -12
  82. data/lib/pacto/rspec.rb +38 -31
  83. data/lib/pacto/server.rb +4 -0
  84. data/lib/pacto/stubs/uri_pattern.rb +21 -11
  85. data/lib/pacto/stubs/webmock_adapter.rb +69 -34
  86. data/lib/pacto/swagger_contract_factory.rb +90 -0
  87. data/lib/pacto/test_helper.rb +37 -0
  88. data/lib/pacto/ui.rb +32 -2
  89. data/lib/pacto/uri.rb +2 -1
  90. data/lib/pacto/version.rb +2 -1
  91. data/pacto-server.gemspec +24 -0
  92. data/pacto.gemspec +13 -9
  93. data/resources/contract_schema.json +46 -18
  94. data/resources/draft-04.json +150 -0
  95. data/sample_apis/album/cover_api.rb +12 -0
  96. data/sample_apis/config.ru +25 -0
  97. data/sample_apis/echo_api.rb +26 -0
  98. data/sample_apis/files_api.rb +50 -0
  99. data/sample_apis/hello_api.rb +14 -0
  100. data/sample_apis/ping_api.rb +11 -0
  101. data/sample_apis/reverse_api.rb +20 -0
  102. data/samples/README.md +11 -0
  103. data/samples/Rakefile +2 -0
  104. data/samples/configuration.rb +33 -0
  105. data/samples/consumer.rb +15 -0
  106. data/samples/contracts/README.md +1 -0
  107. data/samples/contracts/contract.js +93 -0
  108. data/samples/contracts/get_album_cover.json +48 -0
  109. data/samples/contracts/localhost/api/echo.json +37 -0
  110. data/samples/contracts/localhost/api/ping.json +38 -0
  111. data/samples/cops.rb +30 -0
  112. data/samples/forensics.rb +54 -0
  113. data/samples/generation.rb +48 -0
  114. data/samples/rake_tasks.sh +7 -0
  115. data/samples/rspec.rb +1 -0
  116. data/samples/samples.rb +92 -0
  117. data/samples/scripts/bootstrap +2 -0
  118. data/samples/scripts/wrapper +11 -0
  119. data/samples/server.rb +24 -0
  120. data/samples/server_cli.sh +12 -0
  121. data/samples/stenographer.rb +17 -0
  122. data/spec/coveralls_helper.rb +1 -0
  123. data/spec/fabricators/contract_fabricator.rb +94 -0
  124. data/spec/fabricators/http_fabricator.rb +48 -0
  125. data/spec/fabricators/webmock_fabricator.rb +24 -0
  126. data/spec/{unit/data → fixtures/contracts}/contract.json +2 -2
  127. data/spec/fixtures/contracts/contract_with_examples.json +58 -0
  128. data/spec/{unit/data → fixtures/contracts}/simple_contract.json +5 -3
  129. data/spec/{integration/data → fixtures/contracts}/strict_contract.json +5 -3
  130. data/spec/{integration/data → fixtures/contracts}/templating_contract.json +3 -2
  131. data/spec/{integration/data/simple_contract.json → fixtures/deprecated_contracts/deprecated_contract.json} +2 -1
  132. data/spec/fixtures/swagger/petstore.yaml +101 -0
  133. data/spec/integration/e2e_spec.rb +19 -20
  134. data/spec/integration/forensics/integration_matcher_spec.rb +90 -0
  135. data/spec/integration/rspec_spec.rb +22 -25
  136. data/spec/integration/templating_spec.rb +7 -6
  137. data/spec/pacto/dummy_server.rb +4 -0
  138. data/spec/pacto/{server → dummy_server}/dummy.rb +7 -6
  139. data/spec/pacto/dummy_server/jruby_workaround_helper.rb +23 -0
  140. data/spec/pacto/{server → dummy_server}/playback_servlet.rb +3 -2
  141. data/spec/spec_helper.rb +16 -7
  142. data/spec/unit/actors/from_examples_spec.rb +70 -0
  143. data/spec/unit/actors/json_generator_spec.rb +105 -0
  144. data/spec/unit/pacto/actor_spec.rb +23 -0
  145. data/spec/unit/pacto/configuration_spec.rb +7 -6
  146. data/spec/unit/pacto/consumer/faraday_driver_spec.rb +40 -0
  147. data/spec/unit/pacto/contract_builder_spec.rb +89 -0
  148. data/spec/unit/pacto/contract_factory_spec.rb +62 -11
  149. data/spec/unit/pacto/contract_files_spec.rb +1 -0
  150. data/spec/unit/pacto/contract_set_spec.rb +36 -0
  151. data/spec/unit/pacto/contract_spec.rb +51 -39
  152. data/spec/unit/pacto/cops/body_cop_spec.rb +107 -0
  153. data/spec/unit/pacto/{validators/response_header_validator_spec.rb → cops/response_header_cop_spec.rb} +30 -19
  154. data/spec/unit/pacto/cops/response_status_cop_spec.rb +26 -0
  155. data/spec/unit/pacto/cops_spec.rb +75 -0
  156. data/spec/unit/pacto/core/configuration_spec.rb +6 -5
  157. data/spec/unit/pacto/core/contract_registry_spec.rb +16 -83
  158. data/spec/unit/pacto/core/http_middleware_spec.rb +36 -0
  159. data/spec/unit/pacto/core/investigation_spec.rb +62 -0
  160. data/spec/unit/pacto/core/modes_spec.rb +5 -4
  161. data/spec/unit/pacto/erb_processor_spec.rb +3 -2
  162. data/spec/unit/pacto/extensions_spec.rb +10 -20
  163. data/spec/unit/pacto/generator/filters_spec.rb +11 -10
  164. data/spec/unit/pacto/generator/native_contract_generator_spec.rb +171 -0
  165. data/spec/unit/{hooks → pacto/hooks}/erb_hook_spec.rb +18 -11
  166. data/spec/unit/pacto/investigation_registry_spec.rb +77 -0
  167. data/spec/unit/pacto/logger_spec.rb +6 -5
  168. data/spec/unit/pacto/meta_schema_spec.rb +5 -4
  169. data/spec/unit/pacto/native_contract_factory_spec.rb +26 -0
  170. data/spec/unit/pacto/pacto_spec.rb +13 -28
  171. data/spec/unit/pacto/request_clause_spec.rb +16 -51
  172. data/spec/unit/pacto/request_pattern_spec.rb +6 -5
  173. data/spec/unit/pacto/response_clause_spec.rb +6 -19
  174. data/spec/unit/pacto/server/playback_servlet_spec.rb +21 -18
  175. data/spec/unit/pacto/stubs/observers/stenographer_spec.rb +33 -0
  176. data/spec/unit/pacto/stubs/uri_pattern_spec.rb +39 -11
  177. data/spec/unit/pacto/stubs/webmock_adapter_spec.rb +67 -117
  178. data/spec/unit/pacto/swagger_contract_factory_spec.rb +56 -0
  179. data/spec/unit/pacto/uri_spec.rb +1 -0
  180. data/tasks/release.rake +57 -0
  181. metadata +247 -76
  182. data/.rubocop-todo.yml +0 -24
  183. data/.ruby-gemset +0 -1
  184. data/.ruby-version +0 -1
  185. data/CHANGELOG +0 -12
  186. data/features/validate/body_only.feature +0 -85
  187. data/lib/pacto/contract_list.rb +0 -17
  188. data/lib/pacto/contract_validator.rb +0 -29
  189. data/lib/pacto/core/validation_registry.rb +0 -40
  190. data/lib/pacto/stubs/webmock_helper.rb +0 -69
  191. data/lib/pacto/validation.rb +0 -54
  192. data/lib/pacto/validators/body_validator.rb +0 -49
  193. data/lib/pacto/validators/request_body_validator.rb +0 -26
  194. data/lib/pacto/validators/response_body_validator.rb +0 -26
  195. data/lib/pacto/validators/response_status_validator.rb +0 -24
  196. data/spec/pacto/server.rb +0 -2
  197. data/spec/unit/pacto/contract_list_spec.rb +0 -35
  198. data/spec/unit/pacto/contract_validator_spec.rb +0 -85
  199. data/spec/unit/pacto/core/validation_registry_spec.rb +0 -76
  200. data/spec/unit/pacto/core/validation_spec.rb +0 -60
  201. data/spec/unit/pacto/generator_spec.rb +0 -132
  202. data/spec/unit/pacto/stubs/webmock_helper_spec.rb +0 -20
  203. data/spec/unit/pacto/validators/body_validator_spec.rb +0 -118
  204. data/spec/unit/pacto/validators/response_status_validator_spec.rb +0 -20
@@ -1,24 +0,0 @@
1
- module Pacto
2
- module Validators
3
- class ResponseStatusValidator
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- expected_status = env[:contract].response.status
10
- actual_status = env[:actual_response].status
11
- env[:validation_results].concat self.class.validate(expected_status, actual_status)
12
- @app.call env
13
- end
14
-
15
- def self.validate(expected_status, actual_status)
16
- errors = []
17
- if expected_status != actual_status
18
- errors << "Invalid status: expected #{expected_status} but got #{actual_status}"
19
- end
20
- errors
21
- end
22
- end
23
- end
24
- end
@@ -1,2 +0,0 @@
1
- require_relative 'server/dummy'
2
- require_relative 'server/playback_servlet'
@@ -1,35 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Pacto
4
- describe ContractList do
5
- let(:contract1) { double(:contract_1) }
6
- let(:contract2) { double(:contract_2) }
7
-
8
- it 'holds a list of contracts' do
9
- list = ContractList.new([contract1, contract2])
10
- expect(list.contracts).to eq([contract1, contract2])
11
- end
12
-
13
- context 'when validating' do
14
- it 'validates every contract on the list' do
15
- expect(contract1).to receive(:validate_provider)
16
- expect(contract2).to receive(:validate_provider)
17
-
18
- list = ContractList.new([contract1, contract2])
19
- list.validate_all
20
- end
21
- end
22
-
23
- context 'when stubbing' do
24
- let(:values) { Hash.new }
25
-
26
- it 'stubs every contract on the list' do
27
- expect(contract1).to receive(:stub_contract!).with(values)
28
- expect(contract2).to receive(:stub_contract!).with(values)
29
-
30
- list = ContractList.new([contract1, contract2])
31
- list.stub_all(values)
32
- end
33
- end
34
- end
35
- end
@@ -1,85 +0,0 @@
1
- module Pacto
2
- describe ContractValidator do
3
- let(:validation_errors) { ['some error', 'another error'] }
4
-
5
- let(:expected_response) do
6
- ResponseClause.new(
7
- 'status' => 200,
8
- 'headers' => {
9
- 'Content-Type' => 'application/json'
10
- },
11
- 'body' => {:type => 'object', :required => true, :properties => double('body definition properties')}
12
- )
13
- end
14
-
15
- let(:actual_response) do
16
- double(
17
- :status => 200,
18
- :headers => {'Content-Type' => 'application/json', 'Age' => '60'},
19
- :body => { 'message' => 'response' }
20
- )
21
- end
22
-
23
- let(:actual_request) { double :actual_request }
24
-
25
- let(:expected_request) do
26
- RequestClause.new(
27
- 'http://example.com',
28
- 'body' => {
29
- :type => 'object',
30
- :required => true,
31
- :properties => double('body definition properties')
32
- }
33
- )
34
- end
35
-
36
- let(:contract) do
37
- request_pattern_provider = double(for: nil)
38
- Contract.new(expected_request, expected_response, 'some_file.json', 'sample', request_pattern_provider)
39
- end
40
-
41
- let(:opts) { {} }
42
-
43
- describe '.validate' do
44
- before do
45
- allow(Pacto::Validators::RequestBodyValidator).to receive(:validate).with(contract, actual_request).and_return([])
46
- allow(Pacto::Validators::ResponseBodyValidator).to receive(:validate).with(contract, actual_response).and_return([])
47
- end
48
-
49
- context 'default validator stack' do
50
- it 'calls the RequestBodyValidator' do
51
- expect(Pacto::Validators::RequestBodyValidator).to receive(:validate).with(contract, actual_request).and_return(validation_errors)
52
- expect(ContractValidator.validate contract, actual_request, actual_response, opts).to eq(validation_errors)
53
- end
54
-
55
- it 'calls the ResponseStatusValidator' do
56
- expect(Pacto::Validators::ResponseStatusValidator).to receive(:validate).with(expected_response.status, actual_response.status).and_return(validation_errors)
57
- expect(ContractValidator.validate contract, actual_request, actual_response, opts).to eq(validation_errors)
58
- end
59
-
60
- it 'calls the ResponseHeaderValidator' do
61
- expect(Pacto::Validators::ResponseHeaderValidator).to receive(:validate).with(expected_response.headers, actual_response.headers).and_return(validation_errors)
62
- expect(ContractValidator.validate contract, actual_request, actual_response, opts).to eq(validation_errors)
63
- end
64
-
65
- it 'calls the ResponseBodyValidator' do
66
- expect(Pacto::Validators::ResponseBodyValidator).to receive(:validate).with(contract, actual_response).and_return(validation_errors)
67
- expect(ContractValidator.validate contract, actual_request, actual_response, opts).to eq(validation_errors)
68
- end
69
- end
70
-
71
- context 'when headers and body match and the ResponseStatusValidator reports no errors' do
72
- it 'does not return any errors' do
73
- # JSON::Validator.should_receive(:fully_validate).
74
- # with(definition['body'], fake_response.body, :version => :draft3).
75
- # and_return([])
76
- expect(Pacto::Validators::RequestBodyValidator).to receive(:validate).with(contract, actual_request).and_return([])
77
- expect(Pacto::Validators::ResponseStatusValidator).to receive(:validate).with(expected_response.status, actual_response.status).and_return([])
78
- expect(Pacto::Validators::ResponseHeaderValidator).to receive(:validate).with(expected_response.headers, actual_response.headers).and_return([])
79
- expect(Pacto::Validators::ResponseBodyValidator).to receive(:validate).with(contract, actual_response).and_return([])
80
- expect(ContractValidator.validate contract, actual_request, actual_response, opts).to be_empty
81
- end
82
- end
83
- end
84
- end
85
- end
@@ -1,76 +0,0 @@
1
- describe Pacto::ValidationRegistry do
2
- subject(:registry) { Pacto::ValidationRegistry.instance }
3
- let(:request_pattern) { WebMock::RequestPattern.new(:get, 'www.example.com') }
4
- let(:request_signature) { WebMock::RequestSignature.new(:get, 'www.example.com') }
5
- let(:different_request_signature) { WebMock::RequestSignature.new(:get, 'www.thoughtworks.com') }
6
- let(:validation) { Pacto::Validation.new(request_signature, double, nil) }
7
- let(:validation_for_a_similar_request) { Pacto::Validation.new(request_signature, double, nil) }
8
- let(:validation_for_a_different_request) { Pacto::Validation.new(different_request_signature, double, nil) }
9
-
10
- before(:each) do
11
- registry.reset!
12
- end
13
-
14
- describe 'reset!' do
15
- before(:each) do
16
- registry.register_validation(validation)
17
- end
18
-
19
- it 'cleans validations' do
20
- expect { registry.reset! }.to change { registry.validated? request_pattern }.from([validation]).to(nil)
21
- end
22
- end
23
-
24
- describe 'registering and reporting registered validations' do
25
- it 'returns registered validation' do
26
- expect(registry.register_validation validation).to eq(validation)
27
- end
28
-
29
- it 'reports if validation is not registered' do
30
- expect(registry.validated? request_pattern).to be_false
31
- end
32
-
33
- it 'registers and returns matching validations' do
34
- registry.register_validation(validation)
35
- registry.register_validation(validation_for_a_similar_request)
36
- registry.register_validation(validation_for_a_different_request)
37
- expect(registry.validated? request_pattern).to eq([validation, validation_for_a_similar_request])
38
- end
39
- end
40
-
41
- describe '.unmatched_validations' do
42
- let(:contract) { double('contract', :name => 'test') }
43
-
44
- it 'returns validations with no contract' do
45
- allow(contract).to receive(:validate_consumer).with(different_request_signature, anything).and_return(double('results', :empty? => true))
46
- validation_with_results = Pacto::Validation.new(different_request_signature, double, contract)
47
- registry.register_validation(validation)
48
- registry.register_validation(validation_for_a_similar_request)
49
- registry.register_validation(validation_for_a_different_request)
50
- registry.register_validation(validation_with_results)
51
-
52
- expect(registry.unmatched_validations).to match_array([validation, validation_for_a_similar_request, validation_for_a_different_request])
53
- end
54
- end
55
-
56
- describe '.failed_validations' do
57
- let(:contract) { double('contract', :name => 'test') }
58
- let(:results2) { double('results2', :empty? => false, :join => 'wtf') }
59
-
60
- it 'returns validations with unsuccessful results' do
61
- allow(contract).to receive(:name).and_return 'test'
62
- allow(contract).to receive(:validate_consumer).with(request_signature, anything).and_return(results2)
63
- validation_with_successful_results = Pacto::Validation.new(request_signature, double, contract)
64
- validation_with_unsuccessful_results = Pacto::Validation.new(request_signature, double, contract)
65
-
66
- expect(validation_with_successful_results).to receive(:successful?).twice.and_return true
67
- expect(validation_with_unsuccessful_results).to receive(:successful?).twice.and_return false
68
-
69
- registry.register_validation(validation)
70
- registry.register_validation(validation_with_successful_results)
71
- registry.register_validation(validation_with_unsuccessful_results)
72
-
73
- expect(registry.failed_validations).to match_array([validation_with_unsuccessful_results])
74
- end
75
- end
76
- end
@@ -1,60 +0,0 @@
1
- module Pacto
2
- describe Validation do
3
- let(:request) { double('request') }
4
- let(:response) { double('response') }
5
- let(:contract) { double('contract') }
6
- let(:validation_results) { double('validation_results') }
7
-
8
- before(:each) do
9
- allow(contract).to receive(:validate_consumer)
10
- end
11
-
12
- it 'stores the request, response and contract' do
13
- validation = Pacto::Validation.new request, response, contract
14
- expect(validation.request).to eq request
15
- expect(validation.response).to eq response
16
- end
17
-
18
- it 'generates and stores the results' do
19
- expect(contract).to receive(:validate_consumer).with(request, response).and_return(validation_results)
20
- validation = Pacto::Validation.new request, response, contract
21
- expect(validation.results).to eq validation_results
22
- end
23
-
24
- describe '#successful?' do
25
- subject(:validation) do
26
- Pacto::Validation.new request, response, contract
27
- end
28
-
29
- it 'returns true if there were no validation errors' do
30
- expect(validation.successful?).to be_true
31
- end
32
-
33
- it 'returns false if there were validation errors' do
34
- expect(validation.successful?).to be_true
35
- end
36
- end
37
-
38
- describe '#against_contract?' do
39
- it 'returns nil if there was no contract' do
40
- validation = Pacto::Validation.new request, response, nil
41
- expect(validation.against_contract? 'a').to be_nil
42
- end
43
-
44
- it 'returns the contract with an exact string name match' do
45
- allow(contract).to receive(:file).and_return('foo')
46
- validation = Pacto::Validation.new request, response, contract
47
- expect(validation.against_contract? 'foo').to eq(contract)
48
- expect(validation.against_contract? 'bar').to be_nil
49
- end
50
-
51
- it 'returns the contract if there is a regex match' do
52
- allow(contract).to receive(:file).and_return 'foobar'
53
- validation = Pacto::Validation.new request, response, contract
54
- expect(validation.against_contract?(/foo/)).to eq(contract)
55
- expect(validation.against_contract?(/bar/)).to eq(contract)
56
- expect(validation.against_contract?(/baz/)).to be_nil
57
- end
58
- end
59
- end
60
- end
@@ -1,132 +0,0 @@
1
- module Pacto
2
- describe Generator do
3
- let(:record_host) do
4
- 'http://example.com'
5
- end
6
- let(:request) do
7
- Pacto::RequestClause.new(record_host,
8
- 'method' => 'GET',
9
- 'path' => '/abcd',
10
- 'headers' => {
11
- 'Content-Length' => [1234],
12
- 'Via' => ['Some Proxy'],
13
- 'User-Agent' => ['rspec']
14
- },
15
- 'params' => {
16
- 'apikey' => "<%= ENV['MY_API_KEY'] %>"
17
- }
18
- )
19
- end
20
- let(:response_adapter) do
21
- Faraday::Response.new(
22
- :status => 200,
23
- :response_headers => {
24
- 'Date' => [Time.now],
25
- 'Server' => ['Fake Server'],
26
- 'Content-Type' => ['application/json'],
27
- 'Vary' => ['User-Agent']
28
- },
29
- :body => 'dummy body' # body is just a string
30
- )
31
- end
32
- let(:filtered_request_headers) { double('filtered_response_headers') }
33
- let(:filtered_response_headers) { double('filtered_response_headers') }
34
- let(:response_body_schema) { '{"message": "dummy generated schema"}' }
35
- let(:version) { 'draft3' }
36
- let(:schema_generator) { double('schema_generator') }
37
- let(:validator) { double('validator') }
38
- let(:filters) { double :filters }
39
- let(:request_file) { 'request.json' }
40
- let(:options) { Pacto.configuration.generator_options }
41
- let(:generator) { described_class.new version, schema_generator, validator, options, filters }
42
-
43
- def pretty(obj)
44
- MultiJson.encode(obj, :pretty => true).gsub(/^$\n/, '')
45
- end
46
-
47
- describe '#generate' do
48
- let(:request_contract) do
49
- double(
50
- :request => request
51
- )
52
- end
53
- let(:generated_contract) { double('generated contract') }
54
- before do
55
- Pacto.should_receive(:load_contract).with(request_file, record_host).and_return request_contract
56
- request.should_receive(:execute).and_return response_adapter
57
- end
58
-
59
- it 'parses the request' do
60
- generator.should_receive(:save).with(request_file, request, anything)
61
- generator.generate request_file, record_host
62
- end
63
-
64
- it 'fetches a response' do
65
- generator.should_receive(:save).with(request_file, anything, response_adapter)
66
- generator.generate request_file, record_host
67
- end
68
-
69
- it 'saves the result' do
70
- generator.should_receive(:save).with(request_file, request, response_adapter).and_return generated_contract
71
- expect(generator.generate request_file, record_host).to eq(generated_contract)
72
- end
73
- end
74
-
75
- describe '#save' do
76
- before do
77
- filters.should_receive(:filter_request_headers).with(request, response_adapter).and_return filtered_request_headers
78
- filters.should_receive(:filter_response_headers).with(request, response_adapter).and_return filtered_response_headers
79
- end
80
- context 'invalid schema' do
81
- it 'raises an error if schema generation fails' do
82
- JSON::SchemaGenerator.should_receive(:generate).and_raise ArgumentError.new('Could not generate schema')
83
- expect { generator.save request_file, request, response_adapter }.to raise_error
84
- end
85
-
86
- it 'raises an error if the generated contract is invalid' do
87
- JSON::SchemaGenerator.should_receive(:generate).and_return response_body_schema
88
- validator.should_receive(:validate).and_raise InvalidContract.new('dummy error')
89
- expect { generator.save request_file, request, response_adapter }.to raise_error
90
- end
91
- end
92
-
93
- context 'valid schema' do
94
- let(:raw_contract) do
95
- JSON::SchemaGenerator.should_receive(:generate).with(request_file, response_adapter.body, Pacto.configuration.generator_options).and_return response_body_schema
96
- validator.should_receive(:validate).and_return true
97
- generator.save request_file, request, response_adapter
98
- end
99
- subject(:generated_contract) { JSON.parse raw_contract }
100
-
101
- it 'sets the body to the generated json-schema' do
102
- expect(subject['response']['body']).to eq(JSON.parse response_body_schema)
103
- end
104
-
105
- it 'sets the request attributes' do
106
- generated_request = subject['request']
107
- expect(generated_request['params']).to eq(request.params)
108
- expect(generated_request['path']).to eq(request.path)
109
- end
110
-
111
- it 'preserves ERB in the request params' do
112
- generated_request = subject['request']
113
- expect(generated_request['params']['apikey']).to eq("<%= ENV['MY_API_KEY'] %>")
114
- end
115
-
116
- it 'normalizes the request method' do
117
- generated_request = subject['request']
118
- expect(generated_request['method']).to eq(request.method.downcase.to_s)
119
- end
120
-
121
- it 'sets the response attributes' do
122
- generated_response = subject['response']
123
- expect(generated_response['status']).to eq(response_adapter.status)
124
- end
125
-
126
- it 'generates pretty JSON' do
127
- expect(raw_contract).to eq(pretty(subject))
128
- end
129
- end
130
- end
131
- end
132
- end
@@ -1,20 +0,0 @@
1
- module Pacto
2
- module Stubs
3
- describe WebMockHelper do
4
- before do
5
- WebMock.stub_request(:get, 'www.example.com').to_return(:body => 'pacto')
6
- WebMock.after_request do |request_signature, response|
7
- @request_signature = request_signature
8
- @response = response
9
- end
10
- Faraday.get 'http://www.example.com'
11
- end
12
-
13
- describe '#validate' do
14
- it 'validates a WebMock request/response pair' do
15
- described_class.validate @request_signature, @response
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,118 +0,0 @@
1
- module Pacto
2
- module Validators
3
- describe BodyValidator do
4
- class MyBodyValidator < BodyValidator
5
- class << self
6
- attr_writer :subschema
7
-
8
- def section_name
9
- 'my_section'
10
- end
11
-
12
- def subschema(contract)
13
- @subschema
14
- end
15
- end
16
- end
17
-
18
- subject(:validator) { MyBodyValidator }
19
- let(:string_required) { true }
20
- let(:contract) { double('contract', :file => 'file:///a.json') }
21
- let(:body) { 'a simple string' }
22
- let(:fake_interaction) { double(:fake_interaction, body: body) }
23
-
24
- before(:each) do
25
- MyBodyValidator.subschema = schema
26
- end
27
-
28
- describe '#validate' do
29
- context 'when schema is not specified' do
30
- let(:schema) { nil }
31
-
32
- it 'gives no errors without validating body' do
33
- JSON::Validator.should_not_receive(:fully_validate)
34
- expect(validator.validate(contract, fake_interaction)).to be_empty
35
- end
36
- end
37
-
38
- context 'when the body is a string' do
39
- # TODO: Apparently a schema has string as keys. Probably we could
40
- # make convert it into a symbol based key.
41
- let(:schema) { { 'type' => 'string', 'required' => string_required } }
42
-
43
- it 'does not validate using JSON Schema' do
44
- # FIXME: This seems like a design flaw. We're partially reproducing json-schema behavior
45
- # instead of finding a way to use it.
46
- JSON::Validator.should_not_receive(:fully_validate)
47
- validator.validate(contract, fake_interaction)
48
- end
49
-
50
- context 'if required' do
51
- it 'does not return an error when body is a string' do
52
- expect(validator.validate(contract, fake_interaction)).to be_empty
53
- end
54
-
55
- it 'returns an error when body is nil' do
56
- expect(fake_interaction).to receive(:body).and_return nil
57
- expect(validator.validate(contract, fake_interaction).size).to eq 1
58
- end
59
- end
60
-
61
- context 'if not required' do
62
- let(:string_required) { false }
63
-
64
- it 'does not return an error when body is a string' do
65
- expect(validator.validate(contract, fake_interaction)).to be_empty
66
- end
67
-
68
- it 'does not return an error when body is nil' do
69
- expect(fake_interaction).to receive(:body).and_return nil
70
- expect(validator.validate(contract, fake_interaction)).to be_empty
71
- end
72
- end
73
-
74
- context 'if contains pattern' do
75
- let(:schema) do
76
- { type: 'string', required: string_required, pattern: 'a.c' }
77
- end
78
-
79
- context 'body matches pattern' do
80
- let(:body) { 'abc' } # This matches the pattern /a.c/
81
-
82
- it 'does not return an error' do
83
- expect(validator.validate(contract, fake_interaction)).to be_empty
84
- end
85
- end
86
-
87
- context 'body does not match pattern' do
88
- let(:body) { 'acb' } # This does not matches the pattern /a.c/
89
-
90
- it 'returns an error' do
91
- expect(validator.validate(contract, fake_interaction).size).to eq 1
92
- end
93
- end
94
- end
95
- end
96
-
97
- context 'when the body is json' do
98
- let(:schema) { { type: 'object' } }
99
-
100
- context 'when body matches' do
101
- it 'does not return any errors' do
102
- expect(JSON::Validator).to receive(:fully_validate).and_return([])
103
- expect(validator.validate(contract, fake_interaction)).to be_empty
104
- end
105
- end
106
-
107
- context 'when body does not match' do
108
- it 'returns a list of errors' do
109
- errors = double 'some errors'
110
- expect(JSON::Validator).to receive(:fully_validate).and_return(errors)
111
- expect(validator.validate(contract, fake_interaction)).to eq(errors)
112
- end
113
- end
114
- end
115
- end
116
- end
117
- end
118
- end