Skip to content

Commit 2a326f7

Browse files
am-kantoxoz-agent
andcommitted
Extend test coverage and fix flaky tests
- New: options_test.exs, telemetria_core_test.exs, throttler_test.exs, config_provider_test.exs - Extended: telemetria_formatter_test.exs with 10 new data type tests - Fixed flaky tests via persistent_term reset in setup and specific debug assertions - 67 tests, all passing with any seed Co-Authored-By: Oz <oz-agent@warp.dev>
1 parent 812d4f8 commit 2a326f7

6 files changed

Lines changed: 558 additions & 3 deletions

test/config_provider_test.exs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
defmodule Telemetria.ConfigProviderTest do
2+
use ExUnit.Case
3+
4+
alias Telemetria.ConfigProvider
5+
6+
describe "json_config!/1" do
7+
test "returns empty list when file does not exist" do
8+
assert [] == ConfigProvider.json_config!("/tmp/nonexistent_telemetria_config.json")
9+
end
10+
11+
test "parses a valid JSON config file" do
12+
path = Path.join(System.tmp_dir!(), "telemetria_test_config.json")
13+
14+
json =
15+
:json.encode(%{
16+
"otp_app" => "my_app",
17+
"events" => [["my_app", "user", "create"]]
18+
})
19+
|> IO.iodata_to_binary()
20+
21+
File.write!(path, json)
22+
23+
result = ConfigProvider.json_config!(path)
24+
assert Keyword.keyword?(result)
25+
assert Keyword.has_key?(result, :otp_app)
26+
after
27+
path = Path.join(System.tmp_dir!(), "telemetria_test_config.json")
28+
File.rm(path)
29+
end
30+
end
31+
32+
describe "load/2" do
33+
test "merges JSON config into existing config" do
34+
path = Path.join(System.tmp_dir!(), "telemetria_test_load.json")
35+
36+
json =
37+
:json.encode(%{
38+
"otp_app" => "loaded_app",
39+
"events" => [["loaded", "event"]]
40+
})
41+
|> IO.iodata_to_binary()
42+
43+
File.write!(path, json)
44+
45+
config = [telemetria: [enabled: true]]
46+
result = ConfigProvider.load(config, path)
47+
48+
telemetria_config = Keyword.get(result, :telemetria, [])
49+
assert Keyword.has_key?(telemetria_config, :otp_app)
50+
after
51+
path = Path.join(System.tmp_dir!(), "telemetria_test_load.json")
52+
File.rm(path)
53+
end
54+
end
55+
56+
describe "init/1" do
57+
test "returns the path as-is" do
58+
assert "/some/path.json" == ConfigProvider.init("/some/path.json")
59+
end
60+
end
61+
end

test/options_test.exs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
defmodule Telemetria.OptionsTest do
2+
use ExUnit.Case
3+
4+
alias Telemetria.Options
5+
6+
describe "schema/0" do
7+
test "returns a keyword list" do
8+
assert Keyword.keyword?(Options.schema())
9+
end
10+
11+
test "contains all expected top-level keys" do
12+
keys = Keyword.keys(Options.schema())
13+
14+
for expected <- ~w|otp_app enabled backend level purge_level throttle
15+
strict events handler polling process_info|a do
16+
assert expected in keys, "expected #{inspect(expected)} in schema keys"
17+
end
18+
end
19+
end
20+
21+
describe "log_level/1" do
22+
test "accepts valid log levels" do
23+
for level <- ~w|emergency alert critical error warning notice info debug|a do
24+
assert {:ok, ^level} = Options.log_level(level)
25+
end
26+
end
27+
28+
test "rejects invalid log levels" do
29+
assert {:error, msg} = Options.log_level(:verbose)
30+
assert msg =~ "verbose"
31+
end
32+
end
33+
34+
describe "mf/1" do
35+
test "accepts valid MF pair with arity 4" do
36+
assert {:ok, {Telemetria.Handler.Default, :handle_event}} =
37+
Options.mf({Telemetria.Handler.Default, :handle_event})
38+
end
39+
40+
test "rejects MF pair with wrong arity" do
41+
assert {:error, msg} = Options.mf({Enum, :map})
42+
assert msg =~ "arity 4"
43+
end
44+
45+
test "rejects MF pair with non-existent module" do
46+
assert {:error, _} = Options.mf({NonExistent.Module, :fun})
47+
end
48+
end
49+
50+
describe "list/2" do
51+
test "validates all elements match at least one checker" do
52+
assert {:ok, [1, 2, 3]} = Options.list([1, 2, 3], [{Kernel, :is_integer}])
53+
end
54+
55+
test "rejects when elements do not match" do
56+
assert {:error, msg} = Options.list([:a, :b], [{Kernel, :is_integer}])
57+
assert msg =~ "Expected list"
58+
end
59+
end
60+
61+
describe "initial/0" do
62+
test "returns validated config as keyword list" do
63+
result = Options.initial()
64+
assert Keyword.keyword?(result)
65+
assert Keyword.has_key?(result, :enabled)
66+
assert Keyword.has_key?(result, :backend)
67+
end
68+
end
69+
end

test/telemetria_core_test.exs

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
defmodule Telemetria.CoreTest do
2+
use ExUnit.Case
3+
import ExUnit.CaptureLog
4+
5+
describe "Telemetria.otp_app/0" do
6+
test "returns configured otp_app or a fallback" do
7+
result = Telemetria.otp_app()
8+
assert is_atom(result)
9+
end
10+
end
11+
12+
describe "Telemetria.noop/1" do
13+
test "returns the argument unchanged" do
14+
assert 42 == Telemetria.noop(42)
15+
assert :hello == Telemetria.noop(:hello)
16+
assert %{a: 1} == Telemetria.noop(%{a: 1})
17+
end
18+
end
19+
20+
describe "Telemetria.yes/1" do
21+
test "always returns true" do
22+
assert true == Telemetria.yes(nil)
23+
assert true == Telemetria.yes(42)
24+
assert true == Telemetria.yes(:anything)
25+
end
26+
end
27+
28+
describe "Telemetria.telemetry_prefix/2" do
29+
test "builds prefix from module and function call" do
30+
env = %Macro.Env{module: MyApp.Worker, function: {:process, 1}}
31+
call = {:do_work, [], []}
32+
33+
result = Telemetria.telemetry_prefix(env, call)
34+
assert [:my_app, :worker, :process, :do_work] == result
35+
end
36+
37+
test "handles nil module" do
38+
env = %Macro.Env{module: nil, function: nil}
39+
result = Telemetria.telemetry_prefix(env, [])
40+
assert [:module_scope] == result
41+
end
42+
43+
test "handles suffix list" do
44+
env = %Macro.Env{module: Foo.Bar, function: nil}
45+
result = Telemetria.telemetry_prefix(env, [:custom, :suffix])
46+
assert [:foo, :bar, :custom, :suffix] == result
47+
end
48+
49+
test "deduplicates consecutive identical atoms" do
50+
env = %Macro.Env{module: Foo, function: {:foo, 0}}
51+
result = Telemetria.telemetry_prefix(env, {:foo, [], []})
52+
assert [:foo] == result
53+
end
54+
end
55+
end
56+
57+
defmodule Telemetria.ErrorTest do
58+
use ExUnit.Case
59+
60+
describe "Telemetria.Error" do
61+
test "creates exception with message" do
62+
error = Telemetria.Error.exception("something went wrong")
63+
assert %Telemetria.Error{message: "something went wrong"} = error
64+
end
65+
66+
test "can be raised and rescued" do
67+
assert_raise Telemetria.Error, "boom", fn ->
68+
raise Telemetria.Error, "boom"
69+
end
70+
end
71+
end
72+
end
73+
74+
defmodule Telemetria.HandlerTest do
75+
use ExUnit.Case
76+
77+
describe "Telemetria.Handler.process_info/0" do
78+
test "returns keyword list with expected keys" do
79+
info = Telemetria.Handler.process_info()
80+
assert Keyword.keyword?(info)
81+
assert Keyword.has_key?(info, :status)
82+
assert Keyword.has_key?(info, :heap_size)
83+
assert Keyword.has_key?(info, :stack_size)
84+
assert Keyword.has_key?(info, :reductions)
85+
assert Keyword.has_key?(info, :schedulers)
86+
assert is_integer(info[:schedulers])
87+
end
88+
89+
test "accepts a specific pid" do
90+
info = Telemetria.Handler.process_info(self())
91+
assert Keyword.keyword?(info)
92+
assert info[:status] in [:running, :waiting]
93+
end
94+
end
95+
end
96+
97+
defmodule Telemetria.Handler.DefaultTest do
98+
use ExUnit.Case
99+
import ExUnit.CaptureLog
100+
101+
describe "handle_event/4" do
102+
test "logs telemetry event with default (non-smart) format" do
103+
Application.put_env(:telemetria, :smart_log, false)
104+
105+
log =
106+
capture_log(fn ->
107+
Telemetria.Handler.Default.handle_event(
108+
[:test, :handler, :event],
109+
%{consumed: 100},
110+
%{result: :ok, args: [x: 1], env: %{module: Foo, function: {:bar, 1}}},
111+
nil
112+
)
113+
end)
114+
115+
assert log =~ "[:test, :handler, :event]"
116+
assert log =~ "result: :ok"
117+
end
118+
119+
test "respects level filtering" do
120+
Application.put_env(:telemetria, :level, :warning)
121+
122+
log =
123+
capture_log(fn ->
124+
Telemetria.Handler.Default.handle_event(
125+
[:test, :filtered],
126+
%{consumed: 50},
127+
%{
128+
result: :ok,
129+
args: [],
130+
env: %{},
131+
context: %{options: [level: :debug]}
132+
},
133+
nil
134+
)
135+
end)
136+
137+
refute log =~ "[:test, :filtered]"
138+
139+
Application.put_env(:telemetria, :level, :debug)
140+
end
141+
end
142+
end
143+
144+
defmodule Telemetria.Messenger.LoggerTest do
145+
use ExUnit.Case
146+
import ExUnit.CaptureLog
147+
148+
alias Telemetria.Messenger.Logger, as: MLogger
149+
150+
test "format/2 inspects the message" do
151+
result = MLogger.format(%{foo: :bar}, [])
152+
assert result =~ "foo"
153+
assert result =~ "bar"
154+
end
155+
156+
test "debug/2 logs at debug level" do
157+
log = capture_log(fn -> MLogger.debug("debug msg", []) end)
158+
assert log =~ "debug msg"
159+
end
160+
161+
test "info/2 logs at info level" do
162+
log = capture_log(fn -> MLogger.info("info msg", []) end)
163+
assert log =~ "info msg"
164+
end
165+
166+
test "warning/2 logs at warning level" do
167+
log = capture_log(fn -> MLogger.warning("warn msg", []) end)
168+
assert log =~ "warn msg"
169+
end
170+
171+
test "error/2 logs at error level" do
172+
log = capture_log(fn -> MLogger.error("error msg", []) end)
173+
assert log =~ "error msg"
174+
end
175+
end
176+
177+
defmodule Telemetria.Backend.LoggerTest do
178+
use ExUnit.Case
179+
import ExUnit.CaptureLog
180+
181+
alias Telemetria.Backend.Logger, as: BLogger
182+
183+
test "entry/1 returns the block_id" do
184+
assert [:my, :event] == BLogger.entry([:my, :event])
185+
end
186+
187+
test "update/2 returns the block_id unchanged" do
188+
assert :id == BLogger.update(:id, %{foo: :bar})
189+
end
190+
191+
test "return/2 logs the event" do
192+
log =
193+
capture_log(fn ->
194+
BLogger.return([:test, :event], %{measurements: %{time: 42}, result: :ok})
195+
end)
196+
197+
assert log =~ "[:test, :event]"
198+
assert log =~ "time: 42"
199+
end
200+
201+
test "exit/1 returns :ok" do
202+
assert :ok == BLogger.exit(:anything)
203+
end
204+
205+
test "reshape/1 returns updates unchanged" do
206+
data = %{a: 1, b: 2}
207+
assert ^data = BLogger.reshape(data)
208+
end
209+
end

0 commit comments

Comments
 (0)