towerops/test/towerops/profiles/profile_watcher_test.exs
Graham McIntire 2269f38fc5 test: lift coverage 78.42% → 79.59% with focused unit + integration tests
Adds tests across previously-uncovered or under-covered modules:

- Mix tasks: backfill_checks, copy_mibs, import_mibs (new test files)
- Status pages: StatusIncident changeset (new file)
- Webhook signature verification on AgentReleaseWebhookController
- CloudflareBanWorker: HTTP-stubbed success / 5xx / transport-error paths
- FirmwareVersionFetcherWorker: stubbed perform/0 success + non-200 + tx error
- Geoip.Import: production --production code path (HTTP-stubbed)
- AgentLive.Show: superuser restart_agent + update_agent + non-superuser paths
- NetworkMapLive: node_clicked, deep-link node, topology_updated PubSub
- PreseemInsightsLive: toggle_select, deselect_all, filter, dismiss-twice
- AlertQuery: 1-arity defaults variants
- ProfileWatcher: yaml + reload-trigger event passthrough
- MobileAuthController: verify_qr_token success + get/revoke session
- HealthController: redis-configured branch
- RedisHealthCheck: un-tag :integration tests now that Redis is local
- FourOhFourTracker: un-skip module (Redis available)
- PingExecutor: un-tag local-only tests + KeyError surface + clamp branch
- CheckExecutorWorker: dispatch tcp/dns/ssl/ping branches
- UserResetPasswordController: drop dead edit/update + their template

Also removes dead code: edit/update actions on UserResetPasswordController
and the unused edit.html.heex template — both routed via LiveView.
2026-05-07 18:40:43 -05:00

95 lines
2.9 KiB
Elixir

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 ->
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 "GenServer init/handle_info" do
test "init/1 returns :ok with a state map" do
assert {:ok, state} = ProfileWatcher.init([])
assert is_map(state)
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
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