pacto 0.2.1 → 0.2.2
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.
- data/.rspec +1 -1
- data/.rspec_integration +1 -1
- data/.rspec_unit +4 -0
- data/.travis.yml +2 -0
- data/Guardfile +15 -7
- data/Rakefile +3 -3
- data/lib/pacto.rb +1 -1
- data/lib/pacto/response.rb +25 -1
- data/lib/pacto/version.rb +1 -1
- data/pacto.gemspec +1 -2
- data/spec/integration/data/simple_contract.json +4 -7
- data/spec/integration/e2e_spec.rb +28 -16
- data/spec/integration/utils/dummy_server.rb +3 -3
- data/spec/unit/pacto/response_spec.rb +80 -2
- data/spec/unit/spec_helper.rb +5 -2
- metadata +10 -3
data/.rspec
CHANGED
data/.rspec_integration
CHANGED
data/.rspec_unit
ADDED
data/.travis.yml
CHANGED
data/Guardfile
CHANGED
@@ -1,8 +1,16 @@
|
|
1
|
-
guard
|
2
|
-
|
3
|
-
watch(%r{^spec/
|
4
|
-
watch(%r{^lib/
|
5
|
-
watch(
|
6
|
-
watch(
|
7
|
-
watch(
|
1
|
+
guard :rspec do
|
2
|
+
# Unit tests
|
3
|
+
watch(%r{^spec/unit/.+_spec\.rb$})
|
4
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
|
5
|
+
watch('spec/spec_helper.rb') { "spec/unit" }
|
6
|
+
watch('spec/unit/spec_helper.rb') { "spec/unit" }
|
7
|
+
watch(%r{^spec/unit/data/.+\.json$}) { "spec/unit" }
|
8
|
+
|
9
|
+
# Integration tests
|
10
|
+
watch(%r{^spec/integration/.+_spec\.rb$})
|
11
|
+
watch(%r{^spec/integration/utils/.+\.rb$}) { "spec/integration" }
|
12
|
+
watch(%r{^lib/.+.rb$}) { "spec/integration" }
|
13
|
+
watch('spec/spec_helper.rb') { "spec/integration" }
|
14
|
+
watch('spec/integration/spec_helper.rb') { "spec/integration" }
|
15
|
+
watch(%r{^spec/integration/data/.+\.json$}) { "spec/integration" }
|
8
16
|
end
|
data/Rakefile
CHANGED
@@ -3,8 +3,8 @@ require 'rspec/core/rake_task'
|
|
3
3
|
|
4
4
|
if defined?(RSpec)
|
5
5
|
desc "Run unit tests"
|
6
|
-
task :
|
7
|
-
abort unless system('rspec --option .
|
6
|
+
task :unit do
|
7
|
+
abort unless system('rspec --option .rspec_unit')
|
8
8
|
end
|
9
9
|
|
10
10
|
desc "Run integration tests"
|
@@ -12,5 +12,5 @@ if defined?(RSpec)
|
|
12
12
|
abort unless system('rspec --option .rspec_integration')
|
13
13
|
end
|
14
14
|
|
15
|
-
task :default => [:
|
15
|
+
task :default => [:unit, :integration]
|
16
16
|
end
|
data/lib/pacto.rb
CHANGED
data/lib/pacto/response.rb
CHANGED
@@ -22,10 +22,34 @@ module Pacto
|
|
22
22
|
end
|
23
23
|
|
24
24
|
if @definition['body']
|
25
|
-
|
25
|
+
if @definition['body']['type'] && @definition['body']['type'] == 'string'
|
26
|
+
validate_as_pure_string response.body
|
27
|
+
else
|
28
|
+
validate_as_json response.body
|
29
|
+
end
|
26
30
|
else
|
27
31
|
[]
|
28
32
|
end
|
29
33
|
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def validate_as_pure_string response_body
|
38
|
+
errors = []
|
39
|
+
if @definition['body']['required'] && response_body.nil?
|
40
|
+
errors << "The response does not contain a body"
|
41
|
+
end
|
42
|
+
|
43
|
+
pattern = @definition['body']['pattern']
|
44
|
+
if pattern && !(response_body =~ Regexp.new(pattern))
|
45
|
+
errors << "The response does not match the pattern #{pattern}"
|
46
|
+
end
|
47
|
+
|
48
|
+
errors
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate_as_json response_body
|
52
|
+
JSON::Validator.fully_validate(@definition['body'], response_body)
|
53
|
+
end
|
30
54
|
end
|
31
55
|
end
|
data/lib/pacto/version.rb
CHANGED
data/pacto.gemspec
CHANGED
@@ -13,14 +13,13 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.homepage = 'https://github.com/thoughtworks/pacto'
|
14
14
|
gem.license = 'MIT'
|
15
15
|
|
16
|
-
|
17
16
|
gem.files = `git ls-files`.split($/)
|
18
17
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
19
|
gem.require_paths = ["lib"]
|
21
20
|
|
22
21
|
gem.add_dependency "webmock"
|
23
|
-
gem.add_dependency "
|
22
|
+
gem.add_dependency "yajl-ruby"
|
24
23
|
gem.add_dependency "json-schema", "1.0.4"
|
25
24
|
gem.add_dependency "json-generator"
|
26
25
|
gem.add_dependency "hash-deep-merge"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"request": {
|
3
3
|
"method": "GET",
|
4
|
-
"path": "/
|
4
|
+
"path": "/hello",
|
5
5
|
"headers": {
|
6
6
|
"Accept": "application/json"
|
7
7
|
},
|
@@ -10,15 +10,12 @@
|
|
10
10
|
|
11
11
|
"response": {
|
12
12
|
"status": 200,
|
13
|
-
"headers": {
|
14
|
-
"Content-Type": "application/json"
|
15
|
-
},
|
13
|
+
"headers": { "Content-Type": "application/json" },
|
16
14
|
"body": {
|
17
15
|
"type": "object",
|
16
|
+
"required": true,
|
18
17
|
"properties": {
|
19
|
-
"message": {
|
20
|
-
"type": "string"
|
21
|
-
}
|
18
|
+
"message": { "type": "string", "required": true }
|
22
19
|
}
|
23
20
|
}
|
24
21
|
}
|
@@ -1,26 +1,38 @@
|
|
1
|
-
describe
|
1
|
+
describe 'Pacto' do
|
2
|
+
let(:contract_path) { 'spec/integration/data/simple_contract.json' }
|
3
|
+
|
2
4
|
before :all do
|
3
|
-
|
4
|
-
@server.start
|
5
|
+
WebMock.allow_net_connect!
|
5
6
|
end
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
context 'Contract validation' do
|
9
|
+
before :all do
|
10
|
+
@server = DummyServer.new 8000, '/hello', '{"message": "Hello World!"}'
|
11
|
+
@server.start
|
12
|
+
end
|
10
13
|
|
11
|
-
|
12
|
-
|
14
|
+
after :all do
|
15
|
+
@server.terminate
|
16
|
+
end
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
it 'verifies the contract against a producer' do
|
19
|
+
contract = Pacto.build_from_file(contract_path, 'http://localhost:8000')
|
20
|
+
contract.validate.should == []
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
+
context 'Stub generation' do
|
25
|
+
it 'generates a stub to be used by a consumer' do
|
26
|
+
contract = Pacto.build_from_file(contract_path, 'http://dummyprovider.com')
|
27
|
+
Pacto.register('my_contract', contract)
|
28
|
+
Pacto.use('my_contract')
|
29
|
+
response.keys.should == ['message']
|
30
|
+
response['message'].should be_kind_of(String)
|
31
|
+
end
|
24
32
|
|
33
|
+
let :response do
|
34
|
+
raw_response = HTTParty.get('http://dummyprovider.com/hello', headers: {'Accept' => 'application/json' })
|
35
|
+
JSON.parse(raw_response.body)
|
36
|
+
end
|
25
37
|
end
|
26
38
|
end
|
@@ -14,11 +14,11 @@ class Servlet < WEBrick::HTTPServlet::AbstractServlet
|
|
14
14
|
end
|
15
15
|
|
16
16
|
class DummyServer
|
17
|
-
def initialize
|
18
|
-
@server = WEBrick::HTTPServer.new :Port =>
|
17
|
+
def initialize port, path, response
|
18
|
+
@server = WEBrick::HTTPServer.new :Port => port,
|
19
19
|
:AccessLog => [],
|
20
20
|
:Logger => WEBrick::Log::new("/dev/null", 7)
|
21
|
-
@server.mount
|
21
|
+
@server.mount path, Servlet, response
|
22
22
|
end
|
23
23
|
|
24
24
|
def start
|
@@ -1,10 +1,13 @@
|
|
1
1
|
module Pacto
|
2
2
|
describe Response do
|
3
|
+
let(:body_definition) do
|
4
|
+
{:type => "object", :required => true, :properties => double("body definition properties")}
|
5
|
+
end
|
3
6
|
let(:definition) do
|
4
7
|
{
|
5
8
|
'status' => 200,
|
6
9
|
'headers' => {'Content-Type' => 'application/json'},
|
7
|
-
'body' =>
|
10
|
+
'body' => body_definition
|
8
11
|
}
|
9
12
|
end
|
10
13
|
|
@@ -26,11 +29,12 @@ module Pacto
|
|
26
29
|
describe '#validate' do
|
27
30
|
let(:status) { 200 }
|
28
31
|
let(:headers) { {'Content-Type' => 'application/json', 'Age' => '60'} }
|
32
|
+
let(:response_body) { {'message' => 'response'} }
|
29
33
|
let(:fake_response) do
|
30
34
|
double({
|
31
35
|
:status => status,
|
32
36
|
:headers => headers,
|
33
|
-
:body =>
|
37
|
+
:body => response_body
|
34
38
|
})
|
35
39
|
end
|
36
40
|
|
@@ -45,6 +49,80 @@ module Pacto
|
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
52
|
+
context 'when body is a pure string and matches the description' do
|
53
|
+
let(:string_required) { true }
|
54
|
+
let(:body_definition) do
|
55
|
+
{ 'type' => 'string', 'required' => string_required }
|
56
|
+
end
|
57
|
+
let(:response_body) { "a simple string" }
|
58
|
+
|
59
|
+
it 'should not validate using JSON Schema' do
|
60
|
+
response = described_class.new(definition)
|
61
|
+
|
62
|
+
JSON::Validator.should_not_receive(:fully_validate)
|
63
|
+
response.validate(fake_response)
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'if required' do
|
67
|
+
it 'should not return an error when body is a string' do
|
68
|
+
response = described_class.new(definition)
|
69
|
+
|
70
|
+
response.validate(fake_response).should == []
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should return an error when body is nil' do
|
74
|
+
response = described_class.new(definition)
|
75
|
+
|
76
|
+
fake_response.stub(:body).and_return(nil)
|
77
|
+
response.validate(fake_response).size.should == 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'if not required' do
|
82
|
+
let(:string_required) { false }
|
83
|
+
|
84
|
+
it 'should not return an error when body is a string' do
|
85
|
+
response = described_class.new(definition)
|
86
|
+
|
87
|
+
response.validate(fake_response).should == []
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should not return an error when body is nil' do
|
91
|
+
response = described_class.new(definition)
|
92
|
+
|
93
|
+
fake_response.stub(:body).and_return(nil)
|
94
|
+
response.validate(fake_response).should == []
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'if contains pattern' do
|
99
|
+
let(:body_definition) do
|
100
|
+
{ 'type' => 'string', 'required' => string_required, 'pattern' => 'a.c' }
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'body matches pattern' do
|
104
|
+
let(:response_body) { 'cabcd' }
|
105
|
+
|
106
|
+
it "should not return an error" do
|
107
|
+
response = described_class.new(definition)
|
108
|
+
|
109
|
+
response.validate(fake_response).should == []
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'body does not match pattern' do
|
114
|
+
let(:response_body) { 'cabscd' }
|
115
|
+
|
116
|
+
it "should return an error" do
|
117
|
+
response = described_class.new(definition)
|
118
|
+
|
119
|
+
response.validate(fake_response).size.should == 1
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
48
126
|
context 'when status does not match' do
|
49
127
|
let(:status) { 500 }
|
50
128
|
|
data/spec/unit/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pacto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
12
|
+
date: 2013-08-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: webmock
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
31
|
+
name: yajl-ruby
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
@@ -230,6 +230,7 @@ files:
|
|
230
230
|
- .gitignore
|
231
231
|
- .rspec
|
232
232
|
- .rspec_integration
|
233
|
+
- .rspec_unit
|
233
234
|
- .travis.yml
|
234
235
|
- Gemfile
|
235
236
|
- Guardfile
|
@@ -278,12 +279,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
278
279
|
- - ! '>='
|
279
280
|
- !ruby/object:Gem::Version
|
280
281
|
version: '0'
|
282
|
+
segments:
|
283
|
+
- 0
|
284
|
+
hash: -3258303232236998448
|
281
285
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
282
286
|
none: false
|
283
287
|
requirements:
|
284
288
|
- - ! '>='
|
285
289
|
- !ruby/object:Gem::Version
|
286
290
|
version: '0'
|
291
|
+
segments:
|
292
|
+
- 0
|
293
|
+
hash: -3258303232236998448
|
287
294
|
requirements: []
|
288
295
|
rubyforge_project:
|
289
296
|
rubygems_version: 1.8.25
|