Ruby-MemCache 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,226 @@
1
+ #!/usr/bin/ruby -w
2
+ #
3
+ # Unit test for instantiation of MemCache objects
4
+ # $Id: instantiation.tests.rb 12 2004-10-03 21:04:34Z ged $
5
+ #
6
+ # Copyright (c) 2004 RubyCrafters, LLC. Most rights reserved.
7
+ #
8
+ # This work is licensed under the Creative Commons Attribution-ShareAlike
9
+ # License. To view a copy of this license, visit
10
+ # http://creativecommons.org/licenses/by-sa/1.0/ or send a letter to Creative
11
+ # Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
12
+ #
13
+ #
14
+
15
+ unless defined? MemCache::TestCase
16
+ testsdir = File::dirname( File::expand_path(__FILE__) )
17
+ basedir = File::dirname( testsdir )
18
+ $LOAD_PATH.unshift "#{basedir}/lib" unless
19
+ $LOAD_PATH.include?( "#{basedir}/lib" )
20
+ $LOAD_PATH.unshift "#{basedir}/tests" unless
21
+ $LOAD_PATH.include?( "#{basedir}/tests" )
22
+
23
+ require 'mctestcase'
24
+ end
25
+
26
+
27
+ ### Collection of tests for the instantiation class.
28
+ class InstantiationTestCase < MemCache::TestCase
29
+
30
+
31
+ TestServerSets = {
32
+ :simple => [
33
+ {
34
+ :name => 'One IP (unweighted)',
35
+ :servers => %w[ 127.0.0.1 ],
36
+ },
37
+ {
38
+ :name => 'Two IPs (unweighted)',
39
+ :servers => %w[ 127.0.0.1 10.1.0.1 ],
40
+ },
41
+ ],
42
+
43
+ :weighted => [
44
+ {
45
+ :name => 'One IP (weighted)',
46
+ :servers => [['127.0.0.1', 1]],
47
+ },
48
+ {
49
+ :name => 'Two IPs (weighted)',
50
+ :servers => [['127.0.0.1', 1], ['10.1.0.1', 2]],
51
+ },
52
+ ],
53
+
54
+ :ports => [
55
+ {
56
+ :name => 'One IP (w/port)',
57
+ :servers => %w[ 127.0.0.1:11211 ]
58
+ },
59
+ {
60
+ :name => 'Two IPs (w/ports)',
61
+ :servers => %w[ 127.0.0.1:123123 10.1.0.1:11292 ],
62
+ },
63
+ ],
64
+
65
+ :weighted_ports => [
66
+ {
67
+ :name => 'One IP (weighted w/port)',
68
+ :servers => [['127.0.0.1:11001', 1]],
69
+ },
70
+ {
71
+ :name => 'Two IPs (weighted w/ports)',
72
+ :servers => [['127.0.0.1:11211', 1], ['10.1.0.11:11320', 2]],
73
+ },
74
+ ],
75
+
76
+ :with_opts => [
77
+ {
78
+ :name => 'One IP (weighted w/port)',
79
+ :servers => [['127.0.0.1:11001', 1]],
80
+ :opts => { :compression => true },
81
+ },
82
+ {
83
+ :name => 'Two IPs (weighted w/ports)',
84
+ :servers => [['127.0.0.1:11211', 1], ['10.1.0.11:11320', 2]],
85
+ :opts => { :compression => true },
86
+ },
87
+ ],
88
+ }
89
+
90
+ #################################################################
91
+ ### T E S T S
92
+ #################################################################
93
+
94
+ ### Instantiate with no args
95
+ def test_00_no_args
96
+ printTestHeader "Instantiation: No-args construction"
97
+ rval = cache = nil
98
+
99
+ assert_nothing_raised { cache = MemCache::new }
100
+ assert_instance_of MemCache, cache
101
+
102
+ assert_nothing_raised { rval = cache.servers }
103
+ assert_instance_of Array, rval
104
+ assert_equal 0, rval.nitems
105
+ end
106
+
107
+
108
+ ### Instantiate with one or more server args
109
+ def test_01_with_servers
110
+ printTestHeader "Instantiation: Server args"
111
+ rval = cache = nil
112
+
113
+ TestServerSets.each {|key, sets|
114
+ sets.each do |set|
115
+ debugMsg "Testing #{key} sets"
116
+
117
+ # Instantiate with various args specified by the set
118
+ if set.key?( :opts )
119
+ args = set[:servers].dup
120
+ args.push( set[:opts] )
121
+ assert_nothing_raised( set[:name] ) {
122
+ cache = MemCache::new( *args )
123
+ }
124
+ else
125
+ assert_nothing_raised( set[:name] ) {
126
+ cache = MemCache::new( *(set[:servers]) )
127
+ }
128
+ end
129
+
130
+ assert_instance_of MemCache, cache
131
+
132
+ # Check to be sure we can get the server list back out
133
+ assert_nothing_raised { rval = cache.servers }
134
+ assert_instance_of Array, rval
135
+ assert_equal set[:servers].nitems, rval.nitems
136
+
137
+ # Test the #active method while we're at it
138
+ assert_nothing_raised { rval = cache.active? }
139
+ assert_equal true, rval
140
+ end
141
+ }
142
+ end
143
+
144
+
145
+ ### Compression option
146
+ def test_10_compression_opt
147
+ printTestHeader "Instantiation: Compression option"
148
+ rval = cache = nil
149
+
150
+ # Test getter with default value
151
+ cache = MemCache::new
152
+ assert_nothing_raised { rval = cache.compression }
153
+ assert_equal true, rval
154
+
155
+ # Test setting via constructor and getter
156
+ assert_nothing_raised { cache = MemCache::new(:compression => false) }
157
+ assert_nothing_raised { rval = cache.compression }
158
+ assert_equal false, rval
159
+ end
160
+
161
+
162
+ ### Compression threshold option
163
+ def test_20_compression_threshold_opt
164
+ printTestHeader "Instantiation: Compression threshold option"
165
+ rval = cache = nil
166
+
167
+ # Test getter with default value
168
+ cache = MemCache::new
169
+ assert_nothing_raised { rval = cache.c_threshold }
170
+ assert_equal MemCache::DefaultCThreshold, rval
171
+
172
+ # Test setting via constructor with various sizes and getter
173
+ 16.times do |factor|
174
+ thresh = 2 ** factor
175
+
176
+ assert_nothing_raised { cache = MemCache::new(:c_threshold => thresh) }
177
+ assert_nothing_raised { rval = cache.c_threshold }
178
+ assert_equal thresh, rval
179
+ assert_nothing_raised { cache.c_threshold = 2 ** (factor-1) }
180
+ end
181
+ end
182
+
183
+
184
+ ### Compression option
185
+ def test_30_debug_opt
186
+ printTestHeader "Instantiation: Debug option"
187
+ rval = cache = nil
188
+
189
+ # Test default value and getter
190
+ cache = MemCache::new
191
+ assert_nothing_raised { rval = cache.debug }
192
+ assert_equal false, rval
193
+
194
+ # Test <<-style debugging object (String)
195
+ rval = ''
196
+ assert_nothing_raised { cache = MemCache::new(:debug => rval) }
197
+ assert_nothing_raised {
198
+ cache.servers = TestServerSets[:simple][0][:servers]
199
+ }
200
+ assert !rval.empty?, "Rval should not be empty"
201
+ assert_match( /Transforming/, rval )
202
+
203
+ # Test <<-style debugging object (Array)
204
+ rval = []
205
+ assert_nothing_raised { cache = MemCache::new(:debug => rval) }
206
+ assert_nothing_raised {
207
+ cache.servers = TestServerSets[:simple][0][:servers]
208
+ }
209
+ assert !rval.empty?, "Rval should not be empty"
210
+ assert_match( /Transforming/, rval[0] )
211
+
212
+ # Test call-style debugging object (Proc)
213
+ rval = ''
214
+ func = lambda {|msg| rval << msg }
215
+ assert_nothing_raised { cache = MemCache::new(:debug => func) }
216
+ assert_nothing_raised {
217
+ cache.servers = TestServerSets[:simple][0][:servers]
218
+ }
219
+ assert !rval.empty?, "Rval should not be empty"
220
+ assert_match( /Transforming/, rval )
221
+
222
+ end
223
+
224
+ end
225
+
226
+
@@ -0,0 +1,379 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # This is an abstract test case class for building Test::Unit unit tests for the
4
+ # MemCache module. It consolidates most of the maintenance work that must be
5
+ # done to build a test file by adjusting the $LOAD_PATH appropriately, as well
6
+ # as adding some other useful methods that make building and maintaining the
7
+ # tests much easier (IMHO). See the docs for Test::Unit for more info on the
8
+ # particulars of unit testing.
9
+ #
10
+ # == Synopsis
11
+ #
12
+ # # Allow the unit test to be run from the base dir, or from tests/ or
13
+ # # similar:
14
+ # begin
15
+ # require 'tests/mctestcase'
16
+ # rescue
17
+ # require '../mctestcase'
18
+ # end
19
+ #
20
+ # class MySomethingTest < MemCache::TestCase
21
+ # def setup
22
+ # super()
23
+ # @foo = 'bar'
24
+ # end
25
+ #
26
+ # def test_00_something
27
+ # obj = nil
28
+ # assert_nothing_raised { obj = MySomething::new }
29
+ # assert_instance_of MySomething, obj
30
+ # assert_respond_to :myMethod, obj
31
+ # end
32
+ # end
33
+ #
34
+ # == Subversion ID
35
+ #
36
+ # $Id: mctestcase.rb 29 2004-11-13 17:31:44Z ged $
37
+ #
38
+ # == Authors
39
+ #
40
+ # * Michael Granger <ged@FaerieMUD.org>
41
+ #
42
+ #:include: COPYRIGHT
43
+ #
44
+ #---
45
+ #
46
+ # Please see the file COPYRIGHT in the 'docs' directory for licensing details.
47
+ #
48
+
49
+ begin
50
+ basedir = File::dirname( File::dirname(__FILE__) )
51
+ unless $LOAD_PATH.include?( "#{basedir}/lib" )
52
+ $LOAD_PATH.unshift "#{basedir}/lib"
53
+ end
54
+ end
55
+
56
+ require 'test/unit'
57
+ require 'memcache'
58
+
59
+ class MemCache::TestCase < Test::Unit::TestCase
60
+
61
+ # The name of the file containing marshalled configuration values
62
+ ConfigSaveFile = "test.cfg"
63
+
64
+ @methodCounter = 0
65
+ @setupBlocks = []
66
+ @teardownBlocks = []
67
+ class << self
68
+ attr_accessor :methodCounter, :setupBlocks, :teardownBlocks
69
+ end
70
+
71
+
72
+ ### Inheritance callback -- adds @setupBlocks and @teardownBlocks ivars
73
+ ### and accessors to the inheriting class.
74
+ def self::inherited( klass )
75
+ klass.module_eval {
76
+ @setupBlocks = []
77
+ @teardownBlocks = []
78
+
79
+ class << self
80
+ attr_accessor :setupBlocks, :teardownBlocks
81
+ end
82
+ }
83
+ klass.methodCounter = 0
84
+ end
85
+
86
+
87
+
88
+ ### Output the specified <tt>msgs</tt> joined together to
89
+ ### <tt>STDERR</tt> if <tt>$DEBUG</tt> is set.
90
+ def self::debugMsg( *msgs )
91
+ return unless $DEBUG
92
+ self.message "DEBUG>>> %s" % msgs.join('')
93
+ end
94
+
95
+ ### Output the specified <tt>msgs</tt> joined together to
96
+ ### <tt>STDOUT</tt>.
97
+ def self::message( *msgs )
98
+ $stderr.puts msgs.join('')
99
+ $stderr.flush
100
+ end
101
+
102
+
103
+ ### Add a setup block for the current testcase
104
+ def self::addSetupBlock( &block )
105
+ self.methodCounter += 1
106
+ newMethodName = "setup_#{self.methodCounter}".intern
107
+ define_method( newMethodName, &block )
108
+ self.setupBlocks.push newMethodName
109
+ end
110
+
111
+ ### Add a teardown block for the current testcase
112
+ def self::addTeardownBlock( &block )
113
+ self.methodCounter += 1
114
+ newMethodName = "teardown_#{self.methodCounter}".intern
115
+ define_method( newMethodName, &block )
116
+ self.teardownBlocks.unshift newMethodName
117
+ end
118
+
119
+
120
+ #############################################################
121
+ ### I N S T A N C E M E T H O D S
122
+ #############################################################
123
+
124
+ def initialize( *args )
125
+ if $Memcached
126
+ # If there's no readable config file, prompt the user for configuration
127
+ # values and make sure the logs are present and empty.
128
+ unless File::readable?( ConfigSaveFile )
129
+ File::open(ConfigSaveFile, File::CREAT|File::TRUNC|File::WRONLY) {|ofh|
130
+ config = self.promptForConfigValues()
131
+ Marshal::dump( config, ofh )
132
+ }
133
+ end
134
+
135
+ File::open( ConfigSaveFile, File::RDONLY ) {|ifh|
136
+ @config = Marshal::load( ifh )
137
+ }
138
+
139
+
140
+ # If the user said to skip when prompted, kill the config object.
141
+ @config = nil if @config[:server] == :skip
142
+ else
143
+ @config = nil
144
+ end
145
+
146
+ super
147
+ rescue => e
148
+ File::unlink( ConfigSaveFile ) if File::exists?( ConfigSaveFile )
149
+ Kernel::raise( e )
150
+ end
151
+
152
+
153
+ ### Prompt the user with the given <tt>promptString</tt> via #prompt, or
154
+ ### #promptWithDefault if a default is given, and return the answer after
155
+ ### testing to make sure it's been filled. If it has not, a RuntimeError is
156
+ ### raised.
157
+ def promptForRequiredValue( promptString, default=nil )
158
+ res = nil
159
+
160
+ if default
161
+ res = promptWithDefault( promptString, default )
162
+ else
163
+ res = prompt( promptString )
164
+ end
165
+
166
+ if res.nil? || res.empty?
167
+ raise RuntimeError,
168
+ "Cannot test: missing required config value"
169
+ end
170
+
171
+ return res
172
+ end
173
+
174
+
175
+ ### Prompt for configuration values
176
+ def promptForConfigValues
177
+ puts "The test suite can run quite a lot of tests against ",
178
+ "a real memcache server, if you have one running."
179
+ ans = promptWithDefault( "Do you want to run these tests?", "y" )
180
+
181
+ unless /^y/i.match( ans )
182
+ return { :server => :skip }
183
+ end
184
+
185
+ config = {}
186
+ config[:server] =
187
+ promptForRequiredValue( "Memcached host or ip", "localhost" )
188
+ config[:port] =
189
+ promptForRequiredValue( "Memcached port", "11211" )
190
+
191
+ return config
192
+ end
193
+
194
+
195
+ ### A dummy test method to allow this Test::Unit::TestCase to be
196
+ ### subclassed without complaining about the lack of tests.
197
+ def test_0_dummy
198
+ end
199
+
200
+
201
+ ### Forward-compatibility method for namechange in Test::Unit
202
+ def setup( *args )
203
+ self.class.setupBlocks.each {|sblock|
204
+ debugMsg "Calling setup block method #{sblock}"
205
+ self.send( sblock )
206
+ }
207
+ super( *args )
208
+ end
209
+ alias_method :set_up, :setup
210
+
211
+
212
+ ### Forward-compatibility method for namechange in Test::Unit
213
+ def teardown( *args )
214
+ super( *args )
215
+ self.class.teardownBlocks.each {|tblock|
216
+ debugMsg "Calling teardown block method #{tblock}"
217
+ self.send( tblock )
218
+ }
219
+ end
220
+ alias_method :tear_down, :teardown
221
+
222
+
223
+ ### Skip the current step (called from #setup) with the +reason+ given.
224
+ def skip( reason=nil )
225
+ if reason
226
+ msg = "Skipping %s: %s" % [ @method_name, reason ]
227
+ else
228
+ msg = "Skipping %s: No reason given." % @method_name
229
+ end
230
+
231
+ $stderr.puts( msg ) if $VERBOSE
232
+ @method_name = :skipped_test
233
+ end
234
+
235
+
236
+ def skipped_test # :nodoc:
237
+ end
238
+
239
+
240
+ ### Add the specified +block+ to the code that gets executed by #setup.
241
+ def addSetupBlock( &block ); self.class.addSetupBlock( &block ); end
242
+
243
+
244
+ ### Add the specified +block+ to the code that gets executed by #teardown.
245
+ def addTeardownBlock( &block ); self.class.addTeardownBlock( &block ); end
246
+
247
+
248
+ ### Instance alias for the like-named class method.
249
+ def message( *msgs )
250
+ self.class.message( *msgs )
251
+ end
252
+
253
+
254
+ ### Instance alias for the like-named class method
255
+ def debugMsg( *msgs )
256
+ self.class.debugMsg( *msgs )
257
+ end
258
+
259
+
260
+ ### Output a separator line made up of <tt>length</tt> of the specified
261
+ ### <tt>char</tt>.
262
+ def writeLine( length=75, char="-" )
263
+ $stderr.puts "\r" + (char * length )
264
+ end
265
+
266
+
267
+ ### Output a header for delimiting tests
268
+ def printTestHeader( desc )
269
+ return unless $VERBOSE || $DEBUG
270
+ message ">>> %s <<<" % desc
271
+ end
272
+
273
+
274
+ ### Try to force garbage collection to start.
275
+ def collectGarbage
276
+ a = []
277
+ 1000.times { a << {} }
278
+ a = nil
279
+ GC.start
280
+ end
281
+
282
+
283
+ ### Output the name of the test as it's running if in verbose mode.
284
+ def run( result )
285
+ $stderr.puts self.name if $VERBOSE || $DEBUG
286
+
287
+ # Support debugging for individual tests
288
+ olddb = nil
289
+ if $DebugPattern && $DebugPattern =~ @method_name
290
+ olddb = $DEBUG
291
+ $DEBUG = true
292
+ end
293
+
294
+ super
295
+
296
+ $DEBUG = olddb unless olddb.nil?
297
+ end
298
+
299
+
300
+ #############################################################
301
+ ### E X T R A A S S E R T I O N S
302
+ #############################################################
303
+
304
+ ### Negative of assert_respond_to
305
+ def assert_not_respond_to( obj, meth )
306
+ msg = "%s expected NOT to respond to '%s'" %
307
+ [ obj.inspect, meth ]
308
+ assert_block( msg ) {
309
+ !obj.respond_to?( meth )
310
+ }
311
+ rescue Test::Unit::AssertionFailedError => err
312
+ cutframe = err.backtrace.reverse.find {|frame|
313
+ /assert_not_respond_to/ =~ frame
314
+ }
315
+ firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
316
+ Kernel::raise( err, err.message, err.backtrace[firstIdx..-1] )
317
+ end
318
+
319
+
320
+ ### Assert that the instance variable specified by +sym+ of an +object+
321
+ ### is equal to the specified +value+. The '@' at the beginning of the
322
+ ### +sym+ will be prepended if not present.
323
+ def assert_ivar_equal( value, object, sym )
324
+ sym = "@#{sym}".intern unless /^@/ =~ sym.to_s
325
+ msg = "Instance variable '%s'\n\tof <%s>\n\texpected to be <%s>\n" %
326
+ [ sym, object.inspect, value.inspect ]
327
+ msg += "\tbut was: <%s>" % object.instance_variable_get(sym)
328
+ assert_block( msg ) {
329
+ value == object.instance_variable_get(sym)
330
+ }
331
+ rescue Test::Unit::AssertionFailedError => err
332
+ cutframe = err.backtrace.reverse.find {|frame|
333
+ /assert_ivar_equal/ =~ frame
334
+ }
335
+ firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
336
+ Kernel::raise( err, err.message, err.backtrace[firstIdx..-1] )
337
+ end
338
+
339
+
340
+ ### Assert that the specified +object+ has an instance variable which
341
+ ### matches the specified +sym+. The '@' at the beginning of the +sym+
342
+ ### will be prepended if not present.
343
+ def assert_has_ivar( sym, object )
344
+ sym = "@#{sym}" unless /^@/ =~ sym.to_s
345
+ msg = "Object <%s> expected to have an instance variable <%s>" %
346
+ [ object.inspect, sym ]
347
+ assert_block( msg ) {
348
+ object.instance_variables.include?( sym.to_s )
349
+ }
350
+ rescue Test::Unit::AssertionFailedError => err
351
+ cutframe = err.backtrace.reverse.find {|frame|
352
+ /assert_has_ivar/ =~ frame
353
+ }
354
+ firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
355
+ Kernel::raise( err, err.message, err.backtrace[firstIdx..-1] )
356
+ end
357
+
358
+
359
+ ### Assert that the specified +object+ is either nil or equal (via #eql?) to
360
+ ### the given +value+. This is to test return values from the cache, which
361
+ ### should return either the original value or +nil+ if the value has
362
+ ### expired from the cache.
363
+ def assert_nil_or_equal( value, object, msg="" )
364
+ msg += "\n" unless msg.empty?
365
+ msg += "Object <%p> expected to be nil or equal to <%p>" %
366
+ [ object, value ]
367
+ assert_block( msg ) {
368
+ object.nil? || object.eql?( value )
369
+ }
370
+ rescue Test::Unit::AssertionFailedError => err
371
+ cutframe = err.backtrace.reverse.find {|frame|
372
+ /assert_nil_or_equal/ =~ frame
373
+ }
374
+ firstIdx = (err.backtrace.rindex( cutframe )||0) + 1
375
+ Kernel::raise( err, err.message, err.backtrace[firstIdx..-1] )
376
+ end
377
+
378
+ end # class MemCache::TestCase
379
+