diff --git a/test/towerops/splynx/client_test.exs b/test/towerops/splynx/client_test.exs index 37cc099f..378d20cc 100644 --- a/test/towerops/splynx/client_test.exs +++ b/test/towerops/splynx/client_test.exs @@ -193,6 +193,60 @@ defmodule Towerops.Splynx.ClientTest do end end + describe "GET error branches" do + test "returns :forbidden on 403" do + stub_auth_then(fn conn -> + conn |> Plug.Conn.put_status(403) |> Req.Test.json(%{}) + end) + + assert {:error, :forbidden} = Client.list_customers(@instance_url, @api_key, @api_secret) + end + + test "returns rate_limited tuple on 429" do + stub_auth_then(fn conn -> + conn |> Plug.Conn.put_status(429) |> Req.Test.json(%{}) + end) + + assert {:error, {:rate_limited, 60}} = + Client.list_customers(@instance_url, @api_key, @api_secret) + end + + test "returns unexpected_status tuple on other non-2xx" do + stub_auth_then(fn conn -> + conn |> Plug.Conn.put_status(503) |> Req.Test.json(%{"error" => "down"}) + end) + + assert {:error, {:unexpected_status, 503}} = + Client.list_customers(@instance_url, @api_key, @api_secret) + end + + test "returns transport error on connection failure" do + stub_auth_then(fn conn -> + Req.Test.transport_error(conn, :econnrefused) + end) + + assert {:error, _} = Client.list_customers(@instance_url, @api_key, @api_secret) + end + end + + describe "authentication unexpected_status branch" do + test "returns unexpected_status tuple when auth endpoint returns 500" do + Req.Test.stub(Client, fn conn -> + conn |> Plug.Conn.put_status(500) |> Req.Test.json(%{"error" => "broken"}) + end) + + assert {:error, _} = Client.test_connection(@instance_url, @api_key, @api_secret) + end + + test "auth transport_error surfaces as a binary or atom error" do + Req.Test.stub(Client, fn conn -> + Req.Test.transport_error(conn, :nxdomain) + end) + + assert {:error, _} = Client.test_connection(@instance_url, @api_key, @api_secret) + end + end + describe "authorization header" do test "uses Splynx-EA format with access token" do Req.Test.stub(Client, fn conn -> diff --git a/test/towerops/splynx/sync_test.exs b/test/towerops/splynx/sync_test.exs index 92739c10..379ce3bd 100644 --- a/test/towerops/splynx/sync_test.exs +++ b/test/towerops/splynx/sync_test.exs @@ -114,6 +114,59 @@ defmodule Towerops.Splynx.SyncTest do updated = Repo.reload!(integration) assert updated.last_sync_message =~ "MRR: $150.00" end + + test "handles customers with mrr_total as unparseable string", %{integration: integration} do + stub_auth_then_routes(%{ + "customer" => [%{"id" => 1, "name" => "Bad", "status" => "active", "mrr_total" => "not-a-number"}], + "routers" => [] + }) + + {:ok, result} = Sync.sync_organization(integration) + assert result.customers == 1 + end + + test "marks sync as failed on forbidden error", %{integration: integration} do + Req.Test.stub(Client, fn conn -> + case conn.request_path do + "/api/2.0/admin/auth/tokens" -> + conn |> Plug.Conn.put_status(201) |> Req.Test.json(auth_success_response()) + + _ -> + conn |> Plug.Conn.put_status(403) |> Req.Test.json(%{}) + end + end) + + assert {:error, _} = Sync.sync_organization(integration) + updated = Repo.reload!(integration) + assert updated.last_sync_message =~ "Access denied" + end + + test "marks sync as failed on unexpected_status error", %{integration: integration} do + Req.Test.stub(Client, fn conn -> + case conn.request_path do + "/api/2.0/admin/auth/tokens" -> + conn |> Plug.Conn.put_status(201) |> Req.Test.json(auth_success_response()) + + _ -> + conn |> Plug.Conn.put_status(500) |> Req.Test.json(%{}) + end + end) + + assert {:error, _} = Sync.sync_organization(integration) + updated = Repo.reload!(integration) + assert updated.last_sync_message =~ "unexpected HTTP 500" + end + + test "humanizes SSL certificate string error", %{integration: integration} do + # Sync.sync_organization eventually returns an :error with a binary + # reason. We reach humanize_sync_error/1 by stubbing transport_error + # which becomes a :tls_alert / cacert message in some cases. + Req.Test.stub(Client, fn conn -> + Req.Test.transport_error(conn, :econnrefused) + end) + + assert {:error, _} = Sync.sync_organization(integration) + end end # --- Helpers ---