122 lines
3.8 KiB
Elixir
122 lines
3.8 KiB
Elixir
defmodule FakeReloader do
|
|
@moduledoc false
|
|
def reload, do: {:ok, 0}
|
|
end
|
|
|
|
defmodule Towerops.Profiles.ProfileWatcherTest do
|
|
use ExUnit.Case, async: true
|
|
|
|
alias Towerops.Profiles.ProfileWatcher
|
|
|
|
describe "yaml_file?/1" do
|
|
test "returns true for .yaml files" do
|
|
assert ProfileWatcher.yaml_file?("path/to/profile.yaml")
|
|
end
|
|
|
|
test "returns true for .yml files" do
|
|
assert ProfileWatcher.yaml_file?("path/to/profile.yml")
|
|
end
|
|
|
|
test "returns false for other extensions" do
|
|
refute ProfileWatcher.yaml_file?("profile.json")
|
|
refute ProfileWatcher.yaml_file?("profile.txt")
|
|
refute ProfileWatcher.yaml_file?("profile")
|
|
end
|
|
|
|
test "raises on nil" do
|
|
assert_raise FunctionClauseError, fn ->
|
|
apply(ProfileWatcher, :yaml_file?, [nil])
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "should_reload?/1" do
|
|
test "returns true for :created event" do
|
|
assert ProfileWatcher.should_reload?([:created])
|
|
end
|
|
|
|
test "returns true for :modified event" do
|
|
assert ProfileWatcher.should_reload?([:modified])
|
|
end
|
|
|
|
test "returns true for :removed event" do
|
|
assert ProfileWatcher.should_reload?([:removed])
|
|
end
|
|
|
|
test "returns true for :renamed event" do
|
|
assert ProfileWatcher.should_reload?([:renamed])
|
|
end
|
|
|
|
test "returns true when any event triggers reload" do
|
|
assert ProfileWatcher.should_reload?([:accessed, :modified])
|
|
end
|
|
|
|
test "returns false for non-reload events" do
|
|
refute ProfileWatcher.should_reload?([:accessed])
|
|
refute ProfileWatcher.should_reload?([:attrs_changed])
|
|
end
|
|
|
|
test "returns false for empty list" do
|
|
refute ProfileWatcher.should_reload?([])
|
|
end
|
|
|
|
test "returns false for non-list input" do
|
|
refute ProfileWatcher.should_reload?(nil)
|
|
refute ProfileWatcher.should_reload?(:created)
|
|
refute ProfileWatcher.should_reload?(%{})
|
|
end
|
|
end
|
|
|
|
describe "start_link/1" do
|
|
test "starts the GenServer under its registered name" do
|
|
# Stop the dev-only auto-started instance if any so we get a clean start
|
|
_ = if pid = Process.whereis(ProfileWatcher), do: GenServer.stop(pid, :normal)
|
|
|
|
assert {:ok, pid} = ProfileWatcher.start_link([])
|
|
assert Process.alive?(pid)
|
|
GenServer.stop(pid, :normal)
|
|
end
|
|
end
|
|
|
|
describe "GenServer init/handle_info" do
|
|
test "init/1 returns :ok with a state map" do
|
|
assert {:ok, _state} = ProfileWatcher.init([])
|
|
end
|
|
|
|
test "handles :stop file_event without crashing" do
|
|
assert {:noreply, %{}} =
|
|
ProfileWatcher.handle_info({:file_event, self(), :stop}, %{})
|
|
end
|
|
|
|
test "ignores file events for non-yaml files" do
|
|
msg = {:file_event, self(), {"foo.txt", [:modified]}}
|
|
assert {:noreply, %{}} = ProfileWatcher.handle_info(msg, %{})
|
|
end
|
|
|
|
test "ignores file events when no reload-relevant event is present" do
|
|
msg = {:file_event, self(), {"profile.yaml", [:accessed]}}
|
|
assert {:noreply, %{}} = ProfileWatcher.handle_info(msg, %{})
|
|
end
|
|
|
|
test "yaml file event with reload trigger doesn't crash and preserves state" do
|
|
# Stub out the reloader so we don't pay the full YamlProfiles.reload
|
|
# cost (loads ~hundreds of YAML files from disk) just to verify the
|
|
# handle_info branch.
|
|
previous = Application.get_env(:towerops, :profile_reloader)
|
|
Application.put_env(:towerops, :profile_reloader, FakeReloader)
|
|
|
|
on_exit(fn ->
|
|
if previous,
|
|
do: Application.put_env(:towerops, :profile_reloader, previous),
|
|
else: Application.delete_env(:towerops, :profile_reloader)
|
|
end)
|
|
|
|
msg = {:file_event, self(), {"priv/profiles/test.yaml", [:modified]}}
|
|
|
|
ExUnit.CaptureLog.capture_log(fn ->
|
|
assert {:noreply, %{watcher_pid: nil}} =
|
|
ProfileWatcher.handle_info(msg, %{watcher_pid: nil})
|
|
end)
|
|
end
|
|
end
|
|
end
|