Skip to content

Commit

Permalink
[marshaling] specs, specs, specs... (mutli_operations and dalli bugs)
Browse files Browse the repository at this point in the history
  • Loading branch information
0exp committed Dec 2, 2018
1 parent e53f702 commit 3a4b971
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 20 deletions.
2 changes: 1 addition & 1 deletion lib/any_cache/adapters/active_support_naive_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def fetch_multi(*keys, **options, &fallback)
# use own #fetch_multi implementation cuz original #fetch_multi
# does not support :force option
keys.each_with_object({}) do |key, dataset|
dataset[key] = driver.fetch(key, force: force, expires_in: expires_in, &fallback)
dataset[key] = driver.fetch(key, force: force_rewrite, expires_in: expires_in, &fallback)
end
end
end
Expand Down
5 changes: 4 additions & 1 deletion lib/any_cache/adapters/dalli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,13 @@ def read_multi(*keys, **options)
raw = options.fetch(:raw, false)

entries = get_multi(*keys).tap do |res|
# TODO: returned res.keys items should have consistent types with initial keys items
# (at this moment you cant return requested symbolic keys -
# your keys will be stringifed by dalli)
res.merge!(Hash[(keys - res.keys).zip(READ_MULTI_EMPTY_KEYS_SET)])
end

raw ? entires : detransform_pairset(entries)
raw ? entries : detransform_pairset(entries)
end

# @param key [String]
Expand Down
98 changes: 80 additions & 18 deletions spec/features/raw_non_raw_read_write_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@
cached_ruby_object = cache_store.read(:ruby_object)

expect(cached_ruby_object).to be_a(SimpleRubyObject)
expect(cached_ruby_object.a).to eq('a')
expect(cached_ruby_object.b).to eq(123)
expect(cached_ruby_object.c).to eq(true)
expect(cached_ruby_object).to have_attributes(a: 'a', b: 123, c: true)
end

context 'write non-raw (:raw option is false)' do
context 'write non-raw (write real ruby object) (:raw => false)' do
context 'single read/write' do
specify 'writes real ruby object' do
specify '#read/#write works correctly' do
# works with initial structures
ruby_object = { a: 1, b: 2, c: 3 }
cache_store.write(:non_raw, ruby_object, raw: false)
Expand All @@ -33,38 +31,71 @@
cached_another_ruby_object = cache_store.read(:non_raw, raw: false)

expect(cached_another_ruby_object).to be_a(SimpleRubyObject)
expect(cached_another_ruby_object.a).to eq(1)
expect(cached_another_ruby_object.b).to eq(2)
expect(cached_another_ruby_object.c).to eq(3)
expect(cached_another_ruby_object).to have_attributes(a: 1, b: 2, c: 3)
end

specify '#fetch works correctly' do
returned_ruby_object = cache_store.fetch(:non_raw, raw: false) do |key|
SimpleRubyObject.new(key, 1, false)
end

cached_ruby_object = cache_store.fetch(:non_raw, raw: false)

[cached_ruby_object, returned_ruby_object].each do |cached_object|
expect(cached_object).to be_a(SimpleRubyObject)
expect(cached_object).to have_attributes(a: :non_raw, b: 1, c: false)
end
end
end

context 'multi read/write' do
specify 'writes real ruby object' do
specify '#read_multi/#write_multi works correctly' do
# worsk with any adequate type
ruby_entries = {
hash_ruby_obj: { a: 1, b: 2, c: 3 },
bool_ruby_obj: true,
real_ruby_obj: SimpleRubyObject.new(1, 2, 3)
'hash_ruby_obj' => { a: 1, b: 2, c: 3 },
'bool_ruby_obj' => true,
'real_ruby_obj' => SimpleRubyObject.new(1, 2, 3)
}

cache_store.write_multi(ruby_entries, raw: false)
cached_ruby_entries = cache_store.read_multi(*ruby_entries.keys, raw: false)

expect(cached_ruby_entries).to match(ruby_entries)
end

specify '#fetch_multi works correctly' do
returned_ruby_entries = cache_store.fetch_multi(:a, :b, :c, raw: false) do |key|
SimpleRubyObject.new(key, 1, true)
end

cached_ruby_entries = cache_store.fetch_multi(:a, :b, :c, raw: false)

[cached_ruby_entries, returned_ruby_entries].each do |cached_entries|
expect(cached_entries[:a]).to be_a(SimpleRubyObject)
expect(cached_entries[:b]).to be_a(SimpleRubyObject)
expect(cached_entries[:c]).to be_a(SimpleRubyObject)

expect(cached_entries[:a]).to have_attributes(a: :a, b: 1, c: true)
expect(cached_entries[:b]).to have_attributes(a: :b, b: 1, c: true)
expect(cached_entries[:c]).to have_attributes(a: :c, b: 1, c: true)
end
end
end
end

# NOTE:
# ActiveSupport::Cache::FileStore and ActiveSupport::Cache::ReadStore does not support
# raw/non-raw optionality cuz under the hood these classes invokes #write_entry method
# that uses Marshal.dump before the write-to-disk and write-to-memory operations respectively.
context 'write raw (:raw option is true)', exclude: %i[as_file_store as_memory_store] do
context(
'write raw (:raw => true) (uses internal cache-related string-like object write operation)',
exclude: %i[as_file_store as_memory_store]
) do

before { stub_const('SimpleRubyObject', Struct.new(:a, :b, :c)) }

context 'single read/write' do
specify 'uses internal cache-related string-like object write operation' do
specify '#read/#write works correctly' do
ruby_object = { a: 1, b: 2, c: 3}
cache_store.write(:raw, ruby_object, raw: true)
cached_ruby_object = cache_store.read(:raw, raw: true)
Expand All @@ -77,15 +108,30 @@

expect(cached_another_ruby_object).to be_a(String)
end

specify '#fetch works correctly' do
returned_ruby_object = cache_store.fetch(:raw, raw: true) do |key|
SimpleRubyObject.new(key, 1, false)
end

cached_ruby_object = cache_store.fetch(:raw, raw: true)

# TODO: think about consistent fetching
# - expect(returned_ruby_object).to be_a(String)
# - nonexistent value (first #fetch invokation)
# will return the &fallback's proc result (real ruby object)

expect(cached_ruby_object).to be_a(String)
end
end

context 'multi read/write' do
specify 'uses internal cache-related string-like object write operation' do
specify '#read_multi/#write_multi works correctly' do
# works with any adequate type
ruby_entries = {
hash_ruby_obj: { a: 1, b: 2, c: 3 },
bool_ruby_obj: true,
real_ruby_obj: SimpleRubyObject.new(1, 2, 3)
'hash_ruby_obj' => { a: 1, b: 2, c: 3 },
'bool_ruby_obj' => true,
'real_ruby_obj' => SimpleRubyObject.new(1, 2, 3)
}

cache_store.write_multi(ruby_entries, raw: true)
Expand All @@ -94,6 +140,22 @@
expect(cached_ruby_entries.keys).to contain_exactly(*ruby_entries.keys)
expect(cached_ruby_entries.values).to all(be_a(String))
end

specify '#fetch_multi works correctly' do
returned_ruby_entries = cache_store.fetch_multi(:a, :b, raw: true) do |key|
SimpleRubyObject.new(key, true, false)
end

cached_ruby_entries = cache_store.fetch_multi(:a, :b, raw: true)

# TODO: think about consistent fetching
# - expect(returned_ruby_entries.values).to all(be_a(String)) and so on
# - nonexistent value (first #fetch invokation)
# will return the &fallback's proc result (real ruby object)

expect(cached_ruby_entries.keys).to contain_exactly(:a, :b)
expect(cached_ruby_entries.values).to all(be_a(String))
end
end
end
end

0 comments on commit 3a4b971

Please sign in to comment.