File: entity_store_test.rb

package info (click to toggle)
ruby-rack-cache 1.17.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 648 kB
  • sloc: ruby: 3,581; makefile: 4
file content (340 lines) | stat: -rw-r--r-- 10,106 bytes parent folder | download
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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# coding: utf-8
require_relative 'test_helper'
require 'rack/cache/entity_store'
require 'rack/cache/meta_store'

module RackCacheEntityStoreImplementation
  def self.included(base)
    base.class_eval do
      it 'responds to all required messages' do
        %w[read open write exist?].each do |message|
          assert @store.respond_to? message
        end
      end

      it 'stores bodies with #write' do
        key, size = @store.write(['My wild love went riding,'])
        assert_sha_like key

        data = @store.read(key)
        data.must_equal 'My wild love went riding,'
      end

      it 'takes a ttl parameter for #write' do
        key, size = @store.write(['My wild love went riding,'], 0)
        assert_sha_like key

        data = @store.read(key)
        data.must_equal 'My wild love went riding,'
      end

      it 'correctly determines whether cached body exists for key with #exist?' do
        key, size = @store.write(['She rode to the devil,'])
        assert @store.exist? key
        refute @store.exist? '938jasddj83jasdh4438021ksdfjsdfjsdsf'
      end

      it 'can read data written with #write' do
        key, size = @store.write(['And asked him to pay.'])
        data = @store.read(key)
        data.must_equal 'And asked him to pay.'
      end

      it 'gives a 40 character SHA1 hex digest from #write' do
        key, size = @store.write(['she rode to the sea;'])
        refute key.nil?
        key.length.must_equal 40
        key.must_match /^[0-9a-z]+$/
        key.must_equal '90a4c84d51a277f3dafc34693ca264531b9f51b6'
      end

      it 'returns the entire body as a String from #read' do
        key, size = @store.write(['She gathered together'])
        @store.read(key).must_equal 'She gathered together'
      end

      it 'returns nil from #read when key does not exist' do
        @store.read('87fe0a1ae82a518592f6b12b0183e950b4541c62').must_be_nil
      end

      it 'returns a Rack compatible body from #open' do
        key, size = @store.write(['Some shells for her hair.'])
        body = @store.open(key)
        assert body.respond_to? :each
        buf = ''
        body.each { |part| buf << part }
        buf.must_equal 'Some shells for her hair.'
      end

      it 'returns nil from #open when key does not exist' do
        @store.open('87fe0a1ae82a518592f6b12b0183e950b4541c62').must_be_nil
      end

      it 'can store largish bodies with binary data' do
        pony = File.open(File.dirname(__FILE__) + '/pony.jpg', 'rb') { |f| f.read }
        key, size = @store.write([pony])
        key.must_equal 'd0f30d8659b4d268c5c64385d9790024c2d78deb'
        data = @store.read(key)
        data.length.must_equal pony.length
        data.hash.must_equal pony.hash
      end

      it 'deletes stored entries with #purge' do
        key, size = @store.write(['My wild love went riding,'])
        @store.purge(key).must_be_nil
        @store.read(key).must_be_nil
      end
    end
  end
end

describe Rack::Cache::EntityStore do
  def assert_sha_like(object)
    assert object
    object.length.must_equal 40
    object.must_match /^[0-9a-z]+$/
  end

  describe 'Heap' do
    before { @store = Rack::Cache::EntityStore::Heap.new }

    include RackCacheEntityStoreImplementation

    it 'takes a Hash to ::new' do
      @store = Rack::Cache::EntityStore::Heap.new('foo' => ['bar'])
      @store.read('foo').must_equal 'bar'
    end

    it 'uses its own Hash with no args to ::new' do
      @store.read('foo').must_be_nil
    end
  end

  describe 'Disk' do
    before do
      @temp_dir = create_temp_directory
      @store = Rack::Cache::EntityStore::Disk.new(@temp_dir)
    end

    after do
      @store = nil
      remove_entry_secure @temp_dir
    end
    include RackCacheEntityStoreImplementation

    it 'takes a path to ::new and creates the directory' do
      path = @temp_dir + '/foo'
      @store = Rack::Cache::EntityStore::Disk.new(path)
      assert File.directory? path
    end

    it 'produces a body that responds to #to_path' do
      key, size = @store.write(['Some shells for her hair.'])
      body = @store.open(key)
      assert body.respond_to? :to_path
      path = "#{@temp_dir}/#{key[0..1]}/#{key[2..-1]}"
      body.to_path.must_equal path
    end

    it 'spreads data over a 36² hash radius' do
      (<<-PROSE).each_line { |line| assert_sha_like @store.write([line]).first }
        My wild love went riding,
        She rode all the day;
        She rode to the devil,
        And asked him to pay.

        The devil was wiser
        It's time to repent;
        He asked her to give back
        The money she spent

        My wild love went riding,
        She rode to sea;
        She gathered together
        Some shells for her hair

        She rode on to Christmas,
        She rode to the farm;
        She rode to Japan
        And re-entered a town

        My wild love is crazy
        She screams like a bird;
        She moans like a cat
        When she wants to be heard

        She rode and she rode on
        She rode for a while,
        Then stopped for an evening
        And laid her head down

        By this time the weather
        Had changed one degree,
        She asked for the people
        To let her go free

        My wild love went riding,
        She rode for an hour;
        She rode and she rested,
        And then she rode on
        My wild love went riding,
      PROSE
      subdirs = Dir["#{@temp_dir}/*"]
      subdirs.each do |subdir|
        File.basename(subdir).must_match /^[0-9a-z]{2}$/
        files = Dir["#{subdir}/*"]
        files.each do |filename|
          File.basename(filename).must_match /^[0-9a-z]{38}$/
        end
        files.length.must_be :>, 0
      end
      subdirs.length.must_equal 28
    end
  end

  need_memcached 'entity store tests' do
    describe 'MemCached' do
      before do
        @store = Rack::Cache::EntityStore::MemCached.new($memcached)
      end
      after do
        @store = nil
      end
      include RackCacheEntityStoreImplementation
    end

    describe 'options parsing' do
      before do
        uri = URI.parse("memcached://#{ENV['MEMCACHED']}/obj_ns1?show_backtraces=true")
        @memcached_metastore = Rack::Cache::MetaStore::MemCached.resolve uri
      end

      it 'passes options from uri' do
        @memcached_metastore.cache.instance_variable_get(:@options)[:show_backtraces].must_equal true
      end

      it 'takes namespace into account' do
        @memcached_metastore.cache.instance_variable_get(:@options)[:prefix_key].must_equal 'obj_ns1'
      end
    end
  end

  need_dalli 'entity store tests' do
    describe 'Dalli' do
      before do
        $dalli.flush_all
        @store = Rack::Cache::EntityStore::Dalli.new($dalli)
      end
      after do
        @store = nil
      end
      include RackCacheEntityStoreImplementation
    end

    describe 'options parsing' do
      before do
        uri = URI.parse("memcached://#{ENV['MEMCACHED']}/obj_ns1?show_backtraces=true")
        @dalli_metastore = Rack::Cache::MetaStore::Dalli.resolve uri
      end

      it 'passes options from uri' do
        @dalli_metastore.cache.instance_variable_get(:@options)[:show_backtraces].must_equal true
      end

      it 'takes namespace into account' do
        @dalli_metastore.cache.instance_variable_get(:@options)[:namespace].must_equal 'obj_ns1'
      end
    end
  end

  need_java 'entity store testing' do
    module Rack::Cache::AppEngine
      module MC
        class << (Service = {})
          def contains(key); include?(key); end
          def get(key); self[key]; end;
          def put(key, value, ttl = nil)
            self[key] = value
          end
        end

      end
    end

    describe 'GAEStore' do
      before do
        puts Rack::Cache::AppEngine::MC::Service.inspect
        @store = Rack::Cache::EntityStore::GAEStore.new
      end
      after do
        @store = nil
      end
      include RackCacheEntityStoreImplementation
    end

  end

  describe 'Noop' do
    before {@store = Rack::Cache::EntityStore::Noop.new}

    it 'responds to all required messages' do
      %w[read open write exist?].each do |message|
        assert @store.respond_to? message
      end
    end

    it 'accepts bodies with #write' do
      key, size = @store.write(['My wild love went riding,'])
      refute key.nil?
      assert key.length == 40 && key =~ /^[0-9a-z]+$/
    end

    it 'takes a ttl parameter for #write' do
      key, size = @store.write(['My wild love went riding,'], 0)
      refute key.nil?
      assert key.length == 40 && key =~ /^[0-9a-z]+$/
    end

    it 'always responds to #exist? with true, regardless of the content having been saved before' do
      key, size = @store.write(['She rode to the devil,'])
      assert @store.exist? key
      assert @store.exist? '938jasddj83jasdh4438021ksdfjsdfjsdsf'
    end

    it 'always responds to #read with an empty String' do
      key, size = @store.write(['And asked him to pay.'])
      data = @store.read(key)
      data.must_equal ''
      data = @store.read('938jasddj83jasdh4438021ksdfjsdfjsdsf')
      data.must_equal ''
    end

    it 'gives a 40 character SHA1 hex digest from #write' do
      key, size = @store.write(['she rode to the sea;'])
      refute key.nil?
      key.length.must_equal 40
      key.must_match /^[0-9a-z]+$/
      key.must_equal '90a4c84d51a277f3dafc34693ca264531b9f51b6'
    end

    it 'always responds to #open with empty array' do
      key, size = @store.write(['And asked him to pay.'])
      data = @store.open(key)
      data.must_equal []
      data = @store.open('938jasddj83jasdh4438021ksdfjsdfjsdsf')
      data.must_equal []
    end

    it 'returns a Rack compatible body from #open' do
      key, size = @store.write(['Some shells for her hair.'])
      body = @store.open(key)
      assert body.respond_to? :each
      body.must_equal []
    end

    it 'responds to #purge and returns nil' do
      key, size = @store.write(['My wild love went riding,'])
      @store.purge(key).must_be_nil
    end
  end
end