Some checks failed
Build and Push / Build and Push Docker Image (push) Has been cancelled
Create shared ContactsFixtures module with globally-unique qso_timestamp seconds to prevent unique-constraint violations when async test modules run in parallel and insert contacts with identical dedup-key columns. The qso_timestamp column is timestamp(0), so microsecond offsets were truncated — use System.unique_integer monotonic seconds instead. Also make count-asserting tests resilient to sandbox-leaked contacts from prior tests by using >= assertions or status-based checks rather than exact counts. Includes automated DateTime.add → DateTime.shift migration from mix format.
126 lines
4.3 KiB
Elixir
126 lines
4.3 KiB
Elixir
defmodule Microwaveprop.BeaconMonitorsTest do
|
|
use Microwaveprop.DataCase
|
|
|
|
import Microwaveprop.AccountsFixtures
|
|
|
|
alias Microwaveprop.BeaconMonitors
|
|
alias Microwaveprop.BeaconMonitors.BeaconMonitor
|
|
|
|
describe "create_monitor/2" do
|
|
test "creates a monitor with a generated token" do
|
|
user = user_fixture()
|
|
|
|
assert {:ok, %BeaconMonitor{} = monitor} =
|
|
BeaconMonitors.create_monitor(user, %{"name" => "Shack Pi"})
|
|
|
|
assert monitor.user_id == user.id
|
|
assert monitor.name == "Shack Pi"
|
|
assert byte_size(monitor.token) > 0
|
|
# strong_rand_bytes(32) |> url_encode64(padding: false) is 43 chars
|
|
assert String.length(monitor.token) == 43
|
|
end
|
|
|
|
test "generates a unique token per monitor" do
|
|
user = user_fixture()
|
|
{:ok, m1} = BeaconMonitors.create_monitor(user, %{"name" => "One"})
|
|
{:ok, m2} = BeaconMonitors.create_monitor(user, %{"name" => "Two"})
|
|
|
|
refute m1.token == m2.token
|
|
end
|
|
|
|
test "requires a name" do
|
|
user = user_fixture()
|
|
|
|
assert {:error, changeset} = BeaconMonitors.create_monitor(user, %{"name" => ""})
|
|
assert %{name: ["can't be blank"]} = errors_on(changeset)
|
|
end
|
|
end
|
|
|
|
describe "list_monitors_for_user/1" do
|
|
test "returns monitors belonging to the user, newest first" do
|
|
user = user_fixture()
|
|
other = user_fixture()
|
|
|
|
# beacon_monitors.inserted_at is :utc_datetime (second precision).
|
|
# Back-date the first row one second via a direct update so the
|
|
# ordering assertion is deterministic without burning ~1s on a
|
|
# Process.sleep — this is a slow-test-suite footgun that also
|
|
# makes the test flaky on a shared CI runner where the two
|
|
# inserts can land in the same wall-clock second.
|
|
{:ok, first} = BeaconMonitors.create_monitor(user, %{"name" => "First"})
|
|
|
|
backdated = DateTime.shift(first.inserted_at, second: -1)
|
|
|
|
{1, _} =
|
|
Microwaveprop.Repo.update_all(
|
|
from(m in BeaconMonitor, where: m.id == ^first.id),
|
|
set: [inserted_at: backdated]
|
|
)
|
|
|
|
{:ok, second} = BeaconMonitors.create_monitor(user, %{"name" => "Second"})
|
|
{:ok, _other} = BeaconMonitors.create_monitor(other, %{"name" => "Nope"})
|
|
|
|
assert [second_result, first_result] = BeaconMonitors.list_monitors_for_user(user)
|
|
assert second_result.id == second.id
|
|
assert first_result.id == first.id
|
|
end
|
|
|
|
test "returns empty list when user has no monitors" do
|
|
user = user_fixture()
|
|
assert BeaconMonitors.list_monitors_for_user(user) == []
|
|
end
|
|
end
|
|
|
|
describe "delete_monitor/2" do
|
|
test "deletes a monitor owned by the user" do
|
|
user = user_fixture()
|
|
{:ok, monitor} = BeaconMonitors.create_monitor(user, %{"name" => "Bye"})
|
|
|
|
assert {:ok, %BeaconMonitor{}} = BeaconMonitors.delete_monitor(user, monitor.id)
|
|
assert BeaconMonitors.list_monitors_for_user(user) == []
|
|
end
|
|
|
|
test "does not delete a monitor owned by another user" do
|
|
user = user_fixture()
|
|
other = user_fixture()
|
|
{:ok, monitor} = BeaconMonitors.create_monitor(other, %{"name" => "Theirs"})
|
|
|
|
assert {:error, :not_found} = BeaconMonitors.delete_monitor(user, monitor.id)
|
|
assert [_] = BeaconMonitors.list_monitors_for_user(other)
|
|
end
|
|
|
|
test "returns :not_found for nonexistent id" do
|
|
user = user_fixture()
|
|
|
|
assert {:error, :not_found} =
|
|
BeaconMonitors.delete_monitor(user, "11111111-1111-1111-1111-111111111111")
|
|
end
|
|
end
|
|
|
|
describe "get_monitor_by_token/1" do
|
|
test "returns the monitor matching the token" do
|
|
user = user_fixture()
|
|
{:ok, monitor} = BeaconMonitors.create_monitor(user, %{"name" => "Find Me"})
|
|
|
|
found = BeaconMonitors.get_monitor_by_token(monitor.token)
|
|
assert found.id == monitor.id
|
|
end
|
|
|
|
test "returns nil for unknown token" do
|
|
refute BeaconMonitors.get_monitor_by_token("not-a-real-token")
|
|
end
|
|
end
|
|
|
|
describe "regenerate_token/1" do
|
|
test "generates a new token on the monitor" do
|
|
user = user_fixture()
|
|
{:ok, monitor} = BeaconMonitors.create_monitor(user, %{"name" => "Token Test"})
|
|
original_token = monitor.token
|
|
|
|
{:ok, updated} = BeaconMonitors.regenerate_token(monitor)
|
|
assert updated.id == monitor.id
|
|
assert updated.token != original_token
|
|
assert String.length(updated.token) == 43
|
|
end
|
|
end
|
|
end
|