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
@@ -0,0 +1,107 @@
1
+ # -*- encoding : utf-8 -*-
2
+ RSpec.shared_examples 'a body cop' do | section_to_validate |
3
+ subject(:cop) { described_class }
4
+ let(:request_clause) { Fabricate(:request_clause, schema: schema) }
5
+ let(:response_clause) { Fabricate(:response_clause, schema: schema) }
6
+ let(:contract) do
7
+ Fabricate(:contract, file: 'file:///a.json', request: request_clause, response: response_clause)
8
+ end
9
+ let(:string_required) { %w(#) }
10
+ let(:request) { Fabricate(:pacto_request) }
11
+ let(:response) { Fabricate(:pacto_response) }
12
+ let(:clause_to_validate) { contract.send section_to_validate }
13
+ let(:object_to_validate) { send section_to_validate }
14
+
15
+ describe '#validate' do
16
+ context 'when schema is not specified' do
17
+ let(:schema) { nil }
18
+
19
+ it 'gives no errors without validating body' do
20
+ expect(JSON::Validator).not_to receive(:fully_validate)
21
+ expect(cop.investigate(request, response, contract)).to be_empty
22
+ end
23
+ end
24
+
25
+ context 'when the expected body is a string' do
26
+ let(:schema) { { 'type' => 'string', 'required' => string_required } }
27
+
28
+ context 'if required' do
29
+ it 'does not return an error when body is a string' do
30
+ object_to_validate.body = 'asdf'
31
+ expect(cop.investigate(request, response, contract)).to eq([])
32
+ end
33
+
34
+ it 'returns an error when body is nil' do
35
+ object_to_validate.body = nil
36
+ expect(cop.investigate(request, response, contract).size).to eq 1
37
+ end
38
+ end
39
+
40
+ context 'if not required' do
41
+ let(:string_required) { %w() }
42
+
43
+ # Body can be empty but not nil if not required
44
+ # Not sure if this is an issue or not
45
+ skip 'does not return an error when body is a string' do
46
+ expect(cop.investigate(request, response, contract)).to be_empty
47
+ end
48
+
49
+ it 'does not return an error when body is empty' do
50
+ object_to_validate.body = ''
51
+ expect(cop.investigate(request, response, contract)).to be_empty
52
+ end
53
+ end
54
+
55
+ context 'if contains pattern' do
56
+ let(:schema) do
57
+ { type: 'string', required: string_required, pattern: 'a.c' }
58
+ end
59
+
60
+ context 'body matches pattern' do
61
+ it 'does not return an error' do
62
+ object_to_validate.body = 'abc'
63
+ expect(cop.investigate(request, response, contract)).to be_empty
64
+ end
65
+ end
66
+
67
+ context 'body does not match pattern' do
68
+ it 'returns an error' do
69
+ object_to_validate.body = 'acb' # This does not matches the pattern /a.c/
70
+ expect(cop.investigate(request, response, contract).size).to eq 1
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ context 'when the body is json' do
77
+ let(:schema) { { type: 'object' } }
78
+
79
+ context 'when body matches' do
80
+ it 'does not return any errors' do
81
+ expect(JSON::Validator).to receive(:fully_validate).and_return([])
82
+ expect(cop.investigate(request, response, contract)).to be_empty
83
+ end
84
+ end
85
+
86
+ context 'when body does not match' do
87
+ it 'returns a list of errors' do
88
+ errors = double 'some errors'
89
+ expect(JSON::Validator).to receive(:fully_validate).and_return(errors)
90
+ expect(cop.investigate(request, response, contract)).to eq(errors)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ module Pacto
98
+ module Cops
99
+ describe RequestBodyCop do
100
+ it_behaves_like 'a body cop', :request
101
+ end
102
+
103
+ describe ResponseBodyCop do
104
+ it_behaves_like 'a body cop', :response
105
+ end
106
+ end
107
+ end
@@ -1,24 +1,34 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  module Pacto
2
- module Validators
3
- describe ResponseHeaderValidator do
4
- subject(:validator) { described_class }
3
+ module Cops
4
+ describe ResponseHeaderCop do
5
+ subject(:cop) { described_class }
6
+ let(:contract) do
7
+ response_clause = Fabricate(:response_clause, headers: expected_headers)
8
+ Fabricate(:contract, response: response_clause)
9
+ end
10
+ let(:request) { Fabricate(:pacto_request) }
11
+ let(:response) { Fabricate(:pacto_response, headers: actual_headers) }
5
12
  let(:expected_headers) do
6
13
  {
7
14
  'Content-Type' => 'application/json'
8
15
  }
9
16
  end
10
- describe '#validate' do
17
+ describe '#investigate' do
11
18
  context 'when headers do not match' do
12
- let(:actual_headers) { {'Content-Type' => 'text/html'} }
13
-
19
+ let(:actual_headers) do
20
+ { 'Content-Type' => 'text/html' }
21
+ end
14
22
  it 'indicates the exact mismatches' do
15
- expect(validator.validate(expected_headers, actual_headers)).
23
+ expect(cop.investigate(request, response, contract)).
16
24
  to eq ['Invalid response header Content-Type: expected "application/json" but received "text/html"']
17
25
  end
18
26
  end
19
27
 
20
28
  context 'when headers are missing' do
21
- let(:actual_headers) { {} }
29
+ let(:actual_headers) do
30
+ {}
31
+ end
22
32
  let(:expected_headers) do
23
33
  {
24
34
  'Content-Type' => 'application/json',
@@ -26,7 +36,7 @@ module Pacto
26
36
  }
27
37
  end
28
38
  it 'lists the missing headers' do
29
- expect(validator.validate(expected_headers, actual_headers)).
39
+ expect(cop.investigate(request, response, contract)).
30
40
  to eq [
31
41
  'Missing expected response header: Content-Type',
32
42
  'Missing expected response header: My-Cool-Header'
@@ -40,9 +50,9 @@ module Pacto
40
50
  end
41
51
 
42
52
  context 'and no Location header is sent' do
43
- let(:actual_headers) { {'Content-Type' => 'application/json'} }
53
+ let(:actual_headers) { { 'Content-Type' => 'application/json' } }
44
54
  it 'returns a header error when no Location header is sent' do
45
- expect(validator.validate(expected_headers, actual_headers)).to eq ['Missing expected response header: Location']
55
+ expect(cop.investigate(request, response, contract)).to eq ['Missing expected response header: Location']
46
56
  end
47
57
  end
48
58
 
@@ -54,8 +64,9 @@ module Pacto
54
64
  }
55
65
  end
56
66
 
57
- it 'returns a validation error' do
58
- expect(validator.validate(expected_headers, actual_headers)).to eq ["Invalid response header Location: expected URI #{actual_headers['Location']} to match URI Template #{expected_headers['Location']}"]
67
+ it 'returns a investigation error' do
68
+ response.headers = actual_headers
69
+ expect(cop.investigate(request, response, contract)).to eq ["Invalid response header Location: expected URI #{actual_headers['Location']} to match URI Template #{expected_headers['Location']}"]
59
70
  end
60
71
  end
61
72
 
@@ -67,25 +78,25 @@ module Pacto
67
78
  }
68
79
  end
69
80
 
70
- it 'validates successfully' do
71
- expect(validator.validate(expected_headers, actual_headers)).to be_empty
81
+ it 'investigates successfully' do
82
+ expect(cop.investigate(request, response, contract)).to be_empty
72
83
  end
73
84
  end
74
85
  end
75
86
 
76
87
  context 'when headers are a subset of expected headers' do
77
- let(:actual_headers) { {'Content-Type' => 'application/json'} }
88
+ let(:actual_headers) { { 'Content-Type' => 'application/json' } }
78
89
 
79
90
  it 'does not return any errors' do
80
- expect(validator.validate(expected_headers, actual_headers)).to be_empty
91
+ expect(cop.investigate(request, response, contract)).to be_empty
81
92
  end
82
93
  end
83
94
 
84
95
  context 'when headers values match but keys have different case' do
85
- let(:actual_headers) { {'content-type' => 'application/json'} }
96
+ let(:actual_headers) { { 'content-type' => 'application/json' } }
86
97
 
87
98
  it 'does not return any errors' do
88
- expect(validator.validate(expected_headers, actual_headers)).to be_empty
99
+ expect(cop.investigate(request, response, contract)).to be_empty
89
100
  end
90
101
  end
91
102
  end
@@ -0,0 +1,26 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Pacto
3
+ module Cops
4
+ describe ResponseStatusCop do
5
+ subject(:cop) { described_class }
6
+ let(:contract) { Fabricate(:contract) }
7
+ let(:request) { Fabricate(:pacto_request) }
8
+
9
+ describe '#investigate' do
10
+ context 'when status does not match' do
11
+ let(:response) { Fabricate(:pacto_response, status: 500) }
12
+ it 'returns a status error' do
13
+ expect(cop.investigate(request, response, contract)).to eq ['Invalid status: expected 200 but got 500']
14
+ end
15
+ end
16
+
17
+ context 'when the status matches' do
18
+ let(:response) { Fabricate(:pacto_response, status: 200) }
19
+ it 'returns nil' do
20
+ expect(cop.investigate(request, response, contract)).to be_empty
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,75 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Pacto
3
+ describe Cops do
4
+ let(:investigation_errors) { ['some error', 'another error'] }
5
+
6
+ let(:expected_response) do
7
+ Fabricate(:response_clause)
8
+ end
9
+
10
+ let(:actual_response) do
11
+ # TODO: Replace this with a Fabrication for Pacto::PactoResponse (perhaps backed by WebMock)
12
+ Fabricate(:pacto_response)
13
+ # double(
14
+ # status: 200,
15
+ # headers: { 'Content-Type' => 'application/json', 'Age' => '60' },
16
+ # body: { 'message' => 'response' }
17
+ # )
18
+ end
19
+
20
+ let(:actual_request) { Fabricate(:pacto_request) }
21
+
22
+ let(:expected_request) do
23
+ Fabricate(:request_clause)
24
+ end
25
+
26
+ let(:contract) do
27
+ Fabricate(
28
+ :contract,
29
+ request: expected_request,
30
+ response: expected_response
31
+ )
32
+ end
33
+
34
+ describe '#validate_contract' do
35
+ before do
36
+ allow(Pacto::Cops::RequestBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])
37
+ allow(Pacto::Cops::ResponseBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])
38
+ end
39
+
40
+ context 'default cops' do
41
+ let(:investigation) { described_class.perform_investigation actual_request, actual_response, contract }
42
+
43
+ it 'calls the RequestBodyCop' do
44
+ expect(Pacto::Cops::RequestBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return(investigation_errors)
45
+ expect(investigation.citations).to eq(investigation_errors)
46
+ end
47
+
48
+ it 'calls the ResponseStatusCop' do
49
+ expect(Pacto::Cops::ResponseStatusCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return(investigation_errors)
50
+ expect(investigation.citations).to eq(investigation_errors)
51
+ end
52
+
53
+ it 'calls the ResponseHeaderCop' do
54
+ expect(Pacto::Cops::ResponseHeaderCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return(investigation_errors)
55
+ expect(investigation.citations).to eq(investigation_errors)
56
+ end
57
+
58
+ it 'calls the ResponseBodyCop' do
59
+ expect(Pacto::Cops::ResponseBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return(investigation_errors)
60
+ expect(investigation.citations).to eq(investigation_errors)
61
+ end
62
+ end
63
+
64
+ context 'when headers and body match and the ResponseStatusCop reports no errors' do
65
+ it 'does not return any errors' do
66
+ expect(Pacto::Cops::RequestBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])
67
+ expect(Pacto::Cops::ResponseStatusCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])
68
+ expect(Pacto::Cops::ResponseHeaderCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])
69
+ expect(Pacto::Cops::ResponseBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])
70
+ expect(described_class.perform_investigation actual_request, actual_response, contract).to be_successful
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,21 +1,22 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  describe Pacto do
2
3
  describe '.configure' do
3
4
  let(:contracts_path) { 'path_to_contracts' }
4
5
 
5
6
  it 'allows contracts_path manual configuration' do
6
- expect(Pacto.configuration.contracts_path).to be_nil
7
- Pacto.configure do |c|
7
+ expect(described_class.configuration.contracts_path).to eq('.')
8
+ described_class.configure do |c|
8
9
  c.contracts_path = contracts_path
9
10
  end
10
- expect(Pacto.configuration.contracts_path).to eq(contracts_path)
11
+ expect(described_class.configuration.contracts_path).to eq(contracts_path)
11
12
  end
12
13
 
13
14
  it 'register a Pacto Hook' do
14
15
  hook_block = Pacto::Hook.new {}
15
- Pacto.configure do |c|
16
+ described_class.configure do |c|
16
17
  c.register_hook(hook_block)
17
18
  end
18
- expect(Pacto.configuration.hook).to eq(hook_block)
19
+ expect(described_class.configuration.hook).to eq(hook_block)
19
20
  end
20
21
  end
21
22
  end
@@ -1,104 +1,38 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  require_relative '../../../../lib/pacto/core/contract_registry'
2
3
 
3
4
  module Pacto
4
5
  describe ContractRegistry do
5
- let(:tag) { 'contract_tag' }
6
- let(:another_tag) { 'another_tag' }
7
- let(:contract) { double('contract') }
8
- let(:contract_factory) { double }
9
- let(:another_contract) { double('another_contract') }
10
- let(:request_signature) { double('request signature') }
11
- let(:contracts_that_match) { create_contracts 2, true }
12
- let(:contracts_that_dont_match) { create_contracts 3, false }
13
- let(:all_contracts) { contracts_that_match + contracts_that_dont_match }
6
+ let(:contract) { Fabricate(:contract) }
7
+ let(:request_signature) { Fabricate(:webmock_request_signature) }
14
8
 
15
- subject(:contract_list) do
9
+ subject(:contract_registry) do
16
10
  ContractRegistry.new
17
11
  end
18
12
 
19
13
  describe '.register' do
20
- context 'no tag' do
21
- it 'registers the contract with the default tag' do
22
- contract_list.register contract
23
- expect(contract_list[:default]).to include(contract)
24
- end
25
- end
26
-
27
- context 'one tag' do
28
- it 'registers a contract under a given tag' do
29
- contract_list.register(contract, tag)
30
- expect(contract_list[tag]).to include(contract)
31
- end
32
-
33
- it 'does not duplicate a contract when it has already been registered with the same tag' do
34
- contract_list
35
- .register(contract, tag)
36
- .register(contract, tag)
37
-
38
- expect(contract_list[tag]).to include(contract)
39
- expect(contract_list[tag]).to have(1).items
40
- end
41
- end
42
-
43
- context 'multiple tags' do
44
- it 'registers a contract using different tags' do
45
- contract_list.register(contract, tag, another_tag)
46
- expect(contract_list[tag]).to include(contract)
47
- expect(contract_list[another_tag]).to include(contract)
48
- end
49
-
50
- it 'registers a tag with different contracts ' do
51
- contract_list
52
- .register(contract, tag)
53
- .register(another_contract, tag)
54
-
55
- expect(contract_list[tag]).to include(contract, another_contract)
56
- end
57
-
14
+ it 'registers the contract' do
15
+ contract_registry.register contract
16
+ expect(contract_registry).to include(contract)
58
17
  end
59
18
  end
60
19
 
61
- describe '.use' do
62
- before do
63
- contract_list
64
- .register(contract, tag)
65
- .register(another_contract, :default)
66
- end
67
-
68
- context 'when a contract has been registry' do
69
- let(:response_body) { double('response_body') }
70
-
71
- it 'stubs a contract with default values' do
72
- contract.should_receive(:stub_contract!)
73
- another_contract.should_receive(:stub_contract!)
74
- contract_list.use(tag)
75
- end
76
-
77
- it 'stubs default contract if unused tag' do
78
- another_contract.should_receive(:stub_contract!)
79
- contract_list.use(another_tag)
80
- end
81
- end
82
-
83
- context 'when contract has not been registry' do
84
- it 'raises an argument error' do
85
- contract_list = ContractRegistry.new
86
- expect { contract_list.use('unregistry') }.to raise_error ArgumentError
87
- end
20
+ describe '.contracts_for' do
21
+ before(:each) do
22
+ contract_registry.register contract
88
23
  end
89
- end
90
24
 
91
- describe '.contracts_for' do
92
25
  context 'when no contracts are found for a request' do
93
26
  it 'returns an empty list' do
94
- expect(contract_list.contracts_for request_signature).to be_empty
27
+ expect(contract).to receive(:matches?).with(request_signature).and_return false
28
+ expect(contract_registry.contracts_for request_signature).to be_empty
95
29
  end
96
30
  end
97
31
 
98
32
  context 'when contracts are found for a request' do
99
33
  it 'returns the matching contracts' do
100
- register_and_use all_contracts
101
- expect(contract_list.contracts_for request_signature).to eq(contracts_that_match)
34
+ expect(contract).to receive(:matches?).with(request_signature).and_return true
35
+ expect(contract_registry.contracts_for request_signature).to eq([contract])
102
36
  end
103
37
  end
104
38
  end
@@ -111,9 +45,8 @@ module Pacto
111
45
  end
112
46
  end
113
47
 
114
- def register_and_use(contracts)
115
- contracts.each { |contract| contract_list.register contract }
116
- contract_list.use :default
48
+ def register_contracts(contracts)
49
+ contracts.each { |contract| contract_registry.register contract }
117
50
  end
118
51
  end
119
52
  end