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.
Files changed (67) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +17 -0
  3. data/LICENSE +22 -0
  4. data/README.markdown +78 -0
  5. data/Rakefile +4 -0
  6. data/bin/console +12 -0
  7. data/bin/rest-assured +28 -0
  8. data/cucumber.yml +3 -0
  9. data/db/migrate/20110620161740_add_fixtures.rb +12 -0
  10. data/db/migrate/20110625155332_add_redirects_table.rb +12 -0
  11. data/db/migrate/20110709150645_add_description_to_fixtures.rb +9 -0
  12. data/db/migrate/20110807222522_add_active_bit_to_fixtures.rb +9 -0
  13. data/db/migrate/20110818155555_add_position_to_redirects.rb +9 -0
  14. data/db/migrate/20110823132023_add_method_to_fixtures.rb +9 -0
  15. data/db/migrate/20110912162948_rename_url_to_fullpath.rb +9 -0
  16. data/db/migrate/20110912163705_rename_fixtures_to_doubles.rb +9 -0
  17. data/features/doubles_via_api.feature +50 -0
  18. data/features/doubles_via_ui.feature +66 -0
  19. data/features/persistence.feature +24 -0
  20. data/features/redirect_rules_via_api.feature +29 -0
  21. data/features/redirect_rules_via_ui.feature +68 -0
  22. data/features/step_definitions/doubles_steps.rb +143 -0
  23. data/features/step_definitions/persistence_steps.rb +13 -0
  24. data/features/step_definitions/redirect_rules_steps.rb +64 -0
  25. data/features/step_definitions/support/numeric_transforms.rb +3 -0
  26. data/features/support/env.rb +71 -0
  27. data/lib/rest-assured.rb +66 -0
  28. data/lib/rest-assured/config.rb +11 -0
  29. data/lib/rest-assured/init.rb +12 -0
  30. data/lib/rest-assured/models/double.rb +30 -0
  31. data/lib/rest-assured/models/redirect.rb +37 -0
  32. data/lib/rest-assured/routes/double.rb +77 -0
  33. data/lib/rest-assured/routes/redirect.rb +71 -0
  34. data/lib/rest-assured/version.rb +3 -0
  35. data/lib/sinatra/partials.rb +18 -0
  36. data/public/css/grid.inuit.css +76 -0
  37. data/public/css/inuit.css +904 -0
  38. data/public/css/jquery.jgrowl.css +132 -0
  39. data/public/css/style.css +88 -0
  40. data/public/img/css/12-grid-720.png +0 -0
  41. data/public/img/css/12-grid.png +0 -0
  42. data/public/img/css/baseline.gif +0 -0
  43. data/public/img/css/grid-720.png +0 -0
  44. data/public/img/css/grid.png +0 -0
  45. data/public/img/css/icons/error.png +0 -0
  46. data/public/img/css/icons/info.png +0 -0
  47. data/public/img/css/icons/success.png +0 -0
  48. data/public/img/css/icons/warning.png +0 -0
  49. data/public/javascript/application.js +12 -0
  50. data/public/javascript/jquery.jgrowl_minimized.js +11 -0
  51. data/rest-assured.gemspec +36 -0
  52. data/spec/functional/double_routes_spec.rb +117 -0
  53. data/spec/functional/redirect_routes_spec.rb +108 -0
  54. data/spec/models/double_spec.rb +73 -0
  55. data/spec/models/redirect_spec.rb +38 -0
  56. data/spec/spec_helper.rb +47 -0
  57. data/views/base.scss +11 -0
  58. data/views/doubles/_form.haml +16 -0
  59. data/views/doubles/edit.haml +4 -0
  60. data/views/doubles/index.haml +41 -0
  61. data/views/doubles/new.haml +3 -0
  62. data/views/layout.haml +25 -0
  63. data/views/redirects/_form.haml +11 -0
  64. data/views/redirects/edit.haml +4 -0
  65. data/views/redirects/index.haml +33 -0
  66. data/views/redirects/new.haml +3 -0
  67. 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,3 @@
1
+ CAPTURE_A_NUMBER = Transform /^\d+$/ do |n|
2
+ n.to_i
3
+ 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
+
@@ -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