rest-assured 0.3.2 → 1.0.0.rc1
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 -0
- data/Gemfile +4 -1
- data/README.markdown +47 -25
- data/bin/rest-assured +3 -3
- data/features/command_line_options.feature +2 -2
- data/features/rest_api/redirects.feature +10 -9
- data/features/ruby_api/create_double.feature +1 -6
- data/features/ruby_api/test_server.feature +42 -0
- data/features/ruby_api/verify_requests.feature +1 -6
- data/features/ruby_api/wait_for_requests.feature +2 -5
- data/features/step_definitions/command_line_options_steps.rb +1 -1
- data/features/step_definitions/doubles_steps.rb +4 -0
- data/features/step_definitions/redirect_rules_steps.rb +2 -6
- data/features/step_definitions/ruby_api_steps.rb +45 -0
- data/features/support/env.rb +9 -14
- data/features/support/world_helpers.rb +1 -1
- data/lib/rest-assured.rb +1 -45
- data/lib/rest-assured/api.rb +3 -0
- data/lib/rest-assured/api/app_runner.rb +18 -0
- data/lib/rest-assured/api/app_session.rb +33 -0
- data/lib/rest-assured/{client → api}/resources.rb +0 -0
- data/lib/rest-assured/api/server.rb +59 -0
- data/lib/rest-assured/application.rb +46 -0
- data/lib/rest-assured/config.rb +16 -3
- data/lib/rest-assured/models/redirect.rb +6 -0
- data/lib/rest-assured/routes/double.rb +1 -1
- data/lib/rest-assured/routes/redirect.rb +1 -1
- data/lib/rest-assured/routes/response.rb +4 -4
- data/lib/rest-assured/utils/drb_sniffer.rb +11 -0
- data/lib/rest-assured/utils/port_explorer.rb +22 -0
- data/lib/rest-assured/utils/subprocess.rb +50 -0
- data/lib/rest-assured/version.rb +1 -1
- data/prof-result.html +79521 -0
- data/rest-assured.gemspec +2 -1
- data/spec/api/app_runner_spec.rb +27 -0
- data/spec/api/app_session_spec.rb +51 -0
- data/spec/{client → api}/resource_double_spec.rb +1 -14
- data/spec/api/server_spec.rb +138 -0
- data/spec/config_spec.rb +111 -93
- data/spec/functional/response_spec.rb +5 -2
- data/spec/models/redirect_spec.rb +22 -0
- data/spec/port_explorer_spec.rb +32 -0
- data/spec/spec_helper.rb +25 -18
- data/spec/subprocess_spec.rb +138 -0
- data/spec/{custom_matchers.rb → support/custom_matchers.rb} +0 -0
- data/spec/support/reset-singleton.rb +15 -0
- metadata +66 -30
- data/lib/rest-assured/client.rb +0 -17
data/features/support/env.rb
CHANGED
@@ -3,14 +3,18 @@ require 'rubygems'
|
|
3
3
|
require 'spork'
|
4
4
|
|
5
5
|
Spork.prefork do
|
6
|
+
require 'timeout'
|
6
7
|
require 'rspec'
|
7
8
|
require 'rack/test'
|
8
9
|
require 'capybara'
|
9
10
|
require 'capybara/firebug'
|
10
11
|
require 'capybara/cucumber'
|
11
12
|
require 'database_cleaner'
|
13
|
+
require 'awesome_print'
|
14
|
+
require 'rest-assured/utils/port_explorer'
|
12
15
|
require File.dirname(__FILE__) + '/world_helpers'
|
13
16
|
|
17
|
+
|
14
18
|
ENV['RACK_ENV'] = 'test'
|
15
19
|
|
16
20
|
module RackHeaderHack
|
@@ -41,21 +45,8 @@ end
|
|
41
45
|
Spork.each_run do
|
42
46
|
require 'rest-assured/config'
|
43
47
|
RestAssured::Config.build(:adapter => 'mysql')
|
44
|
-
|
45
48
|
require 'rest-assured'
|
46
|
-
require 'rest-assured/
|
47
|
-
require File.expand_path('../test-server', __FILE__)
|
48
|
-
|
49
|
-
at_exit do
|
50
|
-
TestServer.stop
|
51
|
-
end
|
52
|
-
|
53
|
-
TestServer.start(:port => 9876, :db_user => ENV['TRAVIS'] ? "''" : "root")
|
54
|
-
|
55
|
-
while not TestServer.up?
|
56
|
-
puts 'Waiting for TestServer to come up...'
|
57
|
-
sleep 1
|
58
|
-
end
|
49
|
+
require 'rest-assured/application'
|
59
50
|
|
60
51
|
def app
|
61
52
|
RestAssured::Application
|
@@ -68,6 +59,10 @@ Spork.each_run do
|
|
68
59
|
DatabaseCleaner.start
|
69
60
|
end
|
70
61
|
|
62
|
+
Before "@ruby_api" do
|
63
|
+
RestAssured::Server.start(:port => 9876, :dbuser => ENV['TRAVIS'] ? "''" : "root")
|
64
|
+
end
|
65
|
+
|
71
66
|
Before "@ui" do
|
72
67
|
set_headers "HTTP_USER_AGENT" => 'Firefox'
|
73
68
|
end
|
@@ -7,7 +7,7 @@ module WorldHelpers
|
|
7
7
|
code = File.read rest_assured_exec
|
8
8
|
|
9
9
|
code.sub!(/(.*)/, "\\1\nENV['RACK_ENV'] = 'production'")
|
10
|
-
code.sub!(/require 'rest-assured'/, '')
|
10
|
+
code.sub!(/require 'rest-assured\/application'/, '')
|
11
11
|
code.sub!(/RestAssured::Application.run!/, 'puts AppConfig.to_yaml')
|
12
12
|
|
13
13
|
new_exec = "#{rest_assured_exec}_temp"
|
data/lib/rest-assured.rb
CHANGED
@@ -1,45 +1 @@
|
|
1
|
-
require '
|
2
|
-
require 'sinatra/handler_options_patch'
|
3
|
-
require 'haml'
|
4
|
-
require 'rack-flash'
|
5
|
-
require 'sinatra/partials'
|
6
|
-
require 'rest-assured/config'
|
7
|
-
require 'rest-assured/models/double'
|
8
|
-
require 'rest-assured/models/redirect'
|
9
|
-
require 'rest-assured/models/request'
|
10
|
-
require 'rest-assured/routes/double'
|
11
|
-
require 'rest-assured/routes/redirect'
|
12
|
-
require 'rest-assured/routes/response'
|
13
|
-
|
14
|
-
module RestAssured
|
15
|
-
class Application < Sinatra::Base
|
16
|
-
|
17
|
-
include Config
|
18
|
-
|
19
|
-
enable :method_override
|
20
|
-
|
21
|
-
enable :sessions
|
22
|
-
use Rack::Flash, :sweep => true
|
23
|
-
|
24
|
-
set :public_folder, File.expand_path('../../public', __FILE__)
|
25
|
-
set :views, File.expand_path('../../views', __FILE__)
|
26
|
-
set :haml, :format => :html5
|
27
|
-
|
28
|
-
helpers Sinatra::Partials
|
29
|
-
|
30
|
-
helpers do
|
31
|
-
def browser?
|
32
|
-
request.user_agent =~ /Safari|Firefox|Opera|MSIE|Chrome/
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
include DoubleRoutes
|
37
|
-
include RedirectRoutes
|
38
|
-
|
39
|
-
%w{get post put delete}.each do |verb|
|
40
|
-
send verb, /.*/ do
|
41
|
-
Response.perform(self)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
1
|
+
require 'rest-assured/api'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module RestAssured
|
4
|
+
class AppRunner
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def run!
|
8
|
+
unless Kernel.require 'rest-assured/application'
|
9
|
+
RestAssured::Application.send(:include, Config)
|
10
|
+
end
|
11
|
+
RestAssured::Application.run!
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.method_missing(*args)
|
15
|
+
instance.send(*args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rest-assured/utils/subprocess'
|
2
|
+
require 'rest-assured/utils/drb_sniffer'
|
3
|
+
require 'rest-assured/api/app_runner'
|
4
|
+
require 'childprocess'
|
5
|
+
|
6
|
+
module RestAssured
|
7
|
+
class AppSession
|
8
|
+
include Utils::DrbSniffer
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@child = if not running_in_drb? and Process.respond_to?(:fork)
|
12
|
+
Utils::Subprocess.new do
|
13
|
+
AppRunner.run!
|
14
|
+
end
|
15
|
+
else
|
16
|
+
child = ChildProcess.build('rest-assured', *Config.to_cmdargs)
|
17
|
+
child.io.inherit!
|
18
|
+
child.start
|
19
|
+
child
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def alive?
|
24
|
+
@child.alive?
|
25
|
+
rescue Errno::ECHILD
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_missing(*args)
|
30
|
+
@child.send(*args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
File without changes
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'rest-assured/config'
|
3
|
+
require 'rest-assured/api/resources'
|
4
|
+
require 'rest-assured/api/app_session'
|
5
|
+
require 'rest-assured/utils/port_explorer'
|
6
|
+
|
7
|
+
module RestAssured
|
8
|
+
class Server
|
9
|
+
attr_reader :address
|
10
|
+
|
11
|
+
include Singleton
|
12
|
+
|
13
|
+
def start!(opts = {})
|
14
|
+
at_exit { stop }
|
15
|
+
|
16
|
+
stop if up?
|
17
|
+
|
18
|
+
Config.build(opts)
|
19
|
+
|
20
|
+
self.address = "http#{AppConfig.ssl ? 's' : ''}://127.0.0.1:#{AppConfig.port}"
|
21
|
+
|
22
|
+
@session = AppSession.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def start(*args)
|
26
|
+
start!(*args)
|
27
|
+
|
28
|
+
while not up?
|
29
|
+
sleep 0.5
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def address=(address)
|
34
|
+
Double.site = @address = address
|
35
|
+
end
|
36
|
+
|
37
|
+
def stop
|
38
|
+
@session.try(:stop)
|
39
|
+
|
40
|
+
10.times do
|
41
|
+
if up?
|
42
|
+
sleep 0.5
|
43
|
+
next
|
44
|
+
else
|
45
|
+
return
|
46
|
+
end
|
47
|
+
end
|
48
|
+
raise "Failed to stop RestAssured server"
|
49
|
+
end
|
50
|
+
|
51
|
+
def up?
|
52
|
+
!!@session && @session.alive? && !Utils::PortExplorer.port_free?(AppConfig.port)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.method_missing(*args)
|
56
|
+
instance.send(*args)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/handler_options_patch'
|
3
|
+
require 'haml'
|
4
|
+
require 'sinatra/flash'
|
5
|
+
require 'sinatra/partials'
|
6
|
+
require 'rest-assured/config'
|
7
|
+
require 'rest-assured/models/double'
|
8
|
+
require 'rest-assured/models/redirect'
|
9
|
+
require 'rest-assured/models/request'
|
10
|
+
require 'rest-assured/routes/double'
|
11
|
+
require 'rest-assured/routes/redirect'
|
12
|
+
require 'rest-assured/routes/response'
|
13
|
+
|
14
|
+
module RestAssured
|
15
|
+
class Application < Sinatra::Base
|
16
|
+
|
17
|
+
include Config
|
18
|
+
|
19
|
+
enable :method_override
|
20
|
+
|
21
|
+
enable :sessions
|
22
|
+
register Sinatra::Flash
|
23
|
+
|
24
|
+
set :public_folder, File.expand_path('../../../public', __FILE__)
|
25
|
+
set :views, File.expand_path('../../../views', __FILE__)
|
26
|
+
set :haml, :format => :html5
|
27
|
+
|
28
|
+
helpers Sinatra::Partials
|
29
|
+
|
30
|
+
helpers do
|
31
|
+
def browser?
|
32
|
+
request.user_agent =~ /Safari|Firefox|Opera|MSIE|Chrome/
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
include DoubleRoutes
|
37
|
+
include RedirectRoutes
|
38
|
+
|
39
|
+
%w{get post put delete}.each do |verb|
|
40
|
+
send verb, /.*/ do
|
41
|
+
Response.perform(self)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
data/lib/rest-assured/config.rb
CHANGED
@@ -31,7 +31,8 @@ module RestAssured
|
|
31
31
|
|
32
32
|
# this is meant to be called prior to include
|
33
33
|
def self.build(opts = {})
|
34
|
-
|
34
|
+
@user_conf = opts
|
35
|
+
AppConfig.merge!(@user_conf)
|
35
36
|
|
36
37
|
AppConfig.logfile ||= if AppConfig.environment == 'production'
|
37
38
|
'./rest-assured.log'
|
@@ -45,7 +46,7 @@ module RestAssured
|
|
45
46
|
def self.included(klass)
|
46
47
|
init_logger
|
47
48
|
setup_db
|
48
|
-
setup_ssl(klass) if AppConfig.
|
49
|
+
setup_ssl(klass) if AppConfig.ssl
|
49
50
|
|
50
51
|
klass.set :port, AppConfig.port
|
51
52
|
klass.set :environment, AppConfig.environment
|
@@ -54,6 +55,18 @@ module RestAssured
|
|
54
55
|
klass.use Rack::CommonLogger, AppConfig.logger
|
55
56
|
end
|
56
57
|
|
58
|
+
def self.to_cmdargs
|
59
|
+
@user_conf.inject([]) do |acc, (k,v)|
|
60
|
+
if v == true
|
61
|
+
acc << "--#{k}"
|
62
|
+
elsif v.is_a?(String) || v.is_a?(Integer)
|
63
|
+
acc << "--#{k}" << v.to_s
|
64
|
+
else
|
65
|
+
acc
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
57
70
|
private
|
58
71
|
|
59
72
|
def self.setup_ssl(klass)
|
@@ -152,7 +165,7 @@ module RestAssured
|
|
152
165
|
end
|
153
166
|
|
154
167
|
def self.build_ssl_config
|
155
|
-
AppConfig.
|
168
|
+
AppConfig.ssl ||= false
|
156
169
|
AppConfig.ssl_cert ||= File.expand_path('../../../ssl/localhost.crt', __FILE__)
|
157
170
|
AppConfig.ssl_key ||= File.expand_path('../../../ssl/localhost.key', __FILE__)
|
158
171
|
end
|
@@ -9,6 +9,12 @@ module RestAssured
|
|
9
9
|
|
10
10
|
before_create :assign_position
|
11
11
|
|
12
|
+
def self.find_redirect_url_for(fullpath)
|
13
|
+
if redirect = ordered.find { |r| fullpath =~ /#{r.pattern}/ }
|
14
|
+
fullpath.sub /#{redirect.pattern}/, redirect.to
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
12
18
|
def self.update_order(ordered_redirect_ids)
|
13
19
|
success = true
|
14
20
|
|
@@ -48,7 +48,7 @@ module RestAssured
|
|
48
48
|
flash[:notice] = "Double created"
|
49
49
|
redirect '/doubles'
|
50
50
|
else
|
51
|
-
flash[:error] = "Crumps! " + @double.errors.full_messages.join("; ")
|
51
|
+
flash.now[:error] = "Crumps! " + @double.errors.full_messages.join("; ")
|
52
52
|
haml :'doubles/new'
|
53
53
|
end
|
54
54
|
else
|
@@ -19,7 +19,7 @@ module RestAssured
|
|
19
19
|
flash[:notice] = "Redirect created"
|
20
20
|
redirect '/redirects'
|
21
21
|
else
|
22
|
-
flash[:error] = "Crumps! " + @redirect.errors.full_messages.join("; ")
|
22
|
+
flash.now[:error] = "Crumps! " + @redirect.errors.full_messages.join("; ")
|
23
23
|
haml :'redirects/new'
|
24
24
|
end
|
25
25
|
else
|
@@ -5,16 +5,16 @@ module RestAssured
|
|
5
5
|
|
6
6
|
if d = Models::Double.where(:fullpath => request.fullpath, :active => true, :verb => request.request_method).first
|
7
7
|
request.body.rewind
|
8
|
-
body
|
9
|
-
env
|
8
|
+
body = request.body.read #without temp variable ':body = > body' is always nil. mistery
|
9
|
+
env = request.env.except('rack.input', 'rack.errors', 'rack.logger')
|
10
10
|
|
11
11
|
d.requests.create!(:rack_env => env.to_json, :body => body, :params => request.params.to_json)
|
12
12
|
|
13
13
|
app.headers d.response_headers
|
14
14
|
app.body d.content
|
15
15
|
app.status d.status
|
16
|
-
elsif
|
17
|
-
app.redirect
|
16
|
+
elsif redirect_url = Models::Redirect.find_redirect_url_for(request.fullpath)
|
17
|
+
app.redirect redirect_url
|
18
18
|
else
|
19
19
|
app.status 404
|
20
20
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module RestAssured
|
4
|
+
module Utils
|
5
|
+
class PortExplorer
|
6
|
+
def self.free_port
|
7
|
+
server = TCPServer.new('127.0.0.1', 0)
|
8
|
+
free_port = server.addr[1]
|
9
|
+
server.close
|
10
|
+
free_port
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.port_free?(port)
|
14
|
+
Net::HTTP.get('127.0.0.1', '/', port)
|
15
|
+
rescue => e
|
16
|
+
e.is_a?(Errno::ECONNREFUSED)
|
17
|
+
else
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module RestAssured
|
2
|
+
module Utils
|
3
|
+
class Subprocess
|
4
|
+
attr_reader :pid
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@pid = Kernel.fork do
|
8
|
+
trap('USR1') do
|
9
|
+
$stopped = true
|
10
|
+
Process.kill('TERM', Process.pid) # unlike 'exit' this one is NOT being intercepted by Webrick
|
11
|
+
end
|
12
|
+
|
13
|
+
at_exit do
|
14
|
+
if $stopped
|
15
|
+
puts "Being stopped from parent..."
|
16
|
+
#else
|
17
|
+
#puts "Shutting down parent..."
|
18
|
+
#Process.kill('TERM', Process.ppid)
|
19
|
+
end
|
20
|
+
exit!
|
21
|
+
end
|
22
|
+
|
23
|
+
begin
|
24
|
+
yield
|
25
|
+
rescue => e
|
26
|
+
if defined?(EventMachine) && e.is_a?(EventMachine::ConnectionNotBound)
|
27
|
+
retry
|
28
|
+
end
|
29
|
+
puts "#{self} has raised #{e.inspect}:"
|
30
|
+
puts e.backtrace.join("\n")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Process.detach(@pid)
|
35
|
+
at_exit { stop }
|
36
|
+
end
|
37
|
+
|
38
|
+
def alive?
|
39
|
+
Process.kill(0, @pid)
|
40
|
+
true
|
41
|
+
rescue Errno::ESRCH
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def stop
|
46
|
+
Process.kill('USR1', @pid) rescue Errno::ESRCH # no such process
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|