From 638551eb951e608abac73ce5b74e74fe73af0611 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Tue, 20 Jan 2026 11:59:54 -0600 Subject: [PATCH] Add comprehensive tests for Monitoring.Check schema Tests cover: - Valid and invalid changesets - All required field validations - Foreign key constraints - Status enum values - Schema field types and associations - Binary ID usage for primary/foreign keys All 16 tests passing with good coverage of schema validation logic. --- test/towerops/monitoring/check_test.exs | 209 ++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 test/towerops/monitoring/check_test.exs diff --git a/test/towerops/monitoring/check_test.exs b/test/towerops/monitoring/check_test.exs new file mode 100644 index 00000000..88786abf --- /dev/null +++ b/test/towerops/monitoring/check_test.exs @@ -0,0 +1,209 @@ +defmodule Towerops.Monitoring.CheckTest do + use Towerops.DataCase, async: true + + import Towerops.AccountsFixtures + + alias Towerops.Monitoring.Check + + describe "changeset/2" do + setup do + user = user_fixture() + {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id) + + {:ok, site} = + Towerops.Sites.create_site(%{ + name: "Test Site", + organization_id: organization.id + }) + + {:ok, device} = + Towerops.Devices.create_device(%{ + name: "Test Device", + ip_address: "192.168.1.1", + site_id: site.id + }) + + {:ok, device: device} + end + + test "valid changeset with all fields", %{device: device} do + attrs = %{ + device_id: device.id, + status: :success, + response_time_ms: 12.5, + checked_at: DateTime.utc_now() + } + + changeset = Check.changeset(%Check{}, attrs) + + assert changeset.valid? + assert get_change(changeset, :device_id) == device.id + assert get_change(changeset, :status) == :success + assert get_change(changeset, :response_time_ms) == 12.5 + assert get_change(changeset, :checked_at) + end + + test "valid changeset with failure status", %{device: device} do + attrs = %{ + device_id: device.id, + status: :failure, + checked_at: DateTime.utc_now() + } + + changeset = Check.changeset(%Check{}, attrs) + + assert changeset.valid? + assert get_change(changeset, :status) == :failure + # response_time_ms is optional and can be nil for failures + refute Map.has_key?(changeset.changes, :response_time_ms) + end + + test "requires device_id" do + attrs = %{ + status: :success, + checked_at: DateTime.utc_now() + } + + changeset = Check.changeset(%Check{}, attrs) + + refute changeset.valid? + assert "can't be blank" in errors_on(changeset).device_id + end + + test "requires status" do + attrs = %{ + device_id: Ecto.UUID.generate(), + checked_at: DateTime.utc_now() + } + + changeset = Check.changeset(%Check{}, attrs) + + refute changeset.valid? + assert "can't be blank" in errors_on(changeset).status + end + + test "requires checked_at" do + attrs = %{ + device_id: Ecto.UUID.generate(), + status: :success + } + + changeset = Check.changeset(%Check{}, attrs) + + refute changeset.valid? + assert "can't be blank" in errors_on(changeset).checked_at + end + + test "accepts only valid status values", %{device: device} do + # Invalid status value + attrs = %{ + device_id: device.id, + status: :invalid_status, + checked_at: DateTime.utc_now() + } + + changeset = Check.changeset(%Check{}, attrs) + + refute changeset.valid? + assert "is invalid" in errors_on(changeset).status + end + + test "validates foreign key constraint on insert", %{device: device} do + # This test requires actual database insert + valid_attrs = %{ + device_id: device.id, + status: :success, + checked_at: DateTime.utc_now() + } + + changeset = Check.changeset(%Check{}, valid_attrs) + assert {:ok, _check} = Repo.insert(changeset) + + # Now try with invalid device_id + invalid_attrs = %{ + device_id: Ecto.UUID.generate(), + status: :success, + checked_at: DateTime.utc_now() + } + + changeset = Check.changeset(%Check{}, invalid_attrs) + assert {:error, changeset} = Repo.insert(changeset) + assert "does not exist" in errors_on(changeset).device_id + end + + test "response_time_ms can be nil", %{device: device} do + attrs = %{ + device_id: device.id, + status: :failure, + response_time_ms: nil, + checked_at: DateTime.utc_now() + } + + changeset = Check.changeset(%Check{}, attrs) + assert changeset.valid? + end + + test "response_time_ms accepts float values", %{device: device} do + attrs = %{ + device_id: device.id, + status: :success, + response_time_ms: 123.456, + checked_at: DateTime.utc_now() + } + + changeset = Check.changeset(%Check{}, attrs) + assert changeset.valid? + assert get_change(changeset, :response_time_ms) == 123.456 + end + + test "checked_at accepts DateTime", %{device: device} do + now = DateTime.utc_now() + + attrs = %{ + device_id: device.id, + status: :success, + checked_at: now + } + + changeset = Check.changeset(%Check{}, attrs) + assert changeset.valid? + end + end + + describe "schema" do + test "has correct fields" do + fields = Check.__schema__(:fields) + assert :id in fields + assert :device_id in fields + assert :status in fields + assert :response_time_ms in fields + assert :checked_at in fields + assert :inserted_at in fields + end + + test "belongs to device" do + assocs = Check.__schema__(:associations) + assert :device in assocs + + assoc = Check.__schema__(:association, :device) + assert assoc.queryable == Towerops.Devices.Device + end + + test "uses binary_id for primary key" do + assert Check.__schema__(:type, :id) == :binary_id + end + + test "uses binary_id for foreign keys" do + assert Check.__schema__(:type, :device_id) == :binary_id + end + + test "status is an enum" do + assert {:parameterized, {Ecto.Enum, _}} = Check.__schema__(:type, :status) + end + + test "does not have updated_at timestamp" do + fields = Check.__schema__(:fields) + refute :updated_at in fields + end + end +end