Include adapter in cache key

Confirm caching attributes with different key json_api vs. attributes adapter

Adapted from @kevintyll's original test
https://github.com/rails-api/active_model_serializers/pull/1644#issuecomment-204147094
This commit is contained in:
kevintyll
2015-11-25 12:31:32 -05:00
committed by Benjamin Fleischer
parent e118599052
commit 16a3f93ce9
6 changed files with 127 additions and 31 deletions

View File

@@ -102,12 +102,13 @@ module ActiveModelSerializers
render_object_with_cache(uncached_author)
key = "#{uncached_author_serializer.class._cache_key}/#{uncached_author_serializer.object.id}-#{uncached_author_serializer.object.updated_at.strftime("%Y%m%d%H%M%S%9N")}"
key = "#{key}/#{adapter.cached_name}"
assert_equal(uncached_author_serializer.attributes.to_json, cache_store.fetch(key).to_json)
end
def test_default_cache_key_fallback
render_object_with_cache(@comment)
key = @comment.cache_key
key = "#{@comment.cache_key}/#{adapter.cached_name}"
assert_equal(@comment_serializer.attributes.to_json, cache_store.fetch(key).to_json)
end
@@ -138,9 +139,9 @@ module ActiveModelSerializers
Timecop.freeze(Time.current) do
render_object_with_cache(@post)
key = @post.cache_key
key = "#{@post.cache_key}/#{adapter.cached_name}"
assert_equal(@post_serializer.attributes, cache_store.fetch(key))
key = @comment.cache_key
key = "#{@comment.cache_key}/#{adapter.cached_name}"
assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
end
end
@@ -151,9 +152,9 @@ module ActiveModelSerializers
render_object_with_cache(@post)
# Check if it cached the objects separately
key = @post.cache_key
key = "#{@post.cache_key}/#{adapter.cached_name}"
assert_equal(@post_serializer.attributes, cache_store.fetch(key))
key = @comment.cache_key
key = "#{@comment.cache_key}/#{adapter.cached_name}"
assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
# Simulating update on comments relationship with Post
@@ -165,9 +166,9 @@ module ActiveModelSerializers
render_object_with_cache(@post)
# Check if the the new comment was cached
key = new_comment.cache_key
key = "#{new_comment.cache_key}/#{adapter.cached_name}"
assert_equal(new_comment_serializer.attributes, cache_store.fetch(key))
key = @post.cache_key
key = "#{@post.cache_key}/#{adapter.cached_name}"
assert_equal(@post_serializer.attributes, cache_store.fetch(key))
end
end
@@ -183,7 +184,8 @@ module ActiveModelSerializers
hash = render_object_with_cache(@location)
assert_equal(hash, expected_result)
assert_equal({ place: 'Nowhere' }, cache_store.fetch(@location.cache_key))
key = "#{@location.cache_key}/#{adapter.cached_name}"
assert_equal({ place: 'Nowhere' }, cache_store.fetch(key))
end
def test_fragment_cache_with_inheritance
@@ -194,9 +196,87 @@ module ActiveModelSerializers
refute_includes(base.keys, :special_attribute)
end
def test_uses_adapter_in_cache_key
render_object_with_cache(@post)
key = "#{@post.cache_key}/#{adapter.class.to_s.demodulize.underscore}"
assert_equal(@post_serializer.attributes, cache_store.fetch(key))
end
# Based on original failing test by @kevintyll
# rubocop:disable Metrics/AbcSize
def test_a_serializer_rendered_by_two_adapter_returns_differently_cached_attributes
Object.const_set(:Alert, Class.new(ActiveModelSerializers::Model) do
attr_accessor :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
end)
Object.const_set(:UncachedAlertSerializer, Class.new(ActiveModel::Serializer) do
attributes :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
end)
Object.const_set(:AlertSerializer, Class.new(UncachedAlertSerializer) do
cache
end)
alert = Alert.new(
id: 1,
status: 'fail',
resource: 'resource-1',
started_at: Time.new(2016, 3, 31, 21, 36, 35, 0),
ended_at: nil,
updated_at: Time.new(2016, 3, 31, 21, 27, 35, 0),
created_at: Time.new(2016, 3, 31, 21, 37, 35, 0)
)
expected_cached_attributes = {
id: 1,
status: 'fail',
resource: 'resource-1',
started_at: alert.started_at,
ended_at: nil,
updated_at: alert.updated_at,
created_at: alert.created_at
}
expected_cached_jsonapi_attributes = {
id: '1',
type: 'alerts',
attributes: {
status: 'fail',
resource: 'resource-1',
started_at: alert.started_at,
ended_at: nil,
updated_at: alert.updated_at,
created_at: alert.created_at
}
}
# Assert attributes are serialized correctly
serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :attributes)
attributes_serialization = serializable_alert.as_json
assert_equal expected_cached_attributes, alert.attributes
assert_equal alert.attributes, attributes_serialization
attributes_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key(serializable_alert.adapter)
assert_equal attributes_serialization, cache_store.fetch(attributes_cache_key)
serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :json_api)
jsonapi_cache_key = CachedSerializer.new(serializable_alert.adapter.serializer).cache_key(serializable_alert.adapter)
# Assert cache keys differ
refute_equal attributes_cache_key, jsonapi_cache_key
# Assert (cached) serializations differ
jsonapi_serialization = serializable_alert.as_json
assert_equal alert.status, jsonapi_serialization.fetch(:data).fetch(:attributes).fetch(:status)
serializable_alert = serializable(alert, serializer: UncachedAlertSerializer, adapter: :json_api)
assert_equal serializable_alert.as_json, jsonapi_serialization
cached_serialization = cache_store.fetch(jsonapi_cache_key)
assert_equal expected_cached_jsonapi_attributes, cached_serialization
ensure
Object.send(:remove_const, :Alert)
Object.send(:remove_const, :AlertSerializer)
Object.send(:remove_const, :UncachedAlertSerializer)
end
# rubocop:enable Metrics/AbcSize
def test_uses_file_digest_in_cache_key
render_object_with_cache(@blog)
key = "#{@blog.cache_key}/#{::Model::FILE_DIGEST}"
key = "#{@blog.cache_key}/#{adapter.cached_name}/#{::Model::FILE_DIGEST}"
assert_equal(@blog_serializer.attributes, cache_store.fetch(key))
end
@@ -205,13 +285,13 @@ module ActiveModelSerializers
end
def test_object_cache_keys
serializer = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
serializable = ActiveModelSerializers::SerializableResource.new([@comment, @comment])
include_tree = ActiveModel::Serializer::IncludeTree.from_include_args('*')
actual = CachedSerializer.object_cache_keys(serializer, include_tree)
actual = CachedSerializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_tree)
assert_equal actual.size, 3
assert actual.any? { |key| key == 'comment/1' }
assert actual.any? { |key| key == "comment/1/#{serializable.adapter.cached_name}" }
assert actual.any? { |key| key =~ %r{post/post-\d+} }
assert actual.any? { |key| key =~ %r{author/author-\d+} }
end
@@ -226,13 +306,13 @@ module ActiveModelSerializers
attributes.send(:cache_attributes)
cached_attributes = attributes.instance_variable_get(:@cached_attributes)
assert_equal cached_attributes[@comment.cache_key], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
assert_equal cached_attributes[@comment.post.cache_key], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
assert_equal cached_attributes["#{@comment.cache_key}/#{attributes.cached_name}"], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
assert_equal cached_attributes["#{@comment.post.cache_key}/#{attributes.cached_name}"], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
writer = @comment.post.blog.writer
writer_cache_key = writer.cache_key
assert_equal cached_attributes[writer_cache_key], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
assert_equal cached_attributes["#{writer_cache_key}/#{attributes.cached_name}"], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
end
end
@@ -287,16 +367,21 @@ module ActiveModelSerializers
private
def render_object_with_cache(obj, options = {})
serializable(obj, options).serializable_hash
end
def cache_store
ActiveModelSerializers.config.cache_store
end
def render_object_with_cache(obj, options = {})
@serializable_resource = serializable(obj, options)
@serializable_resource.serializable_hash
end
def adapter
@serializable_resource.adapter
end
def cached_serialization(serializer)
cache_key = CachedSerializer.new(serializer).cache_key
cache_key = CachedSerializer.new(serializer).cache_key(adapter)
cache_store.fetch(cache_key)
end
end