active_model_serializers/test/action_controller/serialization_test.rb
Mauro George 51424963da ActiveSupport::Notifications render.active_model_serializers
Squashed commits:

Add Logging

Generates logging when renders a serializer.

Tunning performance on notify_active_support

- Use yield over block.call
- Freeze the event name string

Organize the logger architeture

* Keep only the `ActiveModel::Serializer.logger` to follow the same public API we
  have for example to config, like `ActiveModel::Serializer.config.adapter` and
  remove the `ActiveModelSerializers.logger` API.
* Define the logger on the load of the AMS, following the Rails convention on
  Railties [1], [2] and [3].

This way on non Rails apps we have a default logger and on Rails apps we will
use the `Rails.logger` the same way that Active Job do [4].

[1]: 2ad9afe4ff/activejob/lib/active_job/railtie.rb (L9-L11)
[2]: 2ad9afe4ff/activerecord/lib/active_record/railtie.rb (L75-L77)
[3]: 2ad9afe4ff/actionview/lib/action_view/railtie.rb (L19-L21)
[4]: 2ad9afe4ff/activejob/lib/active_job/logging.rb (L10-L11)

Performance tunning on LogSubscriber#render

Move the definition of locals to inside the `info` block this way the code is
executed only when the logger is called.

Remove not needed check on SerializableResource

Use SerializableResource on ActionController integration

On the ActionController was using a adapter, and since the instrumentation is
made on the SerializableResource we need to use the SerializableResource over
the adapter directly. Otherwise the logger is not called on a Rails app.

Use SerializableResource on the ActionController, since this is the main
interface to create and call a serializer.

Using always the SerializableResource we can keep the adapter code more easy to
mantain since no Adapter will need to call the instrumentation, only the
SerializableResource care about this.

Add docs about logging

Add a CHANGELOG entry

Keep the ActiveModelSerializers.logger

Better wording on Logging docs

[ci skip]

Add doc about instrumentation

[ci skip]

Use ActiveModel::Callbacks on the SerializableResource
2015-11-10 03:09:24 -06:00

436 lines
13 KiB
Ruby

require 'test_helper'
module ActionController
module Serialization
class ImplicitSerializerTest < ActionController::TestCase
include ActiveSupport::Testing::Stream
class ImplicitSerializationTestController < ActionController::Base
include SerializationTesting
def render_using_implicit_serializer
@profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
render json: @profile
end
def render_using_default_adapter_root
@profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
render json: @profile
end
def render_array_using_custom_root
@profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
render json: [@profile], root: 'custom_root'
end
def render_array_that_is_empty_using_custom_root
render json: [], root: 'custom_root'
end
def render_object_using_custom_root
@profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
render json: @profile, root: 'custom_root'
end
def render_array_using_implicit_serializer
array = [
Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
Profile.new(name: 'Name 2', description: 'Description 2', comments: 'Comments 2')
]
render json: array
end
def render_array_using_implicit_serializer_and_meta
@profiles = [
Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
]
render json: @profiles, meta: { total: 10 }
end
def render_object_with_cache_enabled
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
@author = Author.new(id: 1, name: 'Joao Moura.')
@post = Post.new(id: 1, title: 'New Post', body: 'Body', comments: [@comment], author: @author)
generate_cached_serializer(@post)
@post.title = 'ZOMG a New Post'
render json: @post
end
def render_json_object_without_serializer
render json: { error: 'Result is Invalid' }
end
def render_json_array_object_without_serializer
render json: [{ error: 'Result is Invalid' }]
end
def update_and_render_object_with_cache_enabled
@post.updated_at = Time.now
generate_cached_serializer(@post)
render json: @post
end
def render_object_expired_with_cache_enabled
comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
author = Author.new(id: 1, name: 'Joao Moura.')
post = Post.new(id: 1, title: 'New Post', body: 'Body', comments: [comment], author: author)
generate_cached_serializer(post)
post.title = 'ZOMG a New Post'
expires_in = [
PostSerializer._cache_options[:expires_in],
CommentSerializer._cache_options[:expires_in],
].max + 200
Timecop.travel(Time.zone.now + expires_in) do
render json: post
end
end
def render_changed_object_with_cache_enabled
comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
author = Author.new(id: 1, name: 'Joao Moura.')
post = Post.new(id: 1, title: 'ZOMG a New Post', body: 'Body', comments: [comment], author: author)
render json: post
end
def render_fragment_changed_object_with_only_cache_enabled
author = Author.new(id: 1, name: 'Joao Moura.')
role = Role.new(id: 42, name: 'ZOMG A ROLE', description: 'DESCRIPTION HERE', author: author)
generate_cached_serializer(role)
role.name = 'lol'
role.description = 'HUEHUEBRBR'
render json: role
end
def render_fragment_changed_object_with_except_cache_enabled
author = Author.new(id: 1, name: 'Joao Moura.')
bio = Bio.new(id: 42, content: 'ZOMG A ROLE', rating: 5, author: author)
generate_cached_serializer(bio)
bio.content = 'lol'
bio.rating = 0
render json: bio
end
def render_fragment_changed_object_with_relationship
comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
comment2 = Comment.new(id: 1, body: 'ZOMG AN UPDATED-BUT-NOT-CACHE-EXPIRED COMMENT')
like = Like.new(id: 1, likeable: comment, time: 3.days.ago)
generate_cached_serializer(like)
like.likable = comment2
like.time = Time.zone.now.to_s
render json: like
end
end
tests ImplicitSerializationTestController
# We just have Null for now, this will change
def test_render_using_implicit_serializer
get :render_using_implicit_serializer
expected = {
name: 'Name 1',
description: 'Description 1'
}
assert_equal 'application/json', @response.content_type
assert_equal expected.to_json, @response.body
end
def test_render_using_default_root
with_adapter :json_api do
get :render_using_default_adapter_root
end
expected = {
data: {
id: assigns(:profile).id.to_s,
type: 'profiles',
attributes: {
name: 'Name 1',
description: 'Description 1'
}
}
}
assert_equal 'application/json', @response.content_type
assert_equal expected.to_json, @response.body
end
def test_render_array_using_custom_root
with_adapter :json do
get :render_array_using_custom_root
end
expected = { custom_roots: [{ name: 'Name 1', description: 'Description 1' }] }
assert_equal 'application/json', @response.content_type
assert_equal expected.to_json, @response.body
end
def test_render_array_that_is_empty_using_custom_root
with_adapter :json do
get :render_array_that_is_empty_using_custom_root
end
expected = { custom_roots: [] }
assert_equal 'application/json', @response.content_type
assert_equal expected.to_json, @response.body
end
def test_render_object_using_custom_root
with_adapter :json do
get :render_object_using_custom_root
end
expected = { custom_root: { name: 'Name 1', description: 'Description 1' } }
assert_equal 'application/json', @response.content_type
assert_equal expected.to_json, @response.body
end
def test_render_json_object_without_serializer
get :render_json_object_without_serializer
assert_equal 'application/json', @response.content_type
expected_body = { error: 'Result is Invalid' }
assert_equal expected_body.to_json, @response.body
end
def test_render_json_array_object_without_serializer
get :render_json_array_object_without_serializer
assert_equal 'application/json', @response.content_type
expected_body = [{ error: 'Result is Invalid' }]
assert_equal expected_body.to_json, @response.body
end
def test_render_array_using_implicit_serializer
get :render_array_using_implicit_serializer
assert_equal 'application/json', @response.content_type
expected = [
{
name: 'Name 1',
description: 'Description 1'
},
{
name: 'Name 2',
description: 'Description 2'
}
]
assert_equal expected.to_json, @response.body
end
def test_render_array_using_implicit_serializer_and_meta
with_adapter :json_api do
get :render_array_using_implicit_serializer_and_meta
end
expected = {
data: [
{
id: assigns(:profiles).first.id.to_s,
type: 'profiles',
attributes: {
name: 'Name 1',
description: 'Description 1'
}
}
],
meta: {
total: 10
}
}
assert_equal 'application/json', @response.content_type
assert_equal expected.to_json, @response.body
end
def test_render_with_cache_enable
expected = {
id: 1,
title: 'New Post',
body: 'Body',
comments: [
{
id: 1,
body: 'ZOMG A COMMENT' }
],
blog: {
id: 999,
name: 'Custom blog'
},
author: {
id: 1,
name: 'Joao Moura.'
}
}
ActionController::Base.cache_store.clear
Timecop.freeze(Time.zone.now) do
get :render_object_with_cache_enabled
assert_equal 'application/json', @response.content_type
assert_equal expected.to_json, @response.body
get :render_changed_object_with_cache_enabled
assert_equal expected.to_json, @response.body
end
ActionController::Base.cache_store.clear
get :render_changed_object_with_cache_enabled
assert_not_equal expected.to_json, @response.body
end
def test_render_with_cache_enable_and_expired
ActionController::Base.cache_store.clear
get :render_object_expired_with_cache_enabled
expected = {
id: 1,
title: 'ZOMG a New Post',
body: 'Body',
comments: [
{
id: 1,
body: 'ZOMG A COMMENT' }
],
blog: {
id: 999,
name: 'Custom blog'
},
author: {
id: 1,
name: 'Joao Moura.'
}
}
assert_equal 'application/json', @response.content_type
actual = @response.body
expected = expected.to_json
if ENV['APPVEYOR'] && actual != expected
skip('Cache expiration tests sometimes fail on Appveyor. FIXME :)')
else
assert_equal actual, expected
end
end
def test_render_with_fragment_only_cache_enable
ActionController::Base.cache_store.clear
get :render_fragment_changed_object_with_only_cache_enabled
response = JSON.parse(@response.body)
assert_equal 'application/json', @response.content_type
assert_equal 'ZOMG A ROLE', response['name']
assert_equal 'HUEHUEBRBR', response['description']
end
def test_render_with_fragment_except_cache_enable
ActionController::Base.cache_store.clear
get :render_fragment_changed_object_with_except_cache_enabled
response = JSON.parse(@response.body)
assert_equal 'application/json', @response.content_type
assert_equal 5, response['rating']
assert_equal 'lol', response['content']
end
def test_render_fragment_changed_object_with_relationship
ActionController::Base.cache_store.clear
Timecop.freeze(Time.zone.now) do
get :render_fragment_changed_object_with_relationship
response = JSON.parse(@response.body)
expected_return = {
'id' => 1,
'time' => Time.zone.now.to_s,
'likeable' => {
'id' => 1,
'body' => 'ZOMG A COMMENT'
}
}
assert_equal 'application/json', @response.content_type
assert_equal expected_return, response
end
end
def test_cache_expiration_on_update
ActionController::Base.cache_store.clear
get :render_object_with_cache_enabled
expected = {
id: 1,
title: 'ZOMG a New Post',
body: 'Body',
comments: [
{
id: 1,
body: 'ZOMG A COMMENT' }
],
blog: {
id: 999,
name: 'Custom blog'
},
author: {
id: 1,
name: 'Joao Moura.'
}
}
get :update_and_render_object_with_cache_enabled
assert_equal 'application/json', @response.content_type
actual = @response.body
expected = expected.to_json
if ENV['APPVEYOR'] && actual != expected
skip('Cache expiration tests sometimes fail on Appveyor. FIXME :)')
else
assert_equal actual, expected
end
end
def test_warn_overridding_use_adapter_as_falsy_on_controller_instance
controller = Class.new(ImplicitSerializationTestController) do
def use_adapter?
false
end
end.new
assert_match(/adapter: false/, (capture(:stderr) do
controller.get_serializer(Profile.new)
end))
end
def test_dont_warn_overridding_use_adapter_as_truthy_on_controller_instance
controller = Class.new(ImplicitSerializationTestController) do
def use_adapter?
true
end
end.new
assert_equal '', (capture(:stderr) do
controller.get_serializer(Profile.new)
end)
end
def test_render_event_is_emmited
ActiveSupport::Notifications.subscribe('render.active_model_serializers') do |name|
@name = name
end
get :render_using_implicit_serializer
assert_equal 'render.active_model_serializers', @name
end
end
end
end