Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 193
- Log:
First stage commit of Typo 4.1, modified for the ROOL site.
Includes all local modifications but a final pass needs to be
made to delete any files left over from earlier Typo versions
that shouldn't be here anymore. See the 'tags' section of the
repository for a clean Typo 4.1 tree.Note that symlinks to shared files in the RISC OS Open theme
directory have been deliberately included this time around; I
decided that on balance it was better to leave them in as
placeholders, since unlike symlinks in app/views/shared, the
Typo theme structure is not a standard Rails concept.
- Author:
- rool
- Date:
- Wed Apr 04 18:51:02 +0100 2007
- Size:
- 13807 Bytes
1 | require 'rubygems' |
2 | require 'test/unit' |
3 | require 'test/zentest_assertions' |
4 | |
5 | $TESTING = true |
6 | $TESTING_CM = true |
7 | |
8 | RAILS_ENV = 'production' |
9 | |
10 | module Rails; end |
11 | module Rails::VERSION |
12 | MAJOR = 1 |
13 | MINOR = 1 |
14 | TINY = 2 |
15 | end |
16 | |
17 | module ActiveRecord; end |
18 | |
19 | class ActiveRecord::Base |
20 | |
21 | @count = 1000 |
22 | |
23 | attr_accessor :id, :attributes |
24 | |
25 | def self.abstract_class=(arg) |
26 | @abstract_class = arg |
27 | end |
28 | |
29 | def self.abstract_class? |
30 | @abstract_class ||= false |
31 | return !!@abstract_class |
32 | end |
33 | |
34 | ## |
35 | # Need doco, blech |
36 | |
37 | def self.find(*args) |
38 | args.flatten! |
39 | case args.first |
40 | when :first then |
41 | return find(:all, *args).first |
42 | when :all then |
43 | return find_by_sql("SELECT * FROM #{table_name} WHERE (#{table_name}.#{primary_key} = '#{args.last}') LIMIT 1") |
44 | else |
45 | case args.length |
46 | when 1 then |
47 | return find(:first, *args) if Fixnum === args.first |
48 | raise "Dunno what to do" |
49 | when 2 then |
50 | return find(args.first) if Hash === args.last |
51 | return new |
52 | when 3 then |
53 | return [new, new, new] |
54 | else |
55 | raise "Dunno what to do" |
56 | end |
57 | end |
58 | end |
59 | |
60 | def self.find_by_sql(query) |
61 | return [] if query =~ /concrete\.id = -1/ |
62 | return [new] |
63 | end |
64 | |
65 | def self.next_id |
66 | @count += 1 |
67 | return @count |
68 | end |
69 | |
70 | def self.table_name |
71 | name.downcase |
72 | end |
73 | |
74 | def self.transaction(*a) |
75 | yield |
76 | end |
77 | |
78 | def self.primary_key |
79 | 'id' |
80 | end |
81 | |
82 | def initialize |
83 | @id = ActiveRecord::Base.next_id |
84 | @attributes = { :data => 'data' } |
85 | end |
86 | |
87 | def ==(other) |
88 | self.class == other.class and |
89 | id == other.id and |
90 | attributes_before_type_cast == other.attributes_before_type_cast |
91 | end |
92 | |
93 | def attributes_before_type_cast |
94 | { :data => @attributes[:data] } |
95 | end |
96 | |
97 | def destroy |
98 | end |
99 | |
100 | def reload |
101 | @attributes[:data].succ! |
102 | @attributes[:extra] = nil |
103 | end |
104 | |
105 | def save |
106 | update |
107 | end |
108 | |
109 | def transaction(*a, &b) |
110 | self.class.transaction(*a, &b) |
111 | end |
112 | |
113 | def update |
114 | end |
115 | |
116 | end |
117 | |
118 | require 'cached_model' |
119 | |
120 | class Concrete < CachedModel; end |
121 | class STILameness < Concrete; end |
122 | |
123 | module Cache |
124 | |
125 | @cache = {} |
126 | @ttl = {} |
127 | |
128 | class << self; attr_accessor :cache, :ttl; end |
129 | |
130 | def self.delete(key) |
131 | @cache.delete key |
132 | @ttl.delete key |
133 | return nil |
134 | end |
135 | |
136 | def self.get(key) |
137 | @cache[key] |
138 | end |
139 | |
140 | def self.put(key, value, ttl) |
141 | value = Marshal.load Marshal.dump(value) |
142 | @cache[key] = value |
143 | @ttl[key] = ttl |
144 | end |
145 | |
146 | end |
147 | |
148 | class << CachedModel |
149 | |
150 | attr_writer :cache_local |
151 | attr_writer :cache_delay_commit |
152 | |
153 | end |
154 | |
155 | class TestCachedModel < Test::Unit::TestCase |
156 | |
157 | DEFAULT_USE_LOCAL_CACHE = CachedModel.use_local_cache? |
158 | DEFAULT_USE_MEMCACHE = CachedModel.use_memcache? |
159 | |
160 | def setup |
161 | @model = Concrete.new |
162 | Cache.cache = {} |
163 | Cache.ttl = {} |
164 | CachedModel.cache_delay_commit = {} |
165 | CachedModel.cache_local = {} |
166 | CachedModel.use_local_cache = DEFAULT_USE_LOCAL_CACHE |
167 | CachedModel.use_memcache = DEFAULT_USE_MEMCACHE |
168 | end |
169 | |
170 | def teardown |
171 | CachedModel.use_local_cache = DEFAULT_USE_LOCAL_CACHE |
172 | CachedModel.use_memcache = DEFAULT_USE_MEMCACHE |
173 | end |
174 | |
175 | def test_class_abstract_class_eh |
176 | assert_equal true, CachedModel.abstract_class?, 'CachedModel is abstract' |
177 | assert_equal false, Concrete.abstract_class?, 'Concrete is not abstract' |
178 | end |
179 | |
180 | def test_class_cache_delete |
181 | CachedModel.use_local_cache = true |
182 | CachedModel.use_memcache = true |
183 | util_set |
184 | |
185 | CachedModel.cache_delete @model.class, @model.id |
186 | |
187 | assert_empty CachedModel.cache_local |
188 | assert_empty Cache.cache |
189 | end |
190 | |
191 | def test_class_cache_delete_without_local_cache |
192 | CachedModel.use_local_cache = false |
193 | CachedModel.use_memcache = true |
194 | util_set |
195 | |
196 | CachedModel.cache_delete @model.class, @model.id |
197 | |
198 | deny_empty CachedModel.cache_local |
199 | assert_empty Cache.cache |
200 | end |
201 | |
202 | def test_class_cache_delete_without_memcache |
203 | CachedModel.use_local_cache = true |
204 | CachedModel.use_memcache = false |
205 | util_set |
206 | |
207 | CachedModel.cache_delete @model.class, @model.id |
208 | |
209 | assert_empty CachedModel.cache_local |
210 | deny_empty Cache.cache |
211 | end |
212 | |
213 | def test_class_cache_reset |
214 | CachedModel.use_local_cache = true |
215 | CachedModel.use_memcache = true |
216 | util_set |
217 | |
218 | CachedModel.cache_reset |
219 | |
220 | assert_empty CachedModel.cache_local |
221 | deny_empty Cache.cache |
222 | end |
223 | |
224 | def test_class_cache_reset_without_local_cache |
225 | CachedModel.use_local_cache = false |
226 | CachedModel.use_memcache = true |
227 | util_set |
228 | |
229 | CachedModel.cache_reset |
230 | |
231 | deny_empty CachedModel.cache_local |
232 | deny_empty Cache.cache |
233 | end |
234 | |
235 | def test_class_cache_reset_without_memcache |
236 | CachedModel.use_local_cache = true |
237 | CachedModel.use_memcache = false |
238 | util_set |
239 | |
240 | CachedModel.cache_reset |
241 | |
242 | assert_empty CachedModel.cache_local |
243 | deny_empty Cache.cache |
244 | end |
245 | |
246 | def test_class_find_complex |
247 | CachedModel.use_local_cache = true |
248 | CachedModel.use_memcache = true |
249 | |
250 | record = Concrete.find(1, :order => 'lock_version') |
251 | |
252 | assert_equal @model.id + 1, record.id |
253 | |
254 | assert_equal record, util_local(record) |
255 | assert_equal record, util_memcache(record) |
256 | end |
257 | |
258 | def test_class_find_complex_without_local_cache |
259 | CachedModel.use_local_cache = false |
260 | CachedModel.use_memcache = true |
261 | |
262 | record = Concrete.find(1, :order => 'lock_version') |
263 | |
264 | assert_equal @model.id + 1, record.id |
265 | |
266 | assert_equal nil, util_local(record) |
267 | assert_equal record, util_memcache(record) |
268 | end |
269 | |
270 | def test_class_find_complex_without_memcache |
271 | CachedModel.use_local_cache = true |
272 | CachedModel.use_memcache = false |
273 | |
274 | record = Concrete.find(1, :order => 'lock_version') |
275 | |
276 | assert_equal @model.id + 1, record.id |
277 | |
278 | assert_equal record, util_local(record) |
279 | assert_equal nil, util_memcache(record) |
280 | end |
281 | |
282 | def test_class_find_in_local_cache |
283 | CachedModel.use_local_cache = true |
284 | util_set |
285 | |
286 | record = Concrete.find(1, :order => 'lock_version') |
287 | assert_equal @model.id + 1, record.id |
288 | |
289 | assert_equal record, util_local(record) |
290 | end |
291 | |
292 | def test_class_find_in_memcache |
293 | CachedModel.use_local_cache = true |
294 | CachedModel.use_memcache = true |
295 | util_set |
296 | CachedModel.cache_reset |
297 | |
298 | record = Concrete.find @model.id |
299 | |
300 | assert_equal @model, record |
301 | |
302 | assert_equal record, util_local(record) |
303 | end |
304 | |
305 | def test_class_find_multiple |
306 | CachedModel.use_local_cache = true |
307 | ids = [@model.id + 1, @model.id + 2, @model.id + 3] |
308 | records = Concrete.find(*ids) |
309 | assert_equal ids, records.map { |r| r.id } |
310 | |
311 | assert_equal ids.map { |i| "#{@model.class}:#{i}" }.sort, |
312 | CachedModel.cache_local.keys.sort |
313 | assert_equal ids.map { |i| "active_record:#{@model.class}:#{i}" }.sort, |
314 | Cache.cache.keys.sort |
315 | end |
316 | |
317 | def test_class_find_not_cached |
318 | CachedModel.use_local_cache = true |
319 | record = Concrete.find @model.id + 1 |
320 | assert_equal @model.id + 1, record.id |
321 | |
322 | assert_equal record, util_local(record) |
323 | assert_equal record, util_memcache(record) |
324 | end |
325 | |
326 | def test_class_find_by_sql |
327 | CachedModel.use_local_cache = true |
328 | q = "SELECT * FROM concrete WHERE (concrete.id = #{@model.id + 1}) LIMIT 1" |
329 | record = Concrete.find_by_sql(q).first |
330 | assert_equal @model.id + 1, record.id |
331 | |
332 | assert_equal record, util_local(record) |
333 | assert_equal record, util_memcache(record) |
334 | end |
335 | |
336 | def test_class_find_by_sql_extra_space |
337 | CachedModel.use_local_cache = true |
338 | q = "SELECT * FROM concrete WHERE (concrete.id = #{@model.id + 1}) LIMIT 1" |
339 | record = Concrete.find_by_sql(q).first |
340 | assert_equal @model.id + 1, record.id |
341 | |
342 | assert_equal record, util_local(record) |
343 | assert_equal record, util_memcache(record) |
344 | end |
345 | |
346 | def test_class_find_by_sql_no_record |
347 | q = "SELECT * FROM concrete WHERE (concrete.id = -1) LIMIT 1" |
348 | |
349 | records = Concrete.find_by_sql q |
350 | |
351 | assert_equal [], records |
352 | end |
353 | |
354 | def test_class_ttl |
355 | assert_equal 900, CachedModel.ttl |
356 | CachedModel.ttl = 800 |
357 | assert_equal 800, CachedModel.ttl |
358 | end |
359 | |
360 | def test_class_use_local_cache_eh |
361 | CachedModel.use_local_cache = true |
362 | assert_equal true, CachedModel.use_local_cache? |
363 | CachedModel.use_local_cache = false |
364 | assert_equal false, CachedModel.use_local_cache? |
365 | end |
366 | |
367 | def test_class_use_memcache_eh |
368 | CachedModel.use_memcache = true |
369 | assert_equal true, CachedModel.use_memcache? |
370 | CachedModel.use_memcache = false |
371 | assert_equal false, CachedModel.use_memcache? |
372 | end |
373 | |
374 | def test_cache_delete |
375 | CachedModel.use_local_cache = true |
376 | util_set |
377 | |
378 | @model.cache_delete |
379 | |
380 | assert_empty CachedModel.cache_local |
381 | assert_empty Cache.cache |
382 | end |
383 | |
384 | def test_cache_key_local |
385 | assert_equal "#{@model.class}:#{@model.id}", @model.cache_key_local |
386 | end |
387 | |
388 | def test_cache_key_memcache |
389 | assert_equal "active_record:#{@model.class}:#{@model.id}", |
390 | @model.cache_key_memcache |
391 | end |
392 | |
393 | def test_cache_local |
394 | assert_same CachedModel.cache_local, @model.cache_local |
395 | end |
396 | |
397 | def test_cache_store |
398 | CachedModel.use_local_cache = true |
399 | CachedModel.use_memcache = true |
400 | |
401 | @model.cache_store |
402 | |
403 | deny_empty CachedModel.cache_local |
404 | deny_empty Cache.cache |
405 | |
406 | assert_equal @model, util_local(@model) |
407 | assert_equal @model, util_memcache(@model) |
408 | assert_equal CachedModel.ttl, Cache.ttl[@model.cache_key_memcache] |
409 | end |
410 | |
411 | def test_cache_store_in_transaction |
412 | CachedModel.use_local_cache = true |
413 | CachedModel.use_memcache = true |
414 | CachedModel.cache_delay_commit[0] = [] |
415 | |
416 | @model.cache_store |
417 | |
418 | deny_empty CachedModel.cache_delay_commit |
419 | assert_empty CachedModel.cache_local |
420 | assert_empty Cache.cache |
421 | end |
422 | |
423 | def test_cache_store_without_local_cache |
424 | CachedModel.use_local_cache = false |
425 | CachedModel.use_memcache = true |
426 | |
427 | @model.cache_store |
428 | |
429 | assert_empty CachedModel.cache_local |
430 | deny_empty Cache.cache |
431 | |
432 | assert_equal nil, util_local(@model) |
433 | assert_equal @model, util_memcache(@model) |
434 | assert_equal CachedModel.ttl, Cache.ttl[@model.cache_key_memcache] |
435 | end |
436 | |
437 | def test_cache_store_without_memcache |
438 | CachedModel.use_local_cache = true |
439 | CachedModel.use_memcache = false |
440 | |
441 | @model.cache_store |
442 | |
443 | deny_empty CachedModel.cache_local |
444 | assert_empty Cache.cache |
445 | |
446 | assert_equal @model, util_local(@model) |
447 | assert_equal nil, util_memcache(@model) |
448 | end |
449 | |
450 | def test_cache_store_with_attributes |
451 | CachedModel.use_local_cache = true |
452 | @model.attributes[:extra] = 'extra' |
453 | @model.cache_store |
454 | |
455 | deny_empty CachedModel.cache_local |
456 | deny_empty Cache.cache |
457 | |
458 | local_model = util_local(@model) |
459 | mem_model = util_memcache(@model) |
460 | assert_equal @model, local_model |
461 | assert_equal @model, mem_model |
462 | assert_equal CachedModel.ttl, Cache.ttl[@model.cache_key_memcache] |
463 | |
464 | expected = {:data => 'data'} |
465 | |
466 | assert_equal expected, local_model.attributes |
467 | assert_equal expected, mem_model.attributes |
468 | end |
469 | |
470 | def test_destroy |
471 | CachedModel.use_local_cache = true |
472 | util_set |
473 | |
474 | @model.destroy |
475 | |
476 | assert_empty CachedModel.cache_local |
477 | assert_empty Cache.cache |
478 | end |
479 | |
480 | def test_reload |
481 | util_set |
482 | |
483 | @model.reload |
484 | |
485 | deny_empty CachedModel.cache_local |
486 | deny_empty Cache.cache |
487 | |
488 | assert_equal 'datb', |
489 | util_local(@model).attributes[:data] |
490 | assert_equal 'datb', |
491 | util_memcache(@model).attributes[:data] |
492 | end |
493 | |
494 | def test_transaction_fail |
495 | CachedModel.use_local_cache = true |
496 | |
497 | e = assert_raise RuntimeError do |
498 | @model.transaction do |
499 | @model.attributes[:data] = 'atad' |
500 | @model.save |
501 | raise 'Oh nos!' |
502 | end |
503 | end |
504 | |
505 | assert_equal 'Oh nos!', e.message |
506 | assert_equal nil, util_local(@model) |
507 | assert_equal nil, util_memcache(@model) |
508 | end |
509 | |
510 | def test_transaction_nested |
511 | CachedModel.use_local_cache = true |
512 | |
513 | @model.transaction do |
514 | @model.transaction do |
515 | @model.attributes[:data] = 'value1' |
516 | @model.save |
517 | |
518 | assert_equal nil, util_local(@model), 'in t1 local' |
519 | assert_equal nil, util_memcache(@model), 'in t1 memcache' |
520 | end |
521 | |
522 | assert_equal 'value1', util_local(@model).attributes[:data], |
523 | 'completed t1 local' |
524 | assert_equal 'value1', util_memcache(@model).attributes[:data], |
525 | 'completed t1 memcache' |
526 | |
527 | @model.attributes[:data] = 'value2' |
528 | @model.save |
529 | |
530 | assert_equal 'value1', util_local(@model).attributes[:data], |
531 | 'in t2 local' |
532 | assert_equal 'value1', util_memcache(@model).attributes[:data], |
533 | 'in t2 memcache' |
534 | end |
535 | |
536 | assert_equal 'value2', util_local(@model).attributes[:data], |
537 | 'completed t2 local' |
538 | assert_equal 'value2', util_memcache(@model).attributes[:data], |
539 | 'completed t2 local' |
540 | end |
541 | |
542 | def test_transaction_pass |
543 | CachedModel.use_local_cache = true |
544 | |
545 | result = @model.transaction do |
546 | @model.attributes[:data] = 'atad' |
547 | @model.save |
548 | |
549 | assert_equal nil, util_local(@model) |
550 | assert_equal nil, util_memcache(@model) |
551 | |
552 | :some_value |
553 | end |
554 | |
555 | assert_equal :some_value, result |
556 | |
557 | assert_equal 'atad', util_local(@model).attributes[:data] |
558 | assert_equal 'atad', |
559 | util_memcache(@model).attributes[:data] |
560 | |
561 | end |
562 | |
563 | def test_update |
564 | util_set |
565 | |
566 | @model.attributes[:data] = 'atad' |
567 | assert_equal true, @model.update, "Updates should return true" |
568 | |
569 | deny_empty CachedModel.cache_local |
570 | deny_empty Cache.cache |
571 | |
572 | assert_equal 'atad', |
573 | util_local(@model).attributes[:data] |
574 | assert_equal 'atad', |
575 | util_memcache(@model).attributes[:data] |
576 | end |
577 | |
578 | def util_local(model) |
579 | CachedModel.cache_local[model.cache_key_local] |
580 | end |
581 | |
582 | def util_memcache(model) |
583 | Cache.cache[model.cache_key_memcache] |
584 | end |
585 | |
586 | def util_set(klass = @model.class, id = @model.id, data = @model) |
587 | key = "#{klass}:#{id}" |
588 | CachedModel.cache_local[key] = data |
589 | Cache.cache["active_record:#{key}"] = data |
590 | end |
591 | |
592 | end |
593 |