pacto 0.3.0.pre → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rubocop-todo.yml +0 -27
- data/.rubocop.yml +9 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -5
- data/CONTRIBUTING.md +112 -0
- data/Gemfile +5 -0
- data/Guardfile +18 -13
- data/README.md +157 -101
- data/Rakefile +3 -3
- data/features/configuration/strict_matchers.feature +97 -0
- data/features/evolve/README.md +11 -0
- data/features/evolve/existing_services.feature +82 -0
- data/features/generate/README.md +5 -0
- data/features/generate/generation.feature +28 -0
- data/features/steps/pacto_steps.rb +75 -0
- data/features/stub/README.md +2 -0
- data/features/stub/templates.feature +46 -0
- data/features/support/env.rb +11 -5
- data/features/validate/README.md +1 -0
- data/features/validate/body_only.feature +85 -0
- data/features/{journeys/validation.feature → validate/meta_validation.feature} +41 -24
- data/features/validate/validation.feature +36 -0
- data/lib/pacto.rb +61 -33
- data/lib/pacto/contract.rb +18 -15
- data/lib/pacto/contract_factory.rb +14 -11
- data/lib/pacto/contract_files.rb +17 -0
- data/lib/pacto/contract_list.rb +17 -0
- data/lib/pacto/contract_validator.rb +29 -0
- data/lib/pacto/core/configuration.rb +19 -17
- data/lib/pacto/core/contract_registry.rb +43 -0
- data/lib/pacto/core/{callback.rb → hook.rb} +3 -3
- data/lib/pacto/core/modes.rb +33 -0
- data/lib/pacto/core/validation_registry.rb +45 -0
- data/lib/pacto/erb_processor.rb +0 -1
- data/lib/pacto/extensions.rb +18 -4
- data/lib/pacto/generator.rb +34 -49
- data/lib/pacto/generator/filters.rb +41 -0
- data/lib/pacto/hooks/erb_hook.rb +4 -3
- data/lib/pacto/logger.rb +4 -2
- data/lib/pacto/meta_schema.rb +4 -2
- data/lib/pacto/rake_task.rb +28 -25
- data/lib/pacto/request_clause.rb +43 -0
- data/lib/pacto/request_pattern.rb +8 -0
- data/lib/pacto/response_clause.rb +15 -0
- data/lib/pacto/rspec.rb +102 -0
- data/lib/pacto/stubs/uri_pattern.rb +23 -0
- data/lib/pacto/stubs/webmock_adapter.rb +69 -0
- data/lib/pacto/stubs/webmock_helper.rb +71 -0
- data/lib/pacto/ui.rb +7 -0
- data/lib/pacto/uri.rb +9 -0
- data/lib/pacto/validation.rb +57 -0
- data/lib/pacto/validators/body_validator.rb +41 -0
- data/lib/pacto/validators/request_body_validator.rb +23 -0
- data/lib/pacto/validators/response_body_validator.rb +23 -0
- data/lib/pacto/validators/response_header_validator.rb +49 -0
- data/lib/pacto/validators/response_status_validator.rb +24 -0
- data/lib/pacto/version.rb +1 -1
- data/pacto.gemspec +33 -29
- data/resources/contract_schema.json +8 -176
- data/resources/draft-03.json +174 -0
- data/spec/integration/data/strict_contract.json +2 -2
- data/spec/integration/e2e_spec.rb +22 -31
- data/spec/integration/rspec_spec.rb +94 -0
- data/spec/integration/templating_spec.rb +9 -12
- data/{lib → spec}/pacto/server.rb +0 -0
- data/{lib → spec}/pacto/server/dummy.rb +11 -8
- data/{lib → spec}/pacto/server/playback_servlet.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/hooks/erb_hook_spec.rb +15 -15
- data/spec/unit/pacto/configuration_spec.rb +2 -10
- data/spec/unit/pacto/contract_factory_spec.rb +16 -13
- data/spec/unit/pacto/contract_files_spec.rb +42 -0
- data/spec/unit/pacto/contract_list_spec.rb +35 -0
- data/spec/unit/pacto/contract_spec.rb +43 -44
- data/spec/unit/pacto/contract_validator_spec.rb +85 -0
- data/spec/unit/pacto/core/configuration_spec.rb +4 -11
- data/spec/unit/pacto/core/contract_registry_spec.rb +119 -0
- data/spec/unit/pacto/core/modes_spec.rb +18 -0
- data/spec/unit/pacto/core/validation_registry_spec.rb +76 -0
- data/spec/unit/pacto/core/validation_spec.rb +60 -0
- data/spec/unit/pacto/extensions_spec.rb +14 -23
- data/spec/unit/pacto/generator/filters_spec.rb +99 -0
- data/spec/unit/pacto/generator_spec.rb +34 -73
- data/spec/unit/pacto/meta_schema_spec.rb +46 -6
- data/spec/unit/pacto/pacto_spec.rb +17 -15
- data/spec/unit/pacto/{request_spec.rb → request_clause_spec.rb} +32 -44
- data/spec/unit/pacto/request_pattern_spec.rb +22 -0
- data/spec/unit/pacto/response_clause_spec.rb +54 -0
- data/spec/unit/pacto/stubs/uri_pattern_spec.rb +28 -0
- data/spec/unit/pacto/stubs/webmock_adapter_spec.rb +205 -0
- data/spec/unit/pacto/stubs/webmock_helper_spec.rb +20 -0
- data/spec/unit/pacto/uri_spec.rb +20 -0
- data/spec/unit/pacto/validators/body_validator_spec.rb +105 -0
- data/spec/unit/pacto/validators/response_header_validator_spec.rb +94 -0
- data/spec/unit/pacto/validators/response_status_validator_spec.rb +20 -0
- metadata +230 -146
- data/features/generation/generation.feature +0 -25
- data/lib/pacto/core/contract_repository.rb +0 -44
- data/lib/pacto/hash_merge_processor.rb +0 -14
- data/lib/pacto/request.rb +0 -57
- data/lib/pacto/response.rb +0 -63
- data/lib/pacto/response_adapter.rb +0 -24
- data/lib/pacto/stubs/built_in.rb +0 -57
- data/spec/unit/pacto/core/contract_repository_spec.rb +0 -133
- data/spec/unit/pacto/hash_merge_processor_spec.rb +0 -20
- data/spec/unit/pacto/response_adapter_spec.rb +0 -25
- data/spec/unit/pacto/response_spec.rb +0 -201
- data/spec/unit/pacto/stubs/built_in_spec.rb +0 -168
|
@@ -0,0 +1,60 @@
|
|
|
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,32 +1,23 @@
|
|
|
1
1
|
module Pacto
|
|
2
2
|
module Extensions
|
|
3
3
|
describe HashSubsetOf do
|
|
4
|
-
describe '#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
context 'when the other hash is a subset' do
|
|
12
|
-
it 'returns true' do
|
|
13
|
-
expect({:a => 'a'}).to be_subset_of({:a => 'a', :b => 'b'})
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
context 'when the other hash is not a subset' do
|
|
18
|
-
it 'returns false' do
|
|
19
|
-
expect({:a => 'a'}.subset_of?({:a => 'b'})).to be_false
|
|
20
|
-
end
|
|
4
|
+
describe '#normalize_keys' do
|
|
5
|
+
it 'turns keys into downcased strings' do
|
|
6
|
+
expect({:A => 'a'}.normalize_keys).to eq('a' => 'a')
|
|
7
|
+
expect({:a => 'a'}.normalize_keys).to eq('a' => 'a')
|
|
8
|
+
expect({'A' => 'a'}.normalize_keys).to eq('a' => 'a')
|
|
9
|
+
expect({'a' => 'a'}.normalize_keys).to eq('a' => 'a')
|
|
21
10
|
end
|
|
22
11
|
end
|
|
23
12
|
|
|
24
|
-
describe '#
|
|
25
|
-
it '
|
|
26
|
-
expect(
|
|
27
|
-
expect(
|
|
28
|
-
expect(
|
|
29
|
-
expect(
|
|
13
|
+
describe '#normalize_header_keys' do
|
|
14
|
+
it 'matches headers to the style in the RFC documentation' do
|
|
15
|
+
expect(Pacto::Extensions.normalize_header_keys(:'user-agent' => 'a')).to eq('User-Agent' => 'a') # rubocop:disable SymbolName
|
|
16
|
+
expect(Pacto::Extensions.normalize_header_keys(:user_agent => 'a')).to eq('User-Agent' => 'a')
|
|
17
|
+
expect(Pacto::Extensions.normalize_header_keys('User-Agent' => 'a')).to eq('User-Agent' => 'a')
|
|
18
|
+
expect(Pacto::Extensions.normalize_header_keys('user-agent' => 'a')).to eq('User-Agent' => 'a')
|
|
19
|
+
expect(Pacto::Extensions.normalize_header_keys('user_agent' => 'a')).to eq('User-Agent' => 'a')
|
|
20
|
+
expect(Pacto::Extensions.normalize_header_keys('USER_AGENT' => 'a')).to eq('User-Agent' => 'a')
|
|
30
21
|
end
|
|
31
22
|
end
|
|
32
23
|
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module Pacto
|
|
2
|
+
class Generator
|
|
3
|
+
describe Filters do
|
|
4
|
+
let(:record_host) do
|
|
5
|
+
'http://example.com'
|
|
6
|
+
end
|
|
7
|
+
let(:request) do
|
|
8
|
+
RequestClause.new(
|
|
9
|
+
record_host,
|
|
10
|
+
'method' => 'GET',
|
|
11
|
+
'path' => '/abcd',
|
|
12
|
+
'headers' => {
|
|
13
|
+
'Server' => ['example.com'],
|
|
14
|
+
'Connection' => ['Close'],
|
|
15
|
+
'Content-Length' => [1234],
|
|
16
|
+
'Via' => ['Some Proxy'],
|
|
17
|
+
'User-Agent' => ['rspec']
|
|
18
|
+
},
|
|
19
|
+
'params' => {
|
|
20
|
+
'apikey' => "<%= ENV['MY_API_KEY'] %>"
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
let(:varies) { ['User-Agent'] }
|
|
25
|
+
let(:response) do
|
|
26
|
+
Faraday::Response.new(
|
|
27
|
+
:status => 200,
|
|
28
|
+
:response_headers => {
|
|
29
|
+
'Date' => Time.now.rfc2822,
|
|
30
|
+
'Last-Modified' => Time.now.rfc2822,
|
|
31
|
+
'ETag' => 'abc123',
|
|
32
|
+
'Server' => ['Fake Server'],
|
|
33
|
+
'Content-Type' => ['application/json'],
|
|
34
|
+
'Vary' => varies
|
|
35
|
+
},
|
|
36
|
+
:body => double('dummy body')
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe '#filter_request_headers' do
|
|
41
|
+
subject(:filtered_request_headers) { described_class.new.filter_request_headers(request, response).keys.map(&:downcase) }
|
|
42
|
+
it 'keeps important request headers' do
|
|
43
|
+
expect(filtered_request_headers).to include 'user-agent'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'filters informational request headers' do
|
|
47
|
+
expect(filtered_request_headers).not_to include 'via'
|
|
48
|
+
expect(filtered_request_headers).not_to include 'date'
|
|
49
|
+
expect(filtered_request_headers).not_to include 'server'
|
|
50
|
+
expect(filtered_request_headers).not_to include 'content-length'
|
|
51
|
+
expect(filtered_request_headers).not_to include 'connection'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context 'multiple Vary elements' do
|
|
55
|
+
context 'as a single string' do
|
|
56
|
+
let(:varies) do
|
|
57
|
+
['User-Agent,Via']
|
|
58
|
+
end
|
|
59
|
+
it 'keeps each header' do
|
|
60
|
+
expect(filtered_request_headers).to include 'user-agent'
|
|
61
|
+
expect(filtered_request_headers).to include 'via'
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
context 'as multiple items' do
|
|
65
|
+
let(:varies) do
|
|
66
|
+
%w{User-Agent Via}
|
|
67
|
+
end
|
|
68
|
+
it 'keeps each header' do
|
|
69
|
+
expect(filtered_request_headers).to include 'user-agent'
|
|
70
|
+
expect(filtered_request_headers).to include 'via'
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe '#filter_response_headers' do
|
|
77
|
+
subject(:filtered_response_headers) { described_class.new.filter_response_headers(request, response).keys.map(&:downcase) }
|
|
78
|
+
it 'keeps important response headers' do
|
|
79
|
+
expect(filtered_response_headers).to include 'content-type'
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'filters connection control headers' do
|
|
83
|
+
expect(filtered_response_headers).not_to include 'content-length'
|
|
84
|
+
expect(filtered_response_headers).not_to include 'via'
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'filters freshness headers' do
|
|
88
|
+
expect(filtered_response_headers).not_to include 'date'
|
|
89
|
+
expect(filtered_response_headers).not_to include 'last-modified'
|
|
90
|
+
expect(filtered_response_headers).not_to include 'eTag'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'filters x-* headers' do
|
|
94
|
+
expect(filtered_response_headers).not_to include 'x-men'
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -1,73 +1,53 @@
|
|
|
1
1
|
module Pacto
|
|
2
2
|
describe Generator do
|
|
3
|
-
let(:record_host)
|
|
3
|
+
let(:record_host) do
|
|
4
4
|
'http://example.com'
|
|
5
|
-
|
|
5
|
+
end
|
|
6
|
+
|
|
6
7
|
let(:request) do
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
'
|
|
10
|
-
|
|
8
|
+
Faraday::Request.create :get do |req|
|
|
9
|
+
req.path = '/abcd'
|
|
10
|
+
req.params = { 'apikey' => "<%= ENV['MY_API_KEY'] %>" }
|
|
11
|
+
req.headers = {
|
|
11
12
|
'Content-Length' => [1234],
|
|
12
13
|
'Via' => ['Some Proxy'],
|
|
13
14
|
'User-Agent' => ['rspec']
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
})
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
17
|
end
|
|
18
|
+
|
|
18
19
|
let(:response_adapter) do
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
'
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
})
|
|
20
|
+
Faraday::Response.new(
|
|
21
|
+
:status => 200,
|
|
22
|
+
:response_headers => {
|
|
23
|
+
'Date' => [Time.now],
|
|
24
|
+
'Server' => ['Fake Server'],
|
|
25
|
+
'Content-Type' => ['application/json'],
|
|
26
|
+
'Vary' => ['User-Agent']
|
|
27
|
+
},
|
|
28
|
+
:body => 'dummy body' # body is just a string
|
|
29
29
|
)
|
|
30
30
|
end
|
|
31
|
+
let(:filtered_request_headers) { double('filtered_response_headers') }
|
|
32
|
+
let(:filtered_response_headers) { double('filtered_response_headers') }
|
|
31
33
|
let(:response_body_schema) { '{"message": "dummy generated schema"}' }
|
|
32
34
|
let(:version) { 'draft3' }
|
|
33
35
|
let(:schema_generator) { double('schema_generator') }
|
|
34
36
|
let(:validator) { double('validator') }
|
|
37
|
+
let(:filters) { double :filters }
|
|
35
38
|
let(:request_file) { 'request.json' }
|
|
36
|
-
let(:
|
|
39
|
+
let(:options) { Pacto.configuration.generator_options }
|
|
40
|
+
let(:generator) { described_class.new version, schema_generator, validator, options, filters }
|
|
37
41
|
|
|
38
|
-
def pretty
|
|
42
|
+
def pretty(obj)
|
|
39
43
|
MultiJson.encode(obj, :pretty => true).gsub(/^$\n/, '')
|
|
40
44
|
end
|
|
41
45
|
|
|
42
|
-
describe '#
|
|
43
|
-
let(:request_contract) {
|
|
44
|
-
double({
|
|
45
|
-
:request => request,
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
let(:generated_contract) { double('generated contract') }
|
|
46
|
+
describe '#save' do
|
|
49
47
|
before do
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it 'parses the request' do
|
|
55
|
-
generator.should_receive(:save).with(request_file, request, anything)
|
|
56
|
-
generator.generate request_file, record_host
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it 'fetches a response' do
|
|
60
|
-
generator.should_receive(:save).with(request_file, anything, response_adapter)
|
|
61
|
-
generator.generate request_file, record_host
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it 'saves the result' do
|
|
65
|
-
generator.should_receive(:save).with(request_file, request, response_adapter).and_return generated_contract
|
|
66
|
-
expect(generator.generate request_file, record_host).to eq(generated_contract)
|
|
48
|
+
filters.should_receive(:filter_request_headers).with(request, response_adapter).and_return filtered_request_headers
|
|
49
|
+
filters.should_receive(:filter_response_headers).with(request, response_adapter).and_return filtered_response_headers
|
|
67
50
|
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
describe '#save' do
|
|
71
51
|
context 'invalid schema' do
|
|
72
52
|
it 'raises an error if schema generation fails' do
|
|
73
53
|
JSON::SchemaGenerator.should_receive(:generate).and_raise ArgumentError.new('Could not generate schema')
|
|
@@ -82,11 +62,11 @@ module Pacto
|
|
|
82
62
|
end
|
|
83
63
|
|
|
84
64
|
context 'valid schema' do
|
|
85
|
-
let(:raw_contract)
|
|
86
|
-
JSON::SchemaGenerator.should_receive(:generate).with(request_file, response_adapter.body,
|
|
65
|
+
let(:raw_contract) do
|
|
66
|
+
JSON::SchemaGenerator.should_receive(:generate).with(request_file, response_adapter.body, Pacto.configuration.generator_options).and_return response_body_schema
|
|
87
67
|
validator.should_receive(:validate).and_return true
|
|
88
68
|
generator.save request_file, request, response_adapter
|
|
89
|
-
|
|
69
|
+
end
|
|
90
70
|
subject(:generated_contract) { JSON.parse raw_contract }
|
|
91
71
|
|
|
92
72
|
it 'sets the body to the generated json-schema' do
|
|
@@ -99,17 +79,9 @@ module Pacto
|
|
|
99
79
|
expect(generated_request['path']).to eq(request.path)
|
|
100
80
|
end
|
|
101
81
|
|
|
102
|
-
it '
|
|
103
|
-
|
|
104
|
-
expect(
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
it 'filters informational request headers' do
|
|
108
|
-
saved_headers = subject['request']['headers']
|
|
109
|
-
expect(saved_headers).not_to include 'Date'
|
|
110
|
-
expect(saved_headers).not_to include 'Server'
|
|
111
|
-
expect(saved_headers).not_to include 'Content-Length'
|
|
112
|
-
expect(saved_headers).not_to include 'Connection'
|
|
82
|
+
it 'preserves ERB in the request params' do
|
|
83
|
+
generated_request = subject['request']
|
|
84
|
+
expect(generated_request['params']['apikey']).to eq("<%= ENV['MY_API_KEY'] %>")
|
|
113
85
|
end
|
|
114
86
|
|
|
115
87
|
it 'normalizes the request method' do
|
|
@@ -122,17 +94,6 @@ module Pacto
|
|
|
122
94
|
expect(generated_response['status']).to eq(response_adapter.status)
|
|
123
95
|
end
|
|
124
96
|
|
|
125
|
-
it 'keeps important response headers' do
|
|
126
|
-
saved_headers = subject['response']['headers']
|
|
127
|
-
expect(saved_headers.keys).to include 'Content-Type'
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
it 'filters informational response headers' do
|
|
131
|
-
saved_headers = subject['response']['headers']
|
|
132
|
-
expect(saved_headers).not_to include 'Content-Length'
|
|
133
|
-
expect(saved_headers).not_to include 'Via'
|
|
134
|
-
end
|
|
135
|
-
|
|
136
97
|
it 'generates pretty JSON' do
|
|
137
98
|
expect(raw_contract).to eq(pretty(subject))
|
|
138
99
|
end
|
|
@@ -31,7 +31,7 @@ module Pacto
|
|
|
31
31
|
EOF
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
let(:
|
|
34
|
+
let(:partial_contract) do
|
|
35
35
|
<<-EOF
|
|
36
36
|
{
|
|
37
37
|
"request": {
|
|
@@ -47,22 +47,62 @@ module Pacto
|
|
|
47
47
|
EOF
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
let(:invalid_contract) do
|
|
51
|
+
<<-EOF
|
|
52
|
+
{
|
|
53
|
+
"request": {
|
|
54
|
+
"method": "GET",
|
|
55
|
+
"path": "/hello_world",
|
|
56
|
+
"headers": {
|
|
57
|
+
"Accept": "application/json"
|
|
58
|
+
},
|
|
59
|
+
"params": {}
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
"response": {
|
|
63
|
+
"status": 200,
|
|
64
|
+
"headers": {
|
|
65
|
+
"Content-Type": "application/json"
|
|
66
|
+
},
|
|
67
|
+
"body": {
|
|
68
|
+
"description": "A simple response",
|
|
69
|
+
"required": {},
|
|
70
|
+
"type": "object",
|
|
71
|
+
"properties": {
|
|
72
|
+
"message": {
|
|
73
|
+
"type": "string"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
EOF
|
|
80
|
+
end
|
|
81
|
+
|
|
50
82
|
subject(:schema) { MetaSchema.new }
|
|
51
83
|
|
|
52
84
|
describe 'when validating a contract against the master schema' do
|
|
53
85
|
context 'with a valid contract structure' do
|
|
54
86
|
it 'does not raise any exceptions' do
|
|
55
|
-
expect
|
|
87
|
+
expect do
|
|
56
88
|
schema.validate(valid_contract)
|
|
57
|
-
|
|
89
|
+
end.to_not raise_error(Exception)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context 'with an partial contract structure' do
|
|
94
|
+
it 'raises InvalidContract exception' do
|
|
95
|
+
expect do
|
|
96
|
+
schema.validate(invalid_contract)
|
|
97
|
+
end.to raise_error(InvalidContract)
|
|
58
98
|
end
|
|
59
99
|
end
|
|
60
100
|
|
|
61
|
-
context 'with an invalid contract
|
|
101
|
+
context 'with an invalid contract' do
|
|
62
102
|
it 'raises InvalidContract exception' do
|
|
63
|
-
expect
|
|
103
|
+
expect do
|
|
64
104
|
schema.validate(invalid_contract)
|
|
65
|
-
|
|
105
|
+
end.to raise_error(InvalidContract)
|
|
66
106
|
end
|
|
67
107
|
end
|
|
68
108
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
require 'spec_helper'
|
|
2
2
|
|
|
3
|
+
describe Pacto do
|
|
3
4
|
around(:each) do |example|
|
|
4
5
|
$stdout = StringIO.new
|
|
5
6
|
example.run
|
|
@@ -19,7 +20,7 @@ describe Pacto do
|
|
|
19
20
|
it 'displays a success message and return true' do
|
|
20
21
|
mock_validation []
|
|
21
22
|
success = Pacto.validate_contract 'my_contract.json'
|
|
22
|
-
expect(output).to eq '
|
|
23
|
+
expect(output).to eq 'Validating my_contract.json'
|
|
23
24
|
expect(success).to be_true
|
|
24
25
|
end
|
|
25
26
|
end
|
|
@@ -28,7 +29,7 @@ describe Pacto do
|
|
|
28
29
|
it 'displays one error messages and return false' do
|
|
29
30
|
mock_validation ['Error 1']
|
|
30
31
|
success = Pacto.validate_contract 'my_contract.json'
|
|
31
|
-
expect(output).to match
|
|
32
|
+
expect(output).to match(/error/)
|
|
32
33
|
expect(success).to be_false
|
|
33
34
|
end
|
|
34
35
|
|
|
@@ -40,21 +41,22 @@ describe Pacto do
|
|
|
40
41
|
end
|
|
41
42
|
end
|
|
42
43
|
|
|
43
|
-
describe '
|
|
44
|
-
let(:
|
|
45
|
-
let(:host)
|
|
46
|
-
let(:
|
|
47
|
-
let(:
|
|
44
|
+
describe 'loading contracts' do
|
|
45
|
+
let(:contracts_path) { 'path/to/dir' }
|
|
46
|
+
let(:host) { 'localhost' }
|
|
47
|
+
let(:contract1) { double }
|
|
48
|
+
let(:contract2) { double }
|
|
49
|
+
let(:factory) { double(:factory) }
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
Pacto::ContractFactory.
|
|
51
|
-
described_class.build_from_file(path, host, file_pre_processor)
|
|
51
|
+
before do
|
|
52
|
+
allow(Pacto::ContractFactory).to receive(:new).and_return(factory)
|
|
52
53
|
end
|
|
53
54
|
|
|
54
|
-
it '
|
|
55
|
-
Pacto::
|
|
56
|
-
|
|
55
|
+
it 'instantiates a contract list' do
|
|
56
|
+
allow(Pacto::ContractFiles).to receive(:for).with(contracts_path).and_return { %w{file1 file2} }
|
|
57
|
+
allow(factory).to receive(:build).with(%w{file1 file2}, host).and_return { [contract1, contract2] }
|
|
58
|
+
expect(Pacto::ContractList).to receive(:new).with([contract1, contract2])
|
|
59
|
+
Pacto.load_contracts(contracts_path, host)
|
|
57
60
|
end
|
|
58
61
|
end
|
|
59
|
-
|
|
60
62
|
end
|