query_cache_test.rb 7.0 KB
Newer Older
1
require "cases/helper"
J
Jeremy Kemper 已提交
2 3 4 5
require 'models/topic'
require 'models/task'
require 'models/category'
require 'models/post'
6
require 'rack'
7

8
class QueryCacheTest < ActiveRecord::TestCase
9
  fixtures :tasks, :topics, :categories, :posts, :categories_posts
10

11 12
  def setup
    Task.connection.clear_query_cache
13
    ActiveRecord::Base.connection.disable_query_cache!
14 15
  end

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
  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({}) }

A
Aaron Patterson 已提交
39
    assert ActiveRecord::Base.connection.query_cache_enabled, 'cache on'
40 41
  end

K
kennyj 已提交
42 43 44 45 46 47 48 49 50
  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({}) }

D
dfens 已提交
51
    assert_equal connection_id, ActiveRecord::Base.connection_id
K
kennyj 已提交
52 53
  end

54 55 56 57
  def test_middleware_delegates
    called = false
    mw = ActiveRecord::QueryCache.new lambda { |env|
      called = true
58
      [200, {}, nil]
59 60 61 62 63
    }
    mw.call({})
    assert called, 'middleware should delegate'
  end

A
Aaron Patterson 已提交
64
  def test_middleware_caches
65 66 67 68
    mw = ActiveRecord::QueryCache.new lambda { |env|
      Task.find 1
      Task.find 1
      assert_equal 1, ActiveRecord::Base.connection.query_cache.length
69
      [200, {}, nil]
70 71 72 73
    }
    mw.call({})
  end

A
Aaron Patterson 已提交
74 75 76 77 78
  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'
79
      [200, {}, nil]
A
Aaron Patterson 已提交
80 81 82 83
    }
    mw.call({})
  end

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
  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
101
    mw = ActiveRecord::QueryCache.new lambda { |env| [200, {}, nil] }
102 103 104 105 106 107 108
    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

109 110
  def test_cache_clear_after_close
    mw = ActiveRecord::QueryCache.new lambda { |env|
111
      Post.first
112
      [200, {}, nil]
113 114 115 116 117 118 119 120
    }
    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

121
  def test_find_queries
C
Carlos Antonio da Silva 已提交
122
    assert_queries(2) { Task.find(1); Task.find(1) }
123 124 125 126
  end

  def test_find_queries_with_cache
    Task.cache do
127
      assert_queries(1) { Task.find(1); Task.find(1) }
128 129
    end
  end
130

A
Aaron Patterson 已提交
131
  def test_find_queries_with_cache_multi_record
132 133 134 135 136
    Task.cache do
      assert_queries(2) { Task.find(1); Task.find(1); Task.find(2) }
    end
  end

137 138
  def test_count_queries_with_cache
    Task.cache do
139
      assert_queries(1) { Task.count; Task.count }
140 141 142
    end
  end

143 144 145 146 147 148 149 150 151 152
  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
153

154
  def test_cache_is_flat
155
    Task.cache do
156
      Topic.columns # don't count this query
157
      assert_queries(1) { Topic.find(1); Topic.find(1); }
158
    end
159

160
    ActiveRecord::Base.cache do
161
      assert_queries(1) { Task.find(1); Task.find(1) }
162 163
    end
  end
164 165 166

  def test_cache_does_not_wrap_string_results_in_arrays
    Task.cache do
167 168
      # Oracle adapter returns count() as Fixnum or Float
      if current_adapter?(:OracleAdapter)
169
        assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
170
      elsif current_adapter?(:SQLite3Adapter) || current_adapter?(:Mysql2Adapter)
171 172 173
        # Future versions of the sqlite3 adapter will return numeric
        assert_instance_of Fixnum,
         Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
174 175 176
      else
        assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
      end
177 178
    end
  end
179 180 181 182 183 184 185 186

  def test_cache_is_ignored_for_locked_relations
    task = Task.find 1

    Task.cache do
      assert_queries(2) { task.lock!; task.lock! }
    end
  end
187 188
end

189
class QueryCacheExpiryTest < ActiveRecord::TestCase
190
  fixtures :tasks, :posts, :categories, :categories_posts
191

192 193 194 195 196 197 198 199 200 201 202 203
  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

204
  def test_find
205 206 207 208 209
    Task.connection.expects(:clear_query_cache).times(1)

    assert !Task.connection.query_cache_enabled
    Task.cache do
      assert Task.connection.query_cache_enabled
210
      Task.find(1)
211 212 213 214 215 216 217

      Task.uncached do
        assert !Task.connection.query_cache_enabled
        Task.find(1)
      end

      assert Task.connection.query_cache_enabled
218
    end
219
    assert !Task.connection.query_cache_enabled
220 221
  end

222 223 224 225
  def test_update
    Task.connection.expects(:clear_query_cache).times(2)

    Task.cache do
226 227 228
      task = Task.find(1)
      task.starting = Time.now.utc
      task.save!
229 230 231 232
    end
  end

  def test_destroy
233 234 235
    Task.connection.expects(:clear_query_cache).times(2)

    Task.cache do
236 237 238 239
      Task.find(1).destroy
    end
  end

240 241
  def test_insert
    ActiveRecord::Base.connection.expects(:clear_query_cache).times(2)
242

243 244
    Task.cache do
      Task.create!
245 246
    end
  end
247 248 249 250

  def test_cache_is_expired_by_habtm_update
    ActiveRecord::Base.connection.expects(:clear_query_cache).times(2)
    ActiveRecord::Base.cache do
251 252
      c = Category.first
      p = Post.first
253 254 255 256 257 258 259
      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
260 261
      p = Post.find(1)
      assert p.categories.any?
262 263 264
      p.categories.delete_all
    end
  end
265
end