contracto 0.4.2 → 0.4.3
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 +4 -4
- data/README.md +2 -4
- data/lib/contracto/command/init.rb +1 -1
- data/lib/contracto/command/start.rb +1 -0
- data/lib/contracto/command/stop.rb +1 -0
- data/lib/contracto/config.rb +5 -6
- data/lib/contracto/contract.rb +4 -17
- data/lib/contracto/contract/request.rb +61 -0
- data/lib/contracto/contract/response.rb +1 -12
- data/lib/contracto/errors.rb +3 -0
- data/lib/contracto/server.rb +31 -0
- data/lib/contracto/server/contract_routes.rb +22 -0
- data/lib/contracto/server/controller.rb +75 -0
- data/lib/contracto/stats.rb +34 -1
- data/lib/contracto/system_action.rb +10 -38
- data/lib/contracto/version.rb +1 -1
- data/spec/fixtures/{get_users_by_id.con.json → get_user_by_id.contract.json} +6 -4
- data/spec/fixtures/{get_users.con.json → get_users.contract.json} +6 -4
- data/spec/fixtures/{post_users.con.json → post_users.contract.json} +6 -4
- metadata +12 -12
- data/lib/contracto/server/ruby/config.ru +0 -5
- data/lib/contracto/server/ruby/server.rb +0 -66
- data/spec/fixtures/my_data.con.json +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 893f39a06bea5e901e247bab7d2de6c37a3a0825
|
4
|
+
data.tar.gz: 1b8741717d48f6fa368529bfdd0c1c5815d67ba1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18efae1e83e4e38f7746080e0626c18207775f0edd47e5a6b359b66e9266ed57f85b405c38cb977aa22eab1b2b1dfc831f46af2868d76b6a668ab85c7b9385dd
|
7
|
+
data.tar.gz: 975b7ee12c51b0e6d77ea83d1c6510beae86243e872801d3c83b961e3b8d7da17c038234af37bbb72e380dac0644a384c3a4a056b3810e2a1c5afc38f3e1e924
|
data/README.md
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# IN DEVELOPMENT
|
2
|
-
|
3
1
|
# Contracto
|
4
2
|
|
5
3
|
Creates HTTP server based on your contract.
|
@@ -12,11 +10,11 @@ Creates HTTP server based on your contract.
|
|
12
10
|
|
13
11
|
Start server:
|
14
12
|
|
15
|
-
$ contracto start
|
13
|
+
$ contracto start https://github.com/contracto-lab/contracto-format.git
|
16
14
|
|
17
15
|
Test server (default port is __54321__):
|
18
16
|
|
19
|
-
$ curl
|
17
|
+
$ curl localhost:54321/users; curl localhost:54321/users/1; curl localhost:54321/users/2
|
20
18
|
|
21
19
|
Stop server:
|
22
20
|
|
@@ -6,7 +6,7 @@ class Contracto::Command::Init
|
|
6
6
|
initialized = Contracto::SystemActionChain.new(*actions).execute
|
7
7
|
|
8
8
|
if initialized
|
9
|
-
puts 'contract initialized, enter
|
9
|
+
puts 'contract initialized, enter "contracto start" to start server'
|
10
10
|
else
|
11
11
|
puts 'initializing contract failed'
|
12
12
|
end
|
data/lib/contracto/config.rb
CHANGED
@@ -4,18 +4,17 @@ class Contracto::Config
|
|
4
4
|
class << self
|
5
5
|
|
6
6
|
attr_accessor :repo_url
|
7
|
-
attr_accessor :root_dir
|
8
7
|
|
9
8
|
def configure
|
10
9
|
yield self if block_given?
|
11
10
|
end
|
12
11
|
|
12
|
+
def root_dir=(root_dir)
|
13
|
+
@root_dir = "#{current_dir}/#{root_dir}"
|
14
|
+
end
|
15
|
+
|
13
16
|
def root_dir
|
14
|
-
@
|
15
|
-
"#{current_dir}/#{@root_dir}"
|
16
|
-
else
|
17
|
-
default_root_dir
|
18
|
-
end
|
17
|
+
@root_dir || default_root_dir
|
19
18
|
end
|
20
19
|
|
21
20
|
end
|
data/lib/contracto/contract.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
class Contracto::Contract
|
2
|
+
require_relative 'contract/request'
|
2
3
|
require_relative 'contract/response'
|
3
4
|
require_relative 'stats'
|
4
5
|
|
@@ -6,8 +7,8 @@ class Contracto::Contract
|
|
6
7
|
|
7
8
|
def initialize(hash)
|
8
9
|
@hash = hash
|
9
|
-
@request = Contracto::Contract::Request.new(@hash.fetch('request'))
|
10
|
-
@responses = Contracto::Contract::Responses.new(@hash.fetch('
|
10
|
+
@request = Contracto::Contract::Request.new(@hash.fetch('schema').fetch('request'))
|
11
|
+
@responses = Contracto::Contract::Responses.new(@hash.fetch('examples'))
|
11
12
|
end
|
12
13
|
|
13
14
|
def http_method
|
@@ -45,18 +46,4 @@ class Contracto::Contract
|
|
45
46
|
@responses.count
|
46
47
|
end
|
47
48
|
end
|
48
|
-
|
49
|
-
class Contracto::Contract::Request
|
50
|
-
def initialize(hash)
|
51
|
-
@hash = hash
|
52
|
-
end
|
53
|
-
|
54
|
-
def http_method
|
55
|
-
@hash.fetch('http_method')
|
56
|
-
end
|
57
|
-
|
58
|
-
def url_pattern
|
59
|
-
@hash.fetch('path')
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
49
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Contracto::Contract::Request
|
2
|
+
def initialize(hash)
|
3
|
+
@hash = hash
|
4
|
+
end
|
5
|
+
|
6
|
+
def http_method
|
7
|
+
@hash.fetch('method')
|
8
|
+
end
|
9
|
+
|
10
|
+
def url_pattern
|
11
|
+
PathToSinatraPathAdapter.new(@hash.fetch('path')).sinatra_path
|
12
|
+
end
|
13
|
+
|
14
|
+
class PathToSinatraPathAdapter
|
15
|
+
def initialize(path)
|
16
|
+
@path = path
|
17
|
+
end
|
18
|
+
|
19
|
+
def sinatra_path
|
20
|
+
parse_brackets! if path_with_brackets?
|
21
|
+
@path
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def parse_brackets!
|
27
|
+
if fully_dynamic_route?
|
28
|
+
path_to_regexp!
|
29
|
+
else
|
30
|
+
brackets_to_colons!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def brackets_to_colons!
|
35
|
+
@path.gsub!('{', ':')
|
36
|
+
@path.gsub!('}', '')
|
37
|
+
end
|
38
|
+
|
39
|
+
def path_to_regexp!
|
40
|
+
brackets_to_named_captures!
|
41
|
+
@path = Regexp.new(@path)
|
42
|
+
end
|
43
|
+
|
44
|
+
def brackets_to_named_captures!
|
45
|
+
matches = @path.scan(/(\{([^\/])*\})/).map(&:first)
|
46
|
+
matches.each do |match|
|
47
|
+
@path.gsub! match, "(?<#{match}>\\w*)"
|
48
|
+
end
|
49
|
+
@path.gsub!('{', '')
|
50
|
+
@path.gsub!('}', '')
|
51
|
+
end
|
52
|
+
|
53
|
+
def fully_dynamic_route?
|
54
|
+
!@path.scan(/\}[^\/]/).empty? || !@path.scan(/[^\/]\{/).empty?
|
55
|
+
end
|
56
|
+
|
57
|
+
def path_with_brackets?
|
58
|
+
!!@path.match('{')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -50,10 +50,7 @@ class Contracto::Contract::Response
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def body
|
53
|
-
|
54
|
-
@body.tap do
|
55
|
-
replace_params_placeholders_with_params_value
|
56
|
-
end
|
53
|
+
File.read(Contracto::Config.root_dir + body_path)
|
57
54
|
end
|
58
55
|
|
59
56
|
private
|
@@ -66,18 +63,10 @@ class Contracto::Contract::Response
|
|
66
63
|
end
|
67
64
|
end
|
68
65
|
|
69
|
-
def set_body
|
70
|
-
@body = File.read(Contracto::Config.root_dir + body_path)
|
71
|
-
end
|
72
|
-
|
73
66
|
def human_header_key_to_http_header_key(key)
|
74
67
|
key = key.upcase
|
75
68
|
key = key.gsub('-', '_')
|
76
69
|
key = 'HTTP_' + key
|
77
70
|
key
|
78
71
|
end
|
79
|
-
|
80
|
-
def replace_params_placeholders_with_params_value
|
81
|
-
# TODO
|
82
|
-
end
|
83
72
|
end
|
data/lib/contracto/errors.rb
CHANGED
@@ -4,6 +4,9 @@ class Contracto::CouldNotDownloadContractError < StandardError
|
|
4
4
|
end
|
5
5
|
end
|
6
6
|
|
7
|
+
class Contracto::CouldNotStartServer < StandardError
|
8
|
+
end
|
9
|
+
|
7
10
|
class Contracto::ServerAlreadyRunningError < StandardError
|
8
11
|
def initialize
|
9
12
|
super 'Could not start: Contracto server is already running'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
class Contracto::Server < Sinatra::Base
|
4
|
+
|
5
|
+
require_relative 'server/controller'
|
6
|
+
require_relative 'stats'
|
7
|
+
|
8
|
+
set :port, Contracto::Constants::PORT
|
9
|
+
set :show_exceptions, false
|
10
|
+
|
11
|
+
get '/contracto' do
|
12
|
+
"*** Contracto server is working! [#{Gem::Specification.find_by_name('contracto').version}] ***"
|
13
|
+
end
|
14
|
+
|
15
|
+
get '/contracto/terminate' do
|
16
|
+
Thread.new { sleep 1; Process.kill 'INT', Process.pid }
|
17
|
+
status 200
|
18
|
+
Contracto::Stats.summary rescue ''
|
19
|
+
end
|
20
|
+
|
21
|
+
not_found do
|
22
|
+
status 404
|
23
|
+
"Could not found example for #{request.url}"
|
24
|
+
end
|
25
|
+
|
26
|
+
error do |ex|
|
27
|
+
status 500
|
28
|
+
["#{ex.class}: #{ex.message}", ex.backtrace[0, 15].join("\n")].join("\n")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Contracto::Server < Sinatra::Base
|
2
|
+
|
3
|
+
jsons_with_contracts = Dir["#{Contracto::Config.root_dir}/**/*.contract.json"].map do |file_with_contract|
|
4
|
+
File.read file_with_contract
|
5
|
+
end
|
6
|
+
|
7
|
+
if jsons_with_contracts.empty?
|
8
|
+
puts "warning: no contracts found in #{Contracto::Config.root_dir}, create some *.contract.json files"
|
9
|
+
end
|
10
|
+
|
11
|
+
Contracto::Parser.new(jsons_with_contracts).contracts.each do |contract|
|
12
|
+
send(contract.http_method, contract.url_pattern) do
|
13
|
+
contract.response_body(params, http_headers)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def http_headers
|
18
|
+
env.select {|k,v| k.start_with? 'HTTP_'}
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'daemons'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
class Contracto::Server < Sinatra::Base
|
6
|
+
|
7
|
+
extend Contracto::Constants
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def start_contracto_server!
|
12
|
+
if contracto_server_running?
|
13
|
+
puts 'contracto server is already running, enter "contracto stop" to kill it'
|
14
|
+
return
|
15
|
+
elsif !root_dir_exists?
|
16
|
+
puts "current dir does not contain required contracto dir (#{Contracto::Config.root_dir})"
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
20
|
+
create_routes_from_contract
|
21
|
+
start_daemon!
|
22
|
+
wait_until_server_is_running
|
23
|
+
end
|
24
|
+
|
25
|
+
def stop_contracto_server!
|
26
|
+
uri = URI.parse("http://localhost:#{port}/contracto/terminate")
|
27
|
+
response = Net::HTTP.get_response(uri)
|
28
|
+
if response.is_a?(Net::HTTPOK)
|
29
|
+
puts 'contracto server killed'
|
30
|
+
puts response.body
|
31
|
+
else
|
32
|
+
puts "something went wrong: [#{response.code}] #{response.body}]"
|
33
|
+
end
|
34
|
+
rescue Errno::ECONNREFUSED
|
35
|
+
puts 'contracto server could not be killed (already dead or was never alive)'
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def root_dir_exists?
|
41
|
+
Dir.exists?(Contracto::Config.root_dir)
|
42
|
+
end
|
43
|
+
|
44
|
+
def contracto_server_running?
|
45
|
+
uri = URI.parse("http://localhost:#{port}/contracto")
|
46
|
+
Net::HTTP.get_response(uri).is_a?(Net::HTTPOK)
|
47
|
+
rescue Errno::ECONNREFUSED
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_routes_from_contract
|
52
|
+
require_relative 'contract_routes'
|
53
|
+
end
|
54
|
+
|
55
|
+
def start_daemon!
|
56
|
+
Daemons.call(app_name: server_pidfile_name, dir: Contracto::Config.root_dir, dir_mode: :normal) do
|
57
|
+
Contracto::Server.run!
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def wait_until_server_is_running
|
62
|
+
10.downto(0).each do |n|
|
63
|
+
sleep 1
|
64
|
+
puts "waiting for contracto server, #{n} tries left..."
|
65
|
+
if contracto_server_running?
|
66
|
+
puts '...contracto server is working'
|
67
|
+
return true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
raise Contracto::CouldNotStartServer
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
data/lib/contracto/stats.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
class Contracto::Stats
|
2
|
+
|
3
|
+
NA_TEXT = 'N/A'
|
4
|
+
|
2
5
|
class << self
|
3
6
|
attr_accessor :all_contracts
|
4
7
|
|
@@ -13,5 +16,35 @@ class Contracto::Stats
|
|
13
16
|
def all_responses
|
14
17
|
@all_responses ||= all_contracts.map(&:responses).map(&:count).inject(&:+)
|
15
18
|
end
|
19
|
+
|
20
|
+
def contracts_usage
|
21
|
+
return NA_TEXT if all_contracts.size.zero?
|
22
|
+
|
23
|
+
(used_contracts.size/all_contracts.size.to_f).round(2)
|
24
|
+
end
|
25
|
+
|
26
|
+
def responses_usage
|
27
|
+
return NA_TEXT if all_responses.size.zero?
|
28
|
+
|
29
|
+
(used_responses.size/all_responses.size.to_f).round(2)
|
30
|
+
end
|
31
|
+
|
32
|
+
def contracts_stats_summary
|
33
|
+
"contracts usage: #{used_contracts.size}/#{all_contracts.size} (#{contracts_usage * 100}%)"
|
34
|
+
end
|
35
|
+
|
36
|
+
def responses_stats_summary
|
37
|
+
"examples usage: #{used_responses.size}/#{all_responses.size} (#{responses_usage * 100}%)"
|
38
|
+
end
|
39
|
+
|
40
|
+
def summary
|
41
|
+
length = contracts_stats_summary.length
|
42
|
+
[
|
43
|
+
'stats'.center(length, '-'),
|
44
|
+
contracts_stats_summary,
|
45
|
+
responses_stats_summary,
|
46
|
+
('-' * length) + ' '
|
47
|
+
].join("\n")
|
48
|
+
end
|
16
49
|
end
|
17
|
-
end
|
50
|
+
end
|
@@ -1,8 +1,11 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
1
3
|
class Contracto::SystemAction
|
2
|
-
|
4
|
+
require_relative 'server'
|
5
|
+
|
6
|
+
extend Contracto::Constants
|
3
7
|
|
4
8
|
class << self
|
5
|
-
include Contracto::Constants
|
6
9
|
|
7
10
|
def create_sample_contract
|
8
11
|
if Dir.exists?(Contracto::Config.root_dir)
|
@@ -17,37 +20,15 @@ class Contracto::SystemAction
|
|
17
20
|
end
|
18
21
|
|
19
22
|
def start_server
|
20
|
-
|
21
|
-
|
22
|
-
require_relative 'server/ruby/server'
|
23
|
-
require 'daemons'
|
24
|
-
|
25
|
-
options = {
|
26
|
-
app_name: server_pidfile_name,
|
27
|
-
dir: Contracto::Config.root_dir,
|
28
|
-
dir_mode: :normal
|
29
|
-
}
|
30
|
-
|
31
|
-
Daemons.call(options) do
|
32
|
-
Contracto::Server.run!
|
33
|
-
end
|
34
|
-
|
35
|
-
5.downto(0).each do |n|
|
36
|
-
sleep 1
|
37
|
-
puts "waiting for contracto server, #{n} tries left..."
|
38
|
-
break if test_request(silent: true)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def stop_server
|
43
|
-
puts 'killing server...'
|
44
|
-
system "curl 0.0.0.0:#{port}/contracto_terminate"
|
45
|
-
puts '...server killed'
|
23
|
+
Contracto::Server.start_contracto_server!
|
46
24
|
end
|
47
25
|
|
48
26
|
def revert_start_server
|
49
27
|
stop_server
|
50
|
-
|
28
|
+
end
|
29
|
+
|
30
|
+
def stop_server
|
31
|
+
Contracto::Server.stop_contracto_server!
|
51
32
|
end
|
52
33
|
|
53
34
|
def clone_repo
|
@@ -66,15 +47,6 @@ class Contracto::SystemAction
|
|
66
47
|
FileUtils.rm_rf Contracto::Config.root_dir
|
67
48
|
end
|
68
49
|
|
69
|
-
def server_already_running?
|
70
|
-
test_request(silent: true)
|
71
|
-
end
|
72
|
-
|
73
|
-
def test_request(options = {})
|
74
|
-
args = ''
|
75
|
-
args << '-s -o /dev/null' if options[:silent]
|
76
|
-
system "curl #{args} 0.0.0.0:#{port}/contracto"
|
77
|
-
end
|
78
50
|
end
|
79
51
|
end
|
80
52
|
|
data/lib/contracto/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contracto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kacper Walanus
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -119,11 +119,13 @@ files:
|
|
119
119
|
- lib/contracto/config.rb
|
120
120
|
- lib/contracto/constants.rb
|
121
121
|
- lib/contracto/contract.rb
|
122
|
+
- lib/contracto/contract/request.rb
|
122
123
|
- lib/contracto/contract/response.rb
|
123
124
|
- lib/contracto/errors.rb
|
124
125
|
- lib/contracto/parser.rb
|
125
|
-
- lib/contracto/server
|
126
|
-
- lib/contracto/server/
|
126
|
+
- lib/contracto/server.rb
|
127
|
+
- lib/contracto/server/contract_routes.rb
|
128
|
+
- lib/contracto/server/controller.rb
|
127
129
|
- lib/contracto/stats.rb
|
128
130
|
- lib/contracto/system_action.rb
|
129
131
|
- lib/contracto/system_action_chain.rb
|
@@ -131,10 +133,9 @@ files:
|
|
131
133
|
- script/send_test_requests.sh
|
132
134
|
- script/start_from_remote.sh
|
133
135
|
- script/start_locally.sh
|
134
|
-
- spec/fixtures/
|
135
|
-
- spec/fixtures/
|
136
|
-
- spec/fixtures/
|
137
|
-
- spec/fixtures/post_users.con.json
|
136
|
+
- spec/fixtures/get_user_by_id.contract.json
|
137
|
+
- spec/fixtures/get_users.contract.json
|
138
|
+
- spec/fixtures/post_users.contract.json
|
138
139
|
- spec/fixtures/users/get_users.json
|
139
140
|
- spec/fixtures/users/get_users.xml
|
140
141
|
- spec/fixtures/users/get_users_by_id_id_1.json
|
@@ -168,10 +169,9 @@ signing_key:
|
|
168
169
|
specification_version: 4
|
169
170
|
summary: XXX
|
170
171
|
test_files:
|
171
|
-
- spec/fixtures/
|
172
|
-
- spec/fixtures/
|
173
|
-
- spec/fixtures/
|
174
|
-
- spec/fixtures/post_users.con.json
|
172
|
+
- spec/fixtures/get_user_by_id.contract.json
|
173
|
+
- spec/fixtures/get_users.contract.json
|
174
|
+
- spec/fixtures/post_users.contract.json
|
175
175
|
- spec/fixtures/users/get_users.json
|
176
176
|
- spec/fixtures/users/get_users.xml
|
177
177
|
- spec/fixtures/users/get_users_by_id_id_1.json
|
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'sinatra/base'
|
2
|
-
|
3
|
-
class Contracto::Server < Sinatra::Base
|
4
|
-
require_relative '../../stats'
|
5
|
-
|
6
|
-
set :port, Contracto::Constants::PORT
|
7
|
-
|
8
|
-
get '/contracto' do
|
9
|
-
"*** Contracto server is working! [#{Gem::Specification.find_by_name('contracto').version}] ***"
|
10
|
-
end
|
11
|
-
|
12
|
-
get '/contracto_terminate' do
|
13
|
-
Thread.new { sleep 1; Process.kill 'INT', Process.pid }
|
14
|
-
status 200
|
15
|
-
body_on_terminate
|
16
|
-
end
|
17
|
-
|
18
|
-
jsons_with_contracts = Dir["#{Contracto::Config.root_dir}/**/*.con.json"].map do |file_with_contract|
|
19
|
-
File.read file_with_contract
|
20
|
-
end
|
21
|
-
|
22
|
-
Contracto::Parser.new(jsons_with_contracts).contracts.each do |contract|
|
23
|
-
send(contract.http_method, contract.url_pattern) do
|
24
|
-
begin
|
25
|
-
contract.response_body(params, http_headers)
|
26
|
-
rescue StandardError => ex
|
27
|
-
status 500
|
28
|
-
error_response(ex)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def http_headers
|
34
|
-
env.select {|k,v| k.start_with? 'HTTP_'}
|
35
|
-
end
|
36
|
-
|
37
|
-
def error_response(ex)
|
38
|
-
["#{ex.class}: #{ex.message}", ex.backtrace[0, 15].join("\n")].join("\n")
|
39
|
-
end
|
40
|
-
|
41
|
-
def body_on_terminate
|
42
|
-
used_contracts_count = Contracto::Stats.used_contracts.size
|
43
|
-
all_contracts_count = Contracto::Stats.all_contracts.size
|
44
|
-
used_responses_count = Contracto::Stats.used_responses.size
|
45
|
-
all_responses_count = Contracto::Stats.all_responses.size
|
46
|
-
|
47
|
-
contracts_usage = if all_contracts_count.zero?
|
48
|
-
'N/A'
|
49
|
-
else
|
50
|
-
"#{(used_contracts_count / all_contracts_count.to_f).round(2)}%"
|
51
|
-
end
|
52
|
-
|
53
|
-
responses_usage = if all_responses_count.zero?
|
54
|
-
'N/A'
|
55
|
-
else
|
56
|
-
"#{(used_responses_count / all_responses_count.to_f).round(2)}%"
|
57
|
-
end
|
58
|
-
|
59
|
-
[
|
60
|
-
"Used contracts: #{used_contracts_count}/#{all_contracts_count} (#{contracts_usage})",
|
61
|
-
"Used responses: #{used_responses_count}/#{all_responses_count} (#{responses_usage})",
|
62
|
-
''
|
63
|
-
].join("\n")
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
@@ -1,23 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"request": {
|
3
|
-
"http_method": "get",
|
4
|
-
"path": "/my/data",
|
5
|
-
"meta": {
|
6
|
-
"request": {
|
7
|
-
|
8
|
-
},
|
9
|
-
"response": {
|
10
|
-
"body": {
|
11
|
-
"type": "object",
|
12
|
-
"embedded": [
|
13
|
-
{
|
14
|
-
"name": "id",
|
15
|
-
"type": "string"
|
16
|
-
}
|
17
|
-
]
|
18
|
-
}
|
19
|
-
}
|
20
|
-
}
|
21
|
-
},
|
22
|
-
"responses": []
|
23
|
-
}
|