rest-assured 0.2.0.rc8 → 0.2.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 (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