diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..27ecf19 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,60 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + +jobs: + test: + runs-on: ubuntu-24.04 + env: + MIX_ENV: test + strategy: + fail-fast: false + matrix: + include: + - pair: + elixir: "1.15.7" + otp: "24.3.4.17" + - pair: + elixir: "1.16.3" + otp: "25.3.2.20" + - pair: + elixir: "1.17.3" + otp: "26.2.5.11" + - pair: + elixir: "1.18.3" + otp: "27.3.3" + lint: lint + steps: + - uses: actions/checkout@v4 + + - uses: erlef/setup-beam@v1 + with: + otp-version: ${{matrix.pair.otp}} + elixir-version: ${{matrix.pair.elixir}} + version-type: strict + + - uses: actions/cache@v4 + with: + path: | + deps + _build + key: ${{ runner.os }}-mix-${{matrix.pair.elixir}}-${{matrix.pair.otp}}-${{ hashFiles('**/mix.lock') }} + + - run: mix deps.get --check-locked + + - run: mix format --check-formatted + if: ${{ matrix.lint }} + + - run: mix deps.unlock --check-unused + if: ${{ matrix.lint }} + + - run: mix deps.compile + + - run: mix compile --no-optional-deps --warnings-as-errors + if: ${{ matrix.lint }} + + - run: mix test diff --git a/lib/logger_handler_kit/act.ex b/lib/logger_handler_kit/act.ex index 95f273d..912a035 100644 --- a/lib/logger_handler_kit/act.ex +++ b/lib/logger_handler_kit/act.ex @@ -47,7 +47,7 @@ defmodule LoggerHandlerKit.Act do default, but a thorough handler might have an interest in them. """ - require ExUnit.Assertions + import ExUnit.Assertions @doc """ The most basic and perhaps most common log message is a simple [string](`String`) passed to one of the `Logger` functions: @@ -569,19 +569,28 @@ defmodule LoggerHandlerKit.Act do :exit, {{%RuntimeError{message: "oops"}, _}, _} -> :ok end - def genserver_crash(:process_label) do - {:ok, pid} = LoggerHandlerKit.GenServer.start(nil) - - GenServer.call( - pid, - {:run, - fn -> - Process.set_label({:any, "term"}) - raise "oops" - end} - ) - catch - :exit, {{%RuntimeError{message: "oops"}, _}, _} -> :ok + if System.otp_release() < "27" do + def genserver_crash(:process_label), + do: + raise(""" + Process labels were introduced in OTP 27. + If you want to run test suite for older Elixir version, considder skipping the test with `@tag skip: System.otp_release() < "27"` + """) + else + def genserver_crash(:process_label) do + {:ok, pid} = LoggerHandlerKit.GenServer.start(nil) + + GenServer.call( + pid, + {:run, + fn -> + Process.set_label({:any, "term"}) + raise "oops" + end} + ) + catch + :exit, {{%RuntimeError{message: "oops"}, _}, _} -> :ok + end end def genserver_crash(:named_client) do @@ -608,7 +617,7 @@ defmodule LoggerHandlerKit.Act do {:run, fn {caller, _}, _ -> caller_monitor = Process.monitor(caller) - ExUnit.Assertions.assert_receive({:DOWN, ^caller_monitor, _, _, _}) + assert_receive({:DOWN, ^caller_monitor, _, _, _}) raise "oops" end}, 0 @@ -618,7 +627,7 @@ defmodule LoggerHandlerKit.Act do end end) - ExUnit.Assertions.assert_receive({:DOWN, ^mon, _, _, _}) + assert_receive({:DOWN, ^mon, _, _, _}) :ok end @@ -626,7 +635,7 @@ defmodule LoggerHandlerKit.Act do {:ok, pid} = LoggerHandlerKit.GenServer.start(nil) mon = Process.monitor(pid) GenServer.cast(pid, fn -> raise "oops" end) - ExUnit.Assertions.assert_receive({:DOWN, ^mon, _, _, _}) + assert_receive({:DOWN, ^mon, _, _, _}) :ok end @@ -754,28 +763,28 @@ defmodule LoggerHandlerKit.Act do def task_error(:exception) do {:ok, pid} = Task.start(fn -> raise "oops" end) ref = Process.monitor(pid) - ExUnit.Assertions.assert_receive({:DOWN, ^ref, _, _, _}) + assert_receive({:DOWN, ^ref, _, _, _}) :ok end def task_error(:exit) do {:ok, pid} = Task.start(fn -> exit("i quit") end) ref = Process.monitor(pid) - ExUnit.Assertions.assert_receive({:DOWN, ^ref, _, _, _}) + assert_receive({:DOWN, ^ref, _, _, _}) :ok end def task_error(:throw) do {:ok, pid} = Task.start(fn -> throw("catch!") end) ref = Process.monitor(pid) - ExUnit.Assertions.assert_receive({:DOWN, ^ref, _, _, _}) + assert_receive({:DOWN, ^ref, _, _, _}) :ok end def task_error(:undefined) do {:ok, pid} = Task.start(:module_does_not_exist, :undef, []) ref = Process.monitor(pid) - ExUnit.Assertions.assert_receive({:DOWN, ^ref, _, _, _}) + assert_receive({:DOWN, ^ref, _, _, _}) :ok end @@ -1046,7 +1055,7 @@ defmodule LoggerHandlerKit.Act do LoggerHandlerKit.Arrange.allow(self(), pid, handler_id) send(pid, :go) - ExUnit.Assertions.assert_receive({:DOWN, ^ref, _, _, _}) + assert_receive({:DOWN, ^ref, _, _, _}) :ok end @@ -1062,7 +1071,7 @@ defmodule LoggerHandlerKit.Act do LoggerHandlerKit.Arrange.allow(self(), pid, handler_id) send(pid, :go) - ExUnit.Assertions.assert_receive({:DOWN, ^ref, _, _, _}) + assert_receive({:DOWN, ^ref, _, _, _}) :ok end @@ -1428,7 +1437,7 @@ defmodule LoggerHandlerKit.Act do ref = Process.monitor(pid) - ExUnit.Assertions.assert_receive({:DOWN, ^ref, _, _, _}) + assert_receive({:DOWN, ^ref, _, _, _}) :ok end @@ -1443,7 +1452,7 @@ defmodule LoggerHandlerKit.Act do ref = Process.monitor(pid) - ExUnit.Assertions.assert_receive({:DOWN, ^ref, _, _, _}) + assert_receive({:DOWN, ^ref, _, _, _}) :ok end @@ -1458,7 +1467,7 @@ defmodule LoggerHandlerKit.Act do ref = Process.monitor(pid) - ExUnit.Assertions.assert_receive({:DOWN, ^ref, _, _, _}) + assert_receive({:DOWN, ^ref, _, _, _}) :ok end @@ -1591,7 +1600,7 @@ defmodule LoggerHandlerKit.Act do }) Process.exit(pid, :normal) - ExUnit.Assertions.assert_receive({:DOWN, ^ref, _, _, _}) + assert_receive({:DOWN, ^ref, _, _, _}) :ok end @@ -1650,7 +1659,7 @@ defmodule LoggerHandlerKit.Act do exit(:stop) end}) - ExUnit.Assertions.assert_receive({:EXIT, ^pid, _}) + assert_receive({:EXIT, ^pid, _}) :ok end end diff --git a/lib/logger_handler_kit/handler_wrapper.ex b/lib/logger_handler_kit/handler_wrapper.ex index 974405a..210ae5b 100644 --- a/lib/logger_handler_kit/handler_wrapper.ex +++ b/lib/logger_handler_kit/handler_wrapper.ex @@ -47,9 +47,17 @@ defmodule LoggerHandlerKit.HandlerWrapper do ``` """ - @behaviour :logger_handler + # Prior to OTP 27 :logger_handler behaviour didn't exist and callbacks were part of :logger. + # https://github.com/erlang/otp/commit/2afd6748f16ad226d0ae12b54e57e0147dafdbdd + if System.otp_release() < "27" do + @behaviour_module false + else + @behaviour_module :logger_handler + @behaviour @behaviour_module + end + + if @behaviour_module, do: @impl(@behaviour_module) - @impl :logger_handler def adding_handler(config) do unwrapped = unwrap_config(config) Code.ensure_loaded!(unwrapped.module) @@ -62,7 +70,8 @@ defmodule LoggerHandlerKit.HandlerWrapper do end end - @impl :logger_handler + if @behaviour_module, do: @impl(@behaviour_module) + def log(log_event, %{config: %{test_pid: test_pid, ref: ref}} = config) do config |> unwrap_config() @@ -74,7 +83,8 @@ defmodule LoggerHandlerKit.HandlerWrapper do _ -> send(test_pid, {ref, :log_call_completed}) end - @impl :logger_handler + if @behaviour_module, do: @impl(@behaviour_module) + def removing_handler(config) do unwrapped = unwrap_config(config) @@ -83,7 +93,8 @@ defmodule LoggerHandlerKit.HandlerWrapper do end end - @impl :logger_handler + if @behaviour_module, do: @impl(@behaviour_module) + def changing_config(set_or_update, old_config, new_config) do old_unwrapped = unwrap_config(old_config) new_unwrapped = unwrap_config(new_config) diff --git a/mix.exs b/mix.exs index 366b676..1e19a61 100644 --- a/mix.exs +++ b/mix.exs @@ -8,7 +8,7 @@ defmodule LoggerHandlerKit.MixProject do [ app: :logger_handler_kit, version: @version, - elixir: "~> 1.18", + elixir: "~> 1.15", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, deps: deps(), diff --git a/test/default_logger_test.exs b/test/default_logger_test.exs index 0496235..ea017c9 100644 --- a/test/default_logger_test.exs +++ b/test/default_logger_test.exs @@ -151,6 +151,7 @@ defmodule LoggerHandlerKit.DefaultLoggerTest do assert msg =~ "[error] GenServer \"genserver global name\"" end + @tag skip: System.otp_release() < "27" test "genserver crash with process label", %{handler_ref: ref, io_ref: io_ref} do LoggerHandlerKit.Act.genserver_crash(:process_label) LoggerHandlerKit.Assert.assert_logged(ref) @@ -226,6 +227,9 @@ defmodule LoggerHandlerKit.DefaultLoggerTest do "(UndefinedFunctionError) function :module_does_not_exist.undef/0 is undefined" end + # Before Elixir 1.17 gen_statem crashes were swallowed by Logger.Translator + # https://github.com/elixir-lang/elixir/pull/13451 + @tag skip: System.version() < "1.17" test "gen_statem crash exception", %{handler_ref: ref, io_ref: io_ref} do LoggerHandlerKit.Act.gen_statem_crash(:exception) LoggerHandlerKit.Assert.assert_logged(ref) @@ -235,6 +239,7 @@ defmodule LoggerHandlerKit.DefaultLoggerTest do assert msg =~ "** (RuntimeError) oops" end + @tag skip: System.version() < "1.17" test "gen_statem crash exit", %{handler_ref: ref, io_ref: io_ref} do LoggerHandlerKit.Act.gen_statem_crash(:exit) LoggerHandlerKit.Assert.assert_logged(ref) @@ -244,6 +249,7 @@ defmodule LoggerHandlerKit.DefaultLoggerTest do assert msg =~ "** (stop) \"i quit\"" end + @tag skip: System.version() < "1.17" test "gen_statem crash throw", %{handler_ref: ref, io_ref: io_ref} do LoggerHandlerKit.Act.gen_statem_crash(:throw) LoggerHandlerKit.Assert.assert_logged(ref) @@ -327,7 +333,13 @@ defmodule LoggerHandlerKit.DefaultLoggerTest do LoggerHandlerKit.Assert.assert_logged(ref) assert_receive {^io_ref, msg} - assert msg =~ "[debug] Child :task of Supervisor #PID<" + + if System.otp_release() < "27" do + assert msg =~ "[info] Child :task of Supervisor #PID<" + else + assert msg =~ "[debug] Child :task of Supervisor #PID<" + end + assert msg =~ " (Supervisor.Default) started" end