mob-dalli 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,170 @@
1
+ require 'helper'
2
+ require 'benchmark'
3
+
4
+ class TestBenchmark < Test::Unit::TestCase
5
+
6
+ def setup
7
+ puts "Testing #{Dalli::VERSION} with #{RUBY_DESCRIPTION}"
8
+ # We'll use a simple @value to try to avoid spending time in Marshal,
9
+ # which is a constant penalty that both clients have to pay
10
+ @value = []
11
+ @marshalled = Marshal.dump(@value)
12
+
13
+ @servers = ['127.0.0.1:19122', 'localhost:19122']
14
+ @key1 = "Short"
15
+ @key2 = "Sym1-2-3::45"*8
16
+ @key3 = "Long"*40
17
+ @key4 = "Medium"*8
18
+ # 5 and 6 are only used for multiget miss test
19
+ @key5 = "Medium2"*8
20
+ @key6 = "Long3"*40
21
+ @counter = 'counter'
22
+ end
23
+
24
+ def test_benchmark
25
+ memcached do
26
+
27
+ Benchmark.bm(31) do |x|
28
+
29
+ n = 2500
30
+
31
+ @m = Dalli::Client.new(@servers)
32
+ x.report("set:plain:dalli") do
33
+ n.times do
34
+ @m.set @key1, @marshalled, 0, :raw => true
35
+ @m.set @key2, @marshalled, 0, :raw => true
36
+ @m.set @key3, @marshalled, 0, :raw => true
37
+ @m.set @key1, @marshalled, 0, :raw => true
38
+ @m.set @key2, @marshalled, 0, :raw => true
39
+ @m.set @key3, @marshalled, 0, :raw => true
40
+ end
41
+ end
42
+
43
+ @m = Dalli::Client.new(@servers)
44
+ x.report("setq:plain:dalli") do
45
+ @m.multi do
46
+ n.times do
47
+ @m.set @key1, @marshalled, 0, :raw => true
48
+ @m.set @key2, @marshalled, 0, :raw => true
49
+ @m.set @key3, @marshalled, 0, :raw => true
50
+ @m.set @key1, @marshalled, 0, :raw => true
51
+ @m.set @key2, @marshalled, 0, :raw => true
52
+ @m.set @key3, @marshalled, 0, :raw => true
53
+ end
54
+ end
55
+ end
56
+
57
+ @m = Dalli::Client.new(@servers)
58
+ x.report("set:ruby:dalli") do
59
+ n.times do
60
+ @m.set @key1, @value
61
+ @m.set @key2, @value
62
+ @m.set @key3, @value
63
+ @m.set @key1, @value
64
+ @m.set @key2, @value
65
+ @m.set @key3, @value
66
+ end
67
+ end
68
+
69
+ @m = Dalli::Client.new(@servers)
70
+ x.report("get:plain:dalli") do
71
+ n.times do
72
+ @m.get @key1, :raw => true
73
+ @m.get @key2, :raw => true
74
+ @m.get @key3, :raw => true
75
+ @m.get @key1, :raw => true
76
+ @m.get @key2, :raw => true
77
+ @m.get @key3, :raw => true
78
+ end
79
+ end
80
+
81
+ @m = Dalli::Client.new(@servers)
82
+ x.report("get:ruby:dalli") do
83
+ n.times do
84
+ @m.get @key1
85
+ @m.get @key2
86
+ @m.get @key3
87
+ @m.get @key1
88
+ @m.get @key2
89
+ @m.get @key3
90
+ end
91
+ end
92
+
93
+ @m = Dalli::Client.new(@servers)
94
+ x.report("multiget:ruby:dalli") do
95
+ n.times do
96
+ # We don't use the keys array because splat is slow
97
+ @m.get_multi @key1, @key2, @key3, @key4, @key5, @key6
98
+ end
99
+ end
100
+
101
+ @m = Dalli::Client.new(@servers)
102
+ x.report("missing:ruby:dalli") do
103
+ n.times do
104
+ begin @m.delete @key1; rescue; end
105
+ begin @m.get @key1; rescue; end
106
+ begin @m.delete @key2; rescue; end
107
+ begin @m.get @key2; rescue; end
108
+ begin @m.delete @key3; rescue; end
109
+ begin @m.get @key3; rescue; end
110
+ end
111
+ end
112
+
113
+ @m = Dalli::Client.new(@servers)
114
+ x.report("mixed:ruby:dalli") do
115
+ n.times do
116
+ @m.set @key1, @value
117
+ @m.set @key2, @value
118
+ @m.set @key3, @value
119
+ @m.get @key1
120
+ @m.get @key2
121
+ @m.get @key3
122
+ @m.set @key1, @value
123
+ @m.get @key1
124
+ @m.set @key2, @value
125
+ @m.get @key2
126
+ @m.set @key3, @value
127
+ @m.get @key3
128
+ end
129
+ end
130
+
131
+ @m = Dalli::Client.new(@servers)
132
+ x.report("mixedq:ruby:dalli") do
133
+ @m.multi do
134
+ n.times do
135
+ @m.set @key1, @value
136
+ @m.set @key2, @value
137
+ @m.set @key3, @value
138
+ @m.get @key1
139
+ @m.get @key2
140
+ @m.get @key3
141
+ @m.set @key1, @value
142
+ @m.get @key1
143
+ @m.set @key2, @value
144
+ @m.replace @key2, @value
145
+ @m.delete @key3
146
+ @m.add @key3, @value
147
+ @m.get @key2
148
+ @m.set @key3, @value
149
+ @m.get @key3
150
+ end
151
+ end
152
+ end
153
+
154
+ @m = Dalli::Client.new(@servers)
155
+ x.report("incr:ruby:dalli") do
156
+ n.times do
157
+ @m.incr @counter, 1, 0, 1
158
+ end
159
+ n.times do
160
+ @m.decr @counter, 1
161
+ end
162
+
163
+ assert_equal 0, @m.incr(@counter, 0)
164
+ end
165
+
166
+ end
167
+ end
168
+
169
+ end
170
+ end
@@ -0,0 +1,39 @@
1
+ $TESTING = true
2
+ require 'rubygems'
3
+ # require 'simplecov'
4
+ # SimpleCov.start
5
+ WANT_RAILS_VERSION = ENV['RAILS_VERSION'] || '>= 3.0.0'
6
+ gem 'rails', WANT_RAILS_VERSION
7
+ require 'rails'
8
+ puts "Testing with Rails #{Rails.version}"
9
+
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+ require 'memcached_mock'
13
+ require 'mocha'
14
+
15
+ require 'dalli'
16
+ require 'logger'
17
+
18
+ Dalli.logger = Logger.new(STDOUT)
19
+ Dalli.logger.level = Logger::ERROR
20
+
21
+ class Test::Unit::TestCase
22
+ include MemcachedMock::Helper
23
+
24
+ def assert_error(error, regexp=nil, &block)
25
+ ex = assert_raise(error, &block)
26
+ assert_match(regexp, ex.message, "#{ex.class.name}: #{ex.message}\n#{ex.backtrace.join("\n\t")}")
27
+ end
28
+
29
+ def with_activesupport
30
+ require 'active_support/all'
31
+ yield
32
+ end
33
+
34
+ def with_actionpack
35
+ require 'action_dispatch'
36
+ require 'action_controller'
37
+ yield
38
+ end
39
+ end
@@ -0,0 +1,126 @@
1
+ require "socket"
2
+
3
+ $started = {}
4
+
5
+ module MemcachedMock
6
+ def self.start(port=19123, &block)
7
+ server = TCPServer.new("localhost", port)
8
+ session = server.accept
9
+ block.call session
10
+ end
11
+
12
+ def self.delayed_start(port=19123, wait=1, &block)
13
+ server = TCPServer.new("localhost", port)
14
+ sleep wait
15
+ block.call server
16
+ end
17
+
18
+ def self.tmp_socket_path
19
+ "#{Dir.pwd}/tmp.sock"
20
+ end
21
+
22
+ module Helper
23
+ # Forks the current process and starts a new mock Memcached server on
24
+ # port 22122.
25
+ #
26
+ # memcached_mock(lambda {|sock| socket.write('123') }) do
27
+ # assert_equal "PONG", Dalli::Client.new('localhost:22122').get('abc')
28
+ # end
29
+ #
30
+ def memcached_mock(proc, meth = :start)
31
+ return unless supports_fork?
32
+ begin
33
+ pid = fork do
34
+ trap("TERM") { exit }
35
+
36
+ MemcachedMock.send(meth) do |*args|
37
+ proc.call(*args)
38
+ end
39
+ end
40
+
41
+ sleep 0.3 # Give time for the socket to start listening.
42
+ yield
43
+ ensure
44
+ if pid
45
+ Process.kill("TERM", pid)
46
+ Process.wait(pid)
47
+ end
48
+ end
49
+ end
50
+
51
+ PATHS = %w(
52
+ /usr/local/bin/
53
+ /opt/local/bin/
54
+ /usr/bin/
55
+ )
56
+
57
+ def find_memcached
58
+ output = `memcached -h | head -1`.strip
59
+ if output && output =~ /^memcached (\d.\d.\d+)/ && $1 > '1.4'
60
+ return (puts "Found #{output} in PATH"; '')
61
+ end
62
+ PATHS.each do |path|
63
+ output = `memcached -h | head -1`.strip
64
+ if output && output =~ /^memcached (\d\.\d\.\d+)/ && $1 > '1.4'
65
+ return (puts "Found #{output} in #{path}"; path)
66
+ end
67
+ end
68
+
69
+ raise Errno::ENOENT, "Unable to find memcached 1.4+ locally"
70
+ nil
71
+ end
72
+
73
+ def memcached(port=19122, args='', options={})
74
+ return unless supports_fork?
75
+ Memcached.path ||= find_memcached
76
+
77
+ cmd = if options[:unix]
78
+ "#{Memcached.path}memcached #{args} -s #{MemcachedMock.tmp_socket_path}"
79
+ else
80
+ "#{Memcached.path}memcached #{args} -p #{port}"
81
+ end
82
+
83
+ $started[port] ||= begin
84
+ #puts "Starting: #{cmd}..."
85
+ pid = IO.popen(cmd).pid
86
+ at_exit do
87
+ begin
88
+ Process.kill("TERM", pid)
89
+ Process.wait(pid)
90
+ File.delete(MemcachedMock.tmp_socket_path) if options[:unix]
91
+ rescue Errno::ECHILD, Errno::ESRCH
92
+ end
93
+ end
94
+ sleep 0.1
95
+ pid
96
+ end
97
+ if options[:unix]
98
+ yield Dalli::Client.new(MemcachedMock.tmp_socket_path)
99
+ else
100
+ yield Dalli::Client.new(["localhost:#{port}", "127.0.0.1:#{port}"], options)
101
+ end
102
+ end
103
+
104
+ def supports_fork?
105
+ !defined?(RUBY_ENGINE) || RUBY_ENGINE != 'jruby'
106
+ end
107
+
108
+ def memcached_kill(port)
109
+ pid = $started.delete(port)
110
+ if pid
111
+ begin
112
+ Process.kill("TERM", pid)
113
+ Process.wait(pid)
114
+ rescue Errno::ECHILD, Errno::ESRCH
115
+ end
116
+ end
117
+ end
118
+
119
+ end
120
+ end
121
+
122
+ module Memcached
123
+ class << self
124
+ attr_accessor :path
125
+ end
126
+ end
@@ -0,0 +1,201 @@
1
+ # encoding: utf-8
2
+ require 'helper'
3
+
4
+ class TestActiveSupport < Test::Unit::TestCase
5
+ context 'active_support caching' do
6
+
7
+ should 'support fetch' do
8
+ with_activesupport do
9
+ memcached do
10
+ connect
11
+ mvalue = @mc.fetch('somekeywithoutspaces', :expires_in => 1.second) { 123 }
12
+ dvalue = @dalli.fetch('someotherkeywithoutspaces', :expires_in => 1.second) { 123 }
13
+ assert_equal 123, dvalue
14
+ assert_equal mvalue, dvalue
15
+
16
+ o = Object.new
17
+ o.instance_variable_set :@foo, 'bar'
18
+ mvalue = @mc.fetch(rand_key, :raw => true) { o }
19
+ dvalue = @dalli.fetch(rand_key, :raw => true) { o }
20
+ assert_equal mvalue, dvalue
21
+ assert_equal o, mvalue
22
+
23
+ mvalue = @mc.fetch(rand_key) { o }
24
+ dvalue = @dalli.fetch(rand_key) { o }
25
+ assert_equal mvalue, dvalue
26
+ assert_equal o, dvalue
27
+ end
28
+ end
29
+ end
30
+
31
+ should 'support keys with spaces on Rails3' do
32
+ with_activesupport do
33
+ memcached do
34
+ connect
35
+ dvalue = @mc.fetch('some key with spaces', :expires_in => 1.second) { 123 }
36
+ mvalue = @dalli.fetch('some other key with spaces', :expires_in => 1.second) { 123 }
37
+ assert_equal mvalue, dvalue
38
+ end
39
+ end
40
+ end
41
+
42
+ should 'support read_multi' do
43
+ with_activesupport do
44
+ memcached do
45
+ connect
46
+ x = rand_key
47
+ y = rand_key
48
+ assert_equal({}, @mc.read_multi(x, y))
49
+ assert_equal({}, @dalli.read_multi(x, y))
50
+ @dalli.write(x, '123')
51
+ @dalli.write(y, 123)
52
+ @mc.write(x, '123')
53
+ @mc.write(y, 123)
54
+ assert_equal({ x => '123', y => 123 }, @dalli.read_multi(x, y))
55
+ assert_equal({ x => '123', y => 123 }, @mc.read_multi(x, y))
56
+ end
57
+ end
58
+ end
59
+
60
+ should 'support read_multi with an array' do
61
+ with_activesupport do
62
+ memcached do
63
+ connect
64
+ x = rand_key
65
+ y = rand_key
66
+ assert_equal({}, @mc.read_multi([x, y]))
67
+ assert_equal({}, @dalli.read_multi([x, y]))
68
+ @dalli.write(x, '123')
69
+ @dalli.write(y, 123)
70
+ @mc.write(x, '123')
71
+ @mc.write(y, 123)
72
+ assert_equal({ x => '123', y => 123 }, @dalli.read_multi([x, y]))
73
+ assert_equal({}, @mc.read_multi([x,y]))
74
+ end
75
+ end
76
+ end
77
+
78
+ should 'support raw read_multi' do
79
+ with_activesupport do
80
+ memcached do
81
+ connect
82
+ @mc.write("abc", 5, :raw => true)
83
+ @mc.write("cba", 5, :raw => true)
84
+ assert_equal({'abc' => '5', 'cba' => '5' }, @mc.read_multi("abc", "cba"))
85
+
86
+ @dalli.write("abc", 5, :raw => true)
87
+ @dalli.write("cba", 5, :raw => true)
88
+ assert_equal({'abc' => '5', 'cba' => '5' }, @dalli.read_multi("abc", "cba"))
89
+ end
90
+ end
91
+ end
92
+
93
+ should 'support read, write and delete' do
94
+ with_activesupport do
95
+ memcached do
96
+ connect
97
+ x = rand_key
98
+ y = rand_key
99
+ assert_nil @mc.read(x)
100
+ assert_nil @dalli.read(y)
101
+ mres = @mc.write(x, 123)
102
+ dres = @dalli.write(y, 123)
103
+ assert_equal mres, dres
104
+
105
+ mres = @mc.read(x)
106
+ dres = @dalli.read(y)
107
+ assert_equal mres, dres
108
+ assert_equal 123, dres
109
+
110
+ mres = @mc.delete(x)
111
+ dres = @dalli.delete(y)
112
+ assert_equal mres, dres
113
+ assert_equal true, dres
114
+ end
115
+ end
116
+ end
117
+
118
+ should 'support increment/decrement commands' do
119
+ with_activesupport do
120
+ memcached do
121
+ connect
122
+ assert_equal true, @mc.write('counter', 0, :raw => true)
123
+ assert_equal 1, @mc.increment('counter')
124
+ assert_equal 2, @mc.increment('counter')
125
+ assert_equal 1, @mc.decrement('counter')
126
+ assert_equal "1", @mc.read('counter', :raw => true)
127
+
128
+ assert_equal true, @dalli.write('counter', 0, :raw => true)
129
+ assert_equal 1, @dalli.increment('counter')
130
+ assert_equal 2, @dalli.increment('counter')
131
+ assert_equal 1, @dalli.decrement('counter')
132
+ assert_equal "1", @dalli.read('counter', :raw => true)
133
+
134
+ assert_equal 0, @mc.increment('counterX')
135
+ assert_equal 0, @mc.increment('counterX')
136
+ assert_equal nil, @mc.read('counterX')
137
+
138
+ assert_equal 1, @dalli.increment('counterX')
139
+ assert_equal 2, @dalli.increment('counterX')
140
+ assert_equal 2, @dalli.read('counterX', :raw => true).to_i
141
+ end
142
+ end
143
+ end
144
+
145
+ should 'support other esoteric commands' do
146
+ with_activesupport do
147
+ memcached do
148
+ connect
149
+ ms = @mc.stats
150
+ ds = @dalli.stats
151
+ assert_equal ms.keys.sort, ds.keys.sort
152
+ assert_equal ms[ms.keys.first].keys.sort, ds[ds.keys.first].keys.sort
153
+
154
+ assert_equal true, @dalli.write(:foo, 'a')
155
+ assert_equal true, @mc.write(:foo, 'a')
156
+
157
+ assert_equal true, @mc.exist?(:foo)
158
+ assert_equal true, @dalli.exist?(:foo)
159
+
160
+ assert_equal false, @mc.exist?(:bar)
161
+ assert_equal false, @dalli.exist?(:bar)
162
+
163
+ @dalli.reset
164
+ end
165
+ end
166
+ end
167
+ end
168
+
169
+ should 'handle crazy characters from far-away lands' do
170
+ with_activesupport do
171
+ memcached do
172
+ connect
173
+ key = "fooƒ"
174
+ value = 'bafƒ'
175
+ # assert_equal true, @mc.write(key, value)
176
+ assert_equal true, @dalli.write(key, value)
177
+ # assert_equal true, @mc.read(key, value)
178
+ assert_equal value, @dalli.read(key)
179
+ end
180
+ end
181
+ end
182
+
183
+ should 'normalize options as expected' do
184
+ with_activesupport do
185
+ memcached do
186
+ @dalli = ActiveSupport::Cache::DalliStore.new('localhost:19122', :expires_in => 1, :race_condition_ttl => 1)
187
+ assert_equal 2, @dalli.instance_variable_get(:@data).instance_variable_get(:@options)[:expires_in]
188
+ end
189
+ end
190
+ end
191
+
192
+ def connect
193
+ @dalli = ActiveSupport::Cache.lookup_store(:dalli_store, 'localhost:19122', :expires_in => 10.seconds, :namespace => 'x')
194
+ @mc = ActiveSupport::Cache.lookup_store(:mem_cache_store, 'localhost:19122', :expires_in => 10.seconds, :namespace => 'a')
195
+ @dalli.clear
196
+ end
197
+
198
+ def rand_key
199
+ rand(1_000_000_000)
200
+ end
201
+ end