Commit graph

123 commits

Author SHA1 Message Date
1d22e6e59b
test: Packets store_packet edge cases (nested/string-keyed data_extended) 2026-04-24 08:10:25 -05:00
00af878d1d
test: Aprsme.Is init/1 connect success and failure paths 2026-04-24 08:05:27 -05:00
f7a331b708
test: Aprsme.Is reconnect success + connect-failure paths 2026-04-24 08:04:17 -05:00
14c3790df0
test: Aprsme.Is active-socket branches via TCP loopback, IsSupervisor smoke 2026-04-24 08:03:19 -05:00
e95dbb39e0
test: Aprsme.Is helper functions without server running 2026-04-23 18:27:49 -05:00
d9f07e313a
test: QueryBuilder recent_position_packets/callsign_history/weather_packets 2026-04-23 18:25:32 -05:00
1b9743191a
test: broader InfoLive rendering + PacketReplay update_filters branches 2026-04-23 18:23:55 -05:00
b6f34b9cb3
test: PacketConsumer batch sizing branches 2026-04-23 18:20:32 -05:00
59e478449a
test: LeaderElection direct handle_info callbacks 2026-04-23 18:19:42 -05:00
a7071ecef1
test: AprsIsMock, DeviceIdentification, PacketCleanupWorker coverage 2026-04-23 18:13:02 -05:00
fac52cf288
test: broaden coverage across Packets/Weather/Info/Map/Status modules 2026-04-23 18:04:36 -05:00
c8c20add1f
test: expand Is backpressure, PacketReplay, CleanupScheduler coverage 2026-04-23 17:56:07 -05:00
fb1131159b
test: add store_bad_packet binary+map inputs 2026-04-23 17:44:45 -05:00
b085c8fcdb
test: expand QueryBuilder coverage with time range and callsign filters 2026-04-23 17:39:37 -05:00
da080ed55d
test: add RegexCache bulk pattern test and PageController uptime format 2026-04-23 17:31:57 -05:00
1b508ba61d
fix(cache): use case instead of rescue to handle :undefined table info; expand Cache tests 2026-04-23 17:31:56 -05:00
fb2e997ca7
test: cover Aprsme.Is TCP data buffering and deployment init 2026-04-23 17:31:56 -05:00
56bc152b49
test: dispatch various APRS packet formats in Is tests 2026-04-23 17:31:56 -05:00
30d852fbc5
test: info_live full render with various packet types 2026-04-23 17:11:50 -05:00
32d4b6daff
test: cover PacketDistributor GenServer callbacks 2026-04-23 17:11:50 -05:00
e3dfdf03ba
test: cover PacketConsumer init and process_batch callbacks 2026-04-23 16:58:13 -05:00
089ea1f4fb
test: expand Packets tests with positions and latest-packet helpers 2026-04-23 16:49:54 -05:00
49374fdbc3
test: expand Accounts and PartitionManager coverage 2026-04-23 16:49:54 -05:00
a5b2c4bccb
test: cover UserAuth, StatusLive handlers and UserNotifier 2026-04-23 16:40:47 -05:00
46e71019de
test: expand coverage for Layouts, DeviceCache, Components and others 2026-04-23 16:36:01 -05:00
41731257e6
test: cover auth LiveViews, PacketReplay, ShutdownHandler and more 2026-04-23 16:30:51 -05:00
16d2e929c0
test: push coverage to 70% with more CoreComponents and PostgresNotifier
- CoreComponents.input/1: expanded coverage to include the select,
  textarea, generic-text, and unchecked-checkbox branches, plus
  error-vs-no-error border styling.
- PostgresNotifier: handle_info forwards pg_notify payload to
  Aprsme.PubSub and ignores unrelated messages.

Coverage 69.56 → 70.11%.
2026-04-23 16:18:04 -05:00
fa893dd12e
test: cover ErrorHTML, Layouts, MapLive.Components, CoreComponents, Accounts
- ErrorHTML: explicit 400 path + 401/403/999 delegation.
- Layouts.body_class/1 returns the expected light/dark theme classes.
- MapLive.Components: map_container + slideover_panel exercising all
  connection_status variants, loading state, tracked_callsign clear
  button, and view-mode radios.
- CoreComponents: icon (found + fallback), button, label, error,
  flash (info + error + close=false), checkbox input, JS composers.
- Accounts: get_user_by_email{_and_password}, get_user!, register_user
  happy-path + error paths, change_* changesets, session-token
  round-trip.

Refactor: DeviceIdentification.maybe_refresh_devices splits its nested
logic into fetch_most_recent_device/0, to_datetime/1, and
refresh_if_stale/2 — each a multi-clause function matching on shape.

Coverage 68.28 → 69.56%.
2026-04-23 16:16:31 -05:00
ab0204f3dc
test: add StreamData properties for Aprsme.GeoUtils
Four properties exercise haversine_distance / significant_movement?:

- non-negativity across any in-range coordinate pair
- symmetry: d(a, b) == d(b, a) within a tight tolerance
- identity: d(p, p) == 0.0
- significance agrees with (haversine > threshold) for any integer
  threshold in 1..1000

Total: +4 properties, coverage stays clean (dialyzer: 0 new errors).
2026-04-23 15:14:12 -05:00
282d3c1ccb
refactor: pattern-match ShutdownHandler + add tests
- handle_call(:shutdown, _, state): split into a shutting_down=true
  fast-path clause and a normal initiate_shutdown clause. No more
  `if state.shutting_down` inside the callback body.
- terminate/2: extract graceful_shutdown_needed?/1 (four function
  heads on the reason tag) and maybe_graceful_drain/2 (guarded on
  state.shutting_down) so the shutdown side-effects are isolated to
  a single, pattern-matched entry point.

Adds 4 unit tests for the pure callback paths
(shutting_down?, shutdown-already-in-progress, EXIT pass-through,
rescue fallback on unavailable GenServer).
2026-04-23 14:21:15 -05:00
7db78675a2
refactor: collapse nested if/case into pattern-matched helpers
- SharedPacketHandler.handle_packet_update: dispatch on filter-result,
  and use maybe_enrich/2 dispatched on the enrich? boolean instead of
  an inner `if`. lookup_device_info/1 is now a trio of function heads.
- Cluster.Topology.child_spec: build_spec/3 dispatches on
  (cluster_enabled?, topologies) tuples — no more nested `if`.
- Cluster.PacketDistributor.distribute_packet: maybe_broadcast/2
  dispatches on the leader-and-enabled check; the non-leader / disabled
  paths return :ok explicitly instead of relying on an `if` expression's
  implicit nil.

Adds tests for SharedPacketHandler (filter/enrich/match paths,
callsign_filter + callsign_and_weather_filter factories) and extends
Cluster.Topology tests to cover the nil-topology and opts-merge cases.
Coverage 66.41 → 66.81%.
2026-04-23 13:55:11 -05:00
aa0c6e6566
refactor: pattern-match in DeviceCache and DatabaseMetrics + add tests
- DeviceCache.pattern_matches?: replace a 3-branch `cond` with a
  two-clause `case` on `String.contains?(pattern, "?")`. The old `*`
  branch was dead code (it did the same exact-match compare as the
  fallback), so it's removed.
- Telemetry.DatabaseMetrics.collect_postgres_metrics: dispatch on
  environment atom via multi-clause private functions instead of
  `if Application.get_env(...) == :test`.

New tests:
- DeviceCache wildcard/exact lookup paths exercised via a seeded cache.
- MobileUserSocket connect/3 for x_headers/peer_data/empty info and
  rate-limit deny.
- DatabaseMetrics pool-metrics emission captured via :telemetry handler
  and the :test-env short-circuit.
2026-04-23 13:46:00 -05:00
c5a82b77c1
refactor: pattern-match over conditionals in Navigation and InsertOptimizer
Swaps `if`/`cond` branches for multi-clause function heads or head-pattern
matching, making the control flow visible in the function signatures:

- Navigation.determine_map_location: resolve_location/4 now dispatches on
  the shape of the geolocation input and whether URL params are explicit.
- Navigation.handle_callsign_tracking: per-case clauses for empty callsign
  and explicit-URL-params short-circuits, plus a final clause that does the
  DB lookup and rescues once.
- Navigation.handle_callsign_search: dispatch_callsign_search/3 separates
  the valid/invalid callsign branches.
- InsertOptimizer.optimize_based_on_performance: pattern-match on
  [_, _, _ | _] to require ≥3 samples without calling length/1.
- InsertOptimizer.calculate_insert_options and throughput helpers split
  into guarded clauses instead of inline `if`.
- maybe_emit_optimization uses same-var pattern matching to skip the
  telemetry hit when nothing changed.

Adds unit tests covering every branch of both modules plus SignalHandler,
LocaleHook, and the InsertOptimizer's :noproc fallback path. Coverage
64.69% → 65.72%.
2026-04-23 13:38:24 -05:00
403300f696
test: broaden unit & property-test coverage (61.8% → 64.7%)
Adds ~800 new tests (incl. 27 StreamData properties) across 22 modules
that previously had little or no coverage. Highlights:

- Pure utility modules (LogSanitizer, PacketFieldWhitelist,
  PacketSanitizer, DeviceParser, CoordinateUtils, BoundsUtils,
  ParamUtils, Convert, WeatherUnits) get thorough unit + property
  coverage including UTF-8 truncation boundaries, antimeridian
  longitude wrap, Haversine symmetry, and unit-conversion inverses.
- JSON view modules (CallsignJSON, ErrorJSON, ChangesetJSON) verified
  for envelope shape and error templating.
- Plugs (HealthCheck, RateLimiter, ApiCSRF) exercised for happy-path
  and halt paths.
- GenServer modules (RegexCache, CleanupScheduler, DeploymentNotifier)
  tested without touching the supervised singleton where possible.
- Drops the orphaned map_live/map_helpers_test.exs whose module name
  collided with the new live/shared/coordinate_utils_test.exs.
2026-04-23 13:32:09 -05:00
2fc4706d3d
fix: stop silent packet loss, timer leak, and seq-scans
- packet_consumer: when a batch exceeds max_batch_size, carry the
  excess over to the next cycle instead of dropping it. Previously
  any overage was split off into a drop list that was only logged,
  losing packets the producer had already acknowledged.

- map_live: cancel the hover_end_timer in terminate/2 so a user
  disconnecting while a marker is still highlighted doesn't leave
  an orphaned timer behind.

- packet_consumer: rescue/log exceptions inside the async broadcast
  task so PubSub serialization bugs or outages are observable
  instead of silently killing the Task.

- prepared_queries: swap ST_Y/ST_X BETWEEN predicates for the && /
  ST_MakeEnvelope pattern so bounds queries hit the GIST index on
  packets.location instead of sequentially scanning.
2026-04-21 09:29:06 -05:00
2300dcd69c
fix: stabilize moving station tracking 2026-03-26 18:48:43 -05:00
bc82777d34
fix: close review findings 2026-03-26 12:36:50 -05:00
d234c313ca
fix: harden mobile channel numeric params 2026-03-22 17:36:09 -05:00
35962c195b
fix: guard device cache refresh when stopped 2026-03-22 17:31:54 -05:00
f840e8fd34
fix: guard APRS send_message when disconnected 2026-03-22 17:16:44 -05:00
4d45c8351a
fix: guard pubsub APIs when not running 2026-03-22 17:14:24 -05:00
7c0861f216
fix: replace duplicate spatial registrations 2026-03-22 17:12:20 -05:00
1631352786
fix: guard connection monitor stats lookup 2026-03-22 17:09:07 -05:00
c769d89264
fix: stabilize packet broadcast tests 2026-03-22 16:17:55 -05:00
8937c1fb57
fix: handle APRS status DB ownership exits 2026-03-22 16:02:03 -05:00
0d4314b880
Fix object positioning to use object name instead of origin callsign
Objects and items were being displayed at the origin station's location
instead of their actual coordinates because the broadcast used the
sender (origin callsign) as the identifier instead of object_name/item_name.

For example, object CALGRY sent by VE6RWB-15 was appearing at VE6RWB-15's
location instead of CALGRY's actual coordinates.

Changes:
- Modified broadcast_single_packet to use object_name for objects
  and item_name for items as the identifier instead of sender
- Added tests verifying objects and items broadcast with correct identifier
- Objects/items now display at their specified coordinates, not origin station

Fixes the positioning bug where objects appeared at sender location.
2026-03-22 15:19:52 -05:00
0c9087b7f1
Add email notifications for production errors
Implements error email notifications that:
- Send email only for first occurrence of each unique error
- Only send in production environment (dev/test are silent)
- Include error details, location, and link to ErrorTracker UI
- Use existing Resend/Swoosh configuration for delivery
- Email sent to graham@mcintire.me

Integrates with ErrorTracker via telemetry events.
2026-03-22 15:12:59 -05:00
47fc071263
Add get_nearby_weather_stations/4 query function with spatial filtering
Implements PostGIS-based query to find weather stations within a radius:
- Uses ST_DWithin for efficient spatial filtering within radius (miles to meters)
- Orders results by ST_Distance (closest first)
- Filters by has_weather, has_position, and time window (default 6h)
- Deduplicates by base_callsign using DISTINCT ON (avoids duplicate SSIDs)
- Returns all weather fields: temp, humidity, pressure, wind, rain
- Configurable limit (default 50) and hours options

Comprehensive test coverage (10 tests):
- Spatial filtering within/outside radius
- Time window filtering
- Base callsign deduplication (most recent SSID)
- Distance ordering verification
- Required field validation
- Edge cases (empty results, no weather data)
2026-03-22 11:27:45 -05:00
7897fe8a1a
perf: optimize slow tests - 40% reduction in top 10 slowest tests
- Skip expensive scheduler utilization sampling in test env (saves 1s per call)
- Reduce Process.sleep times from 100-300ms to 50-100ms
- Reduce refute_receive timeouts from 500ms to 100ms
- GPS drift test: 1371ms → 431ms (68.5% faster)
- BroadcastTaskSupervisor tests removed from slowest 10 (1000ms+ saved each)
- PacketDistributor tests: 33% faster
- StreamingPacketsPubSub tests removed from slowest 10 (400ms+ saved each)

Top 10 slowest tests reduced from 6.8s to 4.1s (40% improvement)
2026-03-03 10:47:40 -06:00
a74a571844
fix: add Process.sleep to async broadcast tests and update Renovate workflow for Forgejo
- Fix PacketConsumerTest timing issues by adding Process.sleep(50) after handle_events
  to wait for async broadcast tasks to complete before assertions
- Update Renovate workflow to use Docker container directly instead of GitHub Action
- Use full GitHub URL for checkout action to work with Forgejo Actions
2026-03-03 10:41:50 -06:00