test fix and preseem check fix
This commit is contained in:
parent
53ccc27fa8
commit
b3f8204047
11 changed files with 89 additions and 59 deletions
|
|
@ -90,12 +90,21 @@ defmodule Towerops.Preseem.Client do
|
|||
end
|
||||
|
||||
defp request(method, url, api_key) do
|
||||
Req.request(
|
||||
opts = [
|
||||
method: method,
|
||||
url: url,
|
||||
headers: [{"authorization", "Bearer #{api_key}"}, {"accept", "application/json"}],
|
||||
plug: {Req.Test, __MODULE__}
|
||||
)
|
||||
headers: [{"authorization", "Bearer #{api_key}"}, {"accept", "application/json"}]
|
||||
]
|
||||
|
||||
# Only use Req.Test plug in test environment
|
||||
opts =
|
||||
if Application.get_env(:towerops, :env) == :test do
|
||||
Keyword.put(opts, :plug, {Req.Test, __MODULE__})
|
||||
else
|
||||
opts
|
||||
end
|
||||
|
||||
Req.request(opts)
|
||||
rescue
|
||||
exception ->
|
||||
{:error, Exception.message(exception)}
|
||||
|
|
|
|||
|
|
@ -74,8 +74,9 @@ defmodule Towerops.Preseem.FleetIntelligence do
|
|||
|
||||
defp compute_capacity_ceiling(aps) do
|
||||
aps
|
||||
|> Enum.filter(fn ap -> ap.qoe_score != nil and ap.subscriber_count != nil end)
|
||||
|> Enum.filter(fn ap -> ap.qoe_score >= 70 end)
|
||||
|> Enum.filter(fn ap ->
|
||||
ap.qoe_score != nil and ap.subscriber_count != nil and ap.qoe_score >= 70
|
||||
end)
|
||||
|> Enum.map(& &1.subscriber_count)
|
||||
|> Enum.max(fn -> nil end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -112,24 +112,28 @@ defmodule Towerops.Preseem.Insights do
|
|||
device_id: ap.device_id
|
||||
})
|
||||
|
||||
existing =
|
||||
Repo.get_by(Insight,
|
||||
preseem_access_point_id: ap.id,
|
||||
type: full_attrs.type,
|
||||
status: "active"
|
||||
)
|
||||
|
||||
if existing do
|
||||
[]
|
||||
else
|
||||
case %Insight{} |> Insight.changeset(full_attrs) |> Repo.insert() do
|
||||
{:ok, insight} -> [insight]
|
||||
{:error, _} -> []
|
||||
end
|
||||
end
|
||||
insert_insight_if_new(ap.id, full_attrs)
|
||||
end)
|
||||
end
|
||||
|
||||
defp insert_insight_if_new(ap_id, full_attrs) do
|
||||
existing =
|
||||
Repo.get_by(Insight,
|
||||
preseem_access_point_id: ap_id,
|
||||
type: full_attrs.type,
|
||||
status: "active"
|
||||
)
|
||||
|
||||
if existing do
|
||||
[]
|
||||
else
|
||||
case %Insight{} |> Insight.changeset(full_attrs) |> Repo.insert() do
|
||||
{:ok, insight} -> [insight]
|
||||
{:error, _} -> []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp check_qoe_degradation(ap, baselines) do
|
||||
qoe_baseline = Enum.find(baselines, &(&1.metric_name == "qoe_score" and &1.period == "all"))
|
||||
|
||||
|
|
|
|||
|
|
@ -375,6 +375,10 @@ defmodule Towerops.Security.BruteForce do
|
|||
|
||||
defp create_cache_table do
|
||||
:ets.new(@whitelist_cache_table, [:set, :public, :named_table, read_concurrency: true])
|
||||
rescue
|
||||
ArgumentError ->
|
||||
# Table already exists due to race condition in async tests - this is fine
|
||||
:ets.whereis(@whitelist_cache_table)
|
||||
end
|
||||
|
||||
defp load_whitelist do
|
||||
|
|
|
|||
|
|
@ -17,24 +17,7 @@ defmodule Towerops.Workers.PreseemSyncWorker do
|
|||
def perform(%Oban.Job{}) do
|
||||
integrations = Integrations.list_enabled_integrations("preseem")
|
||||
|
||||
results =
|
||||
Enum.map(integrations, fn integration ->
|
||||
if should_sync?(integration) do
|
||||
case Sync.sync_organization(integration) do
|
||||
{:ok, result} ->
|
||||
Logger.info("Preseem sync completed for org #{integration.organization_id}: #{inspect(result)}")
|
||||
|
||||
{:ok, result}
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.error("Preseem sync failed for org #{integration.organization_id}: #{inspect(reason)}")
|
||||
|
||||
{:error, reason}
|
||||
end
|
||||
else
|
||||
:skipped
|
||||
end
|
||||
end)
|
||||
results = Enum.map(integrations, &sync_integration/1)
|
||||
|
||||
synced = Enum.count(results, &match?({:ok, _}, &1))
|
||||
failed = Enum.count(results, &match?({:error, _}, &1))
|
||||
|
|
@ -47,6 +30,22 @@ defmodule Towerops.Workers.PreseemSyncWorker do
|
|||
:ok
|
||||
end
|
||||
|
||||
defp sync_integration(integration) do
|
||||
if should_sync?(integration) do
|
||||
case Sync.sync_organization(integration) do
|
||||
{:ok, result} ->
|
||||
Logger.info("Preseem sync completed for org #{integration.organization_id}: #{inspect(result)}")
|
||||
{:ok, result}
|
||||
|
||||
{:error, reason} ->
|
||||
Logger.error("Preseem sync failed for org #{integration.organization_id}: #{inspect(reason)}")
|
||||
{:error, reason}
|
||||
end
|
||||
else
|
||||
:skipped
|
||||
end
|
||||
end
|
||||
|
||||
defp should_sync?(integration) do
|
||||
case integration.last_synced_at do
|
||||
nil ->
|
||||
|
|
|
|||
|
|
@ -115,19 +115,8 @@ defmodule ToweropsWeb.Org.IntegrationsLive do
|
|||
if api_key == "" or is_nil(api_key) do
|
||||
{:noreply, assign(socket, :test_result, {:error, "Please enter an API key first"})}
|
||||
else
|
||||
case PreseemClient.test_connection(api_key) do
|
||||
{:ok, _body} ->
|
||||
{:noreply, assign(socket, :test_result, {:ok, "Connection successful"})}
|
||||
|
||||
{:error, :unauthorized} ->
|
||||
{:noreply, assign(socket, :test_result, {:error, "Invalid API key"})}
|
||||
|
||||
{:error, :forbidden} ->
|
||||
{:noreply, assign(socket, :test_result, {:error, "Access forbidden"})}
|
||||
|
||||
{:error, reason} ->
|
||||
{:noreply, assign(socket, :test_result, {:error, "Connection failed: #{inspect(reason)}"})}
|
||||
end
|
||||
result = PreseemClient.test_connection(api_key)
|
||||
{:noreply, assign(socket, :test_result, format_connection_result(result))}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -197,4 +186,23 @@ defmodule ToweropsWeb.Org.IntegrationsLive do
|
|||
_ -> nil
|
||||
end
|
||||
end
|
||||
|
||||
defp format_connection_result({:ok, _body}), do: {:ok, "Connection successful"}
|
||||
defp format_connection_result({:error, :unauthorized}), do: {:error, "Invalid API key"}
|
||||
defp format_connection_result({:error, :forbidden}), do: {:error, "Access forbidden"}
|
||||
|
||||
defp format_connection_result({:error, {:unexpected_status, status}}),
|
||||
do: {:error, "API returned unexpected status: #{status}"}
|
||||
|
||||
defp format_connection_result({:error, %{reason: :timeout}}),
|
||||
do: {:error, "Connection timeout - unable to reach Preseem API"}
|
||||
|
||||
defp format_connection_result({:error, %{reason: :econnrefused}}),
|
||||
do: {:error, "Connection refused - check API endpoint"}
|
||||
|
||||
defp format_connection_result({:error, %{reason: :nxdomain}}), do: {:error, "DNS lookup failed - check API endpoint"}
|
||||
|
||||
# Never expose internal error details to users
|
||||
defp format_connection_result({:error, _reason}),
|
||||
do: {:error, "Connection failed - please check your API credentials and try again"}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ defmodule Towerops.Preseem.BaselineTest do
|
|||
assert {:ok, 1} = Baseline.compute_baselines(org.id)
|
||||
|
||||
baselines = Repo.all(DeviceBaseline)
|
||||
assert length(baselines) > 0
|
||||
refute baselines == []
|
||||
|
||||
latency_baseline = Enum.find(baselines, &(&1.metric_name == "avg_latency"))
|
||||
assert latency_baseline
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ defmodule Towerops.Snmp.SensorChangeDetectorTest do
|
|||
%{device: device, snmp_device: snmp_device}
|
||||
end
|
||||
|
||||
defp create_sensor(snmp_device, attrs \\ %{}) do
|
||||
defp create_sensor(snmp_device, attrs) do
|
||||
defaults = %{
|
||||
snmp_device_id: snmp_device.id,
|
||||
sensor_type: "frequency",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
defmodule ToweropsNativeTest do
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
# Suppress false positive dialyzer warnings for NIF return types
|
||||
@dialyzer :no_match
|
||||
|
||||
# NIF not compiled in this worktree — skip all tests
|
||||
@moduletag :skip
|
||||
|
||||
|
|
@ -104,7 +107,7 @@ defmodule ToweropsNativeTest do
|
|||
oid1 = ToweropsNative.resolve_oid("SNMPv2-MIB::sysDescr")
|
||||
oid2 = ToweropsNative.resolve_oid("sysDescr")
|
||||
|
||||
# Both should resolve to the same OID
|
||||
# Both should resolve to the same OID (dialyzer can't infer these always succeed)
|
||||
assert is_binary(oid1)
|
||||
assert is_binary(oid2)
|
||||
assert oid1 == oid2
|
||||
|
|
|
|||
|
|
@ -1206,7 +1206,6 @@ defmodule ToweropsWeb.AgentChannelTest do
|
|||
|
||||
describe "device deletion and job refresh" do
|
||||
test "agent receives updated job list after device deletion", %{
|
||||
socket: socket,
|
||||
device: device,
|
||||
agent_token: agent_token
|
||||
} do
|
||||
|
|
@ -1280,7 +1279,7 @@ defmodule ToweropsWeb.AgentChannelTest do
|
|||
# (This is verified by the channel staying alive)
|
||||
end
|
||||
|
||||
test "multiple rapid assignment changes are debounced", %{socket: socket, agent_token: agent_token} do
|
||||
test "multiple rapid assignment changes are debounced", %{agent_token: agent_token} do
|
||||
# Trigger multiple rapid assignment changes
|
||||
for i <- 1..5 do
|
||||
Phoenix.PubSub.broadcast(
|
||||
|
|
|
|||
|
|
@ -7,10 +7,13 @@ defmodule ToweropsWeb.SiteLiveTest do
|
|||
|
||||
setup :register_and_log_in_user
|
||||
|
||||
setup %{user: user} do
|
||||
setup %{conn: conn, user: user} do
|
||||
{:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)
|
||||
|
||||
%{organization: organization}
|
||||
# Set the current organization in the session to ensure correct scope
|
||||
conn = Plug.Conn.put_session(conn, :current_organization_id, organization.id)
|
||||
|
||||
%{conn: conn, organization: organization}
|
||||
end
|
||||
|
||||
describe "Index" do
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue