ash/test/tracer_test.exs
Zach Daniel f583ababbc fix: fix keyset pagination ordering bug
fix: short names are snake cased
2022-09-12 11:17:44 -04:00

307 lines
8.8 KiB
Elixir

defmodule Ash.Test.TracerTest.AsyncLoadTest do
@moduledoc false
use ExUnit.Case, async: false
import ExUnit.CaptureLog
require Ash.Query
defmodule Author do
@moduledoc false
use Ash.Resource,
data_layer: Ash.DataLayer.Mnesia,
authorizers: [
Ash.Test.Authorizer
]
actions do
defaults [:create, :read, :update, :destroy]
end
attributes do
uuid_primary_key :id
attribute :name, :string
end
relationships do
has_many :posts, Ash.Test.TracerTest.AsyncLoadTest.Post, destination_attribute: :author_id
end
end
defmodule Post do
@moduledoc false
use Ash.Resource,
data_layer: Ash.DataLayer.Mnesia
actions do
defaults [:create, :read, :update, :destroy]
end
attributes do
uuid_primary_key :id
attribute :title, :string
end
relationships do
belongs_to :author, Author
many_to_many :categories, Ash.Test.TracerTest.AsyncLoadTest.Category,
through: Ash.Test.TracerTest.AsyncLoadTest.PostCategory,
destination_attribute_on_join_resource: :category_id,
source_attribute_on_join_resource: :post_id
end
end
defmodule PostCategory do
@moduledoc false
use Ash.Resource, data_layer: Ash.DataLayer.Mnesia
actions do
defaults [:create, :read, :update, :destroy]
end
relationships do
belongs_to :post, Post, primary_key?: true, required?: true
belongs_to :category, Ash.Test.TracerTest.AsyncLoadTest.Category,
primary_key?: true,
required?: true
end
end
defmodule Category do
@moduledoc false
use Ash.Resource, data_layer: Ash.DataLayer.Mnesia
actions do
defaults [:create, :read, :update, :destroy]
end
attributes do
uuid_primary_key :id
attribute :name, :string
end
relationships do
many_to_many :posts, Post,
through: PostCategory,
destination_attribute_on_join_resource: :post_id,
source_attribute_on_join_resource: :category_id
end
end
defmodule Registry do
@moduledoc false
use Ash.Registry
entries do
entry(Author)
entry(Post)
entry(Category)
entry(PostCategory)
end
end
defmodule Api do
@moduledoc false
use Ash.Api
resources do
registry Registry
end
end
setup do
capture_log(fn ->
Ash.DataLayer.Mnesia.start(Api)
end)
pid = self()
events =
[
[:ash, :request_step],
[:ash, :api, :read],
[:ash, :api, :create],
[:ash, :api, :destroy],
[:ash, :api, :update],
[:ash, :flow]
]
|> Enum.flat_map(fn list ->
[list ++ [:start], list ++ [:stop]]
end)
capture_log(fn ->
:telemetry.attach_many(
:test_handler,
events,
fn event_name, event_measurements, event_metadata, handler_config ->
send(
pid,
{:telemetry, {event_name, event_measurements, event_metadata, handler_config}}
)
end,
[]
)
end)
on_exit(fn ->
:telemetry.detach(:test_handler)
capture_log(fn ->
:mnesia.stop()
:mnesia.delete_schema([node()])
end)
end)
start_supervised(
{Ash.Test.Authorizer,
strict_check: :authorized,
check: {:error, Ash.Error.Forbidden.exception([])},
strict_check_context: [:query]}
)
:ok
end
test "a simple read calls the tracer with the action" do
Api.read!(Post, tracer: Ash.Tracer.Simple)
assert [
%Ash.Tracer.Simple.Span{
type: :action,
name: "api:post.read",
metadata: %{
action: :read,
resource: Ash.Test.TracerTest.AsyncLoadTest.Post
}
}
] = Ash.Tracer.Simple.gather_spans()
end
test "a read with async loads calls the tracer for each" do
Ash.Changeset.for_create(Post, :create, %{title: "title"}, tracer: Ash.Tracer.Simple)
|> Api.create!()
assert [
%Ash.Tracer.Simple.Span{
type: :changeset,
name: "changeset:post:create"
},
%Ash.Tracer.Simple.Span{
type: :action,
name: "api:post.create",
metadata: %{
action: :create,
api: Ash.Test.TracerTest.AsyncLoadTest.Api,
resource: Ash.Test.TracerTest.AsyncLoadTest.Post
}
}
] = Ash.Tracer.Simple.gather_spans()
assert_receive {:telemetry,
{[:ash, :request_step, :start], %{system_time: _},
%{name: "perform Ash.Test.TracerTest.AsyncLoadTest.Post.create"}, _}}
assert_receive {:telemetry,
{[:ash, :request_step, :stop], %{duration: _},
%{name: "perform Ash.Test.TracerTest.AsyncLoadTest.Post.create"}, _}}
assert_receive {:telemetry,
{[:ash, :api, :create, :start], %{system_time: _},
%{resource_short_name: :post}, _}}
assert_receive {:telemetry,
{[:ash, :api, :create, :stop], %{duration: _}, %{resource_short_name: :post},
_}}
Post
|> Ash.Query.load(:author)
|> Api.read!(tracer: Ash.Tracer.Simple)
assert_receive {:telemetry,
{[:ash, :api, :read, :start], %{system_time: _},
%{resource_short_name: :post}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :start], %{system_time: _},
%{name: "fetch Ash.Test.TracerTest.AsyncLoadTest.Post.read"}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :stop], %{duration: _},
%{name: "fetch Ash.Test.TracerTest.AsyncLoadTest.Post.read"}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :start], %{system_time: _},
%{name: "process Ash.Test.TracerTest.AsyncLoadTest.Post.read"}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :stop], %{duration: _, system_time: _},
%{name: "process Ash.Test.TracerTest.AsyncLoadTest.Post.read"}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :start], %{system_time: _}, %{name: "load author"}, []}}
assert_receive {:telemetry,
{[:ash, :api, :read, :start], %{system_time: _},
%{resource_short_name: :author}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :start], %{system_time: _},
%{name: "fetch Ash.Test.TracerTest.AsyncLoadTest.Author.read"}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :stop], %{duration: _, system_time: _},
%{name: "fetch Ash.Test.TracerTest.AsyncLoadTest.Author.read"}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :start], %{system_time: _},
%{name: "process Ash.Test.TracerTest.AsyncLoadTest.Author.read"}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :stop], %{duration: _, system_time: _},
%{name: "process Ash.Test.TracerTest.AsyncLoadTest.Author.read"}, []}}
assert_receive {:telemetry,
{[:ash, :api, :read, :stop], %{duration: _, system_time: _},
%{resource_short_name: :author}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :stop], %{duration: _, system_time: _},
%{name: "load author"}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :start], %{system_time: _},
%{name: "process Ash.Test.TracerTest.AsyncLoadTest.Post.read"}, []}}
assert_receive {:telemetry,
{[:ash, :request_step, :stop], %{duration: _, system_time: _},
%{name: "process Ash.Test.TracerTest.AsyncLoadTest.Post.read"}, []}}
assert_receive {:telemetry,
{[:ash, :api, :read, :stop], %{duration: _, system_time: _},
%{resource_short_name: :post}, []}}
refute_receive {:telemetry, _}
assert [
%Ash.Tracer.Simple.Span{
type: :action,
name: "api:post.read",
metadata: %{
action: :read,
resource: Ash.Test.TracerTest.AsyncLoadTest.Post
},
spans: spans
}
] = Ash.Tracer.Simple.gather_spans()
assert load =
Enum.find(spans, fn span ->
span.name == "load author"
end)
assert Enum.find(load.spans, fn span ->
span.name == "api:author.read"
end)
end
end