Skip to content

Commit 6bc5683

Browse files
committed
chore: add controller tests, update review plan, add status reason constants
- Add controller_test.go: indexes, enqueue helpers, node-to-router mapping, condition helpers (1015 lines) - Add reconcile_test.go: BuildDesiredRouter, gatherPeers, gatherPolicies, AFI/timer/validation tests (1163 lines) - Add frr_test.go: FRR stub tests (60 lines) - Update review-plan.md: mark all phases DONE, add Phase 8 for new tests - Add Reason* constants to status.go for BGP session state reasons
1 parent 0b302da commit 6bc5683

5 files changed

Lines changed: 2344 additions & 27 deletions

File tree

docs/review-plan.md

Lines changed: 94 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Overview
44

5-
Review of the rewrite replacing `galactic-agent` with `galactic-router`. The changes remove ~1527 lines (agent, bootstrap, gobgp provider/server) and add ~860 lines (router, controllers, reconcile, runtime, model, hash, metrics). The code has significant issues that must be resolved before it can be committed.
5+
Review of the rewrite replacing `galactic-agent` with `galactic-router`. The changes remove ~1755 lines (agent, bootstrap, gobgp provider/server) and add ~3643 lines (router, controllers, reconcile, runtime, model, hash, frr). All original issues have been resolved; new test files have been added on this branch.
66

77
---
88

@@ -21,7 +21,7 @@ replace go.miloapis.com/cosmos => ../cosmos
2121

2222
**Verification:** Run `go build ./...` and confirm zero errors.
2323

24-
**Status: DONE**also fixed missing `labels` import in `bgprouter_controller.go`.
24+
**Status: DONE**cosmos reference resolved (`go.miloapis.com/cosmos v0.0.0-20260622211233-0e38bdf25eac`). Also fixed missing `labels` import in `bgprouter_controller.go`.
2525

2626
---
2727

@@ -43,7 +43,7 @@ replace go.miloapis.com/cosmos => ../cosmos
4343

4444
## Phase 3: Remove Dead Code (P1)
4545

46-
### 3.1 Delete `internal/metrics/metrics.go`
46+
~~### 3.1 Delete `internal/metrics/metrics.go`~~
4747

4848
**File:** `internal/metrics/metrics.go`
4949

@@ -53,7 +53,9 @@ replace go.miloapis.com/cosmos => ../cosmos
5353

5454
**Verification:** `go build ./...` should still succeed.
5555

56-
### 3.2 Delete unused condition constants from `status.go`
56+
**Status: DONE**`internal/metrics/` directory no longer exists.
57+
58+
~~### 3.2 Delete unused condition constants from `status.go`~~
5759

5860
**File:** `internal/controller/status.go`
5961

@@ -77,9 +79,9 @@ The helper variables `fsmConditions` and `fsmStateToCondition` are also dead cod
7779

7880
**Verification:** `go vet ./internal/controller/` should show no unused imports.
7981

80-
**Status: DONE** — removed in cosmos API v3 migration; `setPeerReadyCondition` now sets a single `Ready` condition using `bgpv1alpha1.ConditionTypeReady`.
82+
**Status: DONE** — removed in cosmos API v3 migration; `setPeerReadyCondition` now sets a single `Ready` condition using `bgpv1alpha1.ConditionTypeReady`. The status.go file now only defines the used condition constants and `Reason*` strings.
8183

82-
### 3.3 Fix `ConditionSessionOpenCfm` typo
84+
~~### 3.3 Fix `ConditionSessionOpenCfm` typo~~
8385

8486
**File:** `internal/controller/status.go`
8587

@@ -93,7 +95,7 @@ The helper variables `fsmConditions` and `fsmStateToCondition` are also dead cod
9395

9496
## Phase 4: Fix EVPN Stub (P1)
9597

96-
### 4.1 Replace `buildEVPNPath` stub with proper error or implementation
98+
~~### 4.1 Replace `buildEVPNPath` stub with proper error or implementation~~
9799

98100
**File:** `internal/runtime/gobgp/paths.go`
99101

@@ -105,11 +107,13 @@ The helper variables `fsmConditions` and `fsmStateToCondition` are also dead cod
105107

106108
**Verification:** After short-term fix, `go test ./internal/runtime/gobgp/` should pass. After long-term fix, EVPN advertisements should appear in GoBGP state.
107109

110+
**Status: DONE** — full EVPN Type 5 IP Prefix path construction implemented in `buildEVPNPaths` (commit `243f37e`). Builds Type 1 RD from router-ID, parses route target communities, constructs MpReachNLRI with EVPN NLRI, and applies via `AddPath`/`DeletePath`.
111+
108112
---
109113

110114
## Phase 5: Improve Controller Efficiency (P2)
111115

112-
### 5.1 Add field index for BGPRouter targetRef.name
116+
~~### 5.1 Add field index for BGPRouter targetRef.name~~
113117

114118
**Files:** `internal/controller/indexer.go`, `internal/controller/node_controller.go`
115119

@@ -122,7 +126,9 @@ The helper variables `fsmConditions` and `fsmStateToCondition` are also dead cod
122126

123127
**Verification:** Node controller should use indexed lookup instead of full list.
124128

125-
### 5.2 Deduplicate peer/policy router-mapping logic
129+
**Status: DONE**`indexer.go` defines `BGPRouterByTargetName` and registers it in `RegisterIndexes`. `node_controller.go` uses `client.MatchingFields{BGPRouterByTargetName: node.Name}` (line 58).
130+
131+
~~### 5.2 Deduplicate peer/policy router-mapping logic~~
126132

127133
**Files:** `internal/controller/bgppeer_controller.go`, `internal/controller/bgppolicy_controller.go`
128134

@@ -138,11 +144,13 @@ Both controllers should call this helper instead of duplicating the logic.
138144

139145
**Verification:** Both controllers should behave identically after the refactor. `go vet` should show no issues.
140146

147+
**Status: DONE** — `internal/controller/routing.go` contains `enqueueRoutersForTarget` with a `resource` parameter for log context. Both `bgppeer_controller.go` (line 43) and `bgppolicy_controller.go` (line 44) call it.
148+
141149
---
142150

143151
## Phase 6: Fix Error Messages (P2)
144152

145-
### 6.1 Return error from `resolveNodeIPv6` when nextHop is empty + EVPN ads present
153+
~~### 6.1 Return error from `resolveNodeIPv6` when nextHop is empty + EVPN ads present~~
146154

147155
**File:** `internal/reconcile/reconcile.go`
148156

@@ -152,19 +160,23 @@ Both controllers should call this helper instead of duplicating the logic.
152160

153161
**Verification:** A node without IPv6 should get a clear error in the BGPRouter status, not a misleading "MissingRouteDistinguisher".
154162

163+
**Status: DONE** — `BuildDesiredRouter` checks `nextHop == ""` with EVPN advertisements and returns `"node %s has no IPv6 InternalIP; EVPN advertisements require it"` (lines 91–94).
164+
155165
---
156166

157167
## Phase 7: Minor Cleanup (P3)
158168

159-
### 7.1 Fix bgppolicy controller name
169+
~~### 7.1 Fix bgppolicy controller name~~
160170

161171
**File:** `internal/controller/bgppolicy_controller.go`
162172

163173
**Problem:** Line 42 names the controller `"bgproutepolicy"` but the CRD kind is `BGPPolicy`.
164174

165175
**Action:** Change to `Named("bgppolicy")`.
166176

167-
### 7.2 Add TODO on FRR stub
177+
**Status: DONE** — `Named("bgppolicy")` (line 33).
178+
179+
~~### 7.2 Add TODO on FRR stub~~
168180

169181
**File:** `internal/runtime/frr/frr.go`
170182

@@ -176,7 +188,9 @@ Both controllers should call this helper instead of duplicating the logic.
176188
// with ROUTER_ROLE=fabric will fail on the first reconcile.
177189
```
178190

179-
### 7.3 Store hash in BGPRouter status for restart resilience
191+
**Status: DONE** — package comment added (lines 5–7).
192+
193+
~~### 7.3 Store hash in BGPRouter status for restart resilience~~
180194

181195
**File:** `internal/controller/bgprouter_controller.go`
182196

@@ -186,17 +200,75 @@ Both controllers should call this helper instead of duplicating the logic.
186200

187201
**Verification:** Restart the router pod — the hash should be restored from status and no-op reconciles should be skipped.
188202

203+
**Status: DONE** — hash persisted as annotation `galactic.datum.net/config-hash` (line 31). Reconciler compares new hash against annotation before applying (line 125).
204+
205+
---
206+
207+
## Phase 8: New Tests (P1) — Review Required
208+
209+
Three new test files were added on this branch but are not yet committed. They should be reviewed and committed.
210+
211+
### 8.1 `internal/controller/controller_test.go` (1015 lines)
212+
213+
**Contents:**
214+
- `fakeCache` / `fakeManager` — minimal controller-runtime interfaces for testing
215+
- `TestRegisterIndexes` — verifies all 5 indexes register without error
216+
- `TestRegisterIndexes_indexFunctions` — verifies each index function returns correct values (BGPPeer by secret, BGPPeer by router, BGPPolicy by router, BGPAdv by router, BGPRouter by target)
217+
- `TestEnqueueRoutersForTarget_*` — 5 tests covering routerRef, routerSelector, both nil, no match, routerRef overrides selector
218+
- `TestNodeToRouterRequests_*` — 4 tests covering no match, single router, multiple routers, cross-namespace scoping, invalid object, list error
219+
- `TestSetRouterPhase_*` — 3 tests for Ready/Failed/Pending phases
220+
- `TestSetPeerReadyCondition` — 8 test cases covering all FSM states (Established, OpenConfirm, OpenSent, Active, Connect, Idle with reasons, unknown)
221+
- `TestSetAdvertisementCondition_*` — 2 tests for True/False conditions
222+
- `TestSetPolicyCondition_*` — 2 tests for True/False conditions
223+
224+
**Review notes:**
225+
- Test coverage is comprehensive. The `fakeCache`/`fakeManager` stubs are minimal but sufficient for the tested functions.
226+
- The `fakeCache.IndexField` implementation keys by `fmt.Sprintf("%T/%s", obj, field)` to avoid collisions between types that share field names (e.g., BGPPeer, BGPPolicy, BGPAdvertisement all use `.spec.routerRef.name`).
227+
228+
### 8.2 `internal/runtime/frr/frr_test.go` (60 lines)
229+
230+
**Contents:**
231+
- `TestApplyReturnsErrNotImplemented`
232+
- `TestStatusReturnsEmptyAndErrNotImplemented`
233+
- `TestStopReturnsNil`
234+
- `TestNewRuntimeFactory`
235+
236+
**Review notes:**
237+
- Small, focused tests for the FRR stub. Appropriate for a stub implementation.
238+
239+
### 8.3 `internal/reconcile/reconcile_test.go` (1163 lines)
240+
241+
**Contents:**
242+
- Test helpers: `testScheme`, `fakeClient`, `testRouter`, `testNode`, `testPeer`, `testPeerSelector`, `testPolicy`, `testPolicySelector`, `testAdv`, `testAuthSecret`
243+
- `TestBuildDesiredRouter` — 7 test cases including happy path, wrong node, wrong role, multi-role error, missing node, missing auth secret
244+
- `TestBuildDesiredRouter_EVPNNoIPv6` — verifies error when EVPN ads present but node has no IPv6
245+
- `TestBuildDesiredRouter_EVPNWithIPv6` — verifies successful build with IPv6
246+
- `TestBuildDesiredRouter_AuthSecret` — verifies auth secret password resolution
247+
- `TestGatherPeers` — 9 test cases: routerRef, routerSelector, matchExpressions, non-matching, invalid AFI, timers, auth secret, missing auth, invalid keepalive
248+
- `TestGatherPolicies` — 6 test cases: routerRef, routerSelector, non-matching, invalid term config, term sorting, set actions
249+
- `TestValidateAFI` — 6 test cases for valid/invalid AFI/SAFI combos
250+
- `TestValidateAFIsAll` — 4 test cases
251+
- `TestValidateTimers` — 7 test cases for holdTime/keepalive validation
252+
- `TestResolveNodeIPv6` — 8 test cases covering IPv6 selection, IPv4 fallback, no addresses, node not found, multiple IPv6, IPv4 skip, external skip, invalid IP
253+
- `TestPeerTargetsRouter` — 5 test cases
254+
- `TestPolicyTargetsRouter` — 5 test cases
255+
256+
**Review notes:**
257+
- Excellent coverage of the reconcile logic. The test helpers are well-structured and reusable.
258+
- `TestBuildDesiredRouter_EVPNNoIPv6` directly validates the fix from Phase 6.1.
259+
- `TestResolveNodeIPv6` is thorough — covers edge cases like multiple IPv6, external addresses, and invalid IPs.
260+
189261
---
190262

191263
## Verification Checklist
192264

193-
After all phases are complete:
265+
After all phases are complete and new tests are committed:
194266

195-
- [ ] `go build ./...` — zero errors
196-
- [ ] `go test ./internal/cni/` — all tests pass
197-
- [ ] `go test ./internal/reconcile/` — all tests pass
198-
- [ ] `go test ./internal/controller/` — all tests pass
199-
- [ ] `go test ./internal/hash/` — all tests pass
200-
- [ ] `go vet ./...` — zero warnings
201-
- [ ] `task lint` — passes
202-
- [ ] `go fmt ./...` — no unformatted files
267+
- [x] `go build ./...` — zero errors
268+
- [x] `go test ./internal/cni/` — all tests pass
269+
- [x] `go test ./internal/reconcile/` — all tests pass
270+
- [x] `go test ./internal/controller/` — all tests pass
271+
- [x] `go test ./internal/hash/` — all tests pass
272+
- [x] `go vet ./...` — zero warnings
273+
- [x] `task lint` — passes
274+
- [x] `go fmt ./...` — no unformatted files

0 commit comments

Comments
 (0)