require 'abstract_unit' class CGI::Session def cache dbman.instance_variable_get(:@cache) end end uses_mocha 'MemCacheStore tests' do if defined? MemCache::MemCacheError class MemCacheStoreTest < Test::Unit::TestCase SESSION_KEY_RE = /^session:[0-9a-z]+/ CONN_TEST_KEY = 'connection_test' MULTI_TEST_KEY = '0123456789' TEST_DATA = 'Hello test' def self.get_mem_cache_if_available begin require 'memcache' cache = MemCache.new('127.0.0.1') # Test availability of the connection cache.set(CONN_TEST_KEY, 1) unless cache.get(CONN_TEST_KEY) == 1 puts 'Warning: memcache server available but corrupted.' return nil end rescue LoadError, MemCache::MemCacheError return nil end return cache end CACHE = get_mem_cache_if_available def test_initialization assert_raise(ArgumentError) { new_session('session_id' => '!invalid_id') } new_session do |s| assert_equal Hash.new, s.cache.get('session:' + s.session_id) end end def test_storage d = rand(0xffff) new_session do |s| session_key = 'session:' + s.session_id unless CACHE s.cache.expects(:get).with(session_key) \ .returns(:test => d) s.cache.expects(:set).with(session_key, has_entry(:test, d), 0) end s[:test] = d s.close assert_equal d, s.cache.get(session_key)[:test] assert_equal d, s[:test] end end def test_deletion new_session do |s| session_key = 'session:' + s.session_id unless CACHE s.cache.expects(:delete) s.cache.expects(:get).with(session_key) \ .returns(nil) end s[:test] = rand(0xffff) s.delete assert_nil s.cache.get(session_key) end end def test_other_session_retrieval new_session do |sa| unless CACHE sa.cache.expects(:set).with('session:' + sa.session_id, has_entry(:test, TEST_DATA), 0) end sa[:test] = TEST_DATA sa.close new_session('session_id' => sa.session_id) do |sb| unless CACHE sb.cache.expects(:[]).with('session:' + sb.session_id) \ .returns(:test => TEST_DATA) end assert_equal(TEST_DATA, sb[:test]) end end end def test_multiple_sessions s_slots = Array.new(10) operation = :write last_data = nil reads = writes = 0 50.times do current = rand(10) s_slots[current] ||= new_session('session_id' => MULTI_TEST_KEY, 'new_session' => true) s = s_slots[current] case operation when :write last_data = rand(0xffff) unless CACHE s.cache.expects(:set).with('session:' + MULTI_TEST_KEY, { :test => last_data }, 0) end s[:test] = last_data s.close writes += 1 when :read # Make CGI::Session#[] think there was no data retrieval yet. # Normally, the session caches the data during its lifetime. s.instance_variable_set(:@data, nil) unless CACHE s.cache.expects(:[]).with('session:' + MULTI_TEST_KEY) \ .returns(:test => last_data) end d = s[:test] assert_equal(last_data, d, "OK reads: #{reads}, OK writes: #{writes}") reads += 1 end operation = rand(5) == 0 ? :write : :read end end private def obtain_session_options options = { 'database_manager' => CGI::Session::MemCacheStore, 'session_key' => '_test_app_session' } # if don't have running memcache server we use mock instead unless CACHE options['cache'] = c = mock c.stubs(:[]).with(regexp_matches(SESSION_KEY_RE)) c.stubs(:get).with(regexp_matches(SESSION_KEY_RE)) \ .returns(Hash.new) c.stubs(:add).with(regexp_matches(SESSION_KEY_RE), instance_of(Hash), 0) end options end def new_session(options = {}) with_cgi do |cgi| @options = obtain_session_options.merge(options) session = CGI::Session.new(cgi, @options) yield session if block_given? return session end end def with_cgi ENV['REQUEST_METHOD'] = 'GET' ENV['HTTP_HOST'] = 'example.com' ENV['QUERY_STRING'] = '' cgi = CGI.new('query', StringIO.new('')) yield cgi if block_given? cgi end end end # defined? MemCache end # uses_mocha