Flipper 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/README +77 -0
- data/Rakefile +51 -0
- data/lib/flipper.rb +37 -0
- data/test/all_tests.rb +1 -0
- data/test/flipper_test.rb +78 -0
- metadata +54 -0
data/README
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
|
|
2
|
+
= Flipper
|
|
3
|
+
|
|
4
|
+
"Switch your database on the fly"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
== Introduction
|
|
8
|
+
|
|
9
|
+
When doing integration and acceptance testing you typically need to:
|
|
10
|
+
|
|
11
|
+
* Change and manage application state.
|
|
12
|
+
* Guarantee test case isolation, even for those that change the application state.
|
|
13
|
+
|
|
14
|
+
9 times out of 10, all you need to do to achieve this for a Rails application is:
|
|
15
|
+
|
|
16
|
+
* Have direct access to the database.
|
|
17
|
+
* Ensure that tests running in parallel access a different database schema.
|
|
18
|
+
|
|
19
|
+
So if you are driving your tests at the HTTP layer (e.g. Selenium tests) you could use a
|
|
20
|
+
single Mongrel cluster to run a lot of tests in parallel, a long as you can change your
|
|
21
|
+
database on the fly for each HTTP requests. This is what Flipper does.
|
|
22
|
+
|
|
23
|
+
== Status
|
|
24
|
+
|
|
25
|
+
The current status is quite good. Flipper is currently used on a daily basis on commercial projects.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
== Installation
|
|
29
|
+
|
|
30
|
+
The easiest way to install is via RubyGems. On the command line enter:
|
|
31
|
+
|
|
32
|
+
> gem install flipper
|
|
33
|
+
|
|
34
|
+
== Usage
|
|
35
|
+
|
|
36
|
+
To use flipper just include the <code>Flipper</code> module and add a before filter in <code>application.rb</code>:
|
|
37
|
+
|
|
38
|
+
class ApplicationController < ActionController::Base
|
|
39
|
+
include Flipper
|
|
40
|
+
|
|
41
|
+
before_filter :switch_database
|
|
42
|
+
|
|
43
|
+
...
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
== License
|
|
47
|
+
|
|
48
|
+
The collection PER COLLECTION is licensed as follows:
|
|
49
|
+
|
|
50
|
+
Ruby Facets
|
|
51
|
+
Copyright (c) 2004-2006 Thomas Sawyer
|
|
52
|
+
|
|
53
|
+
Distributed under the terms of the Ruby license.
|
|
54
|
+
|
|
55
|
+
The Ruby license is a dual license that also provides for use of the GPL.
|
|
56
|
+
Complete texts of both licenses accompany this document (see doc/COPYING).
|
|
57
|
+
|
|
58
|
+
This program is free software; you can redistribute it and/or modify
|
|
59
|
+
it under the terms of the GNU General Public License as published by
|
|
60
|
+
the Free Software Foundation; either version 2 of the License, or
|
|
61
|
+
(at your option) any later version.
|
|
62
|
+
|
|
63
|
+
This program is distributed in the hope that it will be useful,
|
|
64
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
65
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
66
|
+
GNU General Public License for more details.
|
|
67
|
+
|
|
68
|
+
You should have received a copy of the GNU General Public License
|
|
69
|
+
along with this program; if not, write to the Free Software
|
|
70
|
+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
71
|
+
|
|
72
|
+
Acknowledgments and Copyrights for particular snippets of borrowed code
|
|
73
|
+
are given in their respective source. All licenses are either compatible
|
|
74
|
+
with the Ruby license (namely the GPL) or the original author has given
|
|
75
|
+
permission for inclusion of their code under such lincense.
|
|
76
|
+
|
|
77
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'rake'
|
|
2
|
+
require 'rake/testtask'
|
|
3
|
+
require 'rake/rdoctask'
|
|
4
|
+
require 'rake/gempackagetask'
|
|
5
|
+
require 'rake/contrib/sshpublisher'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
desc 'Default: run unit tests.'
|
|
9
|
+
task :default => :test
|
|
10
|
+
|
|
11
|
+
desc 'Test the flipper plugin.'
|
|
12
|
+
Rake::TestTask.new(:test) do |t|
|
|
13
|
+
t.libs << 'lib'
|
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
|
15
|
+
t.verbose = true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc 'Generate documentation for the flipper plugin.'
|
|
19
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
20
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
21
|
+
rdoc.title = 'Flipper'
|
|
22
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
|
23
|
+
rdoc.rdoc_files.include('README')
|
|
24
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Gem::manage_gems
|
|
28
|
+
|
|
29
|
+
specification = Gem::Specification.new do |s|
|
|
30
|
+
s.name = "Flipper"
|
|
31
|
+
s.summary = "Switch your Rails database on the fly for each HTTP request. Useful for integration and acceptance testing (test isolation & state management)."
|
|
32
|
+
s.version = "1.0"
|
|
33
|
+
s.author = 'Philippe Hanrigou & Dan Manges'
|
|
34
|
+
s.description = s.summary
|
|
35
|
+
s.email = 'flipper-developer@rubyforge.org'
|
|
36
|
+
s.homepage = 'http://flipper.rubyforge.org'
|
|
37
|
+
s.rubyforge_project = 'flipper'
|
|
38
|
+
|
|
39
|
+
s.has_rdoc = true
|
|
40
|
+
s.extra_rdoc_files = ['README']
|
|
41
|
+
s.rdoc_options << '--title' << 'Flipper' << '--main' << 'README' << '--line-numbers'
|
|
42
|
+
|
|
43
|
+
s.autorequire = 'flipper'
|
|
44
|
+
s.files = FileList['{lib,test}/**/*.rb', '[A-Z]*$', 'Rakefile'].to_a
|
|
45
|
+
s.test_file = "test/all_tests.rb"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
Rake::GemPackageTask.new(specification) do |package|
|
|
49
|
+
package.need_zip = false
|
|
50
|
+
package.need_tar = false
|
|
51
|
+
end
|
data/lib/flipper.rb
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Include this module in your Rails controller to change database schema on each HTTP request:
|
|
3
|
+
#
|
|
4
|
+
# class ApplicationController < ActionController::Base
|
|
5
|
+
# include Flipper
|
|
6
|
+
#
|
|
7
|
+
# before_filter :switch_database # if RAILS_ENV == "selenium"
|
|
8
|
+
#
|
|
9
|
+
# ...
|
|
10
|
+
# end
|
|
11
|
+
module Flipper
|
|
12
|
+
|
|
13
|
+
#
|
|
14
|
+
# Switch current database based on <code>flipper_db_config</code> HTTP parameter, if any,
|
|
15
|
+
# and store database configuration in session.
|
|
16
|
+
#
|
|
17
|
+
# If there is no <code>flipper_db_config</code> parameter, switch to the database configuration
|
|
18
|
+
# stored in session.
|
|
19
|
+
#
|
|
20
|
+
# If anything goes wrong while switching database, attempts to rollback to the previous database configuration
|
|
21
|
+
# before raising an exception.
|
|
22
|
+
def switch_database
|
|
23
|
+
database_configuration = params[:flipper_db_config] || session[:flipper_db_config]
|
|
24
|
+
return unless database_configuration
|
|
25
|
+
|
|
26
|
+
prior_configuration = ActiveRecord::Base.connection.instance_variable_get(:@config)
|
|
27
|
+
ActiveRecord::Base.clear_active_connections!
|
|
28
|
+
begin
|
|
29
|
+
ActiveRecord::Base.establish_connection database_configuration
|
|
30
|
+
session[:flipper_db_config] = database_configuration
|
|
31
|
+
rescue => ex
|
|
32
|
+
ActiveRecord::Base.establish_connection prior_configuration
|
|
33
|
+
raise
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
data/test/all_tests.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Dir["#{File.dirname __FILE__}/*_test.rb"].each { |test_case| require test_case }
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require "rubygems"
|
|
2
|
+
require "dust"
|
|
3
|
+
require "mocha"
|
|
4
|
+
require 'test/unit'
|
|
5
|
+
|
|
6
|
+
unless defined?(ActiveRecord)
|
|
7
|
+
module ActiveRecord
|
|
8
|
+
class Base; end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
require File.dirname(__FILE__) + "/../lib/flipper"
|
|
13
|
+
|
|
14
|
+
unit_tests do
|
|
15
|
+
|
|
16
|
+
def setup
|
|
17
|
+
@controller = Class.new { include Flipper }.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
test "controller establishes new db connection and clears active connection when receiving database_connection from params" do
|
|
21
|
+
@controller.stubs(:session).returns({})
|
|
22
|
+
@controller.stubs(:params).returns(:flipper_db_config => :connection_hash)
|
|
23
|
+
ActiveRecord::Base.stubs(:connection).returns(stub_everything)
|
|
24
|
+
ActiveRecord::Base.expects(:clear_active_connections!)
|
|
25
|
+
ActiveRecord::Base.expects(:establish_connection).with(:connection_hash)
|
|
26
|
+
@controller.send(:switch_database)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
test "controller establishes new db connection and clears active connection when receiving database_connection from session" do
|
|
30
|
+
@controller.stubs(:session).returns(:flipper_db_config => :connection_hash)
|
|
31
|
+
@controller.stubs(:params).returns(:flipper_db_config => nil)
|
|
32
|
+
ActiveRecord::Base.stubs(:connection).returns(stub_everything)
|
|
33
|
+
ActiveRecord::Base.expects(:clear_active_connections!)
|
|
34
|
+
ActiveRecord::Base.expects(:establish_connection).with(:connection_hash)
|
|
35
|
+
@controller.send(:switch_database)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
test "controller checks for database configuration in params before session" do
|
|
39
|
+
@controller.stubs(:session).returns(:flipper_db_config => :session_connection_hash)
|
|
40
|
+
@controller.stubs(:params).returns(:flipper_db_config => :params_connection_hash)
|
|
41
|
+
ActiveRecord::Base.stubs(:connection).returns(stub_everything)
|
|
42
|
+
ActiveRecord::Base.expects(:clear_active_connections!)
|
|
43
|
+
ActiveRecord::Base.expects(:establish_connection).with(:params_connection_hash)
|
|
44
|
+
@controller.send(:switch_database)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
test "controller does not establish a new db connection nor clears active connection when there is no database_connection neither in params nor in session" do
|
|
48
|
+
@controller.stubs(:session).returns({})
|
|
49
|
+
@controller.stubs(:params).returns(:flipper_db_config => nil)
|
|
50
|
+
ActiveRecord::Base.stubs(:connection).returns(stub_everything)
|
|
51
|
+
ActiveRecord::Base.expects(:clear_active_connections!).never
|
|
52
|
+
ActiveRecord::Base.expects(:establish_connection).never
|
|
53
|
+
@controller.send(:switch_database)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
test "database configuration is stored in session after passed in through params" do
|
|
57
|
+
@controller.stubs(:session).returns(session = {})
|
|
58
|
+
@controller.stubs(:params).returns(:flipper_db_config => :connection_hash)
|
|
59
|
+
ActiveRecord::Base.stubs(:connection).returns(stub_everything)
|
|
60
|
+
ActiveRecord::Base.stubs(:clear_active_connections!)
|
|
61
|
+
ActiveRecord::Base.stubs(:establish_connection)
|
|
62
|
+
@controller.send(:switch_database)
|
|
63
|
+
assert_equal :connection_hash, session[:flipper_db_config]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
test "controller restores original db connection and raises exception when establishing a new database_connection fails" do
|
|
67
|
+
@controller.stubs(:session).returns({})
|
|
68
|
+
@controller.stubs(:params).returns(:flipper_db_config => :connection_hash)
|
|
69
|
+
ActiveRecord::Base.stubs(:connection).returns(connection = stub)
|
|
70
|
+
connection.instance_variable_set "@config", :old_configuration
|
|
71
|
+
ActiveRecord::Base.expects(:clear_active_connections!)
|
|
72
|
+
exception = RuntimeError.new("will be raised if new connection cannot be established")
|
|
73
|
+
ActiveRecord::Base.expects(:establish_connection).with(:connection_hash).raises(exception)
|
|
74
|
+
ActiveRecord::Base.expects(:establish_connection).with(:old_configuration)
|
|
75
|
+
assert_raises(RuntimeError) { @controller.send(:switch_database) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
rubygems_version: 0.9.4
|
|
3
|
+
specification_version: 1
|
|
4
|
+
name: Flipper
|
|
5
|
+
version: !ruby/object:Gem::Version
|
|
6
|
+
version: "1.0"
|
|
7
|
+
date: 2007-09-15 00:00:00 -04:00
|
|
8
|
+
summary: Switch your Rails database on the fly for each HTTP request. Useful for integration and acceptance testing (test isolation & state management).
|
|
9
|
+
require_paths:
|
|
10
|
+
- lib
|
|
11
|
+
email: flipper-developer@rubyforge.org
|
|
12
|
+
homepage: http://flipper.rubyforge.org
|
|
13
|
+
rubyforge_project: flipper
|
|
14
|
+
description: Switch your Rails database on the fly for each HTTP request. Useful for integration and acceptance testing (test isolation & state management).
|
|
15
|
+
autorequire: flipper
|
|
16
|
+
default_executable:
|
|
17
|
+
bindir: bin
|
|
18
|
+
has_rdoc: true
|
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">"
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: 0.0.0
|
|
24
|
+
version:
|
|
25
|
+
platform: ruby
|
|
26
|
+
signing_key:
|
|
27
|
+
cert_chain:
|
|
28
|
+
post_install_message:
|
|
29
|
+
authors:
|
|
30
|
+
- Philippe Hanrigou & Dan Manges
|
|
31
|
+
files:
|
|
32
|
+
- lib/flipper.rb
|
|
33
|
+
- test/flipper_test.rb
|
|
34
|
+
- test/all_tests.rb
|
|
35
|
+
- Rakefile
|
|
36
|
+
- README
|
|
37
|
+
test_files:
|
|
38
|
+
- test/all_tests.rb
|
|
39
|
+
rdoc_options:
|
|
40
|
+
- --title
|
|
41
|
+
- Flipper
|
|
42
|
+
- --main
|
|
43
|
+
- README
|
|
44
|
+
- --line-numbers
|
|
45
|
+
extra_rdoc_files:
|
|
46
|
+
- README
|
|
47
|
+
executables: []
|
|
48
|
+
|
|
49
|
+
extensions: []
|
|
50
|
+
|
|
51
|
+
requirements: []
|
|
52
|
+
|
|
53
|
+
dependencies: []
|
|
54
|
+
|