The object name regex only matched [A-Z0-9 ] which missed names with
hyphens (P-K5SGD), hash symbols (#146.760), and other printable ASCII.
Changed to .{9}[*_] to match all valid object names including killed
objects. Also merged the two cond branches so data_extended is tried
first with information_field parsing as fallback.
Removed dead copy_insert/3 tests from db_optimizer_test.
173 lines
5.2 KiB
Elixir
173 lines
5.2 KiB
Elixir
defmodule Aprsme.DbOptimizerTest do
|
|
use Aprsme.DataCase, async: false
|
|
|
|
alias Aprsme.DbOptimizer
|
|
|
|
describe "calculate_optimal_batch_size/1" do
|
|
test "returns max cap (2000) for small maps" do
|
|
entries = [%{name: "a", value: 1}, %{name: "b", value: 2}]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 2000
|
|
end
|
|
|
|
test "uses default 1024 size when first entry is nil" do
|
|
# With nil as first entry, estimate_entry_size returns 1024
|
|
# available_memory = 14 * 1024 * 1024 = 14_680_064
|
|
# max_batch = div(14_680_064, 1024) = 14_336
|
|
# capped at min(14_336, 2000) = 2000
|
|
entries = [nil, %{name: "a"}]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 2000
|
|
end
|
|
|
|
test "returns 2000 for single-element list with small map" do
|
|
entries = [%{x: 1}]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 2000
|
|
end
|
|
|
|
test "returns minimum of 100 for extremely large entries" do
|
|
# Create a map with very large values to push the estimated size way up
|
|
# We need estimated_size > 14 * 1024 * 1024 / 100 = 146_800
|
|
# Each binary value contributes its byte_size + 100 overhead
|
|
big_value = String.duplicate("x", 200_000)
|
|
entries = [%{data: big_value}]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 100
|
|
end
|
|
end
|
|
|
|
describe "optimized_batch_insert/3" do
|
|
test "inserts valid entries and returns {count, 0}" do
|
|
now = NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
|
|
|
|
entries = [
|
|
%{
|
|
"counter_type" => "test_optimized_1",
|
|
"count" => 100,
|
|
"inserted_at" => now,
|
|
"updated_at" => now
|
|
},
|
|
%{
|
|
"counter_type" => "test_optimized_2",
|
|
"count" => 200,
|
|
"inserted_at" => now,
|
|
"updated_at" => now
|
|
}
|
|
]
|
|
|
|
assert {2, 0} = DbOptimizer.optimized_batch_insert("packet_counters", entries)
|
|
end
|
|
|
|
test "returns {0, 0} for empty list" do
|
|
assert {0, 0} = DbOptimizer.optimized_batch_insert("packet_counters", [])
|
|
end
|
|
end
|
|
|
|
describe "analyze_table/1" do
|
|
test "returns :ok for packets table" do
|
|
assert :ok = DbOptimizer.analyze_table("packets")
|
|
end
|
|
end
|
|
|
|
describe "vacuum_table/1" do
|
|
test "returns :error inside sandbox (VACUUM cannot run in transactions)" do
|
|
assert :error = DbOptimizer.vacuum_table("packets")
|
|
end
|
|
end
|
|
|
|
describe "get_connection_stats/0" do
|
|
test "returns map with expected keys and integer values" do
|
|
stats = DbOptimizer.get_connection_stats()
|
|
|
|
assert is_map(stats)
|
|
assert Map.has_key?(stats, :total)
|
|
assert Map.has_key?(stats, :active)
|
|
assert Map.has_key?(stats, :idle)
|
|
assert Map.has_key?(stats, :idle_in_transaction)
|
|
assert Map.has_key?(stats, :waiting)
|
|
|
|
assert is_integer(stats.total)
|
|
assert is_integer(stats.active)
|
|
assert is_integer(stats.idle)
|
|
assert is_integer(stats.idle_in_transaction)
|
|
assert is_integer(stats.waiting)
|
|
end
|
|
end
|
|
|
|
describe "calculate_optimal_batch_size/1 with various value types" do
|
|
test "handles maps with float values" do
|
|
entries = [%{temp: 98.6, pressure: 1013.25}]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 2000
|
|
end
|
|
|
|
test "handles maps with boolean values" do
|
|
entries = [%{active: true, verified: false}]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 2000
|
|
end
|
|
|
|
test "handles maps with DateTime values" do
|
|
entries = [%{created_at: DateTime.utc_now(), name: "test"}]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 2000
|
|
end
|
|
|
|
test "handles maps with Date values" do
|
|
entries = [%{date: Date.utc_today(), label: "today"}]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 2000
|
|
end
|
|
|
|
test "handles maps with nil values" do
|
|
entries = [%{name: nil, value: nil}]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 2000
|
|
end
|
|
|
|
test "handles maps with mixed value types" do
|
|
entries = [
|
|
%{
|
|
name: "test",
|
|
count: 42,
|
|
ratio: 3.14,
|
|
active: true,
|
|
created: DateTime.utc_now(),
|
|
date: Date.utc_today(),
|
|
extra: nil
|
|
}
|
|
]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 2000
|
|
end
|
|
|
|
test "handles non-map first entry as unknown type" do
|
|
entries = ["just a string", "another"]
|
|
|
|
assert DbOptimizer.calculate_optimal_batch_size(entries) == 2000
|
|
end
|
|
end
|
|
|
|
describe "optimized_batch_insert/3 with invalid data" do
|
|
test "handles insert errors and returns error count" do
|
|
# Insert entries into a nonexistent table - should error
|
|
entries = [%{"bad_col" => "value"}]
|
|
|
|
{success, errors} = DbOptimizer.optimized_batch_insert("nonexistent_table_xyz", entries)
|
|
|
|
assert success == 0
|
|
assert errors == 1
|
|
end
|
|
end
|
|
|
|
describe "vacuum_table/1 with options" do
|
|
test "with full: true returns :error in sandbox" do
|
|
assert :error = DbOptimizer.vacuum_table("packets", full: true)
|
|
end
|
|
|
|
test "with analyze: false returns :error in sandbox" do
|
|
assert :error = DbOptimizer.vacuum_table("packets", analyze: false)
|
|
end
|
|
end
|
|
end
|