For large CSVs (e.g. the 34k-row ARRL dump), the synchronous commit
path blocked for minutes and a crash mid-commit left no audit trail.
Refactor to run inserts + enrichment enqueues via Oban.
- New import_runs table: stores preview rows + running counters (total,
processed, imported, refined, error) + status + errors map + timing.
- New :contact_import Oban queue (limit 4) + ContactImportWorker.
Args: {import_run_id, offset, limit}. Each chunk (100 rows) inserts
its slice via CsvImport.commit_rows/1, atomically increments counters
in one update_all, flips status, and broadcasts progress on
'csv_import:<id>' PubSub topic.
- CsvImport.commit_rows/1 extracted from commit/1 (back-compat preserved).
New CsvImport.enqueue/2 persists the run + dispatches N chunk jobs.
Also: submit page copy updated from '902 MHz and up' to '50 MHz and up'
matching the band allowlist expansion done earlier.
LiveView UI for /imports/:id is a separate commit.
75 lines
2.4 KiB
Elixir
75 lines
2.4 KiB
Elixir
defmodule Microwaveprop.Radio.ImportRunTest do
|
|
use Microwaveprop.DataCase, async: true
|
|
|
|
alias Microwaveprop.Radio.ImportRun
|
|
|
|
@valid_attrs %{
|
|
submitter_email: "test@example.com",
|
|
rows: %{"rows" => [], "refinement_ids" => []},
|
|
total_rows: 0
|
|
}
|
|
|
|
describe "changeset/2" do
|
|
test "accepts a minimal valid attrs map" do
|
|
changeset = ImportRun.changeset(%ImportRun{}, @valid_attrs)
|
|
assert changeset.valid?
|
|
end
|
|
|
|
test "defaults status to pending via schema" do
|
|
run = %ImportRun{}
|
|
assert run.status == "pending"
|
|
assert run.processed_rows == 0
|
|
assert run.imported_count == 0
|
|
assert run.refined_count == 0
|
|
assert run.error_count == 0
|
|
assert run.errors == %{}
|
|
end
|
|
|
|
test "requires submitter_email" do
|
|
changeset = ImportRun.changeset(%ImportRun{}, Map.delete(@valid_attrs, :submitter_email))
|
|
refute changeset.valid?
|
|
assert "can't be blank" in errors_on(changeset).submitter_email
|
|
end
|
|
|
|
test "requires rows" do
|
|
changeset = ImportRun.changeset(%ImportRun{}, Map.delete(@valid_attrs, :rows))
|
|
refute changeset.valid?
|
|
assert "can't be blank" in errors_on(changeset).rows
|
|
end
|
|
|
|
test "requires total_rows" do
|
|
changeset = ImportRun.changeset(%ImportRun{}, Map.delete(@valid_attrs, :total_rows))
|
|
refute changeset.valid?
|
|
assert "can't be blank" in errors_on(changeset).total_rows
|
|
end
|
|
|
|
test "rejects a bad status" do
|
|
changeset = ImportRun.changeset(%ImportRun{}, Map.put(@valid_attrs, :status, "weird"))
|
|
refute changeset.valid?
|
|
assert errors_on(changeset).status != []
|
|
end
|
|
|
|
test "accepts every declared status" do
|
|
for status <- ImportRun.statuses() do
|
|
changeset = ImportRun.changeset(%ImportRun{}, Map.put(@valid_attrs, :status, status))
|
|
assert changeset.valid?, "expected #{inspect(status)} to be valid"
|
|
end
|
|
end
|
|
|
|
test "round-trips through the database" do
|
|
assert {:ok, run} =
|
|
%ImportRun{}
|
|
|> ImportRun.changeset(%{
|
|
submitter_email: "a@example.com",
|
|
rows: %{"rows" => [%{"row_num" => 2}], "refinement_ids" => []},
|
|
total_rows: 1
|
|
})
|
|
|> Repo.insert()
|
|
|
|
reloaded = Repo.get!(ImportRun, run.id)
|
|
assert reloaded.status == "pending"
|
|
assert reloaded.total_rows == 1
|
|
assert reloaded.rows == %{"rows" => [%{"row_num" => 2}], "refinement_ids" => []}
|
|
end
|
|
end
|
|
end
|