test(13-01): add failing tests for InterfaceInfo collector
- InterfaceInfo struct field compilation test - MAC address lowercasing test - Running bool parsing test Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,12 +29,12 @@
|
|||||||
|
|
||||||
### Wireless Collection
|
### Wireless Collection
|
||||||
|
|
||||||
- [ ] **WRCL-01**: Poller collects per-client registration table data from APs (MAC, signal, CCQ, TX/RX rates, distance, uptime) on a 5-minute cadence
|
- [x] **WRCL-01**: Poller collects per-client registration table data from APs (MAC, signal, CCQ, TX/RX rates, distance, uptime) on a 5-minute cadence
|
||||||
- [ ] **WRCL-02**: Poller collects per-interface RF stats (noise floor, channel width, TX power, registered client count) via monitor command
|
- [x] **WRCL-02**: Poller collects per-interface RF stats (noise floor, channel width, TX power, registered client count) via monitor command
|
||||||
- [ ] **WRCL-03**: Per-client wireless data publishes to a dedicated NATS stream (separate from DEVICE_EVENTS) to prevent stream saturation
|
- [x] **WRCL-03**: Per-client wireless data publishes to a dedicated NATS stream (separate from DEVICE_EVENTS) to prevent stream saturation
|
||||||
- [ ] **WRCL-04**: Per-client wireless data stores in a dedicated hypertable with 30-day retention (separate from existing wireless_metrics)
|
- [x] **WRCL-04**: Per-client wireless data stores in a dedicated hypertable with 30-day retention (separate from existing wireless_metrics)
|
||||||
- [ ] **WRCL-05**: Poller handles RouterOS v6/v7 field differences gracefully (CCQ absent in v7 wifi package)
|
- [x] **WRCL-05**: Poller handles RouterOS v6/v7 field differences gracefully (CCQ absent in v7 wifi package)
|
||||||
- [ ] **WRCL-06**: Signal strength parsing handles RouterOS format variations (e.g., `-67@5GHz` suffix)
|
- [x] **WRCL-06**: Signal strength parsing handles RouterOS format variations (e.g., `-67@5GHz` suffix)
|
||||||
|
|
||||||
### Link Discovery
|
### Link Discovery
|
||||||
|
|
||||||
@@ -107,12 +107,12 @@
|
|||||||
| SECT-01 | Phase 14 | Pending |
|
| SECT-01 | Phase 14 | Pending |
|
||||||
| SECT-02 | Phase 14 | Pending |
|
| SECT-02 | Phase 14 | Pending |
|
||||||
| SECT-03 | Phase 14 | Pending |
|
| SECT-03 | Phase 14 | Pending |
|
||||||
| WRCL-01 | Phase 12 | Pending |
|
| WRCL-01 | Phase 12 | Complete |
|
||||||
| WRCL-02 | Phase 12 | Pending |
|
| WRCL-02 | Phase 12 | Complete |
|
||||||
| WRCL-03 | Phase 12 | Pending |
|
| WRCL-03 | Phase 12 | Complete |
|
||||||
| WRCL-04 | Phase 12 | Pending |
|
| WRCL-04 | Phase 12 | Complete |
|
||||||
| WRCL-05 | Phase 12 | Pending |
|
| WRCL-05 | Phase 12 | Complete |
|
||||||
| WRCL-06 | Phase 12 | Pending |
|
| WRCL-06 | Phase 12 | Complete |
|
||||||
| LINK-01 | Phase 13 | Pending |
|
| LINK-01 | Phase 13 | Pending |
|
||||||
| LINK-02 | Phase 13 | Pending |
|
| LINK-02 | Phase 13 | Pending |
|
||||||
| LINK-03 | Phase 13 | Pending |
|
| LINK-03 | Phase 13 | Pending |
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ v9.7 transforms TOD from a flat device list into a site-aware fleet management p
|
|||||||
- Decimal phases (11.1, 11.2): Urgent insertions (marked with INSERTED)
|
- Decimal phases (11.1, 11.2): Urgent insertions (marked with INSERTED)
|
||||||
|
|
||||||
- [x] **Phase 11: Site Data Model + Foundation** - Sites CRUD, device assignment, site list with health rollup (completed 2026-03-19)
|
- [x] **Phase 11: Site Data Model + Foundation** - Sites CRUD, device assignment, site list with health rollup (completed 2026-03-19)
|
||||||
- [ ] **Phase 12: Per-Client Wireless Collection** - Poller extension to collect registration table and per-interface RF stats
|
- [x] **Phase 12: Per-Client Wireless Collection** - Poller extension to collect registration table and per-interface RF stats (completed 2026-03-19)
|
||||||
- [ ] **Phase 13: Link Discovery + Registration Ingestion** - Backend NATS consumer, MAC resolution, AP-CPE link state machine
|
- [ ] **Phase 13: Link Discovery + Registration Ingestion** - Backend NATS consumer, MAC resolution, AP-CPE link state machine
|
||||||
- [ ] **Phase 14: Site Dashboard + Sector Views + Wireless UI** - Site detail page, sector-centric view, per-station wireless tables
|
- [ ] **Phase 14: Site Dashboard + Sector Views + Wireless UI** - Site detail page, sector-centric view, per-station wireless tables
|
||||||
- [ ] **Phase 15: Signal Trending + Site Alerting** - Signal history charts, degradation detection, site/sector alert rules
|
- [ ] **Phase 15: Signal Trending + Site Alerting** - Signal history charts, degradation detection, site/sector alert rules
|
||||||
@@ -69,7 +69,7 @@ Plans:
|
|||||||
3. Per-client data publishes to a dedicated WIRELESS_REGISTRATIONS NATS stream (not DEVICE_EVENTS)
|
3. Per-client data publishes to a dedicated WIRELESS_REGISTRATIONS NATS stream (not DEVICE_EVENTS)
|
||||||
4. Per-client data stores in a dedicated hypertable with 30-day retention
|
4. Per-client data stores in a dedicated hypertable with 30-day retention
|
||||||
5. Collection works correctly on both RouterOS v6 (wireless package) and v7 (wifi package) with graceful handling of missing fields
|
5. Collection works correctly on both RouterOS v6 (wireless package) and v7 (wifi package) with graceful handling of missing fields
|
||||||
**Plans:** 2 plans
|
**Plans:** 2/2 plans complete
|
||||||
|
|
||||||
Plans:
|
Plans:
|
||||||
- [ ] 12-01-PLAN.md — Go poller per-client registration collector, signal parser, RF monitor, NATS stream and publisher
|
- [ ] 12-01-PLAN.md — Go poller per-client registration collector, signal parser, RF monitor, NATS stream and publisher
|
||||||
@@ -84,11 +84,12 @@ Plans:
|
|||||||
2. Link state follows a temporal state machine (discovered, active, degraded, down, stale) with consecutive-miss threshold to prevent false flapping
|
2. Link state follows a temporal state machine (discovered, active, degraded, down, stale) with consecutive-miss threshold to prevent false flapping
|
||||||
3. Discovered links are stored in a materialized wireless_links table for fast dashboard queries
|
3. Discovered links are stored in a materialized wireless_links table for fast dashboard queries
|
||||||
4. Wireless clients whose MACs do not match any managed device appear as "unknown clients" with their signal and rate data preserved
|
4. Wireless clients whose MACs do not match any managed device appear as "unknown clients" with their signal and rate data preserved
|
||||||
**Plans**: TBD
|
**Plans:** 3 plans
|
||||||
|
|
||||||
Plans:
|
Plans:
|
||||||
- [ ] 13-01: TBD
|
- [ ] 13-01-PLAN.md — Go poller interface collector (/interface/print) and DEVICE_EVENTS publisher
|
||||||
- [ ] 13-02: TBD
|
- [ ] 13-02-PLAN.md — Backend device_interfaces and wireless_links table migrations with ORM models
|
||||||
|
- [ ] 13-03-PLAN.md — Link discovery subscriber, interface subscriber, link REST API, and app wiring
|
||||||
|
|
||||||
### Phase 14: Site Dashboard + Sector Views + Wireless UI
|
### Phase 14: Site Dashboard + Sector Views + Wireless UI
|
||||||
**Goal**: Operators can drill into any site to see device health, sector-organized AP/CPE views, and per-station wireless details on device pages
|
**Goal**: Operators can drill into any site to see device health, sector-organized AP/CPE views, and per-station wireless details on device pages
|
||||||
@@ -129,8 +130,7 @@ Plans:
|
|||||||
| Sites | SITE-01, SITE-02, SITE-03, SITE-04, SITE-05, SITE-06 | 11 | 3/3 | Complete | 2026-03-19 | DASH-01 | 11 | 1 |
|
| Sites | SITE-01, SITE-02, SITE-03, SITE-04, SITE-05, SITE-06 | 11 | 3/3 | Complete | 2026-03-19 | DASH-01 | 11 | 1 |
|
||||||
| Site Dashboard | DASH-02, DASH-03, DASH-04 | 14 | 3 |
|
| Site Dashboard | DASH-02, DASH-03, DASH-04 | 14 | 3 |
|
||||||
| Sectors | SECT-01, SECT-02, SECT-03 | 14 | 3 |
|
| Sectors | SECT-01, SECT-02, SECT-03 | 14 | 3 |
|
||||||
| Wireless Collection | WRCL-01, WRCL-02, WRCL-03, WRCL-04, WRCL-05, WRCL-06 | 12 | 6 |
|
| Wireless Collection | WRCL-01, WRCL-02, WRCL-03, WRCL-04, WRCL-05, WRCL-06 | 12 | 2/2 | Complete | 2026-03-19 | LINK-01, LINK-02, LINK-03, LINK-04 | 13 | 4 |
|
||||||
| Link Discovery | LINK-01, LINK-02, LINK-03, LINK-04 | 13 | 4 |
|
|
||||||
| Wireless UI | WRUI-01, WRUI-02, WRUI-03 | 14 | 3 |
|
| Wireless UI | WRUI-01, WRUI-02, WRUI-03 | 14 | 3 |
|
||||||
| Signal Trending | TRND-01, TRND-02 | 15 | 2 |
|
| Signal Trending | TRND-01, TRND-02 | 15 | 2 |
|
||||||
| Site Alerting | ALRT-01, ALRT-02 | 15 | 2 |
|
| Site Alerting | ALRT-01, ALRT-02 | 15 | 2 |
|
||||||
@@ -145,7 +145,7 @@ Phases execute in numeric order: 11 -> 11.x -> 12 -> 12.x -> 13 -> 13.x -> 14 ->
|
|||||||
|-------|----------------|--------|-----------|
|
|-------|----------------|--------|-----------|
|
||||||
| 11. Site Data Model + Foundation | 0/3 | Planning complete | - |
|
| 11. Site Data Model + Foundation | 0/3 | Planning complete | - |
|
||||||
| 12. Per-Client Wireless Collection | 0/2 | Planning complete | - |
|
| 12. Per-Client Wireless Collection | 0/2 | Planning complete | - |
|
||||||
| 13. Link Discovery + Registration Ingestion | 0/? | Not started | - |
|
| 13. Link Discovery + Registration Ingestion | 0/3 | Planning complete | - |
|
||||||
| 14. Site Dashboard + Sector Views + Wireless UI | 0/? | Not started | - |
|
| 14. Site Dashboard + Sector Views + Wireless UI | 0/? | Not started | - |
|
||||||
| 15. Signal Trending + Site Alerting | 0/? | Not started | - |
|
| 15. Signal Trending + Site Alerting | 0/? | Not started | - |
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v9.7
|
milestone: v9.7
|
||||||
milestone_name: Tower & Site Management
|
milestone_name: Tower & Site Management
|
||||||
status: phase-complete
|
status: unknown
|
||||||
stopped_at: Completed 11-03-PLAN.md
|
stopped_at: Completed 12-01-PLAN.md
|
||||||
last_updated: "2026-03-19T02:53:16Z"
|
last_updated: "2026-03-19T10:40:03.896Z"
|
||||||
progress:
|
progress:
|
||||||
total_phases: 5
|
total_phases: 5
|
||||||
completed_phases: 1
|
completed_phases: 2
|
||||||
total_plans: 3
|
total_plans: 5
|
||||||
completed_plans: 3
|
completed_plans: 5
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
@@ -19,12 +19,12 @@ progress:
|
|||||||
See: .planning/PROJECT.md (updated 2026-03-18)
|
See: .planning/PROJECT.md (updated 2026-03-18)
|
||||||
|
|
||||||
**Core value:** Operators can monitor, configure, and troubleshoot their entire MikroTik fleet from a single pane of glass
|
**Core value:** Operators can monitor, configure, and troubleshoot their entire MikroTik fleet from a single pane of glass
|
||||||
**Current focus:** Phase 11 — site-data-model-foundation
|
**Current focus:** Phase 12 — per-client-wireless-collection
|
||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
Phase: 11 (site-data-model-foundation) — COMPLETE
|
Phase: 12 (per-client-wireless-collection) — COMPLETE
|
||||||
Plan: 3 of 3 (all complete)
|
Plan: 2 of 2 (all complete)
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -45,6 +45,9 @@ Plan: 3 of 3 (all complete)
|
|||||||
| Phase 11 P01 | 3min | 2 tasks | 9 files |
|
| Phase 11 P01 | 3min | 2 tasks | 9 files |
|
||||||
| Phase 11 P02 | 6min | 3 tasks | 8 files |
|
| Phase 11 P02 | 6min | 3 tasks | 8 files |
|
||||||
| Phase 11 P03 | 3min | 2 tasks | 5 files |
|
| Phase 11 P03 | 3min | 2 tasks | 5 files |
|
||||||
|
| Phase 12 P01 | 3min | 2 tasks | 6 files |
|
||||||
|
| Phase 12 P02 | 3min | 2 tasks | 3 files |
|
||||||
|
| Phase 12 P01 | 3min | 2 tasks | 6 files |
|
||||||
|
|
||||||
### Decisions
|
### Decisions
|
||||||
|
|
||||||
@@ -58,6 +61,9 @@ Decisions are logged in PROJECT.md Key Decisions table.
|
|||||||
- [Phase 11]: Used Dialog for delete confirmation (no AlertDialog component in UI library)
|
- [Phase 11]: Used Dialog for delete confirmation (no AlertDialog component in UI library)
|
||||||
- [Phase 11]: Site column placed after Model in fleet table for logical grouping
|
- [Phase 11]: Site column placed after Model in fleet table for logical grouping
|
||||||
- [Phase 11]: Viewers see site name text, operators get Select dropdown for assignment
|
- [Phase 11]: Viewers see site name text, operators get Select dropdown for assignment
|
||||||
|
- [Phase 12]: Used unified tenant_isolation RLS policy with super_admin OR clause (matching codebase convention) instead of separate super_admin_bypass policy
|
||||||
|
- [Phase 12]: WIRELESS_REGISTRATIONS NATS stream uses 30-day retention (vs 24h for DEVICE_EVENTS) for historical client analytics
|
||||||
|
- [Phase 12]: RF monitor collection gated on wireless interface presence to avoid unnecessary API calls
|
||||||
|
|
||||||
### Pending Todos
|
### Pending Todos
|
||||||
|
|
||||||
@@ -71,6 +77,6 @@ None yet.
|
|||||||
|
|
||||||
## Session Continuity
|
## Session Continuity
|
||||||
|
|
||||||
Last session: 2026-03-19T02:53:16Z
|
Last session: 2026-03-19T10:40:03.893Z
|
||||||
Stopped at: Completed 11-03-PLAN.md (Phase 11 complete)
|
Stopped at: Completed 12-01-PLAN.md
|
||||||
Resume file: None
|
Resume file: None
|
||||||
|
|||||||
72
poller/internal/device/interfaces_test.go
Normal file
72
poller/internal/device/interfaces_test.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package device
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInterfaceInfoFields(t *testing.T) {
|
||||||
|
// Verify struct compiles with expected fields and JSON tags.
|
||||||
|
info := InterfaceInfo{
|
||||||
|
Name: "ether1",
|
||||||
|
MacAddress: "aa:bb:cc:dd:ee:ff",
|
||||||
|
Type: "ether",
|
||||||
|
Running: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Name != "ether1" {
|
||||||
|
t.Errorf("Name = %q, want %q", info.Name, "ether1")
|
||||||
|
}
|
||||||
|
if info.MacAddress != "aa:bb:cc:dd:ee:ff" {
|
||||||
|
t.Errorf("MacAddress = %q, want %q", info.MacAddress, "aa:bb:cc:dd:ee:ff")
|
||||||
|
}
|
||||||
|
if info.Type != "ether" {
|
||||||
|
t.Errorf("Type = %q, want %q", info.Type, "ether")
|
||||||
|
}
|
||||||
|
if !info.Running {
|
||||||
|
t.Error("Running = false, want true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInterfaceMACLowercasing(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{name: "already lowercase", input: "aa:bb:cc:dd:ee:ff", want: "aa:bb:cc:dd:ee:ff"},
|
||||||
|
{name: "uppercase", input: "AA:BB:CC:DD:EE:FF", want: "aa:bb:cc:dd:ee:ff"},
|
||||||
|
{name: "mixed case", input: "Aa:Bb:Cc:Dd:Ee:Ff", want: "aa:bb:cc:dd:ee:ff"},
|
||||||
|
{name: "empty", input: "", want: ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := normalizeMACAddress(tt.input)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("normalizeMACAddress(%q) = %q, want %q", tt.input, got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInterfaceRunningParsing(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{name: "true string", input: "true", want: true},
|
||||||
|
{name: "false string", input: "false", want: false},
|
||||||
|
{name: "empty string", input: "", want: false},
|
||||||
|
{name: "yes string", input: "yes", want: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := parseRunning(tt.input)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("parseRunning(%q) = %v, want %v", tt.input, got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user