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
@@ -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
|
data/spec/pacto/server.rb
DELETED
@@ -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
|