From d58f6b2d3a753fe8ffe561a4f0308a60ccb5ae46 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Tue, 13 Jan 2026 08:54:49 -0600 Subject: [PATCH] Add tests for Monitoring.Ping and OrgLive.New - Add comprehensive tests for Towerops.Monitoring.Ping module - Test successful pings, timeouts, error handling, and OS detection - Add tests for ToweropsWeb.OrgLive.New LiveView - Test form validation, organization creation, and authentication --- test/towerops/monitoring/ping_test.exs | 72 +++++++++++++++++ test/towerops_web/live/org_live/new_test.exs | 82 ++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 test/towerops/monitoring/ping_test.exs create mode 100644 test/towerops_web/live/org_live/new_test.exs diff --git a/test/towerops/monitoring/ping_test.exs b/test/towerops/monitoring/ping_test.exs new file mode 100644 index 00000000..b4511b53 --- /dev/null +++ b/test/towerops/monitoring/ping_test.exs @@ -0,0 +1,72 @@ +defmodule Towerops.Monitoring.PingTest do + use ExUnit.Case, async: true + + alias Towerops.Monitoring.Ping + + describe "ping/2" do + test "successfully pings localhost" do + assert {:ok, response_time} = Ping.ping("127.0.0.1") + assert is_integer(response_time) + assert response_time >= 0 + end + + test "uses default timeout of 5000ms" do + # Test that ping works without explicit timeout + assert {:ok, _response_time} = Ping.ping("127.0.0.1") + end + + test "accepts custom timeout" do + assert {:ok, _response_time} = Ping.ping("127.0.0.1", 1000) + end + + test "returns error for unreachable host" do + # Use an address that should be unreachable + # 192.0.2.0/24 is TEST-NET-1, reserved for documentation + assert {:error, :timeout_or_unreachable} = Ping.ping("192.0.2.1", 1000) + end + + test "returns error for invalid IP address" do + # Invalid IP address should fail + assert {:error, :timeout_or_unreachable} = Ping.ping("999.999.999.999", 1000) + end + + test "calculates response time" do + # Ping should complete in reasonable time + {:ok, response_time} = Ping.ping("127.0.0.1", 5000) + + # Response time should be positive and reasonable (< 5 seconds) + assert response_time > 0 + assert response_time < 5000 + end + + test "handles timeout correctly" do + # Very short timeout should likely fail or be very fast + result = Ping.ping("127.0.0.1", 1) + + case result do + {:ok, time} -> assert time >= 0 + {:error, _} -> assert true + end + end + + test "minimum timeout is 1 second" do + # Even with 0ms timeout, should use minimum of 1 second + result = Ping.ping("127.0.0.1", 0) + assert {:ok, _} = result + end + + test "respects different OS types" do + # This test just ensures the OS detection doesn't crash + case :os.type() do + {:unix, :darwin} -> + assert {:ok, _} = Ping.ping("127.0.0.1") + + {:unix, _} -> + assert {:ok, _} = Ping.ping("127.0.0.1") + + {:win32, _} -> + assert {:ok, _} = Ping.ping("127.0.0.1") + end + end + end +end diff --git a/test/towerops_web/live/org_live/new_test.exs b/test/towerops_web/live/org_live/new_test.exs new file mode 100644 index 00000000..0d7db774 --- /dev/null +++ b/test/towerops_web/live/org_live/new_test.exs @@ -0,0 +1,82 @@ +defmodule ToweropsWeb.OrgLive.NewTest do + use ToweropsWeb.ConnCase + + import Phoenix.LiveViewTest + + setup :register_and_log_in_user + + describe "New" do + test "renders new organization form", %{conn: conn} do + {:ok, _view, html} = live(conn, ~p"/orgs/new") + + assert html =~ "New Organization" + assert html =~ "name=\"organization[name]\"" + end + + test "validates organization name", %{conn: conn} do + {:ok, view, _html} = live(conn, ~p"/orgs/new") + + html = + view + |> form("#organization-form", %{organization: %{name: ""}}) + |> render_change() + + assert html =~ "can't be blank" + end + + test "creates new organization", %{conn: conn, user: user} do + {:ok, view, _html} = live(conn, ~p"/orgs/new") + + assert view + |> form("#organization-form", %{organization: %{name: "Test Organization"}}) + |> render_submit() + + # Get the redirect path + {path, _flash} = assert_redirect(view) + + # Verify organization was created + assert path =~ ~r/\/orgs\/.+/ + + # Extract slug from redirect path + slug = path |> String.split("/") |> List.last() + org = Towerops.Organizations.get_organization_by_slug!(slug) + assert org.name == "Test Organization" + + # Verify user is a member + membership = Towerops.Organizations.get_membership(org.id, user.id) + assert membership.role == :owner + end + + test "shows error when organization name is invalid", %{conn: conn} do + {:ok, view, _html} = live(conn, ~p"/orgs/new") + + html = + view + |> form("#organization-form", %{organization: %{name: ""}}) + |> render_submit() + + assert html =~ "can't be blank" + end + + test "shows error when organization name is too long", %{conn: conn} do + {:ok, view, _html} = live(conn, ~p"/orgs/new") + + long_name = String.duplicate("a", 256) + + html = + view + |> form("#organization-form", %{organization: %{name: long_name}}) + |> render_submit() + + assert html =~ "should be at most" + end + + test "requires authentication", %{} do + conn = build_conn() + {:error, redirect} = live(conn, ~p"/orgs/new") + + assert {:redirect, %{to: path}} = redirect + assert path == ~p"/users/log-in" + end + end +end