Skip to content

Commit

Permalink
Add session_store test, start Ginger integration
Browse files Browse the repository at this point in the history
  • Loading branch information
mperham committed Sep 2, 2010
1 parent 8d85115 commit 561969a
Show file tree
Hide file tree
Showing 6 changed files with 570 additions and 46 deletions.
33 changes: 19 additions & 14 deletions lib/action_dispatch/middleware/session/dalli_store.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
require 'active_support/cache'
require 'action_dispatch/middleware/session/abstract_store'
require 'dalli'

# Dalli-based session store for Rails 3.0. Use like so:
#
# require 'action_dispatch/middleware/session/dalli_store'
# config.session_store ActionDispatch::Session::DalliStore, ['cache-1', 'cache-2'], :expire_after => 2.weeks
module ActionDispatch
module Session
class DalliStore < AbstractStore
Expand All @@ -16,26 +22,25 @@ def initialize(app, options = {})
}.merge(@default_options)

@pool = options[:cache] || begin
store = if Rails.version < '3.0'
require 'active_support/cache/dalli_store23'
:dalli_store23
else
:dalli_store
end
ActiveSupport::Cache.lookup_store(store, @default_options[:memcache_server], @default_options)
Dalli::Client.new(
@default_options[:memcache_server], @default_options)
end
# unless @pool.servers.any? { |s| s.alive? }
# raise "#{self} unable to find server during initialization."
# end
@mutex = Mutex.new
@namespace = @default_options[:namespace]

super
end

private

def session_key(sid)
# Dalli does not support namespaces directly so we have
# to roll our own.
@namespace ? "#{@namespace}:#{sid}" : sid
end

def get_session(env, sid)
begin
session = @pool.get(sid) || {}
session = @pool.get(session_key(sid)) || {}
rescue Dalli::DalliError => de
Rails.logger.warn("Session::DalliStore: #{$!.message}")
session = {}
Expand All @@ -46,7 +51,7 @@ def get_session(env, sid)
def set_session(env, sid, session_data)
options = env['rack.session.options']
expiry = options[:expire_after] || 0
@pool.set(sid, session_data, expiry)
@pool.set(session_key(sid), session_data, expiry)
sid
rescue Dalli::DalliError
Rails.logger.warn("Session::DalliStore: #{$!.message}")
Expand All @@ -55,7 +60,7 @@ def set_session(env, sid, session_data)

def destroy(env)
if sid = current_session_id(env)
@pool.delete(sid)
@pool.delete(session_key(sid))
end
rescue Dalli::DalliError
Rails.logger.warn("Session::DalliStore: #{$!.message}")
Expand Down
286 changes: 286 additions & 0 deletions test/abstract_unit.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@

# Used to test the full Rails stack.
# Stolen from the Rails 3.0 source.
# Needed for the session store tests.

require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/string/encoding'
if "ruby".encoding_aware?
# These are the normal settings that will be set up by Railties
# TODO: Have these tests support other combinations of these values
silence_warnings do
Encoding.default_internal = "UTF-8"
Encoding.default_external = "UTF-8"
end
end

require 'test/unit'
require 'abstract_controller'
require 'action_controller'
require 'action_view'
require 'action_dispatch'
require 'active_support/dependencies'
require 'action_controller/caching'
require 'action_controller/caching/sweeping'

require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late

module Rails
def self.logger
@logger ||= begin
l = Logger.new(STDOUT)
l.level = Logger::INFO; l
end
end
end

# Monkey patch the old routes initialization to be silenced.
class ActionDispatch::Routing::DeprecatedMapper
def initialize_with_silencer(*args)
ActiveSupport::Deprecation.silence { initialize_without_silencer(*args) }
end
alias_method_chain :initialize, :silencer
end

ActiveSupport::Dependencies.hook!

# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true

ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort

module RackTestUtils
def body_to_string(body)
if body.respond_to?(:each)
str = ""
body.each {|s| str << s }
str
else
body
end
end
extend self
end

module SetupOnce
extend ActiveSupport::Concern

included do
cattr_accessor :setup_once_block
self.setup_once_block = nil

setup :run_setup_once
end

module ClassMethods
def setup_once(&block)
self.setup_once_block = block
end
end

private
def run_setup_once
if self.setup_once_block
self.setup_once_block.call
self.setup_once_block = nil
end
end
end

SharedTestRoutes = ActionDispatch::Routing::RouteSet.new

module ActiveSupport
class TestCase
include SetupOnce
# Hold off drawing routes until all the possible controller classes
# have been loaded.
setup_once do
SharedTestRoutes.draw do |map|
# FIXME: match ':controller(/:action(/:id))'
map.connect ':controller/:action/:id'
end

ActionController::IntegrationTest.app.routes.draw do |map|
# FIXME: match ':controller(/:action(/:id))'
map.connect ':controller/:action/:id'
end
end
end
end

class RoutedRackApp
attr_reader :routes

def initialize(routes, &blk)
@routes = routes
@stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
end

def call(env)
@stack.call(env)
end
end

class BasicController
attr_accessor :request

def config
@config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config).tap do |config|
# VIEW TODO: View tests should not require a controller
public_dir = File.expand_path("../fixtures/public", __FILE__)
config.assets_dir = public_dir
config.javascripts_dir = "#{public_dir}/javascripts"
config.stylesheets_dir = "#{public_dir}/stylesheets"
config
end
end
end

class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
setup do
@routes = SharedTestRoutes
end
end

class ActionController::IntegrationTest < ActiveSupport::TestCase
def self.build_app(routes = nil)
RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
middleware.use "ActionDispatch::ShowExceptions"
middleware.use "ActionDispatch::Callbacks"
middleware.use "ActionDispatch::ParamsParser"
middleware.use "ActionDispatch::Cookies"
middleware.use "ActionDispatch::Flash"
middleware.use "ActionDispatch::Head"
yield(middleware) if block_given?
end
end

self.app = build_app

# Stub Rails dispatcher so it does not get controller references and
# simply return the controller#action as Rack::Body.
class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher
protected
def controller_reference(controller_param)
controller_param
end

def dispatch(controller, action, env)
[200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
end
end

def self.stub_controllers
old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher
ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher }
yield ActionDispatch::Routing::RouteSet.new
ensure
ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher }
end

def with_routing(&block)
temporary_routes = ActionDispatch::Routing::RouteSet.new
old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes)
old_routes = SharedTestRoutes
silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) }

yield temporary_routes
ensure
self.class.app = old_app
silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
end

def with_autoload_path(path)
path = File.join(File.dirname(__FILE__), "fixtures", path)
if ActiveSupport::Dependencies.autoload_paths.include?(path)
yield
else
begin
ActiveSupport::Dependencies.autoload_paths << path
yield
ensure
ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path}
ActiveSupport::Dependencies.clear
end
end
end
end

# Temporary base class
class Rack::TestCase < ActionController::IntegrationTest
def self.testing(klass = nil)
if klass
@testing = "/#{klass.name.underscore}".sub!(/_controller$/, '')
else
@testing
end
end

def get(thing, *args)
if thing.is_a?(Symbol)
super("#{self.class.testing}/#{thing}", *args)
else
super
end
end

def assert_body(body)
assert_equal body, Array.wrap(response.body).join
end

def assert_status(code)
assert_equal code, response.status
end

def assert_response(body, status = 200, headers = {})
assert_body body
assert_status status
headers.each do |header, value|
assert_header header, value
end
end

def assert_content_type(type)
assert_equal type, response.headers["Content-Type"]
end

def assert_header(name, value)
assert_equal value, response.headers[name]
end
end

class ActionController::Base
def self.test_routes(&block)
routes = ActionDispatch::Routing::RouteSet.new
routes.draw(&block)
include routes.url_helpers
end
end

class ::ApplicationController < ActionController::Base
end

module ActionController
class Base
include ActionController::Testing
end

Base.view_paths = []

class TestCase
include ActionDispatch::TestProcess

setup do
@routes = SharedTestRoutes
end
end
end

# This stub emulates the Railtie including the URL helpers from a Rails application
module ActionController
class Base
include SharedTestRoutes.url_helpers
end
end
11 changes: 11 additions & 0 deletions test/ginger_scenarios.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require 'ginger'

Ginger.configure do |config|
rails_2_3_8 = Ginger::Scenario.new
rails_2_3_8[/^rails$/] = "2.3.8"

rails_3_0_0 = Ginger::Scenario.new
rails_3_0_0[/^rails$/] = "3.0.0"

config.scenarios << rails_2_3_8 << rails_3_0_0
end
Loading

0 comments on commit 561969a

Please sign in to comment.