1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
|
require "cases/helper"
require 'models/topic'
require 'models/task'
require 'models/category'
require 'models/post'
require 'rack'
class QueryCacheTest < ActiveRecord::TestCase
fixtures :tasks, :topics, :categories, :posts, :categories_posts
def setup
Task.connection.clear_query_cache
ActiveRecord::Base.connection.disable_query_cache!
end
def test_exceptional_middleware_clears_and_disables_cache_on_error
assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache off'
mw = ActiveRecord::QueryCache.new lambda { |env|
Task.find 1
Task.find 1
assert_equal 1, ActiveRecord::Base.connection.query_cache.length
raise "lol borked"
}
assert_raises(RuntimeError) { mw.call({}) }
assert_equal 0, ActiveRecord::Base.connection.query_cache.length
assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache off'
end
def test_exceptional_middleware_leaves_enabled_cache_alone
ActiveRecord::Base.connection.enable_query_cache!
mw = ActiveRecord::QueryCache.new lambda { |env|
raise "lol borked"
}
assert_raises(RuntimeError) { mw.call({}) }
assert ActiveRecord::Base.connection.query_cache_enabled, 'cache on'
end
def test_exceptional_middleware_assigns_original_connection_id_on_error
connection_id = ActiveRecord::Base.connection_id
mw = ActiveRecord::QueryCache.new lambda { |env|
ActiveRecord::Base.connection_id = self.object_id
raise "lol borked"
}
assert_raises(RuntimeError) { mw.call({}) }
assert_equal connection_id, ActiveRecord::Base.connection_id
end
def test_middleware_delegates
called = false
mw = ActiveRecord::QueryCache.new lambda { |env|
called = true
[200, {}, nil]
}
mw.call({})
assert called, 'middleware should delegate'
end
def test_middleware_caches
mw = ActiveRecord::QueryCache.new lambda { |env|
Task.find 1
Task.find 1
assert_equal 1, ActiveRecord::Base.connection.query_cache.length
[200, {}, nil]
}
mw.call({})
end
def test_cache_enabled_during_call
assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache off'
mw = ActiveRecord::QueryCache.new lambda { |env|
assert ActiveRecord::Base.connection.query_cache_enabled, 'cache on'
[200, {}, nil]
}
mw.call({})
end
def test_cache_on_during_body_write
streaming = Class.new do
def each
yield ActiveRecord::Base.connection.query_cache_enabled
end
end
mw = ActiveRecord::QueryCache.new lambda { |env|
[200, {}, streaming.new]
}
body = mw.call({}).last
body.each { |x| assert x, 'cache should be on' }
body.close
assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache disabled'
end
def test_cache_off_after_close
mw = ActiveRecord::QueryCache.new lambda { |env| [200, {}, nil] }
body = mw.call({}).last
assert ActiveRecord::Base.connection.query_cache_enabled, 'cache enabled'
body.close
assert !ActiveRecord::Base.connection.query_cache_enabled, 'cache disabled'
end
def test_cache_clear_after_close
mw = ActiveRecord::QueryCache.new lambda { |env|
Post.first
[200, {}, nil]
}
body = mw.call({}).last
assert !ActiveRecord::Base.connection.query_cache.empty?, 'cache not empty'
body.close
assert ActiveRecord::Base.connection.query_cache.empty?, 'cache should be empty'
end
def test_find_queries
assert_queries(2) { Task.find(1); Task.find(1) }
end
def test_find_queries_with_cache
Task.cache do
assert_queries(1) { Task.find(1); Task.find(1) }
end
end
def test_find_queries_with_cache_multi_record
Task.cache do
assert_queries(2) { Task.find(1); Task.find(1); Task.find(2) }
end
end
def test_count_queries_with_cache
Task.cache do
assert_queries(1) { Task.count; Task.count }
end
end
def test_query_cache_dups_results_correctly
Task.cache do
now = Time.now.utc
task = Task.find 1
assert_not_equal now, task.starting
task.starting = now
task.reload
assert_not_equal now, task.starting
end
end
def test_cache_is_flat
Task.cache do
Topic.columns # don't count this query
assert_queries(1) { Topic.find(1); Topic.find(1); }
end
ActiveRecord::Base.cache do
assert_queries(1) { Task.find(1); Task.find(1) }
end
end
def test_cache_does_not_wrap_string_results_in_arrays
Task.cache do
# Oracle adapter returns count() as Fixnum or Float
if current_adapter?(:OracleAdapter)
assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter)
# Future versions of the sqlite3 adapter will return numeric
assert_instance_of Fixnum,
Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
else
assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
end
end
end
def test_cache_is_ignored_for_locked_relations
task = Task.find 1
Task.cache do
assert_queries(2) { task.lock!; task.lock! }
end
end
def test_cache_is_available_when_connection_is_connected
conf = ActiveRecord::Base.configurations
ActiveRecord::Base.configurations = {}
Task.cache do
assert_queries(1) { Task.find(1); Task.find(1) }
end
ensure
ActiveRecord::Base.configurations = conf
end
end
class QueryCacheExpiryTest < ActiveRecord::TestCase
fixtures :tasks, :posts, :categories, :categories_posts
def test_cache_gets_cleared_after_migration
# warm the cache
Post.find(1)
# change the column definition
Post.connection.change_column :posts, :title, :string, :limit => 80
assert_nothing_raised { Post.find(1) }
# restore the old definition
Post.connection.change_column :posts, :title, :string
end
def test_find
Task.connection.expects(:clear_query_cache).times(1)
assert !Task.connection.query_cache_enabled
Task.cache do
assert Task.connection.query_cache_enabled
Task.find(1)
Task.uncached do
assert !Task.connection.query_cache_enabled
Task.find(1)
end
assert Task.connection.query_cache_enabled
end
assert !Task.connection.query_cache_enabled
end
def test_update
Task.connection.expects(:clear_query_cache).times(2)
Task.cache do
task = Task.find(1)
task.starting = Time.now.utc
task.save!
end
end
def test_destroy
Task.connection.expects(:clear_query_cache).times(2)
Task.cache do
Task.find(1).destroy
end
end
def test_insert
ActiveRecord::Base.connection.expects(:clear_query_cache).times(2)
Task.cache do
Task.create!
end
end
def test_cache_is_expired_by_habtm_update
ActiveRecord::Base.connection.expects(:clear_query_cache).times(2)
ActiveRecord::Base.cache do
c = Category.first
p = Post.first
p.categories << c
end
end
def test_cache_is_expired_by_habtm_delete
ActiveRecord::Base.connection.expects(:clear_query_cache).times(2)
ActiveRecord::Base.cache do
p = Post.find(1)
assert p.categories.any?
p.categories.delete_all
end
end
end
|