rest-assured 0.1.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.
- data/.gitignore +7 -0
- data/Gemfile +17 -0
- data/LICENSE +22 -0
- data/README.markdown +78 -0
- data/Rakefile +4 -0
- data/bin/console +12 -0
- data/bin/rest-assured +28 -0
- data/cucumber.yml +3 -0
- data/db/migrate/20110620161740_add_fixtures.rb +12 -0
- data/db/migrate/20110625155332_add_redirects_table.rb +12 -0
- data/db/migrate/20110709150645_add_description_to_fixtures.rb +9 -0
- data/db/migrate/20110807222522_add_active_bit_to_fixtures.rb +9 -0
- data/db/migrate/20110818155555_add_position_to_redirects.rb +9 -0
- data/db/migrate/20110823132023_add_method_to_fixtures.rb +9 -0
- data/db/migrate/20110912162948_rename_url_to_fullpath.rb +9 -0
- data/db/migrate/20110912163705_rename_fixtures_to_doubles.rb +9 -0
- data/features/doubles_via_api.feature +50 -0
- data/features/doubles_via_ui.feature +66 -0
- data/features/persistence.feature +24 -0
- data/features/redirect_rules_via_api.feature +29 -0
- data/features/redirect_rules_via_ui.feature +68 -0
- data/features/step_definitions/doubles_steps.rb +143 -0
- data/features/step_definitions/persistence_steps.rb +13 -0
- data/features/step_definitions/redirect_rules_steps.rb +64 -0
- data/features/step_definitions/support/numeric_transforms.rb +3 -0
- data/features/support/env.rb +71 -0
- data/lib/rest-assured.rb +66 -0
- data/lib/rest-assured/config.rb +11 -0
- data/lib/rest-assured/init.rb +12 -0
- data/lib/rest-assured/models/double.rb +30 -0
- data/lib/rest-assured/models/redirect.rb +37 -0
- data/lib/rest-assured/routes/double.rb +77 -0
- data/lib/rest-assured/routes/redirect.rb +71 -0
- data/lib/rest-assured/version.rb +3 -0
- data/lib/sinatra/partials.rb +18 -0
- data/public/css/grid.inuit.css +76 -0
- data/public/css/inuit.css +904 -0
- data/public/css/jquery.jgrowl.css +132 -0
- data/public/css/style.css +88 -0
- data/public/img/css/12-grid-720.png +0 -0
- data/public/img/css/12-grid.png +0 -0
- data/public/img/css/baseline.gif +0 -0
- data/public/img/css/grid-720.png +0 -0
- data/public/img/css/grid.png +0 -0
- data/public/img/css/icons/error.png +0 -0
- data/public/img/css/icons/info.png +0 -0
- data/public/img/css/icons/success.png +0 -0
- data/public/img/css/icons/warning.png +0 -0
- data/public/javascript/application.js +12 -0
- data/public/javascript/jquery.jgrowl_minimized.js +11 -0
- data/rest-assured.gemspec +36 -0
- data/spec/functional/double_routes_spec.rb +117 -0
- data/spec/functional/redirect_routes_spec.rb +108 -0
- data/spec/models/double_spec.rb +73 -0
- data/spec/models/redirect_spec.rb +38 -0
- data/spec/spec_helper.rb +47 -0
- data/views/base.scss +11 -0
- data/views/doubles/_form.haml +16 -0
- data/views/doubles/edit.haml +4 -0
- data/views/doubles/index.haml +41 -0
- data/views/doubles/new.haml +3 -0
- data/views/layout.haml +25 -0
- data/views/redirects/_form.haml +11 -0
- data/views/redirects/edit.haml +4 -0
- data/views/redirects/index.haml +33 -0
- data/views/redirects/new.haml +3 -0
- metadata +250 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
@ui
|
2
|
+
Feature: manage redirects via ui
|
3
|
+
In order to set up 'pass through' for requests that don't match any double
|
4
|
+
As a developer
|
5
|
+
I want to have a ui to set up redirects
|
6
|
+
|
7
|
+
Scenario: view existing redirects
|
8
|
+
Given the following redirects exist:
|
9
|
+
| pattern | to |
|
10
|
+
| /url1/.* | http://google.com/api |
|
11
|
+
| /url2/bbb | http://twitter.com/api |
|
12
|
+
When I visit "redirects" page
|
13
|
+
Then I should see that I am on "redirects" page
|
14
|
+
And I should see existing redirects:
|
15
|
+
| pattern | to |
|
16
|
+
| /url1/.* | http://google.com/api |
|
17
|
+
| /url2/bbb | http://twitter.com/api |
|
18
|
+
|
19
|
+
Scenario: add new redirect
|
20
|
+
Given I visit "redirects" page
|
21
|
+
When I choose to create a redirect
|
22
|
+
And I enter redirect details:
|
23
|
+
| pattern | to |
|
24
|
+
| /url1/.* | http://google.com/api |
|
25
|
+
And I save it
|
26
|
+
Then I should see "Redirect created"
|
27
|
+
And I should see existing redirects:
|
28
|
+
| pattern | to |
|
29
|
+
| /url1/.* | http://google.com/api |
|
30
|
+
|
31
|
+
Scenario: edit redirect
|
32
|
+
Given the following redirects exist:
|
33
|
+
| pattern | to |
|
34
|
+
| /url1/.* | http://google.com/api |
|
35
|
+
And I visit "redirects" page
|
36
|
+
And I choose to edit redirect
|
37
|
+
When I change "redirect" "pattern" to "/some/remote.*"
|
38
|
+
And I save it
|
39
|
+
Then I should see that I am on "redirects" page
|
40
|
+
And I should see existing redirects:
|
41
|
+
| pattern | to |
|
42
|
+
| /some/remote.* | http://google.com/api |
|
43
|
+
|
44
|
+
# XXX This does not pass due to Capybara/Selelium broken drag and drop support
|
45
|
+
@javascript @pending
|
46
|
+
Scenario: reorder redirects
|
47
|
+
Given the following redirects exist:
|
48
|
+
| pattern | to |
|
49
|
+
| /api/.* | http://google.com/api |
|
50
|
+
| /api/bbb | http://twitter.com/api |
|
51
|
+
And I am on "redirects" page
|
52
|
+
When I reorder second redirect to be the first one
|
53
|
+
Then "/api/bbb" should be redirected to "http://twitter.com/api"
|
54
|
+
When I reorder second redirect to be the first one
|
55
|
+
Then "/api/bbb" should be redirected to "http://google.com/api"
|
56
|
+
|
57
|
+
@javascript
|
58
|
+
Scenario: delete redirect
|
59
|
+
Given the following redirects exist:
|
60
|
+
| pattern | to |
|
61
|
+
| /url1/.* | http://google.com/api |
|
62
|
+
| /url2/bbb | http://twitter.com/api |
|
63
|
+
And I visit "redirects" page
|
64
|
+
And I choose to delete redirect with pattern "/url1/.*"
|
65
|
+
Then I should be asked to confirm delete
|
66
|
+
And I should see "Redirect deleted"
|
67
|
+
And I should not see "/url1/.*"
|
68
|
+
And I should see "/url2/bbb"
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# REST api steps
|
2
|
+
|
3
|
+
Given /^there are no doubles$/ do
|
4
|
+
Double.destroy_all
|
5
|
+
end
|
6
|
+
|
7
|
+
When /^I create a double with "([^"]*)" as fullpath and "([^"]*)" as response content$/ do |fullpath, content|
|
8
|
+
post '/doubles', { :fullpath => fullpath, :content => content }
|
9
|
+
last_response.should be_ok
|
10
|
+
end
|
11
|
+
|
12
|
+
When /^I create a double with "([^"]*)" as fullpath, "([^"]*)" as response content and "([^"]*)" as request method$/ do |fullpath, content, method|
|
13
|
+
post '/doubles', { :fullpath => fullpath, :content => content, :method => method }
|
14
|
+
last_response.should be_ok
|
15
|
+
end
|
16
|
+
|
17
|
+
Then /^there should be (#{CAPTURE_A_NUMBER}) double with "([^"]*)" as fullpath and "([^"]*)" as response content$/ do |n, fullpath, content|
|
18
|
+
Double.where(:fullpath => fullpath, :content => content).count.should == 1
|
19
|
+
end
|
20
|
+
|
21
|
+
Then /^there should be (#{CAPTURE_A_NUMBER}) double with "([^"]*)" as fullpath, "([^"]*)" as response content and "([^"]*)" as request method$/ do |n, fullpath, content, method|
|
22
|
+
Double.where(:fullpath => fullpath, :content => content, :method => method).count.should == n
|
23
|
+
end
|
24
|
+
|
25
|
+
Given /^there is double with "([^"]*)" as fullpath and "([^"]*)" as response content$/ do |fullpath, content|
|
26
|
+
Double.create(:fullpath => fullpath, :content => content)
|
27
|
+
end
|
28
|
+
|
29
|
+
Given /^there is double with "([^"]*)" as fullpath, "([^"]*)" as response content and "([^"]*)" as request method$/ do |fullpath, content, method|
|
30
|
+
Double.create(:fullpath => fullpath, :content => content, :method => method)
|
31
|
+
end
|
32
|
+
|
33
|
+
Given /^I register "([^"]*)" as fullpath and "([^"]*)" as response content$/ do |fullpath, content|
|
34
|
+
post '/doubles', { :fullpath => fullpath, :content => content }
|
35
|
+
last_response.should be_ok
|
36
|
+
end
|
37
|
+
|
38
|
+
When /^I request "([^"]*)"$/ do |fullpath|
|
39
|
+
get fullpath
|
40
|
+
end
|
41
|
+
|
42
|
+
When /^I "([^"]*)" "([^"]*)"$/ do |method, fullpath|
|
43
|
+
send(method.downcase, fullpath)
|
44
|
+
end
|
45
|
+
|
46
|
+
Then /^I should get "([^"]*)" in response content$/ do |content|
|
47
|
+
last_response.body.should == content
|
48
|
+
end
|
49
|
+
|
50
|
+
Given /^there are some doubles$/ do
|
51
|
+
[['fullpath1', 'content1'], ['fullpath2', 'content2'], ['fullpath3', 'content3']].each do |double|
|
52
|
+
Double.create(:fullpath => double[0], :content => double[1])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
When /^I delete all doubles$/ do
|
57
|
+
delete '/doubles/all'
|
58
|
+
last_response.should be_ok
|
59
|
+
end
|
60
|
+
|
61
|
+
Then /^there should be no doubles$/ do
|
62
|
+
Double.count.should == 0
|
63
|
+
end
|
64
|
+
|
65
|
+
# UI steps
|
66
|
+
|
67
|
+
Given /^the following doubles exist:$/ do |doubles|
|
68
|
+
doubles.hashes.each do |row|
|
69
|
+
Double.create(:fullpath => row['fullpath'], :description => row['description'], :content => row['content'])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Then /^I should see that I am on "([^""]*)" page$/ do |name|
|
74
|
+
find('title').text.should =~ /#{name} -/
|
75
|
+
end
|
76
|
+
|
77
|
+
Then /^I should see existing doubles:$/ do |doubles|
|
78
|
+
doubles.hashes.each do |row|
|
79
|
+
page.should have_content(row[:fullpath])
|
80
|
+
page.should have_content(row[:description])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
Given /^I am on "([^"]*)" page$/ do |page|
|
85
|
+
When "I visit \"#{page}\" page"
|
86
|
+
end
|
87
|
+
|
88
|
+
When /^I choose to create a double$/ do
|
89
|
+
find(:xpath, '//a[text()="New double"]').click
|
90
|
+
end
|
91
|
+
|
92
|
+
When /^I enter double details:$/ do |details|
|
93
|
+
double = details.hashes.first
|
94
|
+
|
95
|
+
fill_in 'Request fullpath', :with => double['fullpath']
|
96
|
+
fill_in 'Content', :with => double['content']
|
97
|
+
fill_in 'Description', :with => double['description']
|
98
|
+
end
|
99
|
+
|
100
|
+
When /^I save it$/ do
|
101
|
+
find('input[type="submit"]').click
|
102
|
+
end
|
103
|
+
|
104
|
+
Then /^I should (not)? ?see "([^"]*)"$/ do |see, text|
|
105
|
+
if see == 'not'
|
106
|
+
page.should_not have_content(text)
|
107
|
+
else
|
108
|
+
page.should have_content(text)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
Given /^there are two doubles for the same fullpath$/ do
|
113
|
+
@first = Double.create :fullpath => '/api/something', :content => 'some content'
|
114
|
+
@second = Double.create :fullpath => '/api/something', :content => 'other content'
|
115
|
+
end
|
116
|
+
|
117
|
+
When /^I make (first|second) double active$/ do |ord|
|
118
|
+
within "#double_row_#{instance_variable_get('@' + ord).id}" do
|
119
|
+
find('input[type="radio"]').click
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
Then /^(first|second) double should be served$/ do |ord|
|
124
|
+
f = instance_variable_get('@' + ord)
|
125
|
+
get f.fullpath
|
126
|
+
last_response.body.should == f.content
|
127
|
+
end
|
128
|
+
|
129
|
+
Given /^I choose to edit (?:double|redirect)$/ do
|
130
|
+
find('.edit-link a').click
|
131
|
+
end
|
132
|
+
|
133
|
+
When /^I change "([^"]*)" "([^"]*)" to "([^"]*)"$/ do |obj, prop, value|
|
134
|
+
fill_in "#{obj}_#{prop}", :with => value
|
135
|
+
end
|
136
|
+
|
137
|
+
Given /^I choose to delete double with fullpath "([^"]*)"$/ do |fullpath|
|
138
|
+
find(:xpath, "//tr[td[text()='#{fullpath}']]//a[text()='Delete']").click
|
139
|
+
end
|
140
|
+
|
141
|
+
Then /^I should be asked to confirm delete$/ do
|
142
|
+
page.driver.browser.switch_to.alert.accept
|
143
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Given /^I (?:re)?start service without \-\-database option$/ do
|
2
|
+
AppConfig[:database] = ':memory:' #default value
|
3
|
+
load 'rest-assured/init.rb'
|
4
|
+
end
|
5
|
+
|
6
|
+
Then /^I should get (#{CAPTURE_A_NUMBER}) in response status$/ do |status|
|
7
|
+
last_response.status.should == status
|
8
|
+
end
|
9
|
+
|
10
|
+
Given /^I (?:re)?start service with \-\-database "([^"]*)" option$/ do |db_path|
|
11
|
+
AppConfig[:database] = db_path
|
12
|
+
load 'rest-assured/init.rb'
|
13
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
Given /^there are no redirect rules$/ do
|
2
|
+
Redirect.destroy_all
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^I should get (\d+)$/ do |code|
|
6
|
+
last_response.status.should.to_s == code
|
7
|
+
end
|
8
|
+
|
9
|
+
When /^I register redirect with pattern "([^"]*)" and uri "([^"]*)"$/ do |pattern, uri|
|
10
|
+
post '/redirects', { :pattern => pattern, :to => uri }
|
11
|
+
last_response.should be_ok
|
12
|
+
end
|
13
|
+
|
14
|
+
Then /^it should redirect to "([^"]*)"$/ do |real_api_url|
|
15
|
+
follow_redirect!
|
16
|
+
last_response.header['Location'].should == real_api_url
|
17
|
+
end
|
18
|
+
|
19
|
+
Given /^the following redirects exist:$/ do |redirects|
|
20
|
+
redirects.hashes.each do |row|
|
21
|
+
Redirect.create(:pattern => row['pattern'], :to => row['to'])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
When /^I visit "([^"]+)" page$/ do |page|
|
26
|
+
visit '/'
|
27
|
+
find(:xpath, "//a[text()='#{page.capitalize}']").click
|
28
|
+
end
|
29
|
+
|
30
|
+
When /^I choose to create a redirect$/ do
|
31
|
+
find(:xpath, '//a[text()="New redirect"]').click
|
32
|
+
end
|
33
|
+
|
34
|
+
When /^I enter redirect details:$/ do |details|
|
35
|
+
redirect = details.hashes.first
|
36
|
+
|
37
|
+
fill_in 'Pattern', :with => redirect['pattern']
|
38
|
+
fill_in 'Redirect to', :with => redirect['to']
|
39
|
+
end
|
40
|
+
|
41
|
+
Then /^I should see existing redirects:$/ do |redirects|
|
42
|
+
redirects.hashes.each do |row|
|
43
|
+
page.should have_content(row[:pattern])
|
44
|
+
page.should have_content(row[:to])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Given /^I choose to delete redirect with pattern "([^"]*)"$/ do |pattern|
|
49
|
+
find(:xpath, "//tr[td[text()='#{pattern}']]//a[text()='Delete']").click
|
50
|
+
end
|
51
|
+
|
52
|
+
When /^I reorder second redirect to be the first one$/ do
|
53
|
+
handler = find("#redirects #redirect_#{Redirect.last.id} td.handle")
|
54
|
+
target = find('#redirects thead')
|
55
|
+
|
56
|
+
handler.drag_to target
|
57
|
+
end
|
58
|
+
|
59
|
+
Then /^"([^"]*)" should be redirected to "([^"]*)"$/ do |missing_request, url|
|
60
|
+
get missing_request
|
61
|
+
follow_redirect!
|
62
|
+
|
63
|
+
last_request.url.should == "#{url}#{missing_request}"
|
64
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
$:.push File.expand_path('../../../lib', __FILE__)
|
2
|
+
require 'rspec/expectations'
|
3
|
+
require 'rack/test'
|
4
|
+
require 'capybara'
|
5
|
+
require 'capybara/firebug'
|
6
|
+
require 'capybara/cucumber'
|
7
|
+
require 'database_cleaner'
|
8
|
+
require 'logger'
|
9
|
+
|
10
|
+
ENV['RACK_ENV'] = 'test'
|
11
|
+
|
12
|
+
require 'rest-assured'
|
13
|
+
|
14
|
+
module RackHeaderHack
|
15
|
+
def set_headers(headers)
|
16
|
+
browser = page.driver.browser
|
17
|
+
def browser.env
|
18
|
+
@env.merge(super)
|
19
|
+
end
|
20
|
+
def browser.env=(env)
|
21
|
+
@env = env
|
22
|
+
end
|
23
|
+
browser.env = headers
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup_logger
|
28
|
+
Logger.class_eval do
|
29
|
+
alias_method :write, :<<
|
30
|
+
end
|
31
|
+
|
32
|
+
logger = Logger.new(File.expand_path("../../../test.log", __FILE__))
|
33
|
+
logger.level = Logger::DEBUG
|
34
|
+
|
35
|
+
RestAssured::Application.class_eval do
|
36
|
+
use Rack::CommonLogger, logger
|
37
|
+
end
|
38
|
+
|
39
|
+
ActiveRecord::Base.logger = logger
|
40
|
+
end
|
41
|
+
|
42
|
+
setup_logger
|
43
|
+
|
44
|
+
def app
|
45
|
+
RestAssured::Application
|
46
|
+
end
|
47
|
+
Capybara.app = app
|
48
|
+
|
49
|
+
Capybara.register_driver :selenium do |app|
|
50
|
+
profile = Selenium::WebDriver::Firefox::Profile.new
|
51
|
+
profile.enable_firebug
|
52
|
+
|
53
|
+
Capybara::Selenium::Driver.new(app, :browser => :firefox, :profile => profile)
|
54
|
+
end
|
55
|
+
|
56
|
+
World(Capybara, Rack::Test::Methods, RackHeaderHack)
|
57
|
+
|
58
|
+
DatabaseCleaner.strategy = :truncation
|
59
|
+
|
60
|
+
Before do
|
61
|
+
DatabaseCleaner.start
|
62
|
+
end
|
63
|
+
|
64
|
+
Before "@ui" do
|
65
|
+
set_headers "HTTP_USER_AGENT" => 'Firefox'
|
66
|
+
end
|
67
|
+
|
68
|
+
After do
|
69
|
+
DatabaseCleaner.clean
|
70
|
+
end
|
71
|
+
|
data/lib/rest-assured.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'haml'
|
4
|
+
require 'sass'
|
5
|
+
require 'sinatra/static_assets'
|
6
|
+
#require 'sinatra/reloader'
|
7
|
+
require 'rack-flash'
|
8
|
+
require 'sinatra/partials'
|
9
|
+
require 'rest-assured/init'
|
10
|
+
require 'rest-assured/models/double'
|
11
|
+
require 'rest-assured/models/redirect'
|
12
|
+
require 'rest-assured/routes/double'
|
13
|
+
require 'rest-assured/routes/redirect'
|
14
|
+
|
15
|
+
module RestAssured
|
16
|
+
class Application < Sinatra::Base
|
17
|
+
set :environment, AppConfig[:environment]
|
18
|
+
set :port, AppConfig[:port]
|
19
|
+
|
20
|
+
enable :method_override
|
21
|
+
|
22
|
+
enable :logging
|
23
|
+
|
24
|
+
enable :sessions
|
25
|
+
use Rack::Flash, :sweep => true
|
26
|
+
|
27
|
+
set :public, File.expand_path('../../public', __FILE__)
|
28
|
+
set :views, File.expand_path('../../views', __FILE__)
|
29
|
+
set :haml, :format => :html5
|
30
|
+
|
31
|
+
helpers Sinatra::Partials
|
32
|
+
register Sinatra::StaticAssets
|
33
|
+
|
34
|
+
helpers do
|
35
|
+
def browser?
|
36
|
+
request.user_agent =~ /Safari|Firefox|Opera|MSIE|Chrome/
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
include DoubleRoutes
|
41
|
+
include RedirectRoutes
|
42
|
+
|
43
|
+
get '/css/base.css' do
|
44
|
+
scss :base
|
45
|
+
end
|
46
|
+
|
47
|
+
%w{get post put delete}.each do |method|
|
48
|
+
send method, /.*/ do
|
49
|
+
Double.where(:fullpath => request.fullpath, :active => true, :method => method.upcase).first.try(:content) or try_redirect(request) or status 404
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#configure(:development) do
|
54
|
+
#register Sinatra::Reloader
|
55
|
+
#end
|
56
|
+
|
57
|
+
private
|
58
|
+
def try_redirect(request)
|
59
|
+
r = Redirect.ordered.find do |r|
|
60
|
+
request.fullpath =~ /#{r.pattern}/
|
61
|
+
end
|
62
|
+
|
63
|
+
r && redirect( "#{r.to}#{request.fullpath}" )
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
AppConfig = {
|
2
|
+
:port => 4578,
|
3
|
+
:environment => ENV['RACK_ENV'] || 'production'
|
4
|
+
}
|
5
|
+
|
6
|
+
AppConfig[:database] = case AppConfig[:environment]
|
7
|
+
when 'production'
|
8
|
+
'./rest-assured.db'
|
9
|
+
else
|
10
|
+
File.expand_path("../../../db/#{AppConfig[:environment]}.db", __FILE__)
|
11
|
+
end
|