rest-assured 0.3.2 → 1.0.0.rc1

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 (48) hide show
  1. data/.rspec +1 -0
  2. data/Gemfile +4 -1
  3. data/README.markdown +47 -25
  4. data/bin/rest-assured +3 -3
  5. data/features/command_line_options.feature +2 -2
  6. data/features/rest_api/redirects.feature +10 -9
  7. data/features/ruby_api/create_double.feature +1 -6
  8. data/features/ruby_api/test_server.feature +42 -0
  9. data/features/ruby_api/verify_requests.feature +1 -6
  10. data/features/ruby_api/wait_for_requests.feature +2 -5
  11. data/features/step_definitions/command_line_options_steps.rb +1 -1
  12. data/features/step_definitions/doubles_steps.rb +4 -0
  13. data/features/step_definitions/redirect_rules_steps.rb +2 -6
  14. data/features/step_definitions/ruby_api_steps.rb +45 -0
  15. data/features/support/env.rb +9 -14
  16. data/features/support/world_helpers.rb +1 -1
  17. data/lib/rest-assured.rb +1 -45
  18. data/lib/rest-assured/api.rb +3 -0
  19. data/lib/rest-assured/api/app_runner.rb +18 -0
  20. data/lib/rest-assured/api/app_session.rb +33 -0
  21. data/lib/rest-assured/{client → api}/resources.rb +0 -0
  22. data/lib/rest-assured/api/server.rb +59 -0
  23. data/lib/rest-assured/application.rb +46 -0
  24. data/lib/rest-assured/config.rb +16 -3
  25. data/lib/rest-assured/models/redirect.rb +6 -0
  26. data/lib/rest-assured/routes/double.rb +1 -1
  27. data/lib/rest-assured/routes/redirect.rb +1 -1
  28. data/lib/rest-assured/routes/response.rb +4 -4
  29. data/lib/rest-assured/utils/drb_sniffer.rb +11 -0
  30. data/lib/rest-assured/utils/port_explorer.rb +22 -0
  31. data/lib/rest-assured/utils/subprocess.rb +50 -0
  32. data/lib/rest-assured/version.rb +1 -1
  33. data/prof-result.html +79521 -0
  34. data/rest-assured.gemspec +2 -1
  35. data/spec/api/app_runner_spec.rb +27 -0
  36. data/spec/api/app_session_spec.rb +51 -0
  37. data/spec/{client → api}/resource_double_spec.rb +1 -14
  38. data/spec/api/server_spec.rb +138 -0
  39. data/spec/config_spec.rb +111 -93
  40. data/spec/functional/response_spec.rb +5 -2
  41. data/spec/models/redirect_spec.rb +22 -0
  42. data/spec/port_explorer_spec.rb +32 -0
  43. data/spec/spec_helper.rb +25 -18
  44. data/spec/subprocess_spec.rb +138 -0
  45. data/spec/{custom_matchers.rb → support/custom_matchers.rb} +0 -0
  46. data/spec/support/reset-singleton.rb +15 -0
  47. metadata +66 -30
  48. data/lib/rest-assured/client.rb +0 -17
@@ -63,11 +63,13 @@ module RestAssured
63
63
  end
64
64
 
65
65
  it "redirects if double not hit but there is redirect that matches request" do
66
- r = Models::Redirect.create :to => 'http://exmple.com/api', :pattern => '.*'
66
+ #r = Models::Redirect.create :to => 'http://exmple.com/api', :pattern => '.*'
67
+ #
67
68
  fullpath = '/some/other/path'
68
69
  request.stub(:fullpath).and_return(fullpath)
70
+ Models::Redirect.stub(:find_redirect_url_for).with(fullpath).and_return('new_url')
69
71
 
70
- rest_assured_app.should_receive(:redirect).with(r.to + fullpath)
72
+ rest_assured_app.should_receive(:redirect).with('new_url')
71
73
 
72
74
  Response.perform(rest_assured_app)
73
75
  end
@@ -78,6 +80,7 @@ module RestAssured
78
80
  Response.perform(rest_assured_app)
79
81
  end
80
82
 
83
+ # TODO change to instead exclude anything that does not respond_to?(:to_s)
81
84
  it 'excludes "rack.input" and "rack.errors" as they break with "IOError - not opened for reading:" on consequent #to_json (as they are IO and StringIO)' do
82
85
  requests = double.as_null_object
83
86
  Models::Double.stub_chain('where.first').and_return(double(:requests => requests).as_null_object)
@@ -37,5 +37,27 @@ module RestAssured::Models
37
37
 
38
38
  Redirect.update_order([nil, 34]).should == false
39
39
  end
40
+
41
+ context 'redirect url' do
42
+ it 'constructs url to redirect to' do
43
+ path = rand(1000)
44
+ r = Redirect.create :pattern => '/api/(.*)\?.*', :to => 'http://external.com/some/url/\1?p=5'
45
+ Redirect.find_redirect_url_for("/api/#{path}?param=1").should == "http://external.com/some/url/#{path}?p=5"
46
+ end
47
+
48
+ it 'returns the one that matches the substring' do
49
+ r1 = Redirect.create :pattern => '/ai/path', :to => 'someurl'
50
+ r2 = Redirect.create :pattern => '/api/path', :to => 'someurl'
51
+
52
+ Redirect.find_redirect_url_for('/api/path').should == 'someurl'
53
+ end
54
+
55
+ it 'returns the oldest one that match' do
56
+ r1 = Redirect.create :pattern => '/api', :to => 'someurl'
57
+ r2 = Redirect.create :pattern => '/api/path', :to => 'otherurl'
58
+
59
+ Redirect.find_redirect_url_for('/api/path').should == 'someurl/path'
60
+ end
61
+ end
40
62
  end
41
63
  end
@@ -0,0 +1,32 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ require File.expand_path('../../lib/rest-assured/utils/port_explorer', __FILE__)
3
+
4
+ module RestAssured::Utils
5
+ describe PortExplorer do
6
+ it 'finds free tcp port' do
7
+ free_port = PortExplorer.free_port
8
+ lambda { Net::HTTP.get('127.0.0.1', '/', free_port) }.should raise_error(Errno::ECONNREFUSED)
9
+ end
10
+
11
+ it 'knows if port is in use' do
12
+ port = PortExplorer.free_port
13
+
14
+ Thread.new do
15
+ TCPServer.open('127.0.0.1', port) do |serv|
16
+ s = serv.accept
17
+ s.puts 'Hello from test'
18
+ s.close
19
+ end
20
+ end
21
+ sleep 0.5
22
+
23
+ PortExplorer.port_free?(port).should == false
24
+ end
25
+
26
+ it 'knows that port is free' do
27
+ port = PortExplorer.free_port
28
+
29
+ PortExplorer.port_free?(port).should == true
30
+ end
31
+ end
32
+ end
data/spec/spec_helper.rb CHANGED
@@ -4,10 +4,14 @@ require 'spork'
4
4
  $:.unshift(File.expand_path('../../lib'), __FILE__)
5
5
 
6
6
  Spork.prefork do
7
+ require 'rspec'
7
8
  require 'capybara/rspec'
8
9
  require 'rack/test'
9
10
  require 'database_cleaner'
10
- require File.expand_path('../custom_matchers', __FILE__)
11
+ require 'awesome_print'
12
+ require File.expand_path('../support/custom_matchers', __FILE__)
13
+ require File.expand_path('../support/reset-singleton', __FILE__)
14
+ require 'rest-assured/utils/drb_sniffer'
11
15
 
12
16
  ENV['RACK_ENV'] = 'test'
13
17
 
@@ -23,6 +27,7 @@ Spork.prefork do
23
27
  c.include Capybara::DSL
24
28
  c.include Rack::Test::Methods
25
29
  c.include XhrHelpers
30
+ c.include RestAssured::Utils::DrbSniffer
26
31
 
27
32
  c.before(:each) do
28
33
  DatabaseCleaner.start
@@ -40,29 +45,31 @@ Spork.prefork do
40
45
  header 'User-Agent', nil
41
46
  end
42
47
  end
43
- end
44
-
45
- Spork.each_run do
46
48
  require 'rest-assured/config'
47
- RestAssured::Config.build(:adapter => 'mysql')
49
+ db_opts = { :dbuser => ENV['TRAVIS'] ? "''" : "root", :adapter => 'mysql' }
50
+ RestAssured::Config.build(db_opts)
48
51
 
49
52
  require 'rest-assured'
50
- require 'rest-assured/client'
53
+ require 'rest-assured/application'
51
54
  require 'shoulda-matchers'
52
- require File.expand_path('../../features/support/test-server', __FILE__)
53
-
54
- at_exit do
55
- TestServer.stop
56
- end
57
55
 
58
- TestServer.start(:port => 9876, :db_user => ENV['TRAVIS'] ? "''" : "root")
59
-
60
- while not TestServer.up?
61
- puts 'Waiting for TestServer to come up...'
62
- sleep 1
63
- end
56
+ RestAssured::Server.start(db_opts.merge(:port => 9876))
57
+ end
64
58
 
65
- RestAssured::Client.config.server_address = 'http://localhost:9876'
59
+ Spork.each_run do
60
+ #require 'rest-assured/config'
61
+ #db_opts = { :dbuser => ENV['TRAVIS'] ? "''" : "root", :adapter => 'mysql' }
62
+ #RestAssured::Config.build(db_opts)
63
+
64
+ #require 'rest-assured'
65
+ #require 'rest-assured/application'
66
+ #require 'shoulda-matchers'
67
+
68
+ #RSpec.configure do |c|
69
+ #c.before(:each, "ruby-api" => true) do
70
+ #RestAssured::Server.start(db_opts.merge(:port => 9876))
71
+ #end
72
+ #end
66
73
 
67
74
  Capybara.app = RestAssured::Application
68
75
 
@@ -0,0 +1,138 @@
1
+ require 'tempfile'
2
+ require File.expand_path('../spec_helper', __FILE__)
3
+ require File.expand_path('../../lib/rest-assured/utils/subprocess', __FILE__)
4
+
5
+ module RestAssured::Utils
6
+ describe Subprocess do
7
+
8
+ it 'forks passed block' do
9
+ ppid_file = Tempfile.new('ppidfile')
10
+ pid_file = Tempfile.new('pidfile')
11
+
12
+ fork do
13
+ pid_file.write(Process.pid)
14
+ pid_file.rewind
15
+ at_exit { exit! }
16
+ Subprocess.new do
17
+ ppid_file.write(Process.ppid)
18
+ ppid_file.rewind
19
+ sleep 2
20
+ end
21
+ sleep 0.5
22
+ end
23
+ Process.wait
24
+ ppid_file.read.should == pid_file.read
25
+ end
26
+
27
+ it 'ensures no zombies' do
28
+ Kernel.stub(:fork).and_return(pid = 1)
29
+ Process.should_receive(:detach).with(pid)
30
+
31
+ Subprocess.new {1}
32
+ end
33
+
34
+ it 'knows when it is running' do
35
+ res_file = Tempfile.new('res')
36
+ fork do
37
+ at_exit { exit! }
38
+ child = Subprocess.new { sleep 0.5 }
39
+ res_file.write(child.alive?)
40
+ res_file.rewind
41
+ end
42
+ Process.wait
43
+ res_file.read.should == 'true'
44
+ end
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
+ context 'shuts down child process' do
76
+ let(:child_pid) do
77
+ Tempfile.new('child_pid')
78
+ end
79
+
80
+ let(:child_alive?) do
81
+ begin
82
+ Process.kill(0, child_pid.read.to_i)
83
+ true
84
+ rescue Errno::ESRCH
85
+ false
86
+ end
87
+ end
88
+
89
+ it 'when stopped' do
90
+ res_file = Tempfile.new('res')
91
+ fork do
92
+ at_exit { exit! }
93
+ child = Subprocess.new { sleep 2 }
94
+ child.stop
95
+ sleep 1
96
+ res_file.write(child.alive?)
97
+ res_file.rewind
98
+ end
99
+ Process.wait
100
+ res_file.read.should == 'false'
101
+ end
102
+
103
+ it 'when exits normally' do
104
+ if not running_in_drb? # drb breaks fork sandbox: at_exits a collected and fired all together on master process exit
105
+ child_pid # Magic touch. Literally. Else Tempfile gets created in fork and that messes things up
106
+
107
+ fork do
108
+ at_exit { exit! }
109
+ child = Subprocess.new { sleep 2 }
110
+ child_pid.write(child.pid)
111
+ child_pid.rewind
112
+ end
113
+
114
+ sleep 0.5
115
+ child_alive?.should == false
116
+ end
117
+ end
118
+
119
+ it 'when killed violently' do
120
+ if not running_in_drb?
121
+ child_pid
122
+
123
+ fork do
124
+ at_exit { exit! }
125
+ child = Subprocess.new { sleep 2 }
126
+ child_pid.write(child.pid)
127
+ child_pid.rewind
128
+
129
+ Process.kill('TERM', Process.pid)
130
+ end
131
+
132
+ sleep 0.5
133
+ child_alive?.should == false
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,15 @@
1
+ require 'singleton'
2
+
3
+ class <<Singleton
4
+ def included_with_reset(klass)
5
+ included_without_reset(klass)
6
+ class <<klass
7
+ def reset_instance
8
+ Singleton.send :__init__, self
9
+ self
10
+ end
11
+ end
12
+ end
13
+ alias_method :included_without_reset, :included
14
+ alias_method :included, :included_with_reset
15
+ end
metadata CHANGED
@@ -1,19 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest-assured
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
5
- prerelease:
4
+ version: 1.0.0.rc1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Artem Avetisyan
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-23 00:00:00.000000000 Z
12
+ date: 2012-02-10 00:00:00.000000000 +00:00
13
+ default_executable:
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: sinatra
16
- requirement: &2156381020 !ruby/object:Gem::Requirement
17
+ requirement: &2157171280 !ruby/object:Gem::Requirement
17
18
  none: false
18
19
  requirements:
19
20
  - - ! '>='
@@ -21,32 +22,43 @@ dependencies:
21
22
  version: 1.3.1
22
23
  type: :runtime
23
24
  prerelease: false
24
- version_requirements: *2156381020
25
+ version_requirements: *2157171280
25
26
  - !ruby/object:Gem::Dependency
26
- name: rack-flash
27
- requirement: &2156380560 !ruby/object:Gem::Requirement
27
+ name: rack
28
+ requirement: &2157166140 !ruby/object:Gem::Requirement
28
29
  none: false
29
30
  requirements:
30
- - - ! '>='
31
+ - - <=
31
32
  - !ruby/object:Gem::Version
32
- version: 0.1.2
33
+ version: 1.3.6
33
34
  type: :runtime
34
35
  prerelease: false
35
- version_requirements: *2156380560
36
+ version_requirements: *2157166140
36
37
  - !ruby/object:Gem::Dependency
37
- name: rack
38
- requirement: &2156380100 !ruby/object:Gem::Requirement
38
+ name: childprocess
39
+ requirement: &2157165680 !ruby/object:Gem::Requirement
39
40
  none: false
40
41
  requirements:
41
- - - <=
42
+ - - ~>
42
43
  - !ruby/object:Gem::Version
43
- version: 1.3.6
44
+ version: 0.2.8
44
45
  type: :runtime
45
46
  prerelease: false
46
- version_requirements: *2156380100
47
+ version_requirements: *2157165680
48
+ - !ruby/object:Gem::Dependency
49
+ name: sinatra-flash
50
+ requirement: &2157165300 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: *2157165300
47
59
  - !ruby/object:Gem::Dependency
48
60
  name: haml
49
- requirement: &2156379640 !ruby/object:Gem::Requirement
61
+ requirement: &2157164700 !ruby/object:Gem::Requirement
50
62
  none: false
51
63
  requirements:
52
64
  - - ! '>='
@@ -54,10 +66,10 @@ dependencies:
54
66
  version: 3.1.3
55
67
  type: :runtime
56
68
  prerelease: false
57
- version_requirements: *2156379640
69
+ version_requirements: *2157164700
58
70
  - !ruby/object:Gem::Dependency
59
71
  name: activerecord
60
- requirement: &2156379180 !ruby/object:Gem::Requirement
72
+ requirement: &2157164060 !ruby/object:Gem::Requirement
61
73
  none: false
62
74
  requirements:
63
75
  - - ~>
@@ -65,10 +77,10 @@ dependencies:
65
77
  version: 3.1.0
66
78
  type: :runtime
67
79
  prerelease: false
68
- version_requirements: *2156379180
80
+ version_requirements: *2157164060
69
81
  - !ruby/object:Gem::Dependency
70
82
  name: activeresource
71
- requirement: &2156356520 !ruby/object:Gem::Requirement
83
+ requirement: &2157163540 !ruby/object:Gem::Requirement
72
84
  none: false
73
85
  requirements:
74
86
  - - ~>
@@ -76,7 +88,7 @@ dependencies:
76
88
  version: 3.1.0
77
89
  type: :runtime
78
90
  prerelease: false
79
- version_requirements: *2156356520
91
+ version_requirements: *2157163540
80
92
  description:
81
93
  email:
82
94
  - artem.avetisyan@bbc.co.uk
@@ -86,6 +98,7 @@ extensions: []
86
98
  extra_rdoc_files: []
87
99
  files:
88
100
  - .gitignore
101
+ - .rspec
89
102
  - .travis.yml
90
103
  - Gemfile
91
104
  - Guardfile
@@ -111,6 +124,7 @@ files:
111
124
  - features/rest_api/doubles.feature
112
125
  - features/rest_api/redirects.feature
113
126
  - features/ruby_api/create_double.feature
127
+ - features/ruby_api/test_server.feature
114
128
  - features/ruby_api/verify_requests.feature
115
129
  - features/ruby_api/wait_for_requests.feature
116
130
  - features/step_definitions/command_line_options_steps.rb
@@ -126,8 +140,12 @@ files:
126
140
  - features/web_ui/redirects.feature
127
141
  - lib/active_record/leaky_connections_patch.rb
128
142
  - lib/rest-assured.rb
129
- - lib/rest-assured/client.rb
130
- - lib/rest-assured/client/resources.rb
143
+ - lib/rest-assured/api.rb
144
+ - lib/rest-assured/api/app_runner.rb
145
+ - lib/rest-assured/api/app_session.rb
146
+ - lib/rest-assured/api/resources.rb
147
+ - lib/rest-assured/api/server.rb
148
+ - lib/rest-assured/application.rb
131
149
  - lib/rest-assured/config.rb
132
150
  - lib/rest-assured/models/double.rb
133
151
  - lib/rest-assured/models/redirect.rb
@@ -135,9 +153,13 @@ files:
135
153
  - lib/rest-assured/routes/double.rb
136
154
  - lib/rest-assured/routes/redirect.rb
137
155
  - lib/rest-assured/routes/response.rb
156
+ - lib/rest-assured/utils/drb_sniffer.rb
157
+ - lib/rest-assured/utils/port_explorer.rb
158
+ - lib/rest-assured/utils/subprocess.rb
138
159
  - lib/rest-assured/version.rb
139
160
  - lib/sinatra/handler_options_patch.rb
140
161
  - lib/sinatra/partials.rb
162
+ - prof-result.html
141
163
  - public/css/base.css
142
164
  - public/css/grid.inuit.css
143
165
  - public/css/inuit.css
@@ -155,16 +177,22 @@ files:
155
177
  - public/javascript/application.js
156
178
  - public/javascript/jquery.jgrowl_minimized.js
157
179
  - rest-assured.gemspec
158
- - spec/client/resource_double_spec.rb
180
+ - spec/api/app_runner_spec.rb
181
+ - spec/api/app_session_spec.rb
182
+ - spec/api/resource_double_spec.rb
183
+ - spec/api/server_spec.rb
159
184
  - spec/config_spec.rb
160
- - spec/custom_matchers.rb
161
185
  - spec/functional/double_routes_spec.rb
162
186
  - spec/functional/redirect_routes_spec.rb
163
187
  - spec/functional/response_spec.rb
164
188
  - spec/models/double_spec.rb
165
189
  - spec/models/redirect_spec.rb
166
190
  - spec/models/request_spec.rb
191
+ - spec/port_explorer_spec.rb
167
192
  - spec/spec_helper.rb
193
+ - spec/subprocess_spec.rb
194
+ - spec/support/custom_matchers.rb
195
+ - spec/support/reset-singleton.rb
168
196
  - ssl/localhost.crt
169
197
  - ssl/localhost.key
170
198
  - views/doubles/_form.haml
@@ -176,6 +204,7 @@ files:
176
204
  - views/redirects/edit.haml
177
205
  - views/redirects/index.haml
178
206
  - views/redirects/new.haml
207
+ has_rdoc: true
179
208
  homepage: https://github.com/BBC/rest-assured
180
209
  licenses: []
181
210
  post_install_message:
@@ -191,12 +220,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
191
220
  required_rubygems_version: !ruby/object:Gem::Requirement
192
221
  none: false
193
222
  requirements:
194
- - - ! '>='
223
+ - - ! '>'
195
224
  - !ruby/object:Gem::Version
196
- version: '0'
225
+ version: 1.3.1
197
226
  requirements: []
198
227
  rubyforge_project: rest-assured
199
- rubygems_version: 1.8.10
228
+ rubygems_version: 1.6.2
200
229
  signing_key:
201
230
  specification_version: 3
202
231
  summary: A tool for high level mocking/stubbing HTTP based REST services
@@ -205,6 +234,7 @@ test_files:
205
234
  - features/rest_api/doubles.feature
206
235
  - features/rest_api/redirects.feature
207
236
  - features/ruby_api/create_double.feature
237
+ - features/ruby_api/test_server.feature
208
238
  - features/ruby_api/verify_requests.feature
209
239
  - features/ruby_api/wait_for_requests.feature
210
240
  - features/step_definitions/command_line_options_steps.rb
@@ -218,13 +248,19 @@ test_files:
218
248
  - features/support/world_helpers.rb
219
249
  - features/web_ui/doubles.feature
220
250
  - features/web_ui/redirects.feature
221
- - spec/client/resource_double_spec.rb
251
+ - spec/api/app_runner_spec.rb
252
+ - spec/api/app_session_spec.rb
253
+ - spec/api/resource_double_spec.rb
254
+ - spec/api/server_spec.rb
222
255
  - spec/config_spec.rb
223
- - spec/custom_matchers.rb
224
256
  - spec/functional/double_routes_spec.rb
225
257
  - spec/functional/redirect_routes_spec.rb
226
258
  - spec/functional/response_spec.rb
227
259
  - spec/models/double_spec.rb
228
260
  - spec/models/redirect_spec.rb
229
261
  - spec/models/request_spec.rb
262
+ - spec/port_explorer_spec.rb
230
263
  - spec/spec_helper.rb
264
+ - spec/subprocess_spec.rb
265
+ - spec/support/custom_matchers.rb
266
+ - spec/support/reset-singleton.rb