rest-assured 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +2 -0
- data/README.markdown +9 -8
- data/features/rest_api/doubles.feature +1 -0
- data/features/step_definitions/ruby_api_steps.rb +1 -1
- data/lib/rest-assured/models/double.rb +1 -1
- data/lib/rest-assured/routes/response.rb +21 -11
- data/lib/rest-assured/utils/subprocess.rb +1 -10
- data/lib/rest-assured/version.rb +1 -1
- data/rest-assured.gemspec +3 -4
- data/spec/functional/response_spec.rb +13 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/subprocess_spec.rb +1 -29
- metadata +18 -30
- data/lib/active_record/leaky_connections_patch.rb +0 -55
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -27,8 +27,8 @@ It is also recommended to have thin installed. This improves startup time (over
|
|
27
27
|
|
28
28
|
Then install gem and run:
|
29
29
|
|
30
|
-
bash$ gem install rest-assured
|
31
|
-
bash$ rest-assured
|
30
|
+
bash$ gem install rest-assured
|
31
|
+
bash$ rest-assured &
|
32
32
|
|
33
33
|
Or clone from github and run:
|
34
34
|
|
@@ -40,8 +40,6 @@ This starts up an instance of rest-assured on port 4578. It is accessible via RE
|
|
40
40
|
|
41
41
|
Various options (such as ssl, port, db credentials, etc.) are available through command line options. Check out `rest-assured -h` to see what they are.
|
42
42
|
|
43
|
-
NOTE that although sqlite is an extremely handy option (especially with `-d :memory:`), I found it sometimes locking tables under non-trivial load. Hence there is a Plan B - mysql. But may be that is just me sqliting it wrong.
|
44
|
-
|
45
43
|
## Doubles
|
46
44
|
|
47
45
|
Double is a stub/spy of HTTP request. Create a double that has the same request fullpath and method as the one your app is sending to a dependant service and then convience your app that rest-assured is that dependency (hint: by making endpoints configurable).
|
@@ -171,7 +169,7 @@ For those using rest-assured from non-ruby environments.
|
|
171
169
|
|
172
170
|
It is sometimes desirable to only double certain calls while letting others through to the "real" services. Meet Redirects. Kind of "rewrite rules" for requests that didn't match any double.
|
173
171
|
|
174
|
-
Another
|
172
|
+
Another use for redirects is setting up a "default" double that matches multiple fullpaths. If a redirect pattern matches a defined double then it will act like a double and respond directly. If it does not match a double then it will return HTTP 303 redirect instead. Note that HTTP redirects are usually converted to GET requests by HTTP clients.
|
175
173
|
|
176
174
|
Here is the rest API for managing redirects:
|
177
175
|
|
@@ -200,7 +198,11 @@ Here is the rest API for managing redirects:
|
|
200
198
|
|
201
199
|
## Changelog
|
202
200
|
|
203
|
-
#### 1.
|
201
|
+
#### 1.1.0 (17 Feb 2012)
|
202
|
+
|
203
|
+
* Redirects supports 'real' (without http redirect) rewrite to local double
|
204
|
+
|
205
|
+
#### 1.0.0 (14 Feb 2012)
|
204
206
|
|
205
207
|
* start/stop rest-assured via api
|
206
208
|
* redirects support pattern/replacement
|
@@ -211,8 +213,7 @@ Here is the rest API for managing redirects:
|
|
211
213
|
|
212
214
|
#### 0.3.1 (09 Jan 2012)
|
213
215
|
|
214
|
-
* lock rack version to <= 1.3.6 until they release fix for
|
215
|
-
https://github.com/rack/rack/issues/299
|
216
|
+
* lock rack version to <= 1.3.6 until they release fix for https://github.com/rack/rack/issues/299
|
216
217
|
|
217
218
|
#### 0.3 (12 Dec 2011)
|
218
219
|
|
@@ -15,6 +15,7 @@ Feature: use doubles via api
|
|
15
15
|
| /api/some | text content | GET | GET | 303 | 303 |
|
16
16
|
| /api/some?a=3&b=dd | more content | | GET | | 200 |
|
17
17
|
| /api/empty | | POST | POST | | 200 |
|
18
|
+
| /api/file | | HEAD | HEAD | | 200 |
|
18
19
|
|
19
20
|
Scenario: view created double details
|
20
21
|
When I create a double
|
@@ -55,7 +55,7 @@ Then /^it should wait for (#{CAPTURE_A_NUMBER}) seconds(?: \(default timeout\))?
|
|
55
55
|
wait_time = Time.now - @wait_start
|
56
56
|
#(timeout..(timeout+1)).should cover(wait_time) # cover() only avilable in 1.9
|
57
57
|
wait_time.should >= timeout
|
58
|
-
wait_time.should < timeout + 1
|
58
|
+
wait_time.should < timeout + 1.5
|
59
59
|
end
|
60
60
|
|
61
61
|
Then /^it should raise MoreRequestsExpected error after with the following message:$/ do |string|
|
@@ -1,23 +1,33 @@
|
|
1
1
|
module RestAssured
|
2
2
|
class Response
|
3
|
+
|
3
4
|
def self.perform(app)
|
4
5
|
request = app.request
|
5
|
-
|
6
6
|
if d = Models::Double.where(:fullpath => request.fullpath, :active => true, :verb => request.request_method).first
|
7
|
-
|
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
|
-
|
11
|
-
d.requests.create!(:rack_env => env.to_json, :body => body, :params => request.params.to_json)
|
12
|
-
|
13
|
-
app.headers d.response_headers
|
14
|
-
app.body d.content
|
15
|
-
app.status d.status
|
7
|
+
return_double app, d
|
16
8
|
elsif redirect_url = Models::Redirect.find_redirect_url_for(request.fullpath)
|
17
|
-
|
9
|
+
if d = Models::Double.where(:fullpath => redirect_url, :active => true, :verb => request.request_method).first
|
10
|
+
return_double app, d
|
11
|
+
else
|
12
|
+
app.redirect redirect_url
|
13
|
+
end
|
18
14
|
else
|
19
15
|
app.status 404
|
20
16
|
end
|
21
17
|
end
|
18
|
+
|
19
|
+
def self.return_double(app, d)
|
20
|
+
request = app.request
|
21
|
+
request.body.rewind
|
22
|
+
body = request.body.read #without temp variable ':body = > body' is always nil. mistery
|
23
|
+
env = request.env.except('rack.input', 'rack.errors', 'rack.logger')
|
24
|
+
|
25
|
+
d.requests.create!(:rack_env => env.to_json, :body => body, :params => request.params.to_json)
|
26
|
+
|
27
|
+
app.headers d.response_headers
|
28
|
+
app.body d.content
|
29
|
+
app.status d.status
|
30
|
+
end
|
31
|
+
|
22
32
|
end
|
23
33
|
end
|
@@ -6,19 +6,10 @@ module RestAssured
|
|
6
6
|
def initialize
|
7
7
|
@pid = Kernel.fork do
|
8
8
|
trap('USR1') do
|
9
|
-
$stopped = true
|
10
9
|
Process.kill('TERM', Process.pid) # unlike 'exit' this one is NOT being intercepted by Webrick
|
11
10
|
end
|
12
11
|
|
13
|
-
at_exit
|
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
|
12
|
+
at_exit { exit! }
|
22
13
|
|
23
14
|
begin
|
24
15
|
yield
|
data/lib/rest-assured/version.rb
CHANGED
data/rest-assured.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ['Artem Avetisyan']
|
10
10
|
s.email = ['artem.avetisyan@bbc.co.uk']
|
11
11
|
s.homepage = "https://github.com/BBC/rest-assured"
|
12
|
-
s.summary = %q{
|
12
|
+
s.summary = %q{Real stubs and spies for HTTP(S) services}
|
13
13
|
#s.description = %q{TODO: Write a gem description}
|
14
14
|
|
15
15
|
s.rubyforge_project = "rest-assured"
|
@@ -20,9 +20,8 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.executables = ['rest-assured']
|
21
21
|
s.require_paths = ['lib']
|
22
22
|
|
23
|
-
s.add_dependency 'sinatra', '>= 1.3.
|
24
|
-
s.add_dependency '
|
25
|
-
s.add_dependency 'childprocess', '~> 0.2.8'
|
23
|
+
s.add_dependency 'sinatra', '>= 1.3.2'
|
24
|
+
s.add_dependency 'childprocess', '~> 0.3.0'
|
26
25
|
s.add_dependency 'sinatra-flash'
|
27
26
|
s.add_dependency 'haml', '>= 3.1.3'
|
28
27
|
s.add_dependency 'activerecord', '~> 3.1.0'
|
@@ -60,6 +60,19 @@ module RestAssured
|
|
60
60
|
|
61
61
|
Response.perform(rest_assured_app)
|
62
62
|
end
|
63
|
+
|
64
|
+
it "returns double when redirect matches double" do
|
65
|
+
fullpath = '/some/other/path'
|
66
|
+
request.stub(:fullpath).and_return(fullpath)
|
67
|
+
Models::Redirect.stub(:find_redirect_url_for).with(fullpath).and_return('/some/path')
|
68
|
+
|
69
|
+
rest_assured_app.should_receive(:body).with(@double.content)
|
70
|
+
rest_assured_app.should_receive(:status).with(@double.status)
|
71
|
+
rest_assured_app.should_receive(:headers).with(@double.response_headers)
|
72
|
+
|
73
|
+
Response.perform(rest_assured_app)
|
74
|
+
end
|
75
|
+
|
63
76
|
end
|
64
77
|
|
65
78
|
it "redirects if double not hit but there is redirect that matches request" do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,17 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
|
3
|
+
if RUBY_VERSION =~ /^1.9/
|
4
|
+
begin
|
5
|
+
require 'simplecov'
|
6
|
+
SimpleCov.start do
|
7
|
+
at_exit {} # reset built in at_exit or else it gets triggered when RestAssured::Server.stop is called from tests
|
8
|
+
add_filter "/spec/"
|
9
|
+
add_filter "/sinatra/"
|
10
|
+
end
|
11
|
+
rescue LoadError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
2
15
|
require 'spork'
|
3
16
|
|
4
17
|
$:.unshift(File.expand_path('../../lib'), __FILE__)
|
@@ -44,6 +57,12 @@ Spork.prefork do
|
|
44
57
|
c.before(:each, :ui => false) do
|
45
58
|
header 'User-Agent', nil
|
46
59
|
end
|
60
|
+
|
61
|
+
if defined?(SimpleCov)
|
62
|
+
c.after(:suite) do
|
63
|
+
SimpleCov.result.format!
|
64
|
+
end
|
65
|
+
end
|
47
66
|
end
|
48
67
|
require 'rest-assured/config'
|
49
68
|
db_opts = { :dbuser => ENV['TRAVIS'] ? "''" : "root", :adapter => 'mysql' }
|
data/spec/subprocess_spec.rb
CHANGED
@@ -43,35 +43,6 @@ module RestAssured::Utils
|
|
43
43
|
res_file.read.should == 'true'
|
44
44
|
end
|
45
45
|
|
46
|
-
# I am not sure this is actually useful
|
47
|
-
#describe 'commits seppuku' do
|
48
|
-
#it 'if child raises exception' do
|
49
|
-
#res_file = Tempfile.new('res')
|
50
|
-
#fork do
|
51
|
-
#at_exit { exit! }
|
52
|
-
#Subprocess.new { raise "!!NO PANIC!! This exception is part of test"; sleep 1 }
|
53
|
-
#sleep 0.5
|
54
|
-
#res_file.write('should not exist because this process should be killed by now')
|
55
|
-
#res_file.rewind
|
56
|
-
#end
|
57
|
-
#Process.wait
|
58
|
-
#res_file.read.should == ''
|
59
|
-
#end
|
60
|
-
|
61
|
-
#it 'if child just quits' do
|
62
|
-
#res_file = Tempfile.new('res')
|
63
|
-
#fork do
|
64
|
-
#at_exit { exit! }
|
65
|
-
#Subprocess.new { 1 }
|
66
|
-
#sleep 0.5
|
67
|
-
#res_file.write('should not exist because this process should be killed by now')
|
68
|
-
#res_file.rewind
|
69
|
-
#end
|
70
|
-
#Process.wait
|
71
|
-
#res_file.read.should == ''
|
72
|
-
#end
|
73
|
-
#end
|
74
|
-
|
75
46
|
context 'shuts down child process' do
|
76
47
|
let(:child_pid) do
|
77
48
|
Tempfile.new('child_pid')
|
@@ -97,6 +68,7 @@ module RestAssured::Utils
|
|
97
68
|
res_file.rewind
|
98
69
|
end
|
99
70
|
Process.wait
|
71
|
+
sleep 0.5
|
100
72
|
res_file.read.should == 'false'
|
101
73
|
end
|
102
74
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-assured
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,44 +9,33 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|
16
|
-
requirement: &
|
16
|
+
requirement: &2168491020 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.3.
|
21
|
+
version: 1.3.2
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: rack
|
27
|
-
requirement: &2154191300 !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
29
|
-
requirements:
|
30
|
-
- - <=
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 1.3.6
|
33
|
-
type: :runtime
|
34
|
-
prerelease: false
|
35
|
-
version_requirements: *2154191300
|
24
|
+
version_requirements: *2168491020
|
36
25
|
- !ruby/object:Gem::Dependency
|
37
26
|
name: childprocess
|
38
|
-
requirement: &
|
27
|
+
requirement: &2168528060 !ruby/object:Gem::Requirement
|
39
28
|
none: false
|
40
29
|
requirements:
|
41
30
|
- - ~>
|
42
31
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0.
|
32
|
+
version: 0.3.0
|
44
33
|
type: :runtime
|
45
34
|
prerelease: false
|
46
|
-
version_requirements: *
|
35
|
+
version_requirements: *2168528060
|
47
36
|
- !ruby/object:Gem::Dependency
|
48
37
|
name: sinatra-flash
|
49
|
-
requirement: &
|
38
|
+
requirement: &2168523560 !ruby/object:Gem::Requirement
|
50
39
|
none: false
|
51
40
|
requirements:
|
52
41
|
- - ! '>='
|
@@ -54,10 +43,10 @@ dependencies:
|
|
54
43
|
version: '0'
|
55
44
|
type: :runtime
|
56
45
|
prerelease: false
|
57
|
-
version_requirements: *
|
46
|
+
version_requirements: *2168523560
|
58
47
|
- !ruby/object:Gem::Dependency
|
59
48
|
name: haml
|
60
|
-
requirement: &
|
49
|
+
requirement: &2168565440 !ruby/object:Gem::Requirement
|
61
50
|
none: false
|
62
51
|
requirements:
|
63
52
|
- - ! '>='
|
@@ -65,10 +54,10 @@ dependencies:
|
|
65
54
|
version: 3.1.3
|
66
55
|
type: :runtime
|
67
56
|
prerelease: false
|
68
|
-
version_requirements: *
|
57
|
+
version_requirements: *2168565440
|
69
58
|
- !ruby/object:Gem::Dependency
|
70
59
|
name: activerecord
|
71
|
-
requirement: &
|
60
|
+
requirement: &2168564340 !ruby/object:Gem::Requirement
|
72
61
|
none: false
|
73
62
|
requirements:
|
74
63
|
- - ~>
|
@@ -76,10 +65,10 @@ dependencies:
|
|
76
65
|
version: 3.1.0
|
77
66
|
type: :runtime
|
78
67
|
prerelease: false
|
79
|
-
version_requirements: *
|
68
|
+
version_requirements: *2168564340
|
80
69
|
- !ruby/object:Gem::Dependency
|
81
70
|
name: activeresource
|
82
|
-
requirement: &
|
71
|
+
requirement: &2168563340 !ruby/object:Gem::Requirement
|
83
72
|
none: false
|
84
73
|
requirements:
|
85
74
|
- - ~>
|
@@ -87,7 +76,7 @@ dependencies:
|
|
87
76
|
version: 3.1.0
|
88
77
|
type: :runtime
|
89
78
|
prerelease: false
|
90
|
-
version_requirements: *
|
79
|
+
version_requirements: *2168563340
|
91
80
|
description:
|
92
81
|
email:
|
93
82
|
- artem.avetisyan@bbc.co.uk
|
@@ -137,7 +126,6 @@ files:
|
|
137
126
|
- features/support/world_helpers.rb
|
138
127
|
- features/web_ui/doubles.feature
|
139
128
|
- features/web_ui/redirects.feature
|
140
|
-
- lib/active_record/leaky_connections_patch.rb
|
141
129
|
- lib/rest-assured.rb
|
142
130
|
- lib/rest-assured/api.rb
|
143
131
|
- lib/rest-assured/api/app_runner.rb
|
@@ -223,13 +211,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
223
211
|
version: '0'
|
224
212
|
segments:
|
225
213
|
- 0
|
226
|
-
hash:
|
214
|
+
hash: 1944321672567783063
|
227
215
|
requirements: []
|
228
216
|
rubyforge_project: rest-assured
|
229
217
|
rubygems_version: 1.8.10
|
230
218
|
signing_key:
|
231
219
|
specification_version: 3
|
232
|
-
summary:
|
220
|
+
summary: Real stubs and spies for HTTP(S) services
|
233
221
|
test_files:
|
234
222
|
- features/command_line_options.feature
|
235
223
|
- features/rest_api/doubles.feature
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# fix leaking db connections https://github.com/rails/rails/commit/ea341b8e043160a7ddaba9e6b2bb6044f73c31a8
|
2
|
-
# TODO remove with the next ActiveRecord update as this patch will be there
|
3
|
-
module ActiveRecord
|
4
|
-
class ConnectionAdapters::ConnectionPool
|
5
|
-
def current_connection_id #:nodoc:
|
6
|
-
ActiveRecord::Base.connection_id ||= Thread.current.object_id
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
class Base::ConnectionSpecification
|
11
|
-
class << self
|
12
|
-
def connection_id
|
13
|
-
Thread.current['ActiveRecord::Base.connection_id']
|
14
|
-
end
|
15
|
-
|
16
|
-
def connection_id=(connection_id)
|
17
|
-
Thread.current['ActiveRecord::Base.connection_id'] = connection_id
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class QueryCache
|
23
|
-
class BodyProxy
|
24
|
-
def initialize(original_cache_value, target, connection_id)
|
25
|
-
@original_cache_value = original_cache_value
|
26
|
-
@target = target
|
27
|
-
@connection_id = connection_id
|
28
|
-
end
|
29
|
-
|
30
|
-
def close
|
31
|
-
@target.close if @target.respond_to?(:close)
|
32
|
-
ensure
|
33
|
-
ActiveRecord::Base.connection_id = @connection_id
|
34
|
-
ActiveRecord::Base.connection.clear_query_cache
|
35
|
-
unless @original_cache_value
|
36
|
-
ActiveRecord::Base.connection.disable_query_cache!
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def call(env)
|
42
|
-
old = ActiveRecord::Base.connection.query_cache_enabled
|
43
|
-
ActiveRecord::Base.connection.enable_query_cache!
|
44
|
-
|
45
|
-
status, headers, body = @app.call(env)
|
46
|
-
[status, headers, BodyProxy.new(old, body, ActiveRecord::Base.connection_id)]
|
47
|
-
rescue Exception => e
|
48
|
-
ActiveRecord::Base.connection.clear_query_cache
|
49
|
-
unless old
|
50
|
-
ActiveRecord::Base.connection.disable_query_cache!
|
51
|
-
end
|
52
|
-
raise e
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|