juno 0.2.5 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +5 -1
- data/Gemfile +27 -21
- data/README.md +41 -2
- data/Rakefile +3 -3
- data/juno.gemspec +12 -12
- data/lib/juno.rb +4 -4
- data/lib/juno/adapters/couch.rb +1 -1
- data/lib/juno/adapters/datamapper.rb +1 -1
- data/lib/juno/adapters/dbm.rb +1 -1
- data/lib/juno/adapters/file.rb +1 -1
- data/lib/juno/adapters/fog.rb +1 -1
- data/lib/juno/adapters/gdbm.rb +1 -1
- data/lib/juno/adapters/localmemcache.rb +1 -1
- data/lib/juno/adapters/pstore.rb +1 -1
- data/lib/juno/adapters/redis.rb +3 -2
- data/lib/juno/adapters/sdbm.rb +1 -1
- data/lib/juno/adapters/sequel.rb +1 -1
- data/lib/juno/adapters/sqlite.rb +1 -1
- data/lib/juno/adapters/tokyocabinet.rb +1 -1
- data/lib/juno/builder.rb +10 -0
- data/lib/juno/cache.rb +1 -0
- data/lib/juno/expires.rb +1 -1
- data/lib/juno/proxy.rb +2 -0
- data/lib/juno/stack.rb +1 -0
- data/lib/juno/transformer.rb +34 -18
- data/lib/juno/version.rb +1 -1
- data/lib/rack/cache/juno.rb +93 -0
- data/lib/rack/session/juno.rb +63 -0
- data/spec/generate.rb +41 -2
- data/spec/{adapter_activerecord_spec.rb → juno/adapter_activerecord_spec.rb} +0 -0
- data/spec/{adapter_cassandra_spec.rb → juno/adapter_cassandra_spec.rb} +0 -0
- data/spec/{adapter_couch_spec.rb → juno/adapter_couch_spec.rb} +0 -0
- data/spec/{adapter_datamapper_spec.rb → juno/adapter_datamapper_spec.rb} +0 -0
- data/spec/{adapter_dbm_spec.rb → juno/adapter_dbm_spec.rb} +0 -0
- data/spec/{adapter_file_spec.rb → juno/adapter_file_spec.rb} +0 -0
- data/spec/{adapter_fog_spec.rb → juno/adapter_fog_spec.rb} +0 -0
- data/spec/{adapter_gdbm_spec.rb → juno/adapter_gdbm_spec.rb} +0 -0
- data/spec/{adapter_localmemcache_spec.rb → juno/adapter_localmemcache_spec.rb} +0 -0
- data/spec/{adapter_lruhash_spec.rb → juno/adapter_lruhash_spec.rb} +0 -0
- data/spec/{adapter_memcached_dalli_spec.rb → juno/adapter_memcached_dalli_spec.rb} +0 -0
- data/spec/{adapter_memcached_native_spec.rb → juno/adapter_memcached_native_spec.rb} +0 -0
- data/spec/{adapter_memcached_spec.rb → juno/adapter_memcached_spec.rb} +0 -0
- data/spec/{adapter_memory_spec.rb → juno/adapter_memory_spec.rb} +0 -0
- data/spec/{adapter_mongo_spec.rb → juno/adapter_mongo_spec.rb} +0 -0
- data/spec/{adapter_pstore_spec.rb → juno/adapter_pstore_spec.rb} +0 -0
- data/spec/{adapter_redis_spec.rb → juno/adapter_redis_spec.rb} +0 -0
- data/spec/{adapter_riak_spec.rb → juno/adapter_riak_spec.rb} +0 -0
- data/spec/{adapter_sdbm_spec.rb → juno/adapter_sdbm_spec.rb} +0 -0
- data/spec/{adapter_sequel_spec.rb → juno/adapter_sequel_spec.rb} +0 -0
- data/spec/{adapter_sqlite_spec.rb → juno/adapter_sqlite_spec.rb} +0 -0
- data/spec/{adapter_tokyocabinet_bdb_spec.rb → juno/adapter_tokyocabinet_bdb_spec.rb} +0 -0
- data/spec/{adapter_tokyocabinet_hdb_spec.rb → juno/adapter_tokyocabinet_hdb_spec.rb} +0 -0
- data/spec/{adapter_yaml_spec.rb → juno/adapter_yaml_spec.rb} +0 -0
- data/spec/{cache_file_memory_spec.rb → juno/cache_file_memory_spec.rb} +0 -0
- data/spec/{cache_memory_null_spec.rb → juno/cache_memory_null_spec.rb} +0 -0
- data/spec/{expires_file_spec.rb → juno/expires_file_spec.rb} +0 -0
- data/spec/{expires_memory_spec.rb → juno/expires_memory_spec.rb} +0 -0
- data/spec/{lock_spec.rb → juno/lock_spec.rb} +0 -0
- data/spec/{null_adapter_spec.rb → juno/null_adapter_spec.rb} +0 -0
- data/spec/{proxy_expires_memory_spec.rb → juno/proxy_expires_memory_spec.rb} +0 -0
- data/spec/{proxy_redis_spec.rb → juno/proxy_redis_spec.rb} +0 -0
- data/spec/{simple_activerecord_spec.rb → juno/simple_activerecord_spec.rb} +0 -0
- data/spec/{simple_activerecord_with_expires_spec.rb → juno/simple_activerecord_with_expires_spec.rb} +0 -0
- data/spec/{simple_cassandra_spec.rb → juno/simple_cassandra_spec.rb} +0 -0
- data/spec/{simple_couch_spec.rb → juno/simple_couch_spec.rb} +0 -0
- data/spec/{simple_couch_with_expires_spec.rb → juno/simple_couch_with_expires_spec.rb} +0 -0
- data/spec/{simple_datamapper_spec.rb → juno/simple_datamapper_spec.rb} +0 -0
- data/spec/{simple_datamapper_with_expires_spec.rb → juno/simple_datamapper_with_expires_spec.rb} +0 -0
- data/spec/{simple_datamapper_with_repository_spec.rb → juno/simple_datamapper_with_repository_spec.rb} +0 -0
- data/spec/{simple_dbm_spec.rb → juno/simple_dbm_spec.rb} +0 -0
- data/spec/{simple_dbm_with_expires_spec.rb → juno/simple_dbm_with_expires_spec.rb} +0 -0
- data/spec/{simple_file_spec.rb → juno/simple_file_spec.rb} +0 -0
- data/spec/{simple_file_with_expires_spec.rb → juno/simple_file_with_expires_spec.rb} +0 -0
- data/spec/{simple_fog_spec.rb → juno/simple_fog_spec.rb} +0 -0
- data/spec/{simple_fog_with_expires_spec.rb → juno/simple_fog_with_expires_spec.rb} +0 -0
- data/spec/{simple_gdbm_spec.rb → juno/simple_gdbm_spec.rb} +0 -0
- data/spec/{simple_gdbm_with_expires_spec.rb → juno/simple_gdbm_with_expires_spec.rb} +0 -0
- data/spec/{simple_hashfile_spec.rb → juno/simple_hashfile_spec.rb} +0 -0
- data/spec/{simple_hashfile_with_expires_spec.rb → juno/simple_hashfile_with_expires_spec.rb} +0 -0
- data/spec/{simple_localmemcache_spec.rb → juno/simple_localmemcache_spec.rb} +0 -0
- data/spec/{simple_localmemcache_with_expires_spec.rb → juno/simple_localmemcache_with_expires_spec.rb} +0 -0
- data/spec/{simple_lruhash_spec.rb → juno/simple_lruhash_spec.rb} +0 -0
- data/spec/{simple_lruhash_with_expires_spec.rb → juno/simple_lruhash_with_expires_spec.rb} +0 -0
- data/spec/{simple_memcached_dalli_spec.rb → juno/simple_memcached_dalli_spec.rb} +0 -0
- data/spec/{simple_memcached_native_spec.rb → juno/simple_memcached_native_spec.rb} +0 -0
- data/spec/{simple_memcached_spec.rb → juno/simple_memcached_spec.rb} +0 -0
- data/spec/{simple_memory_spec.rb → juno/simple_memory_spec.rb} +0 -0
- data/spec/{simple_memory_with_expires_spec.rb → juno/simple_memory_with_expires_spec.rb} +0 -0
- data/spec/{simple_mongo_spec.rb → juno/simple_mongo_spec.rb} +0 -0
- data/spec/{simple_mongo_with_expires_spec.rb → juno/simple_mongo_with_expires_spec.rb} +0 -0
- data/spec/{simple_null_spec.rb → juno/simple_null_spec.rb} +0 -0
- data/spec/{simple_pstore_spec.rb → juno/simple_pstore_spec.rb} +0 -0
- data/spec/{simple_pstore_with_expires_spec.rb → juno/simple_pstore_with_expires_spec.rb} +0 -0
- data/spec/{simple_redis_spec.rb → juno/simple_redis_spec.rb} +0 -0
- data/spec/{simple_riak_spec.rb → juno/simple_riak_spec.rb} +0 -0
- data/spec/{simple_riak_with_expires_spec.rb → juno/simple_riak_with_expires_spec.rb} +0 -0
- data/spec/{simple_sdbm_spec.rb → juno/simple_sdbm_spec.rb} +0 -0
- data/spec/{simple_sdbm_with_expires_spec.rb → juno/simple_sdbm_with_expires_spec.rb} +0 -0
- data/spec/{simple_sequel_spec.rb → juno/simple_sequel_spec.rb} +0 -0
- data/spec/{simple_sequel_with_expires_spec.rb → juno/simple_sequel_with_expires_spec.rb} +0 -0
- data/spec/{simple_sqlite_spec.rb → juno/simple_sqlite_spec.rb} +0 -0
- data/spec/{simple_sqlite_with_expires_spec.rb → juno/simple_sqlite_with_expires_spec.rb} +0 -0
- data/spec/{simple_tokyocabinet_spec.rb → juno/simple_tokyocabinet_spec.rb} +0 -0
- data/spec/{simple_tokyocabinet_with_expires_spec.rb → juno/simple_tokyocabinet_with_expires_spec.rb} +0 -0
- data/spec/{simple_yaml_spec.rb → juno/simple_yaml_spec.rb} +0 -0
- data/spec/{simple_yaml_with_expires_spec.rb → juno/simple_yaml_with_expires_spec.rb} +0 -0
- data/spec/{stack_file_memory_spec.rb → juno/stack_file_memory_spec.rb} +0 -0
- data/spec/{stack_memory_file_spec.rb → juno/stack_memory_file_spec.rb} +0 -0
- data/spec/{transformer_bencode_spec.rb → juno/transformer_bencode_spec.rb} +0 -0
- data/spec/{transformer_bert_spec.rb → juno/transformer_bert_spec.rb} +0 -0
- data/spec/{transformer_bson_spec.rb → juno/transformer_bson_spec.rb} +0 -0
- data/spec/{transformer_compress_spec.rb → juno/transformer_compress_spec.rb} +0 -0
- data/spec/{transformer_json_spec.rb → juno/transformer_json_spec.rb} +0 -0
- data/spec/juno/transformer_lzma_spec.rb +22 -0
- data/spec/juno/transformer_lzo_spec.rb +22 -0
- data/spec/{transformer_marshal_base64_spec.rb → juno/transformer_marshal_base64_spec.rb} +0 -0
- data/spec/{transformer_marshal_escape_spec.rb → juno/transformer_marshal_escape_spec.rb} +0 -0
- data/spec/{transformer_marshal_md5_spec.rb → juno/transformer_marshal_md5_spec.rb} +0 -0
- data/spec/{transformer_marshal_md5_spread_spec.rb → juno/transformer_marshal_md5_spread_spec.rb} +0 -0
- data/spec/juno/transformer_marshal_prefix_spec.rb +41 -0
- data/spec/{transformer_marshal_uuencode_spec.rb → juno/transformer_marshal_uuencode_spec.rb} +0 -0
- data/spec/{transformer_msgpack_spec.rb → juno/transformer_msgpack_spec.rb} +0 -0
- data/spec/{transformer_ox_spec.rb → juno/transformer_ox_spec.rb} +0 -0
- data/spec/juno/transformer_quicklz_spec.rb +22 -0
- data/spec/juno/transformer_snappy_spec.rb +22 -0
- data/spec/{transformer_tnet_spec.rb → juno/transformer_tnet_spec.rb} +0 -0
- data/spec/{transformer_yaml_spec.rb → juno/transformer_yaml_spec.rb} +0 -0
- data/spec/rack/cache_juno_spec.rb +355 -0
- data/spec/rack/session_juno_spec.rb +305 -0
- metadata +206 -190
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Generated by generate.rb
|
|
2
|
+
require 'helper'
|
|
3
|
+
|
|
4
|
+
describe_juno "transformer_lzo" do
|
|
5
|
+
def new_store
|
|
6
|
+
Juno.build do
|
|
7
|
+
use :Transformer, :value => :lzo
|
|
8
|
+
adapter :Memory
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
include_context 'setup_store'
|
|
13
|
+
it_should_behave_like 'null_objectkey_stringvalue'
|
|
14
|
+
it_should_behave_like 'null_stringkey_stringvalue'
|
|
15
|
+
it_should_behave_like 'null_hashkey_stringvalue'
|
|
16
|
+
it_should_behave_like 'store_objectkey_stringvalue'
|
|
17
|
+
it_should_behave_like 'store_stringkey_stringvalue'
|
|
18
|
+
it_should_behave_like 'store_hashkey_stringvalue'
|
|
19
|
+
it_should_behave_like 'returndifferent_objectkey_stringvalue'
|
|
20
|
+
it_should_behave_like 'returndifferent_stringkey_stringvalue'
|
|
21
|
+
it_should_behave_like 'returndifferent_hashkey_stringvalue'
|
|
22
|
+
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/spec/{transformer_marshal_md5_spread_spec.rb → juno/transformer_marshal_md5_spread_spec.rb}
RENAMED
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Generated by generate.rb
|
|
2
|
+
require 'helper'
|
|
3
|
+
|
|
4
|
+
describe_juno "transformer_marshal_prefix" do
|
|
5
|
+
def new_store
|
|
6
|
+
Juno.build do
|
|
7
|
+
use :Transformer, :key => [:marshal, :prefix], :value => :marshal, :prefix => 'juno'
|
|
8
|
+
adapter :Memory
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
include_context 'setup_store'
|
|
13
|
+
it_should_behave_like 'null_objectkey_objectvalue'
|
|
14
|
+
it_should_behave_like 'null_objectkey_stringvalue'
|
|
15
|
+
it_should_behave_like 'null_objectkey_hashvalue'
|
|
16
|
+
it_should_behave_like 'null_stringkey_objectvalue'
|
|
17
|
+
it_should_behave_like 'null_stringkey_stringvalue'
|
|
18
|
+
it_should_behave_like 'null_stringkey_hashvalue'
|
|
19
|
+
it_should_behave_like 'null_hashkey_objectvalue'
|
|
20
|
+
it_should_behave_like 'null_hashkey_stringvalue'
|
|
21
|
+
it_should_behave_like 'null_hashkey_hashvalue'
|
|
22
|
+
it_should_behave_like 'store_objectkey_objectvalue'
|
|
23
|
+
it_should_behave_like 'store_objectkey_stringvalue'
|
|
24
|
+
it_should_behave_like 'store_objectkey_hashvalue'
|
|
25
|
+
it_should_behave_like 'store_stringkey_objectvalue'
|
|
26
|
+
it_should_behave_like 'store_stringkey_stringvalue'
|
|
27
|
+
it_should_behave_like 'store_stringkey_hashvalue'
|
|
28
|
+
it_should_behave_like 'store_hashkey_objectvalue'
|
|
29
|
+
it_should_behave_like 'store_hashkey_stringvalue'
|
|
30
|
+
it_should_behave_like 'store_hashkey_hashvalue'
|
|
31
|
+
it_should_behave_like 'returndifferent_objectkey_objectvalue'
|
|
32
|
+
it_should_behave_like 'returndifferent_objectkey_stringvalue'
|
|
33
|
+
it_should_behave_like 'returndifferent_objectkey_hashvalue'
|
|
34
|
+
it_should_behave_like 'returndifferent_stringkey_objectvalue'
|
|
35
|
+
it_should_behave_like 'returndifferent_stringkey_stringvalue'
|
|
36
|
+
it_should_behave_like 'returndifferent_stringkey_hashvalue'
|
|
37
|
+
it_should_behave_like 'returndifferent_hashkey_objectvalue'
|
|
38
|
+
it_should_behave_like 'returndifferent_hashkey_stringvalue'
|
|
39
|
+
it_should_behave_like 'returndifferent_hashkey_hashvalue'
|
|
40
|
+
it_should_behave_like 'marshallable_key'
|
|
41
|
+
end
|
data/spec/{transformer_marshal_uuencode_spec.rb → juno/transformer_marshal_uuencode_spec.rb}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Generated by generate.rb
|
|
2
|
+
require 'helper'
|
|
3
|
+
|
|
4
|
+
describe_juno "transformer_quicklz" do
|
|
5
|
+
def new_store
|
|
6
|
+
Juno.build do
|
|
7
|
+
use :Transformer, :value => :quicklz
|
|
8
|
+
adapter :Memory
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
include_context 'setup_store'
|
|
13
|
+
it_should_behave_like 'null_objectkey_stringvalue'
|
|
14
|
+
it_should_behave_like 'null_stringkey_stringvalue'
|
|
15
|
+
it_should_behave_like 'null_hashkey_stringvalue'
|
|
16
|
+
it_should_behave_like 'store_objectkey_stringvalue'
|
|
17
|
+
it_should_behave_like 'store_stringkey_stringvalue'
|
|
18
|
+
it_should_behave_like 'store_hashkey_stringvalue'
|
|
19
|
+
it_should_behave_like 'returndifferent_objectkey_stringvalue'
|
|
20
|
+
it_should_behave_like 'returndifferent_stringkey_stringvalue'
|
|
21
|
+
it_should_behave_like 'returndifferent_hashkey_stringvalue'
|
|
22
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Generated by generate.rb
|
|
2
|
+
require 'helper'
|
|
3
|
+
|
|
4
|
+
describe_juno "transformer_snappy" do
|
|
5
|
+
def new_store
|
|
6
|
+
Juno.build do
|
|
7
|
+
use :Transformer, :value => :snappy
|
|
8
|
+
adapter :Memory
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
include_context 'setup_store'
|
|
13
|
+
it_should_behave_like 'null_objectkey_stringvalue'
|
|
14
|
+
it_should_behave_like 'null_stringkey_stringvalue'
|
|
15
|
+
it_should_behave_like 'null_hashkey_stringvalue'
|
|
16
|
+
it_should_behave_like 'store_objectkey_stringvalue'
|
|
17
|
+
it_should_behave_like 'store_stringkey_stringvalue'
|
|
18
|
+
it_should_behave_like 'store_hashkey_stringvalue'
|
|
19
|
+
it_should_behave_like 'returndifferent_objectkey_stringvalue'
|
|
20
|
+
it_should_behave_like 'returndifferent_stringkey_stringvalue'
|
|
21
|
+
it_should_behave_like 'returndifferent_hashkey_stringvalue'
|
|
22
|
+
end
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
require 'rack/cache/juno'
|
|
2
|
+
require 'rack/mock'
|
|
3
|
+
require 'rack/cache'
|
|
4
|
+
|
|
5
|
+
class Object
|
|
6
|
+
def sha_like?
|
|
7
|
+
length == 40 && self =~ /^[0-9a-z]+$/
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe Rack::Cache::MetaStore::Juno do
|
|
12
|
+
before do
|
|
13
|
+
Rack::Cache::Juno['meta'] = Juno.new(:Memory, :expires => true)
|
|
14
|
+
Rack::Cache::Juno['entity'] = Juno.new(:Memory, :expires => true)
|
|
15
|
+
@store = Rack::Cache::MetaStore::Juno.resolve uri('juno://entity')
|
|
16
|
+
@entity_store = Rack::Cache::EntityStore::Juno.resolve uri('juno://meta')
|
|
17
|
+
@request = mock_request('/', {})
|
|
18
|
+
@response = mock_response(200, {}, ['hello world'])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
after do
|
|
22
|
+
Rack::Cache::Juno['meta'].clear
|
|
23
|
+
Rack::Cache::Juno['entity'].clear
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "has the class referenced by homonym constant" do
|
|
27
|
+
Rack::Cache::MetaStore::JUNO.should == Rack::Cache::MetaStore::Juno
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "instantiates the store" do
|
|
31
|
+
@store.should be_kind_of(Rack::Cache::MetaStore::Juno)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "resolves the connection uri" do
|
|
35
|
+
Rack::Cache::MetaStore::Juno.resolve(uri('juno://Memory?expires=true')).should be_kind_of(Rack::Cache::MetaStore::Juno)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Low-level implementation methods ===========================================
|
|
39
|
+
|
|
40
|
+
it 'writes a list of negotation tuples with #write' do
|
|
41
|
+
# lambda {
|
|
42
|
+
@store.write('/test', [[{}, {}]])
|
|
43
|
+
# }.should_not raise Exception
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'reads a list of negotation tuples with #read' do
|
|
47
|
+
@store.write('/test', [[{},{}],[{},{}]])
|
|
48
|
+
tuples = @store.read('/test')
|
|
49
|
+
tuples.should == [ [{},{}], [{},{}] ]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'reads an empty list with #read when nothing cached at key' do
|
|
53
|
+
@store.read('/nothing').should be_empty
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'removes entries for key with #purge' do
|
|
57
|
+
@store.write('/test', [[{},{}]])
|
|
58
|
+
@store.read('/test').should_not be_empty
|
|
59
|
+
|
|
60
|
+
@store.purge('/test')
|
|
61
|
+
@store.read('/test').should be_empty
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'succeeds when purging non-existing entries' do
|
|
65
|
+
@store.read('/test').should be_empty
|
|
66
|
+
@store.purge('/test')
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'returns nil from #purge' do
|
|
70
|
+
@store.write('/test', [[{},{}]])
|
|
71
|
+
@store.purge('/test').should be_nil
|
|
72
|
+
@store.read('/test').should == []
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
%w[/test http://example.com:8080/ /test?x=y /test?x=y&p=q].each do |key|
|
|
76
|
+
it "can read and write key: '#{key}'" do
|
|
77
|
+
# lambda {
|
|
78
|
+
@store.write(key, [[{},{}]])
|
|
79
|
+
# }.should_not raise Exception
|
|
80
|
+
@store.read(key).should == [[{},{}]]
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "can read and write fairly large keys" do
|
|
85
|
+
key = "b" * 4096
|
|
86
|
+
# lambda {
|
|
87
|
+
@store.write(key, [[{},{}]])
|
|
88
|
+
# }.should_not raise Exception
|
|
89
|
+
@store.read(key).should == [[{},{}]]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "allows custom cache keys from block" do
|
|
93
|
+
request = mock_request('/test', {})
|
|
94
|
+
request.env['rack-cache.cache_key'] =
|
|
95
|
+
lambda { |request| request.path_info.reverse }
|
|
96
|
+
@store.cache_key(request).should == 'tset/'
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "allows custom cache keys from class" do
|
|
100
|
+
request = mock_request('/test', {})
|
|
101
|
+
request.env['rack-cache.cache_key'] = Class.new do
|
|
102
|
+
def self.call(request); request.path_info.reverse end
|
|
103
|
+
end
|
|
104
|
+
@store.cache_key(request).should == 'tset/'
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'does not blow up when given a non-marhsalable object with an ALL_CAPS key' do
|
|
108
|
+
store_simple_entry('/bad', { 'SOME_THING' => Proc.new {} })
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Abstract methods ===========================================================
|
|
112
|
+
|
|
113
|
+
it 'stores a cache entry' do
|
|
114
|
+
cache_key = store_simple_entry
|
|
115
|
+
@store.read(cache_key).should_not be_empty
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'sets the X-Content-Digest response header before storing' do
|
|
119
|
+
cache_key = store_simple_entry
|
|
120
|
+
req, res = @store.read(cache_key).first
|
|
121
|
+
res['X-Content-Digest'].should == 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it 'finds a stored entry with #lookup' do
|
|
125
|
+
store_simple_entry
|
|
126
|
+
response = @store.lookup(@request, @entity_store)
|
|
127
|
+
response.should_not be_nil
|
|
128
|
+
response.should be_kind_of(Rack::Cache::Response)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'does not find an entry with #lookup when none exists' do
|
|
132
|
+
req = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
|
133
|
+
@store.lookup(req, @entity_store).should be_nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "canonizes urls for cache keys" do
|
|
137
|
+
store_simple_entry(path='/test?x=y&p=q')
|
|
138
|
+
|
|
139
|
+
hits_req = mock_request(path, {})
|
|
140
|
+
miss_req = mock_request('/test?p=x', {})
|
|
141
|
+
|
|
142
|
+
@store.lookup(hits_req, @entity_store).should_not be_nil
|
|
143
|
+
@store.lookup(miss_req, @entity_store).should be_nil
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'does not find an entry with #lookup when the body does not exist' do
|
|
147
|
+
store_simple_entry
|
|
148
|
+
@response.headers['X-Content-Digest'].should_not be_nil
|
|
149
|
+
@entity_store.purge(@response.headers['X-Content-Digest'])
|
|
150
|
+
@store.lookup(@request, @entity_store).should be_nil
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it 'restores response headers properly with #lookup' do
|
|
154
|
+
store_simple_entry
|
|
155
|
+
response = @store.lookup(@request, @entity_store)
|
|
156
|
+
response.headers.should == @response.headers.merge('Content-Length' => '4')
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'restores response body from entity store with #lookup' do
|
|
160
|
+
store_simple_entry
|
|
161
|
+
response = @store.lookup(@request, @entity_store)
|
|
162
|
+
body = '' ; response.body.each {|p| body << p}
|
|
163
|
+
body.should == 'test'
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it 'invalidates meta and entity store entries with #invalidate' do
|
|
167
|
+
store_simple_entry
|
|
168
|
+
@store.invalidate(@request, @entity_store)
|
|
169
|
+
response = @store.lookup(@request, @entity_store)
|
|
170
|
+
response.should be_kind_of(Rack::Cache::Response)
|
|
171
|
+
response.should_not be :fresh?
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'succeeds quietly when #invalidate called with no matching entries' do
|
|
175
|
+
req = mock_request('/test', {})
|
|
176
|
+
@store.invalidate(req, @entity_store)
|
|
177
|
+
@store.lookup(@request, @entity_store).should be_nil
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Vary =======================================================================
|
|
181
|
+
|
|
182
|
+
it 'does not return entries that Vary with #lookup' do
|
|
183
|
+
req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
|
184
|
+
req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
|
|
185
|
+
res = mock_response(200, {'Vary' => 'Foo Bar'}, ['test'])
|
|
186
|
+
@store.store(req1, res, @entity_store)
|
|
187
|
+
|
|
188
|
+
@store.lookup(req2, @entity_store).should be_nil
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it 'stores multiple responses for each Vary combination' do
|
|
192
|
+
req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
|
193
|
+
res1 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 1'])
|
|
194
|
+
key = @store.store(req1, res1, @entity_store)
|
|
195
|
+
|
|
196
|
+
req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
|
|
197
|
+
res2 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 2'])
|
|
198
|
+
@store.store(req2, res2, @entity_store)
|
|
199
|
+
|
|
200
|
+
req3 = mock_request('/test', {'HTTP_FOO' => 'Baz', 'HTTP_BAR' => 'Boom'})
|
|
201
|
+
res3 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 3'])
|
|
202
|
+
@store.store(req3, res3, @entity_store)
|
|
203
|
+
|
|
204
|
+
slurp(@store.lookup(req3, @entity_store).body).should == 'test 3'
|
|
205
|
+
slurp(@store.lookup(req1, @entity_store).body).should == 'test 1'
|
|
206
|
+
slurp(@store.lookup(req2, @entity_store).body).should == 'test 2'
|
|
207
|
+
|
|
208
|
+
@store.read(key).length.should == 3
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it 'overwrites non-varying responses with #store' do
|
|
212
|
+
req1 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
|
213
|
+
res1 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 1'])
|
|
214
|
+
key = @store.store(req1, res1, @entity_store)
|
|
215
|
+
slurp(@store.lookup(req1, @entity_store).body).should == 'test 1'
|
|
216
|
+
|
|
217
|
+
req2 = mock_request('/test', {'HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam'})
|
|
218
|
+
res2 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 2'])
|
|
219
|
+
@store.store(req2, res2, @entity_store)
|
|
220
|
+
slurp(@store.lookup(req2, @entity_store).body).should == 'test 2'
|
|
221
|
+
|
|
222
|
+
req3 = mock_request('/test', {'HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar'})
|
|
223
|
+
res3 = mock_response(200, {'Vary' => 'Foo Bar'}, ['test 3'])
|
|
224
|
+
@store.store(req3, res3, @entity_store)
|
|
225
|
+
slurp(@store.lookup(req1, @entity_store).body).should == 'test 3'
|
|
226
|
+
|
|
227
|
+
@store.read(key).length.should == 2
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
private
|
|
231
|
+
def mock_request(uri, opts)
|
|
232
|
+
env = Rack::MockRequest.env_for(uri, opts || {})
|
|
233
|
+
Rack::Cache::Request.new(env)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def mock_response(status, headers, body)
|
|
237
|
+
headers ||= {}
|
|
238
|
+
body = Array(body).compact
|
|
239
|
+
Rack::Cache::Response.new(status, headers, body)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def slurp(body)
|
|
243
|
+
buf = ''
|
|
244
|
+
body.each { |part| buf << part }
|
|
245
|
+
buf
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Stores an entry for the given request args, returns a url encoded cache key
|
|
249
|
+
# for the request.
|
|
250
|
+
def store_simple_entry(*request_args)
|
|
251
|
+
path, headers = request_args
|
|
252
|
+
@request = mock_request(path || '/test', headers || {})
|
|
253
|
+
@response = mock_response(200, {'Cache-Control' => 'max-age=420'}, ['test'])
|
|
254
|
+
body = @response.body
|
|
255
|
+
cache_key = @store.store(@request, @response, @entity_store)
|
|
256
|
+
@response.body.should == body
|
|
257
|
+
cache_key
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def uri(uri)
|
|
261
|
+
URI.parse uri
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
describe Rack::Cache::EntityStore::Juno do
|
|
266
|
+
before do
|
|
267
|
+
@store = Rack::Cache::EntityStore::Juno.resolve(uri('juno://Memory?expires=true'))
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
it 'has the class referenced by homonym constant' do
|
|
271
|
+
Rack::Cache::EntityStore::JUNO.should == Rack::Cache::EntityStore::Juno
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
it 'resolves the connection uri' do
|
|
275
|
+
Rack::Cache::EntityStore::Juno.resolve(uri('juno://Memory?expires=true')).should be_kind_of(Rack::Cache::EntityStore::Juno)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
it 'responds to all required messages' do
|
|
279
|
+
%w[read open write exist?].each do |message|
|
|
280
|
+
@store.should respond_to message
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
it 'stores bodies with #write' do
|
|
285
|
+
key, size = @store.write(['My wild love went riding,'])
|
|
286
|
+
key.should_not be_nil
|
|
287
|
+
key.should be_sha_like
|
|
288
|
+
|
|
289
|
+
data = @store.read(key)
|
|
290
|
+
data.should == 'My wild love went riding,'
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
it 'takes a ttl parameter for #write' do
|
|
294
|
+
key, size = @store.write(['My wild love went riding,'], 0)
|
|
295
|
+
key.should_not be_nil
|
|
296
|
+
key.should be_sha_like
|
|
297
|
+
|
|
298
|
+
data = @store.read(key)
|
|
299
|
+
data.should == 'My wild love went riding,'
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it 'correctly determines whether cached body exists for key with #exist?' do
|
|
303
|
+
key, size = @store.write(['She rode to the devil,'])
|
|
304
|
+
@store.exist?(key).should be_true
|
|
305
|
+
@store.exist?('938jasddj83jasdh4438021ksdfjsdfjsdsf').should be_false
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it 'can read data written with #write' do
|
|
309
|
+
key, size = @store.write(['And asked him to pay.'])
|
|
310
|
+
data = @store.read(key)
|
|
311
|
+
data.should == 'And asked him to pay.'
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it 'gives a 40 character SHA1 hex digest from #write' do
|
|
315
|
+
key, size = @store.write(['she rode to the sea;'])
|
|
316
|
+
key.should_not be_nil
|
|
317
|
+
key.length.should == 40
|
|
318
|
+
key.should match(/^[0-9a-z]+$/)
|
|
319
|
+
key.should == '90a4c84d51a277f3dafc34693ca264531b9f51b6'
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
it 'returns the entire body as a String from #read' do
|
|
323
|
+
key, size = @store.write(['She gathered together'])
|
|
324
|
+
@store.read(key).should == 'She gathered together'
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
it 'returns nil from #read when key does not exist' do
|
|
328
|
+
@store.read('87fe0a1ae82a518592f6b12b0183e950b4541c62').should be_nil
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
it 'returns a Rack compatible body from #open' do
|
|
332
|
+
key, size = @store.write(['Some shells for her hair.'])
|
|
333
|
+
body = @store.open(key)
|
|
334
|
+
body.should respond_to :each
|
|
335
|
+
buf = ''
|
|
336
|
+
body.each { |part| buf << part }
|
|
337
|
+
buf.should == 'Some shells for her hair.'
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
it 'returns nil from #open when key does not exist' do
|
|
341
|
+
@store.open('87fe0a1ae82a518592f6b12b0183e950b4541c62').should be_nil
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
it 'deletes stored entries with #purge' do
|
|
345
|
+
key, size = @store.write(['My wild love went riding,'])
|
|
346
|
+
@store.purge(key).should be_nil
|
|
347
|
+
@store.read(key).should be_nil
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
private
|
|
351
|
+
|
|
352
|
+
def uri(uri)
|
|
353
|
+
URI.parse uri
|
|
354
|
+
end
|
|
355
|
+
end
|