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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rubocop.yml +29 -7
- data/.travis.yml +8 -1
- data/CONTRIBUTING.md +3 -6
- data/Gemfile +13 -2
- data/Guardfile +4 -4
- data/Procfile +1 -0
- data/README.md +47 -13
- data/Rakefile +66 -19
- data/TODO.md +33 -10
- data/bin/pacto +4 -0
- data/changelog.md +30 -0
- data/docs/configuration.md +69 -0
- data/docs/consumer.md +18 -0
- data/docs/cops.md +39 -0
- data/docs/forensics.md +66 -0
- data/docs/generation.md +65 -0
- data/docs/rake_tasks.md +10 -0
- data/docs/rspec.md +0 -0
- data/docs/samples.md +133 -0
- data/docs/server.md +34 -0
- data/docs/server_cli.md +18 -0
- data/docs/stenographer.md +20 -0
- data/features/configuration/strict_matchers.feature +10 -10
- data/features/evolve/existing_services.feature +12 -10
- data/features/generate/generation.feature +11 -11
- data/features/steps/pacto_steps.rb +17 -12
- data/features/stub/templates.feature +4 -4
- data/features/support/env.rb +21 -9
- data/features/validate/meta_validation.feature +9 -17
- data/features/validate/validation.feature +5 -6
- data/lib/pacto.rb +41 -33
- data/lib/pacto/actor.rb +5 -0
- data/lib/pacto/actors/from_examples.rb +67 -0
- data/lib/pacto/actors/json_generator.rb +20 -0
- data/lib/pacto/cli.rb +75 -0
- data/lib/pacto/cli/helpers.rb +20 -0
- data/lib/pacto/consumer.rb +80 -0
- data/lib/pacto/consumer/faraday_driver.rb +34 -0
- data/lib/pacto/contract.rb +48 -20
- data/lib/pacto/contract_builder.rb +125 -0
- data/lib/pacto/contract_factory.rb +31 -12
- data/lib/pacto/contract_files.rb +1 -0
- data/lib/pacto/contract_set.rb +12 -0
- data/lib/pacto/cops.rb +46 -0
- data/lib/pacto/cops/body_cop.rb +23 -0
- data/lib/pacto/cops/request_body_cop.rb +10 -0
- data/lib/pacto/cops/response_body_cop.rb +10 -0
- data/lib/pacto/{validators/response_header_validator.rb → cops/response_header_cop.rb} +9 -15
- data/lib/pacto/cops/response_status_cop.rb +18 -0
- data/lib/pacto/core/configuration.rb +16 -5
- data/lib/pacto/core/contract_registry.rb +13 -32
- data/lib/pacto/core/hook.rb +1 -0
- data/lib/pacto/core/http_middleware.rb +23 -0
- data/lib/pacto/core/investigation_registry.rb +60 -0
- data/lib/pacto/core/modes.rb +1 -0
- data/lib/pacto/core/pacto_request.rb +59 -0
- data/lib/pacto/core/pacto_response.rb +41 -0
- data/lib/pacto/dash.rb +9 -0
- data/lib/pacto/erb_processor.rb +1 -0
- data/lib/pacto/exceptions/invalid_contract.rb +1 -0
- data/lib/pacto/extensions.rb +3 -16
- data/lib/pacto/forensics/investigation_filter.rb +90 -0
- data/lib/pacto/forensics/investigation_matcher.rb +80 -0
- data/lib/pacto/generator.rb +31 -53
- data/lib/pacto/generator/filters.rb +8 -7
- data/lib/pacto/generator/hint.rb +26 -0
- data/lib/pacto/generator/native_contract_generator.rb +74 -0
- data/lib/pacto/hooks/erb_hook.rb +2 -1
- data/lib/pacto/investigation.rb +49 -0
- data/lib/pacto/logger.rb +1 -0
- data/lib/pacto/meta_schema.rb +12 -6
- data/lib/pacto/native_contract_factory.rb +60 -0
- data/lib/pacto/observers/stenographer.rb +42 -0
- data/lib/pacto/provider.rb +27 -0
- data/lib/pacto/rake_task.rb +25 -70
- data/lib/pacto/request_clause.rb +31 -29
- data/lib/pacto/request_pattern.rb +20 -3
- data/lib/pacto/resettable.rb +22 -0
- data/lib/pacto/response_clause.rb +5 -12
- data/lib/pacto/rspec.rb +38 -31
- data/lib/pacto/server.rb +4 -0
- data/lib/pacto/stubs/uri_pattern.rb +21 -11
- data/lib/pacto/stubs/webmock_adapter.rb +69 -34
- data/lib/pacto/swagger_contract_factory.rb +90 -0
- data/lib/pacto/test_helper.rb +37 -0
- data/lib/pacto/ui.rb +32 -2
- data/lib/pacto/uri.rb +2 -1
- data/lib/pacto/version.rb +2 -1
- data/pacto-server.gemspec +24 -0
- data/pacto.gemspec +13 -9
- data/resources/contract_schema.json +46 -18
- data/resources/draft-04.json +150 -0
- data/sample_apis/album/cover_api.rb +12 -0
- data/sample_apis/config.ru +25 -0
- data/sample_apis/echo_api.rb +26 -0
- data/sample_apis/files_api.rb +50 -0
- data/sample_apis/hello_api.rb +14 -0
- data/sample_apis/ping_api.rb +11 -0
- data/sample_apis/reverse_api.rb +20 -0
- data/samples/README.md +11 -0
- data/samples/Rakefile +2 -0
- data/samples/configuration.rb +33 -0
- data/samples/consumer.rb +15 -0
- data/samples/contracts/README.md +1 -0
- data/samples/contracts/contract.js +93 -0
- data/samples/contracts/get_album_cover.json +48 -0
- data/samples/contracts/localhost/api/echo.json +37 -0
- data/samples/contracts/localhost/api/ping.json +38 -0
- data/samples/cops.rb +30 -0
- data/samples/forensics.rb +54 -0
- data/samples/generation.rb +48 -0
- data/samples/rake_tasks.sh +7 -0
- data/samples/rspec.rb +1 -0
- data/samples/samples.rb +92 -0
- data/samples/scripts/bootstrap +2 -0
- data/samples/scripts/wrapper +11 -0
- data/samples/server.rb +24 -0
- data/samples/server_cli.sh +12 -0
- data/samples/stenographer.rb +17 -0
- data/spec/coveralls_helper.rb +1 -0
- data/spec/fabricators/contract_fabricator.rb +94 -0
- data/spec/fabricators/http_fabricator.rb +48 -0
- data/spec/fabricators/webmock_fabricator.rb +24 -0
- data/spec/{unit/data → fixtures/contracts}/contract.json +2 -2
- data/spec/fixtures/contracts/contract_with_examples.json +58 -0
- data/spec/{unit/data → fixtures/contracts}/simple_contract.json +5 -3
- data/spec/{integration/data → fixtures/contracts}/strict_contract.json +5 -3
- data/spec/{integration/data → fixtures/contracts}/templating_contract.json +3 -2
- data/spec/{integration/data/simple_contract.json → fixtures/deprecated_contracts/deprecated_contract.json} +2 -1
- data/spec/fixtures/swagger/petstore.yaml +101 -0
- data/spec/integration/e2e_spec.rb +19 -20
- data/spec/integration/forensics/integration_matcher_spec.rb +90 -0
- data/spec/integration/rspec_spec.rb +22 -25
- data/spec/integration/templating_spec.rb +7 -6
- data/spec/pacto/dummy_server.rb +4 -0
- data/spec/pacto/{server → dummy_server}/dummy.rb +7 -6
- data/spec/pacto/dummy_server/jruby_workaround_helper.rb +23 -0
- data/spec/pacto/{server → dummy_server}/playback_servlet.rb +3 -2
- data/spec/spec_helper.rb +16 -7
- data/spec/unit/actors/from_examples_spec.rb +70 -0
- data/spec/unit/actors/json_generator_spec.rb +105 -0
- data/spec/unit/pacto/actor_spec.rb +23 -0
- data/spec/unit/pacto/configuration_spec.rb +7 -6
- data/spec/unit/pacto/consumer/faraday_driver_spec.rb +40 -0
- data/spec/unit/pacto/contract_builder_spec.rb +89 -0
- data/spec/unit/pacto/contract_factory_spec.rb +62 -11
- data/spec/unit/pacto/contract_files_spec.rb +1 -0
- data/spec/unit/pacto/contract_set_spec.rb +36 -0
- data/spec/unit/pacto/contract_spec.rb +51 -39
- data/spec/unit/pacto/cops/body_cop_spec.rb +107 -0
- data/spec/unit/pacto/{validators/response_header_validator_spec.rb → cops/response_header_cop_spec.rb} +30 -19
- data/spec/unit/pacto/cops/response_status_cop_spec.rb +26 -0
- data/spec/unit/pacto/cops_spec.rb +75 -0
- data/spec/unit/pacto/core/configuration_spec.rb +6 -5
- data/spec/unit/pacto/core/contract_registry_spec.rb +16 -83
- data/spec/unit/pacto/core/http_middleware_spec.rb +36 -0
- data/spec/unit/pacto/core/investigation_spec.rb +62 -0
- data/spec/unit/pacto/core/modes_spec.rb +5 -4
- data/spec/unit/pacto/erb_processor_spec.rb +3 -2
- data/spec/unit/pacto/extensions_spec.rb +10 -20
- data/spec/unit/pacto/generator/filters_spec.rb +11 -10
- data/spec/unit/pacto/generator/native_contract_generator_spec.rb +171 -0
- data/spec/unit/{hooks → pacto/hooks}/erb_hook_spec.rb +18 -11
- data/spec/unit/pacto/investigation_registry_spec.rb +77 -0
- data/spec/unit/pacto/logger_spec.rb +6 -5
- data/spec/unit/pacto/meta_schema_spec.rb +5 -4
- data/spec/unit/pacto/native_contract_factory_spec.rb +26 -0
- data/spec/unit/pacto/pacto_spec.rb +13 -28
- data/spec/unit/pacto/request_clause_spec.rb +16 -51
- data/spec/unit/pacto/request_pattern_spec.rb +6 -5
- data/spec/unit/pacto/response_clause_spec.rb +6 -19
- data/spec/unit/pacto/server/playback_servlet_spec.rb +21 -18
- data/spec/unit/pacto/stubs/observers/stenographer_spec.rb +33 -0
- data/spec/unit/pacto/stubs/uri_pattern_spec.rb +39 -11
- data/spec/unit/pacto/stubs/webmock_adapter_spec.rb +67 -117
- data/spec/unit/pacto/swagger_contract_factory_spec.rb +56 -0
- data/spec/unit/pacto/uri_spec.rb +1 -0
- data/tasks/release.rake +57 -0
- metadata +247 -76
- data/.rubocop-todo.yml +0 -24
- data/.ruby-gemset +0 -1
- data/.ruby-version +0 -1
- data/CHANGELOG +0 -12
- data/features/validate/body_only.feature +0 -85
- data/lib/pacto/contract_list.rb +0 -17
- data/lib/pacto/contract_validator.rb +0 -29
- data/lib/pacto/core/validation_registry.rb +0 -40
- data/lib/pacto/stubs/webmock_helper.rb +0 -69
- data/lib/pacto/validation.rb +0 -54
- data/lib/pacto/validators/body_validator.rb +0 -49
- data/lib/pacto/validators/request_body_validator.rb +0 -26
- data/lib/pacto/validators/response_body_validator.rb +0 -26
- data/lib/pacto/validators/response_status_validator.rb +0 -24
- data/spec/pacto/server.rb +0 -2
- data/spec/unit/pacto/contract_list_spec.rb +0 -35
- data/spec/unit/pacto/contract_validator_spec.rb +0 -85
- data/spec/unit/pacto/core/validation_registry_spec.rb +0 -76
- data/spec/unit/pacto/core/validation_spec.rb +0 -60
- data/spec/unit/pacto/generator_spec.rb +0 -132
- data/spec/unit/pacto/stubs/webmock_helper_spec.rb +0 -20
- data/spec/unit/pacto/validators/body_validator_spec.rb +0 -118
- 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
|
3
|
-
describe
|
4
|
-
subject(:
|
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 '#
|
17
|
+
describe '#investigate' do
|
11
18
|
context 'when headers do not match' do
|
12
|
-
let(:actual_headers)
|
13
|
-
|
19
|
+
let(:actual_headers) do
|
20
|
+
{ 'Content-Type' => 'text/html' }
|
21
|
+
end
|
14
22
|
it 'indicates the exact mismatches' do
|
15
|
-
expect(
|
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(
|
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(
|
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
|
58
|
-
|
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 '
|
71
|
-
expect(
|
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(
|
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(
|
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(
|
7
|
-
|
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(
|
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
|
-
|
16
|
+
described_class.configure do |c|
|
16
17
|
c.register_hook(hook_block)
|
17
18
|
end
|
18
|
-
expect(
|
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(:
|
6
|
-
let(:
|
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(:
|
9
|
+
subject(:contract_registry) do
|
16
10
|
ContractRegistry.new
|
17
11
|
end
|
18
12
|
|
19
13
|
describe '.register' do
|
20
|
-
|
21
|
-
|
22
|
-
|
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 '.
|
62
|
-
before do
|
63
|
-
|
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(
|
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
|
-
|
101
|
-
expect(
|
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
|
115
|
-
contracts.each { |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
|