rest-assured 0.2.0.rc8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/Gemfile.lock +2 -2
  2. data/LICENSE +4 -19
  3. data/README.markdown +123 -36
  4. data/bin/console +1 -2
  5. data/bin/rest-assured +12 -0
  6. data/features/command_line_options.feature +20 -1
  7. data/features/{doubles_via_api.feature → rest_api/doubles.feature} +0 -0
  8. data/features/{redirect_rules_via_api.feature → rest_api/redirects.feature} +11 -8
  9. data/features/{call_history.feature → ruby_api/verify_requests.feature} +0 -0
  10. data/features/ruby_api/wait_for_requests.feature +39 -0
  11. data/features/step_definitions/command_line_options_steps.rb +12 -0
  12. data/features/step_definitions/doubles_steps.rb +10 -10
  13. data/features/step_definitions/redirect_rules_steps.rb +24 -5
  14. data/features/step_definitions/ruby_api_steps.rb +69 -0
  15. data/features/support/env.rb +3 -1
  16. data/features/{doubles_via_ui.feature → web_ui/doubles.feature} +0 -0
  17. data/features/{redirect_rules_via_ui.feature → web_ui/redirects.feature} +0 -0
  18. data/lib/rest-assured.rb +2 -1
  19. data/lib/rest-assured/client/resources.rb +12 -2
  20. data/lib/rest-assured/config.rb +24 -0
  21. data/lib/rest-assured/models/double.rb +32 -28
  22. data/lib/rest-assured/models/redirect.rb +28 -24
  23. data/lib/rest-assured/models/request.rb +11 -7
  24. data/lib/rest-assured/routes/double.rb +8 -8
  25. data/lib/rest-assured/routes/redirect.rb +8 -8
  26. data/lib/rest-assured/routes/response.rb +16 -14
  27. data/lib/rest-assured/version.rb +1 -1
  28. data/lib/sinatra/handler_options_patch.rb +25 -0
  29. data/spec/client/resource_double_spec.rb +42 -6
  30. data/spec/config_spec.rb +35 -0
  31. data/spec/functional/double_routes_spec.rb +109 -107
  32. data/spec/functional/redirect_routes_spec.rb +86 -75
  33. data/spec/functional/response_spec.rb +57 -55
  34. data/spec/models/double_spec.rb +67 -65
  35. data/spec/models/redirect_spec.rb +28 -26
  36. data/spec/models/request_spec.rb +10 -8
  37. data/ssl/localhost.crt +14 -0
  38. data/ssl/localhost.key +15 -0
  39. metadata +25 -24
  40. data/features/step_definitions/call_history_steps.rb +0 -24
@@ -1,16 +1,20 @@
1
1
  Given /^there are no redirect rules$/ do
2
- Redirect.destroy_all
2
+ RestAssured::Models::Redirect.destroy_all
3
3
  end
4
4
 
5
5
  Then /^I should get (\d+)$/ do |code|
6
6
  last_response.status.should.to_s == code
7
7
  end
8
8
 
9
- When /^I register redirect with pattern "([^"]*)" and uri "([^"]*)"$/ do |pattern, uri|
10
- post '/redirects', { :pattern => pattern, :to => uri }
9
+ Given /^there is redirect with pattern "([^"]*)" and uri "([^"]*)"$/ do |pattern, url|
10
+ post '/redirects', { :pattern => pattern, :to => url }
11
11
  last_response.should be_ok
12
12
  end
13
13
 
14
+ When /^I register redirect with pattern "([^"]*)" and uri "([^"]*)"$/ do |pattern, url|
15
+ Given %{there is redirect with pattern "#{pattern}" and uri "#{url}"}
16
+ end
17
+
14
18
  Then /^it should redirect to "([^"]*)"$/ do |real_api_url|
15
19
  follow_redirect!
16
20
  last_response.header['Location'].should == real_api_url
@@ -18,7 +22,7 @@ end
18
22
 
19
23
  Given /^the following redirects exist:$/ do |redirects|
20
24
  redirects.hashes.each do |row|
21
- Redirect.create(:pattern => row['pattern'], :to => row['to'])
25
+ RestAssured::Models::Redirect.create(:pattern => row['pattern'], :to => row['to'])
22
26
  end
23
27
  end
24
28
 
@@ -50,7 +54,7 @@ Given /^I choose to delete redirect with pattern "([^"]*)"$/ do |pattern|
50
54
  end
51
55
 
52
56
  When /^I reorder second redirect to be the first one$/ do
53
- handler = find("#redirects #redirect_#{Redirect.last.id} td.handle")
57
+ handler = find("#redirects #redirect_#{RestAssured::Models::Redirect.last.id} td.handle")
54
58
  target = find('#redirects thead')
55
59
 
56
60
  handler.drag_to target
@@ -64,3 +68,18 @@ Then /^"([^"]*)" should be redirected to "([^"]*)"$/ do |missing_request, url|
64
68
 
65
69
  last_request.url.should == "#{url}#{missing_request}"
66
70
  end
71
+
72
+ Given /^blank slate$/ do
73
+ end
74
+
75
+ Given /^there are some redirects$/ do
76
+ RestAssured::Models::Redirect.create(:pattern => 'something', :to => 'somewhere')
77
+ end
78
+
79
+ When /^I delete all redirects$/ do
80
+ delete '/redirects/all'
81
+ end
82
+
83
+ Then /^there should be no redirects$/ do
84
+ RestAssured::Models::Redirect.count.should == 0
85
+ end
@@ -0,0 +1,69 @@
1
+ Given /^there is a double$/ do
2
+ @double = RestAssured::Double.create(:fullpath => '/some/path', :content => 'some content', :verb => 'POST')
3
+ end
4
+
5
+ When /^that double gets requested$/ do
6
+ post @double.fullpath, { :foo => 'bar' }.to_json, "CONTENT_TYPE" => "application/json"
7
+ post @double.fullpath, { :fooz => 'baaz'}, 'SOME_HEADER' => 'header_data'
8
+ end
9
+
10
+ When /^I request call history for that double$/ do
11
+ @requests = @double.reload.requests
12
+ end
13
+
14
+ Then /^I should see history records for those requests$/ do
15
+ @requests.first.body.should == { :foo => 'bar' }.to_json
16
+ JSON.parse( @requests.first.rack_env )["CONTENT_TYPE"].should == 'application/json'
17
+
18
+ JSON.parse( @requests.last.params ).should == { 'fooz' => 'baaz' }
19
+ JSON.parse( @requests.last.rack_env )["SOME_HEADER"].should == 'header_data'
20
+ end
21
+
22
+ Then /^it should be empty$/ do
23
+ @requests.size.should == 0
24
+ end
25
+
26
+ Given /^I created a double:$/ do |string|
27
+ # expected string is:
28
+ # @double = RestAssured::Double.create(:fullpath => '/some/api', :verb => 'POST')
29
+ eval string
30
+ end
31
+
32
+ When /^that double gets requested (#{CAPTURE_A_NUMBER}) times$/ do |num|
33
+ num.times do
34
+ sleep 0.5
35
+ send(@double.verb.downcase, @double.fullpath)
36
+ end
37
+ end
38
+
39
+ When /^I wait for (\d+) requests:$/ do |num, string|
40
+ # expected string
41
+ # @double.wait_for_requests(3)
42
+
43
+ @wait_start = Time.now
44
+ @t = Thread.new do
45
+ begin
46
+ eval string
47
+ rescue RestAssured::MoreRequestsExpected => e
48
+ @more_reqs_exc = e
49
+ end
50
+ end
51
+ end
52
+
53
+ Then /^it should let me through$/ do
54
+ @t.join
55
+ @more_reqs_exc.should == nil
56
+ end
57
+
58
+ Then /^it should wait for (#{CAPTURE_A_NUMBER}) seconds(?: \(default timeout\))?$/ do |timeout|
59
+ @t.join
60
+ wait_time = Time.now - @wait_start
61
+ #(timeout..(timeout+1)).should cover(wait_time) # cover() only avilable in 1.9
62
+ wait_time.should >= timeout
63
+ wait_time.should < timeout + 1
64
+ end
65
+
66
+ Then /^it should raise MoreRequestsExpected error after with the following message:$/ do |string|
67
+ @more_reqs_exc.should be_instance_of RestAssured::MoreRequestsExpected
68
+ @more_reqs_exc.message.should =~ /#{string}/
69
+ end
@@ -3,7 +3,7 @@ require 'rubygems'
3
3
  require 'spork'
4
4
 
5
5
  Spork.prefork do
6
- require 'rspec/expectations'
6
+ require 'rspec'
7
7
  require 'rack/test'
8
8
  require 'capybara'
9
9
  require 'capybara/firebug'
@@ -77,6 +77,8 @@ Spork.each_run do
77
77
  After do
78
78
  sleep 0.1
79
79
  DatabaseCleaner.clean
80
+
81
+ @t.join if @t.is_a?(Thread)
80
82
  end
81
83
  end
82
84
 
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'sinatra/base'
3
+ require 'sinatra/handler_options_patch'
3
4
  require 'haml'
4
5
  require 'rack-flash'
5
6
  require 'sinatra/partials'
@@ -14,7 +15,7 @@ require 'rest-assured/routes/response'
14
15
  module RestAssured
15
16
  class Application < Sinatra::Base
16
17
 
17
- include RestAssured::Config
18
+ include Config
18
19
 
19
20
  enable :method_override
20
21
 
@@ -1,8 +1,18 @@
1
1
  require 'active_resource'
2
2
 
3
3
  module RestAssured
4
- module Client
5
- class Double < ActiveResource::Base
4
+ class MoreRequestsExpected < StandardError; end
5
+
6
+ class Double < ActiveResource::Base
7
+ def wait_for_requests(n, opts = {})
8
+ timeout = opts[:timeout] || 5
9
+
10
+ timeout.times do
11
+ sleep 1
12
+ reload
13
+ return if requests.count >= n
14
+ end
15
+ raise MoreRequestsExpected.new("Expected #{n} requests. Got #{requests.count}.")
6
16
  end
7
17
  end
8
18
  end
@@ -1,6 +1,8 @@
1
1
  require 'logger'
2
2
  require 'active_record'
3
3
  require 'active_support/core_ext/kernel/reporting'
4
+ require 'webrick'
5
+ require 'webrick/https'
4
6
 
5
7
  module RestAssured
6
8
  module Config
@@ -37,11 +39,13 @@ module RestAssured
37
39
  File.expand_path("../../../#{AppConfig.environment}.log", __FILE__)
38
40
  end
39
41
  build_db_config
42
+ build_ssl_config
40
43
  end
41
44
 
42
45
  def self.included(klass)
43
46
  init_logger
44
47
  setup_db
48
+ setup_ssl(klass) if AppConfig.use_ssl
45
49
 
46
50
  klass.set :port, AppConfig.port
47
51
  klass.set :environment, AppConfig.environment
@@ -52,6 +56,19 @@ module RestAssured
52
56
 
53
57
  private
54
58
 
59
+ def self.setup_ssl(klass)
60
+ ssl_config = {
61
+ :SSLEnable => true,
62
+ :SSLCertificate => OpenSSL::X509::Certificate.new( File.read( AppConfig.ssl_cert ) ),
63
+ :SSLPrivateKey => OpenSSL::PKey::RSA.new( File.read( AppConfig.ssl_key ) ),
64
+ :SSLCertName => [ ["CN", WEBrick::Utils::getservername] ],
65
+ :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE
66
+ }
67
+
68
+ klass.set :server, %[webrick]
69
+ klass.set :webrick, ssl_config
70
+ end
71
+
55
72
  def self.setup_db
56
73
  setup_db_logging
57
74
  connect_db
@@ -118,6 +135,7 @@ module RestAssured
118
135
  opts = {
119
136
  :adapter => 'mysql',
120
137
  :reconnect => true,
138
+ :pool => 20,
121
139
  :user => AppConfig.user || 'root',
122
140
  :database => AppConfig.database || default_database
123
141
  }
@@ -132,6 +150,12 @@ module RestAssured
132
150
  raise "Unsupported db adapter '#{AppConfig.adapter}'. Valid adapters are sqlite and mysql"
133
151
  end
134
152
  end
153
+
154
+ def self.build_ssl_config
155
+ AppConfig.use_ssl ||= false
156
+ AppConfig.ssl_cert ||= File.expand_path('../../../ssl/localhost.crt', __FILE__)
157
+ AppConfig.ssl_key ||= File.expand_path('../../../ssl/localhost.key', __FILE__)
158
+ end
135
159
  end
136
160
  end
137
161
 
@@ -1,43 +1,47 @@
1
1
  require 'net/http'
2
2
 
3
- class Double < ActiveRecord::Base
4
- attr_accessible :fullpath, :content, :description, :verb, :status
3
+ module RestAssured
4
+ module Models
5
+ class Double < ActiveRecord::Base
6
+ attr_accessible :fullpath, :content, :description, :verb, :status
5
7
 
6
- VERBS = %w{GET POST PUT DELETE}
7
- STATUSES = Net::HTTPResponse::CODE_TO_OBJ.keys.map(&:to_i)
8
+ VERBS = %w{GET POST PUT DELETE}
9
+ STATUSES = Net::HTTPResponse::CODE_TO_OBJ.keys.map(&:to_i)
8
10
 
9
- validates_presence_of :fullpath
10
- validates_inclusion_of :verb, :in => VERBS
11
- validates_inclusion_of :status, :in => STATUSES
11
+ validates_presence_of :fullpath
12
+ validates_inclusion_of :verb, :in => VERBS
13
+ validates_inclusion_of :status, :in => STATUSES
12
14
 
13
- before_save :toggle_active
14
- before_validation :set_verb
15
- before_validation :set_status
16
- after_destroy :set_active
15
+ before_save :toggle_active
16
+ before_validation :set_verb
17
+ before_validation :set_status
18
+ after_destroy :set_active
17
19
 
18
- has_many :requests, :dependent => :destroy
20
+ has_many :requests, :dependent => :destroy
19
21
 
20
- private
21
- def toggle_active
22
- ne = id ? '!=' : 'IS NOT'
22
+ private
23
+ def toggle_active
24
+ ne = id ? '!=' : 'IS NOT'
23
25
 
24
- if active && Double.where("fullpath = ? AND active = ? AND id #{ne} ?", fullpath, true, id).exists?
25
- Double.where("fullpath = ? AND id #{ne} ?", fullpath, id).update_all :active => false
26
+ if active && Double.where("fullpath = ? AND active = ? AND id #{ne} ?", fullpath, true, id).exists?
27
+ Double.where("fullpath = ? AND id #{ne} ?", fullpath, id).update_all :active => false
28
+ end
26
29
  end
27
- end
28
30
 
29
- def set_verb
30
- self.verb = 'GET' unless verb.present?
31
- end
31
+ def set_verb
32
+ self.verb = 'GET' unless verb.present?
33
+ end
32
34
 
33
- def set_status
34
- self.status = 200 unless status.present?
35
- end
35
+ def set_status
36
+ self.status = 200 unless status.present?
37
+ end
36
38
 
37
- def set_active
38
- if active && f = Double.where(:fullpath => fullpath).last
39
- f.active = true
40
- f.save
39
+ def set_active
40
+ if active && f = Double.where(:fullpath => fullpath).last
41
+ f.active = true
42
+ f.save
43
+ end
41
44
  end
42
45
  end
46
+ end
43
47
  end
@@ -1,35 +1,39 @@
1
- class Redirect < ActiveRecord::Base
2
- attr_accessible :pattern, :to, :position
1
+ module RestAssured
2
+ module Models
3
+ class Redirect < ActiveRecord::Base
4
+ attr_accessible :pattern, :to, :position
3
5
 
4
- validates_presence_of :pattern, :to
6
+ validates_presence_of :pattern, :to
5
7
 
6
- scope :ordered, order('position')
8
+ scope :ordered, order('position')
7
9
 
8
- before_create :assign_position
10
+ before_create :assign_position
9
11
 
10
- def self.update_order(ordered_redirect_ids)
11
- success = true
12
+ def self.update_order(ordered_redirect_ids)
13
+ success = true
12
14
 
13
- transaction do
14
- begin
15
- ordered_redirect_ids.each_with_index do |r_id, idx|
16
- r = find(r_id)
17
- r.position = idx
18
- r.save!
15
+ transaction do
16
+ begin
17
+ ordered_redirect_ids.each_with_index do |r_id, idx|
18
+ r = find(r_id)
19
+ r.position = idx
20
+ r.save!
21
+ end
22
+ rescue => e
23
+ # TODO log exception
24
+ puts e.inspect
25
+ success = false
26
+ raise ActiveRecord::Rollback
27
+ end
19
28
  end
20
- rescue => e
21
- # TODO log exception
22
- puts e.inspect
23
- success = false
24
- raise ActiveRecord::Rollback
29
+ success
25
30
  end
26
- end
27
- success
28
- end
29
31
 
30
- private
32
+ private
31
33
 
32
- def assign_position
33
- self.position = ( self.class.maximum(:position) || -1 ) + 1
34
+ def assign_position
35
+ self.position = ( self.class.maximum(:position) || -1 ) + 1
36
+ end
34
37
  end
38
+ end
35
39
  end
@@ -1,12 +1,16 @@
1
- class Request < ActiveRecord::Base
2
- belongs_to :double
1
+ module RestAssured
2
+ module Models
3
+ class Request < ActiveRecord::Base
4
+ belongs_to :double
3
5
 
4
- validates_presence_of :rack_env
6
+ validates_presence_of :rack_env
5
7
 
6
- after_create :save_created_at
8
+ after_create :save_created_at
7
9
 
8
- private
9
- def save_created_at
10
- self.created_at = Time.now
10
+ private
11
+ def save_created_at
12
+ self.created_at = Time.now
13
+ end
11
14
  end
15
+ end
12
16
  end
@@ -8,18 +8,18 @@ module RestAssured
8
8
  end
9
9
 
10
10
  router.get '/doubles' do
11
- @doubles = Double.all
11
+ @doubles = Models::Double.all
12
12
  haml :'doubles/index'
13
13
  end
14
14
 
15
15
  router.get '/doubles/new' do
16
- @double = Double.new
16
+ @double = Models::Double.new
17
17
  haml :'doubles/new'
18
18
  end
19
19
 
20
20
  router.get '/doubles/:id.json' do |id|
21
21
  begin
22
- double = Double.find(id)
22
+ double = Models::Double.find(id)
23
23
  body double.to_json(:include => :requests)
24
24
  rescue ActiveRecord::RecordNotFound
25
25
  status 404
@@ -29,7 +29,7 @@ module RestAssured
29
29
  router.post /^\/doubles(\.json)?$/ do |passes_json|
30
30
  f = { :fullpath => params['fullpath'], :content => params['content'], :description => params['description'], :verb => params['verb'], :status => params['status'] }
31
31
 
32
- @double = Double.create(passes_json ? JSON.parse(request.body.read)['double'] : ( params['double'] || f ))
32
+ @double = Models::Double.create(passes_json ? JSON.parse(request.body.read)['double'] : ( params['double'] || f ))
33
33
 
34
34
  if browser?
35
35
  if @double.errors.blank?
@@ -50,12 +50,12 @@ module RestAssured
50
50
  end
51
51
 
52
52
  router.get %r{/doubles/(\d+)/edit} do |id|
53
- @double = Double.find(id)
53
+ @double = Models::Double.find(id)
54
54
  haml :'doubles/edit'
55
55
  end
56
56
 
57
57
  router.put %r{/doubles/(\d+)} do |id|
58
- @double = Double.find(id)
58
+ @double = Models::Double.find(id)
59
59
 
60
60
  if request.xhr?
61
61
  if params['active']
@@ -77,14 +77,14 @@ module RestAssured
77
77
  end
78
78
 
79
79
  router.delete %r{/doubles/(\d+)} do |id|
80
- if Double.destroy(id)
80
+ if Models::Double.destroy(id)
81
81
  flash[:notice] = 'Double deleted'
82
82
  redirect '/doubles'
83
83
  end
84
84
  end
85
85
 
86
86
  router.delete '/doubles/all' do
87
- status Double.delete_all ? 200 : 500
87
+ status Models::Double.delete_all ? 200 : 500
88
88
  end
89
89
  end
90
90
  end