[management] fix the concurrency handling within the update message tests (#8000)

This commit is contained in:
Pascal Fischer
2026-10-06 14:53:16 +02:00
committed by GitHub
parent f5707c3485
commit a816acd97c
17 changed files with 3417 additions and 3267 deletions
+69 -8
View File
@@ -13,6 +13,7 @@ import (
"strings" "strings"
"sync" "sync"
"testing" "testing"
"testing/synctest"
"time" "time"
"github.com/prometheus/client_golang/prometheus/push" "github.com/prometheus/client_golang/prometheus/push"
@@ -40,6 +41,7 @@ import (
"github.com/netbirdio/netbird/management/internals/modules/zones" "github.com/netbirdio/netbird/management/internals/modules/zones"
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db" networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
networkmapdbfactory "github.com/netbirdio/netbird/management/internals/network_map_db/factory" networkmapdbfactory "github.com/netbirdio/netbird/management/internals/network_map_db/factory"
networkmap_sqlite "github.com/netbirdio/netbird/management/internals/network_map_db/sqlite"
"github.com/netbirdio/netbird/management/internals/server/config" "github.com/netbirdio/netbird/management/internals/server/config"
nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc" nbgrpc "github.com/netbirdio/netbird/management/internals/shared/grpc"
nbAccount "github.com/netbirdio/netbird/management/server/account" nbAccount "github.com/netbirdio/netbird/management/server/account"
@@ -1297,7 +1299,9 @@ func TestAccountManager_AddPeerWithUserID(t *testing.T) {
} }
func TestAccountManager_NetworkUpdates_SaveGroup(t *testing.T) { func TestAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
testAccountManager_NetworkUpdates_SaveGroup(t) testAccountManager_NetworkUpdates_SaveGroup(t)
})
} }
func testAccountManager_NetworkUpdates_SaveGroup(t *testing.T) { func testAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
@@ -1330,6 +1334,8 @@ func testAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID) updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
defer updateManager.CloseChannel(context.Background(), peer1.ID) defer updateManager.CloseChannel(context.Background(), peer1.ID)
settleAffectedUpdates(updMsg)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(1) wg.Add(1)
go func() { go func() {
@@ -1352,7 +1358,9 @@ func testAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
} }
func TestAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) { func TestAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
testAccountManager_NetworkUpdates_DeletePolicy(t) testAccountManager_NetworkUpdates_DeletePolicy(t)
})
} }
func testAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) { func testAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) {
@@ -1361,13 +1369,7 @@ func testAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) {
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID) updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
defer updateManager.CloseChannel(context.Background(), peer1.ID) defer updateManager.CloseChannel(context.Background(), peer1.ID)
// Ensure that we do not receive an update message before the policy is deleted settleAffectedUpdates(updMsg)
time.Sleep(time.Second)
select {
case <-updMsg:
t.Logf("received addPeer update message before policy deletion")
default:
}
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(1) wg.Add(1)
@@ -1390,7 +1392,9 @@ func testAccountManager_NetworkUpdates_DeletePolicy(t *testing.T) {
} }
func TestAccountManager_NetworkUpdates_SavePolicy(t *testing.T) { func TestAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
testAccountManager_NetworkUpdates_SavePolicy(t) testAccountManager_NetworkUpdates_SavePolicy(t)
})
} }
func testAccountManager_NetworkUpdates_SavePolicy(t *testing.T) { func testAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
@@ -1410,6 +1414,8 @@ func testAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID) updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
defer updateManager.CloseChannel(context.Background(), peer1.ID) defer updateManager.CloseChannel(context.Background(), peer1.ID)
settleAffectedUpdates(updMsg)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(1) wg.Add(1)
go func() { go func() {
@@ -1443,7 +1449,9 @@ func testAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
} }
func TestAccountManager_NetworkUpdates_DeletePeer(t *testing.T) { func TestAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
testAccountManager_NetworkUpdates_DeletePeer(t) testAccountManager_NetworkUpdates_DeletePeer(t)
})
} }
func testAccountManager_NetworkUpdates_DeletePeer(t *testing.T) { func testAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
@@ -1482,6 +1490,8 @@ func testAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID) updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
defer updateManager.CloseChannel(context.Background(), peer1.ID) defer updateManager.CloseChannel(context.Background(), peer1.ID)
settleAffectedUpdates(updMsg)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(1) wg.Add(1)
go func() { go func() {
@@ -1503,7 +1513,9 @@ func testAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
} }
func TestAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) { func TestAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
testAccountManager_NetworkUpdates_DeleteGroup(t) testAccountManager_NetworkUpdates_DeleteGroup(t)
})
} }
func testAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) { func testAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) {
@@ -1550,6 +1562,8 @@ func testAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) {
} }
} }
settleAffectedUpdates(updMsg)
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(1) wg.Add(1)
go func() { go func() {
@@ -3582,6 +3596,9 @@ func createManagerWithNetworkMapStore(t testing.TB) (*DefaultAccountManager, *up
nmdataStore, err := networkmapdbfactory.NewNetworkMapDBStore(context.Background(), types.SqliteStoreEngine, dataDir, MockIntegratedValidator{}, newSettingsMockManager(t)) nmdataStore, err := networkmapdbfactory.NewNetworkMapDBStore(context.Background(), types.SqliteStoreEngine, dataDir, MockIntegratedValidator{}, newSettingsMockManager(t))
require.NoError(t, err) require.NoError(t, err)
sqliteStore, ok := nmdataStore.Store.(*networkmap_sqlite.SqliteStore)
require.True(t, ok, "network map store is %T, want *networkmap_sqlite.SqliteStore", nmdataStore.Store)
t.Cleanup(func() { assert.NoError(t, sqliteStore.Db.Close()) })
manager, updateManager, err := buildTestManager(t, store, nmdataStore) manager, updateManager, err := buildTestManager(t, store, nmdataStore)
require.NoError(t, err) require.NoError(t, err)
@@ -3636,7 +3653,8 @@ func buildTestManager(t testing.TB, store store.Store, nmdataStore *networkmapdb
Return(nil). Return(nil).
AnyTimes() AnyTimes()
cacheStore, err := cache.NewStore(ctx, 100*time.Millisecond, 300*time.Millisecond, 100) // The go-cache janitor only stops via a GC finalizer and would outlive synctest bubbles.
cacheStore, err := cache.NewStore(ctx, 100*time.Millisecond, 0, 100)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -3648,8 +3666,11 @@ func buildTestManager(t testing.TB, store store.Store, nmdataStore *networkmapdb
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
cacheManager := manager.cacheManager
t.Cleanup(func() { assert.NoError(t, cacheManager.Close()) })
proxyGrpcServer := nbgrpc.NewProxyServiceServer(nil, nil, nil, nbgrpc.ProxyOIDCConfig{}, peersManager, nil, nil, proxyManager, nil) proxyGrpcServer := nbgrpc.NewProxyServiceServer(nil, nil, nil, nbgrpc.ProxyOIDCConfig{}, peersManager, nil, nil, proxyManager, nil)
t.Cleanup(proxyGrpcServer.Close)
proxyController, err := proxymanager.NewGRPCController(proxyGrpcServer, noop.Meter{}) proxyController, err := proxymanager.NewGRPCController(proxyGrpcServer, noop.Meter{})
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@@ -3743,6 +3764,33 @@ func setupNetworkMapTest(t *testing.T) (*DefaultAccountManager, *update_channel.
// when the channel delivers. // when the channel delivers.
const peerUpdateTimeout = 5 * time.Second const peerUpdateTimeout = 5 * time.Second
// peerUpdateSettleTime bounds how far settleAffectedUpdates advances the fake clock. It must exceed
// the account request and peer update buffer intervals.
const peerUpdateSettleTime = time.Second
// runPeerUpdateTest runs f inside synctest.Test, so the peer update helpers observe every background
// goroutine of the test, and lets the updates still in flight when f returns finish before the bubble
// ends, since the bubble's clock stops with it.
func runPeerUpdateTest(t *testing.T, f func(t *testing.T)) {
synctest.Test(t, func(t *testing.T) {
defer settleAffectedUpdates()
f(t)
})
}
// settleAffectedUpdates runs the synctest bubble's fake clock past every update buffer interval until
// all goroutines are blocked, then discards the updates already delivered to chans, so the next
// assertion only observes updates from the action under test. It must be called inside synctest.Test.
func settleAffectedUpdates(chans ...<-chan *network_map.UpdateMessage) {
time.Sleep(peerUpdateSettleTime)
synctest.Wait()
for _, ch := range chans {
for len(ch) > 0 {
<-ch
}
}
}
func drainPeerUpdates(ch <-chan *network_map.UpdateMessage) { func drainPeerUpdates(ch <-chan *network_map.UpdateMessage) {
for { for {
select { select {
@@ -3756,6 +3804,19 @@ func drainPeerUpdates(ch <-chan *network_map.UpdateMessage) {
} }
} }
// step runs f as one named stage of a test inside synctest.Test, which forbids t.Run, and names the
// stage when it fails the test. Stages share t, so a fatal failure ends the remaining stages as well.
func step(t *testing.T, name string, f func(t *testing.T)) {
t.Helper()
failedBefore := t.Failed()
defer func() {
if !failedBefore && t.Failed() {
t.Logf("step %q failed", name)
}
}()
f(t)
}
func peerShouldNotReceiveUpdate(t *testing.T, updateMessage <-chan *network_map.UpdateMessage) { func peerShouldNotReceiveUpdate(t *testing.T, updateMessage <-chan *network_map.UpdateMessage) {
t.Helper() t.Helper()
select { select {
+5 -5
View File
@@ -87,6 +87,7 @@ func TestAffectedPeers_AllowedUsersChange_RefreshesSSHDestinations(t *testing.T)
// auto-group change updates only the user's peers and the peers linked to the changed // auto-group change updates only the user's peers and the peers linked to the changed
// group through policies, instead of fanning out to the whole account. // group through policies, instead of fanning out to the whole account.
func TestAffectedPeers_SyncUserJWTGroups_OnlyAffectedPeersUpdated(t *testing.T) { func TestAffectedPeers_SyncUserJWTGroups_OnlyAffectedPeersUpdated(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -144,10 +145,8 @@ func TestAffectedPeers_SyncUserJWTGroups_OnlyAffectedPeersUpdated(t *testing.T)
Groups: []string{"jwt-linked"}, Groups: []string{"jwt-linked"},
} }
t.Run("adding JWT group updates only linked peers", func(t *testing.T) { step(t, "adding JWT group updates only linked peers", func(t *testing.T) {
drainPeerUpdates(updUser) settleAffectedUpdates(updUser, upd2, upd3)
drainPeerUpdates(upd2)
drainPeerUpdates(upd3)
require.NoError(t, manager.SyncUserJWTGroups(ctx, userAuth)) require.NoError(t, manager.SyncUserJWTGroups(ctx, userAuth))
@@ -160,7 +159,7 @@ func TestAffectedPeers_SyncUserJWTGroups_OnlyAffectedPeersUpdated(t *testing.T)
assert.Contains(t, user.AutoGroups, "jwt-grp") assert.Contains(t, user.AutoGroups, "jwt-grp")
}) })
t.Run("removing JWT group updates only linked peers", func(t *testing.T) { step(t, "removing JWT group updates only linked peers", func(t *testing.T) {
drainPeerUpdates(updUser) drainPeerUpdates(updUser)
drainPeerUpdates(upd2) drainPeerUpdates(upd2)
drainPeerUpdates(upd3) drainPeerUpdates(upd3)
@@ -176,4 +175,5 @@ func TestAffectedPeers_SyncUserJWTGroups_OnlyAffectedPeersUpdated(t *testing.T)
require.NoError(t, err) require.NoError(t, err)
assert.NotContains(t, user.AutoGroups, "jwt-grp") assert.NotContains(t, user.AutoGroups, "jwt-grp")
}) })
})
} }
@@ -24,6 +24,7 @@ import (
// detaching one of them must still refresh that group's policy source peers, even // detaching one of them must still refresh that group's policy source peers, even
// though the post-update resource no longer maps to it. // though the post-update resource no longer maps to it.
func TestAffectedPeers_E2E_UpdateResource_DetachGroup_RefreshesOldGroupSources(t *testing.T) { func TestAffectedPeers_E2E_UpdateResource_DetachGroup_RefreshesOldGroupSources(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
ctx := context.Background() ctx := context.Background()
@@ -87,12 +88,14 @@ func TestAffectedPeers_E2E_UpdateResource_DetachGroup_RefreshesOldGroupSources(t
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: detaching a resource group did not refresh the old group's policy source peer") t.Error("timeout: detaching a resource group did not refresh the old group's policy source peer")
} }
})
} }
// TestAffectedPeers_E2E_UpdateRouter_RepointPeer_RefreshesOldRoutingPeer: // TestAffectedPeers_E2E_UpdateRouter_RepointPeer_RefreshesOldRoutingPeer:
// changing router.Peer within the same network must still refresh the OLD routing // changing router.Peer within the same network must still refresh the OLD routing
// peer, which loses its routing role. // peer, which loses its routing role.
func TestAffectedPeers_E2E_UpdateRouter_RepointPeer_RefreshesOldRoutingPeer(t *testing.T) { func TestAffectedPeers_E2E_UpdateRouter_RepointPeer_RefreshesOldRoutingPeer(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
ctx := context.Background() ctx := context.Background()
@@ -140,4 +143,5 @@ func TestAffectedPeers_E2E_UpdateRouter_RepointPeer_RefreshesOldRoutingPeer(t *t
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: re-pointing the router peer did not refresh the old routing peer") t.Error("timeout: re-pointing the router peer did not refresh the old routing peer")
} }
})
} }
@@ -165,6 +165,7 @@ func (s *routerScenario) createPostureCheckGatedPolicy(t *testing.T, ctx context
} }
func TestAffectedPeers_E2E_SavePostureCheck_RefreshesRoutingPeer(t *testing.T) { func TestAffectedPeers_E2E_SavePostureCheck_RefreshesRoutingPeer(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
ctx := context.Background() ctx := context.Background()
@@ -203,9 +204,11 @@ func TestAffectedPeers_E2E_SavePostureCheck_RefreshesRoutingPeer(t *testing.T) {
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: editing a posture check did not refresh source + routing peers") t.Error("timeout: editing a posture check did not refresh source + routing peers")
} }
})
} }
func TestAffectedPeers_E2E_UpdateResource_DestinationResourcePolicy_RefreshesSourcePeer(t *testing.T) { func TestAffectedPeers_E2E_UpdateResource_DestinationResourcePolicy_RefreshesSourcePeer(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
ctx := context.Background() ctx := context.Background()
@@ -249,11 +252,13 @@ func TestAffectedPeers_E2E_UpdateResource_DestinationResourcePolicy_RefreshesSou
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: updating a DestinationResource-targeted resource did not refresh its policy source peer") t.Error("timeout: updating a DestinationResource-targeted resource did not refresh its policy source peer")
} }
})
} }
// A disabled sibling router routes to nobody, so updating a resource on its network // A disabled sibling router routes to nobody, so updating a resource on its network
// must NOT refresh its peer (the enabled router carries the bridge instead). // must NOT refresh its peer (the enabled router carries the bridge instead).
func TestAffectedPeers_E2E_UpdateResource_DisabledSiblingRouterNotBridged(t *testing.T) { func TestAffectedPeers_E2E_UpdateResource_DisabledSiblingRouterNotBridged(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
ctx := context.Background() ctx := context.Background()
@@ -307,6 +312,7 @@ func TestAffectedPeers_E2E_UpdateResource_DisabledSiblingRouterNotBridged(t *tes
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout") t.Error("timeout")
} }
})
} }
func TestAffectedPeers_GroupChange_RouterInOtherNetworkNotAffected(t *testing.T) { func TestAffectedPeers_GroupChange_RouterInOtherNetworkNotAffected(t *testing.T) {
@@ -346,18 +352,22 @@ func TestAffectedPeers_PeerChange_RouterInOtherNetworkNotAffected(t *testing.T)
// shortcut (the denied peer's map holds no router) and the allow direction // shortcut (the denied peer's map holds no router) and the allow direction
// depends on which meta field moved, leaving the routers with a stale map. // depends on which meta field moved, leaving the routers with a stale map.
func TestAffectedPeers_E2E_PostureFlip_RefreshesRoutingPeer(t *testing.T) { func TestAffectedPeers_E2E_PostureFlip_RefreshesRoutingPeer(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy { runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy {
return peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID) return peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID)
}) })
})
} }
// TestAffectedPeers_E2E_PostureFlip_DirectSourcePeer_RefreshesRoutingPeer is the same // TestAffectedPeers_E2E_PostureFlip_DirectSourcePeer_RefreshesRoutingPeer is the same
// scenario with the source peer named directly in the rule: it must receive its posture // scenario with the source peer named directly in the rule: it must receive its posture
// checks and have its flips detected exactly like a group member. // checks and have its flips detected exactly like a group member.
func TestAffectedPeers_E2E_PostureFlip_DirectSourcePeer_RefreshesRoutingPeer(t *testing.T) { func TestAffectedPeers_E2E_PostureFlip_DirectSourcePeer_RefreshesRoutingPeer(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy { runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy {
return peerToResourcePolicyByPeer(s.sourcePeerID, s.resourceGroupID) return peerToResourcePolicyByPeer(s.sourcePeerID, s.resourceGroupID)
}) })
})
} }
func runPostureFlipRefreshesRoutingPeer(t *testing.T, policyFor func(s *routerScenario) *types.Policy) { func runPostureFlipRefreshesRoutingPeer(t *testing.T, policyFor func(s *routerScenario) *types.Policy) {
+18 -14
View File
@@ -8,7 +8,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/netbirdio/netbird/management/internals/controllers/network_map"
"github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel" "github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel"
"github.com/netbirdio/netbird/management/server/affectedpeers" "github.com/netbirdio/netbird/management/server/affectedpeers"
"github.com/netbirdio/netbird/management/server/groups" "github.com/netbirdio/netbird/management/server/groups"
@@ -320,6 +319,7 @@ func TestAffectedPeers_PolicyToResource_UnrelatedPeerNotAffected(t *testing.T) {
} }
func TestAffectedPeers_ResourceSideBridgesToRoutingPeer_DirectRouter(t *testing.T) { func TestAffectedPeers_ResourceSideBridgesToRoutingPeer_DirectRouter(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
ctx := context.Background() ctx := context.Background()
@@ -343,6 +343,8 @@ func TestAffectedPeers_ResourceSideBridgesToRoutingPeer_DirectRouter(t *testing.
s.updateManager.CloseChannel(ctx, s.routerPeerID) s.updateManager.CloseChannel(ctx, s.routerPeerID)
}) })
settleAffectedUpdates(srcCh, routerCh)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, srcCh) peerShouldReceiveUpdate(t, srcCh)
@@ -366,22 +368,11 @@ func TestAffectedPeers_ResourceSideBridgesToRoutingPeer_DirectRouter(t *testing.
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: resource update did not refresh source peer + routing peer") t.Error("timeout: resource update did not refresh source peer + routing peer")
} }
} })
// settleAffectedUpdates waits for in-flight async updates to arrive, then drains
// every given channel so subsequent assertions start from a clean slate.
//
// Setup (CreateNetwork/CreateResource/CreateRouter) fires async UpdateAffectedPeers
// goroutines; draining first means the assertion only observes updates from the
// action under test, not setup stragglers.
func settleAffectedUpdates(chans ...<-chan *network_map.UpdateMessage) {
time.Sleep(300 * time.Millisecond)
for _, ch := range chans {
drainPeerUpdates(ch)
}
} }
func TestAffectedPeers_E2E_CreatePolicy_RoutingPeer_DirectRouter(t *testing.T) { func TestAffectedPeers_E2E_CreatePolicy_RoutingPeer_DirectRouter(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
ctx := context.Background() ctx := context.Background()
@@ -412,9 +403,11 @@ func TestAffectedPeers_E2E_CreatePolicy_RoutingPeer_DirectRouter(t *testing.T) {
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: creating peer->resource policy did not refresh the routing peer") t.Error("timeout: creating peer->resource policy did not refresh the routing peer")
} }
})
} }
func TestAffectedPeers_E2E_CreatePolicy_RoutingPeer_RouterPeerGroups(t *testing.T) { func TestAffectedPeers_E2E_CreatePolicy_RoutingPeer_RouterPeerGroups(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, false) s := setupRouterScenario(t, false)
ctx := context.Background() ctx := context.Background()
@@ -442,9 +435,11 @@ func TestAffectedPeers_E2E_CreatePolicy_RoutingPeer_RouterPeerGroups(t *testing.
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: routing peer (PeerGroups) not refreshed on policy create") t.Error("timeout: routing peer (PeerGroups) not refreshed on policy create")
} }
})
} }
func TestAffectedPeers_E2E_DestResource_RoutingPeer(t *testing.T) { func TestAffectedPeers_E2E_DestResource_RoutingPeer(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
ctx := context.Background() ctx := context.Background()
@@ -472,9 +467,11 @@ func TestAffectedPeers_E2E_DestResource_RoutingPeer(t *testing.T) {
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: routing peer not refreshed when policy targets DestinationResource") t.Error("timeout: routing peer not refreshed when policy targets DestinationResource")
} }
})
} }
func TestAffectedPeers_E2E_DeletePolicy_RoutingPeer(t *testing.T) { func TestAffectedPeers_E2E_DeletePolicy_RoutingPeer(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
ctx := context.Background() ctx := context.Background()
@@ -504,6 +501,7 @@ func TestAffectedPeers_E2E_DeletePolicy_RoutingPeer(t *testing.T) {
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: deleting peer->resource policy did not refresh the routing peer") t.Error("timeout: deleting peer->resource policy did not refresh the routing peer")
} }
})
} }
func (s *routerScenario) managers() (resources.Manager, routers.Manager, networks.Manager) { func (s *routerScenario) managers() (resources.Manager, routers.Manager, networks.Manager) {
@@ -572,6 +570,7 @@ func (s *routerScenario) addSecondTopology(t *testing.T, suffix string) secondTo
} }
func TestAffectedPeers_E2E_UpdatePolicy_BothRoutingPeers(t *testing.T) { func TestAffectedPeers_E2E_UpdatePolicy_BothRoutingPeers(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
second := s.addSecondTopology(t, "b") second := s.addSecondTopology(t, "b")
ctx := context.Background() ctx := context.Background()
@@ -607,9 +606,11 @@ func TestAffectedPeers_E2E_UpdatePolicy_BothRoutingPeers(t *testing.T) {
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: re-pointing the policy destination did not refresh both routing peers") t.Error("timeout: re-pointing the policy destination did not refresh both routing peers")
} }
})
} }
func TestAffectedPeers_E2E_UpdatePolicy_AddSource(t *testing.T) { func TestAffectedPeers_E2E_UpdatePolicy_AddSource(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, true) s := setupRouterScenario(t, true)
ctx := context.Background() ctx := context.Background()
@@ -649,9 +650,11 @@ func TestAffectedPeers_E2E_UpdatePolicy_AddSource(t *testing.T) {
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: adding a source group did not refresh the new source peer + routing peer") t.Error("timeout: adding a source group did not refresh the new source peer + routing peer")
} }
})
} }
func TestAffectedPeers_E2E_DestResource_RouterPeerGroups(t *testing.T) { func TestAffectedPeers_E2E_DestResource_RouterPeerGroups(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
s := setupRouterScenario(t, false) s := setupRouterScenario(t, false)
ctx := context.Background() ctx := context.Background()
@@ -679,6 +682,7 @@ func TestAffectedPeers_E2E_DestResource_RouterPeerGroups(t *testing.T) {
case <-time.After(peerUpdateTimeout): case <-time.After(peerUpdateTimeout):
t.Error("timeout: DestinationResource policy with PeerGroups router did not refresh the routing peer") t.Error("timeout: DestinationResource policy with PeerGroups router did not refresh the routing peer")
} }
})
} }
func TestAffectedPeers_AllRoutingPeers_Network(t *testing.T) { func TestAffectedPeers_AllRoutingPeers_Network(t *testing.T) {
+53 -11
View File
@@ -955,6 +955,7 @@ func TestAffectedPeers_IsolatedRouteAndPolicy(t *testing.T) {
} }
func TestAffectedPeers_GroupUpdateOnlyAffectsLinkedPeers(t *testing.T) { func TestAffectedPeers_GroupUpdateOnlyAffectsLinkedPeers(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -1001,7 +1002,9 @@ func TestAffectedPeers_GroupUpdateOnlyAffectsLinkedPeers(t *testing.T) {
result := manager.resolveAffectedPeersForPeerChanges(ctx, manager.Store, accountID, []string{peer1.ID}) result := manager.resolveAffectedPeersForPeerChanges(ctx, manager.Store, accountID, []string{peer1.ID})
assert.ElementsMatch(t, []string{peer1.ID, peer2.ID}, result) assert.ElementsMatch(t, []string{peer1.ID, peer2.ID}, result)
t.Run("group change updates all peers in policy groups", func(t *testing.T) { settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
step(t, "group change updates all peers in policy groups", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -1023,6 +1026,7 @@ func TestAffectedPeers_GroupUpdateOnlyAffectsLinkedPeers(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
// A peer in no policy/route refreshes only itself — no other peer is affected. // A peer in no policy/route refreshes only itself — no other peer is affected.
@@ -1037,6 +1041,7 @@ func TestAffectedPeers_UnlinkedPeerChange_RefreshesSelfOnly(t *testing.T) {
// TestAffectedPeers_PolicyChange_UnrelatedPeerNoUpdate verifies that creating/deleting a // TestAffectedPeers_PolicyChange_UnrelatedPeerNoUpdate verifies that creating/deleting a
// policy only sends updates to peers in the policy's groups, not to unrelated peers. // policy only sends updates to peers in the policy's groups, not to unrelated peers.
func TestAffectedPeers_PolicyChange_UnrelatedPeerNoUpdate(t *testing.T) { func TestAffectedPeers_PolicyChange_UnrelatedPeerNoUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -1066,7 +1071,9 @@ func TestAffectedPeers_PolicyChange_UnrelatedPeerNoUpdate(t *testing.T) {
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
}) })
t.Run("create policy only affects linked peers", func(t *testing.T) { settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
step(t, "create policy only affects linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -1095,11 +1102,13 @@ func TestAffectedPeers_PolicyChange_UnrelatedPeerNoUpdate(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
// TestAffectedPeers_RouteChange_UnrelatedPeerNoUpdate verifies that creating a route // TestAffectedPeers_RouteChange_UnrelatedPeerNoUpdate verifies that creating a route
// only sends updates to peers in the route's groups, not to unrelated peers. // only sends updates to peers in the route's groups, not to unrelated peers.
func TestAffectedPeers_RouteChange_UnrelatedPeerNoUpdate(t *testing.T) { func TestAffectedPeers_RouteChange_UnrelatedPeerNoUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -1129,7 +1138,9 @@ func TestAffectedPeers_RouteChange_UnrelatedPeerNoUpdate(t *testing.T) {
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
}) })
t.Run("create route only affects linked peers", func(t *testing.T) { settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
step(t, "create route only affects linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -1163,11 +1174,13 @@ func TestAffectedPeers_RouteChange_UnrelatedPeerNoUpdate(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
// TestAffectedPeers_NameServerChange_UnrelatedPeerNoUpdate verifies that creating a // TestAffectedPeers_NameServerChange_UnrelatedPeerNoUpdate verifies that creating a
// nameserver group only sends updates to peers in its groups, not to unrelated peers. // nameserver group only sends updates to peers in its groups, not to unrelated peers.
func TestAffectedPeers_NameServerChange_UnrelatedPeerNoUpdate(t *testing.T) { func TestAffectedPeers_NameServerChange_UnrelatedPeerNoUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -1196,7 +1209,9 @@ func TestAffectedPeers_NameServerChange_UnrelatedPeerNoUpdate(t *testing.T) {
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
}) })
t.Run("create nameserver group only affects linked peers", func(t *testing.T) { settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
step(t, "create nameserver group only affects linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -1222,11 +1237,13 @@ func TestAffectedPeers_NameServerChange_UnrelatedPeerNoUpdate(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
// TestAffectedPeers_DNSSettingsChange_UnrelatedPeerNoUpdate verifies that changing DNS // TestAffectedPeers_DNSSettingsChange_UnrelatedPeerNoUpdate verifies that changing DNS
// settings only sends updates to peers in the affected groups, not to unrelated peers. // settings only sends updates to peers in the affected groups, not to unrelated peers.
func TestAffectedPeers_DNSSettingsChange_UnrelatedPeerNoUpdate(t *testing.T) { func TestAffectedPeers_DNSSettingsChange_UnrelatedPeerNoUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -1255,7 +1272,9 @@ func TestAffectedPeers_DNSSettingsChange_UnrelatedPeerNoUpdate(t *testing.T) {
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
}) })
t.Run("dns settings change only affects linked peers", func(t *testing.T) { settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
step(t, "dns settings change only affects linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -1275,12 +1294,14 @@ func TestAffectedPeers_DNSSettingsChange_UnrelatedPeerNoUpdate(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
// TestAffectedPeers_UnlinkedGroupChange_NoUpdateIntegration tests the full integration: // TestAffectedPeers_UnlinkedGroupChange_NoUpdateIntegration tests the full integration:
// updating a group that is NOT referenced by any policy/route/ns/dns should not send // updating a group that is NOT referenced by any policy/route/ns/dns should not send
// updates to any peer. // updates to any peer.
func TestAffectedPeers_UnlinkedGroupChange_NoUpdateIntegration(t *testing.T) { func TestAffectedPeers_UnlinkedGroupChange_NoUpdateIntegration(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -1308,7 +1329,9 @@ func TestAffectedPeers_UnlinkedGroupChange_NoUpdateIntegration(t *testing.T) {
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
}) })
t.Run("updating unlinked group sends no peer updates", func(t *testing.T) { settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
step(t, "updating unlinked group sends no peer updates", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg1) peerShouldNotReceiveUpdate(t, updMsg1)
@@ -1330,11 +1353,13 @@ func TestAffectedPeers_UnlinkedGroupChange_NoUpdateIntegration(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
// TestAffectedPeers_NetworkRouterUnlinkedPeerNoUpdate: a network router with peer // TestAffectedPeers_NetworkRouterUnlinkedPeerNoUpdate: a network router with peer
// groups updates only those groups' peers (and resource policy sources), not others. // groups updates only those groups' peers (and resource policy sources), not others.
func TestAffectedPeers_NetworkRouterUnlinkedPeerNoUpdate(t *testing.T) { func TestAffectedPeers_NetworkRouterUnlinkedPeerNoUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
// Delete the default policy before adding peers so AddPeer schedules no async // Delete the default policy before adding peers so AddPeer schedules no async
// update that races with the test. // update that races with the test.
manager, updateManager, err := createManager(t) manager, updateManager, err := createManager(t)
@@ -1394,7 +1419,9 @@ func TestAffectedPeers_NetworkRouterUnlinkedPeerNoUpdate(t *testing.T) {
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
}) })
t.Run("network router group change only affects linked peers", func(t *testing.T) { settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
step(t, "network router group change only affects linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -1416,11 +1443,13 @@ func TestAffectedPeers_NetworkRouterUnlinkedPeerNoUpdate(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
// TestAffectedPeers_IsolatedEntitiesOnlyAffectTheirPeers: with a policy (peer1<->peer2) // TestAffectedPeers_IsolatedEntitiesOnlyAffectTheirPeers: with a policy (peer1<->peer2)
// and a separate route (peer3), changing one entity's groups affects only its peers. // and a separate route (peer3), changing one entity's groups affects only its peers.
func TestAffectedPeers_IsolatedEntitiesOnlyAffectTheirPeers(t *testing.T) { func TestAffectedPeers_IsolatedEntitiesOnlyAffectTheirPeers(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -1487,7 +1516,7 @@ func TestAffectedPeers_IsolatedEntitiesOnlyAffectTheirPeers(t *testing.T) {
// drain any in-flight ones so the assertions only observe the UpdateGroup below. // drain any in-flight ones so the assertions only observe the UpdateGroup below.
settleAffectedUpdates(updMsg1, updMsg2, updMsg3) settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
t.Run("policy group change does not affect route-only peer", func(t *testing.T) { step(t, "policy group change does not affect route-only peer", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -1509,11 +1538,13 @@ func TestAffectedPeers_IsolatedEntitiesOnlyAffectTheirPeers(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
// TestAffectedPeers_DeleteRoute_UnrelatedPeerNoUpdate verifies that deleting a route // TestAffectedPeers_DeleteRoute_UnrelatedPeerNoUpdate verifies that deleting a route
// only sends updates to peers in the route's groups. // only sends updates to peers in the route's groups.
func TestAffectedPeers_DeleteRoute_UnrelatedPeerNoUpdate(t *testing.T) { func TestAffectedPeers_DeleteRoute_UnrelatedPeerNoUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -1561,7 +1592,9 @@ func TestAffectedPeers_DeleteRoute_UnrelatedPeerNoUpdate(t *testing.T) {
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
}) })
t.Run("delete route only affects linked peers", func(t *testing.T) { settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
step(t, "delete route only affects linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -1579,11 +1612,13 @@ func TestAffectedPeers_DeleteRoute_UnrelatedPeerNoUpdate(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
// TestAffectedPeers_DeletePolicy_UnrelatedPeerNoUpdate verifies that deleting a policy // TestAffectedPeers_DeletePolicy_UnrelatedPeerNoUpdate verifies that deleting a policy
// only sends updates to peers in the policy's groups. // only sends updates to peers in the policy's groups.
func TestAffectedPeers_DeletePolicy_UnrelatedPeerNoUpdate(t *testing.T) { func TestAffectedPeers_DeletePolicy_UnrelatedPeerNoUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -1626,7 +1661,9 @@ func TestAffectedPeers_DeletePolicy_UnrelatedPeerNoUpdate(t *testing.T) {
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
}) })
t.Run("delete policy only affects linked peers", func(t *testing.T) { settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
step(t, "delete policy only affects linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -1644,11 +1681,13 @@ func TestAffectedPeers_DeletePolicy_UnrelatedPeerNoUpdate(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
// TestAffectedPeers_DeleteNameServer_UnrelatedPeerNoUpdate verifies that deleting a // TestAffectedPeers_DeleteNameServer_UnrelatedPeerNoUpdate verifies that deleting a
// nameserver group only sends updates to peers in its groups. // nameserver group only sends updates to peers in its groups.
func TestAffectedPeers_DeleteNameServer_UnrelatedPeerNoUpdate(t *testing.T) { func TestAffectedPeers_DeleteNameServer_UnrelatedPeerNoUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -1687,7 +1726,9 @@ func TestAffectedPeers_DeleteNameServer_UnrelatedPeerNoUpdate(t *testing.T) {
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
}) })
t.Run("delete nameserver group only affects linked peers", func(t *testing.T) { settleAffectedUpdates(updMsg1, updMsg2, updMsg3)
step(t, "delete nameserver group only affects linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -1705,6 +1746,7 @@ func TestAffectedPeers_DeleteNameServer_UnrelatedPeerNoUpdate(t *testing.T) {
t.Error("timeout") t.Error("timeout")
} }
}) })
})
} }
func addPeerToAccount(t *testing.T, manager *DefaultAccountManager, _, setupKeyKey string) *nbpeer.Peer { func addPeerToAccount(t *testing.T, manager *DefaultAccountManager, _, setupKeyKey string) *nbpeer.Peer {
+11 -15
View File
@@ -17,6 +17,7 @@ import (
// A user update refreshes only the peers its auto-group change reaches, and a user // A user update refreshes only the peers its auto-group change reaches, and a user
// update that changes no group membership refreshes nobody. // update that changes no group membership refreshes nobody.
func TestAffectedPeers_SaveUser_OnlyAffectedPeersUpdated(t *testing.T) { func TestAffectedPeers_SaveUser_OnlyAffectedPeersUpdated(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t)
ctx := context.Background() ctx := context.Background()
accountID := account.Id accountID := account.Id
@@ -71,10 +72,8 @@ func TestAffectedPeers_SaveUser_OnlyAffectedPeersUpdated(t *testing.T) {
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
}) })
t.Run("auto group change updates only linked peers", func(t *testing.T) { step(t, "auto group change updates only linked peers", func(t *testing.T) {
drainPeerUpdates(updTarget) settleAffectedUpdates(updTarget, upd2, upd3)
drainPeerUpdates(upd2)
drainPeerUpdates(upd3)
_, err := manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{ _, err := manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser, Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
@@ -87,7 +86,7 @@ func TestAffectedPeers_SaveUser_OnlyAffectedPeersUpdated(t *testing.T) {
peerShouldNotReceiveUpdate(t, upd3) peerShouldNotReceiveUpdate(t, upd3)
}) })
t.Run("update without group changes refreshes nobody", func(t *testing.T) { step(t, "update without group changes refreshes nobody", func(t *testing.T) {
drainPeerUpdates(updTarget) drainPeerUpdates(updTarget)
drainPeerUpdates(upd2) drainPeerUpdates(upd2)
drainPeerUpdates(upd3) drainPeerUpdates(upd3)
@@ -107,18 +106,16 @@ func TestAffectedPeers_SaveUser_OnlyAffectedPeersUpdated(t *testing.T) {
assert.Equal(t, "renamed", user.Name) assert.Equal(t, "renamed", user.Name)
}) })
t.Run("auto group change reassigning IPv6 refreshes the changed peers and their observers", func(t *testing.T) { step(t, "auto group change reassigning IPv6 refreshes the changed peers and their observers", func(t *testing.T) {
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-v6", Name: "ug-v6"}))
// Apply through the settings API so the reconciliation that strips the other require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-v6", Name: "ug-v6"}))// Apply through the settings API so the reconciliation that strips the other
// peers' addresses happens here, leaving the target as the only peer the // peers' addresses happens here, leaving the target as the only peer the
// user update reassigns. // user update reassigns.
updateIPv6TestSettings(t, manager, accountID, func(s *types.Settings) { updateIPv6TestSettings(t, manager, accountID, func(s *types.Settings) {
s.IPv6EnabledGroups = []string{"ug-v6"} s.IPv6EnabledGroups = []string{"ug-v6"}
}) })
drainPeerUpdates(updTarget) settleAffectedUpdates(updTarget, upd2, upd3)
drainPeerUpdates(upd2)
drainPeerUpdates(upd3)
_, err = manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{ _, err = manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser, Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
@@ -133,7 +130,7 @@ func TestAffectedPeers_SaveUser_OnlyAffectedPeersUpdated(t *testing.T) {
peerShouldNotReceiveUpdate(t, upd3) peerShouldNotReceiveUpdate(t, upd3)
}) })
t.Run("unblocking a user refreshes only the SSH rule destinations", func(t *testing.T) { step(t, "unblocking a user refreshes only the SSH rule destinations", func(t *testing.T) {
// An SSH rule that authorizes no group of its own ships the account's // An SSH rule that authorizes no group of its own ships the account's
// allowed-user set to its destinations, so those are the peers an unblock // allowed-user set to its destinations, so those are the peers an unblock
// reaches — not the whole account. // reaches — not the whole account.
@@ -154,9 +151,7 @@ func TestAffectedPeers_SaveUser_OnlyAffectedPeersUpdated(t *testing.T) {
blocked.Blocked = true blocked.Blocked = true
require.NoError(t, manager.Store.SaveUser(ctx, blocked)) require.NoError(t, manager.Store.SaveUser(ctx, blocked))
drainPeerUpdates(updTarget) settleAffectedUpdates(updTarget, upd2, upd3)
drainPeerUpdates(upd2)
drainPeerUpdates(upd3)
// Same auto-groups as the previous subtest left them, so no group change and // Same auto-groups as the previous subtest left them, so no group change and
// no IPv6 reconciliation interferes: the unblock alone drives the refresh. // no IPv6 reconciliation interferes: the unblock alone drives the refresh.
@@ -169,4 +164,5 @@ func TestAffectedPeers_SaveUser_OnlyAffectedPeersUpdated(t *testing.T) {
peerShouldReceiveUpdate(t, upd2) peerShouldReceiveUpdate(t, upd2)
peerShouldNotReceiveUpdate(t, upd3) peerShouldNotReceiveUpdate(t, upd3)
}) })
})
} }
+8 -2
View File
@@ -89,6 +89,7 @@ func NewUserDataCache(store store.StoreInterface) *UserDataCacheImpl {
// AccountUserDataCache wraps the basic Get, Set and Delete methods for []*idp.UserData objects. // AccountUserDataCache wraps the basic Get, Set and Delete methods for []*idp.UserData objects.
type AccountUserDataCache struct { type AccountUserDataCache struct {
cache Marshaler cache Marshaler
loadable *cache.LoadableCache[any]
} }
func (a *AccountUserDataCache) Get(ctx context.Context, key string) ([]*idp.UserData, error) { func (a *AccountUserDataCache) Get(ctx context.Context, key string) ([]*idp.UserData, error) {
@@ -127,13 +128,18 @@ func (a *AccountUserDataCache) Delete(ctx context.Context, key string) error {
return a.cache.Delete(ctx, key) return a.cache.Delete(ctx, key)
} }
// Close stops the goroutine that stores loaded values. The cache must not be used afterwards.
func (a *AccountUserDataCache) Close() error {
return a.loadable.Close()
}
// NewAccountUserDataCache creates a new AccountUserDataCache object. // NewAccountUserDataCache creates a new AccountUserDataCache object.
func NewAccountUserDataCache(loadableFunc cache.LoadFunction[any], store store.StoreInterface) *AccountUserDataCache { func NewAccountUserDataCache(loadableFunc cache.LoadFunction[any], store store.StoreInterface) *AccountUserDataCache {
simpleCache := cache.New[any](store) simpleCache := cache.New[any](store)
loadable := cache.NewLoadable[any](loadableFunc, simpleCache) loadable := cache.NewLoadable[any](loadableFunc, simpleCache)
if store.GetType() == redis.RedisType { if store.GetType() == redis.RedisType {
m := marshaler.New(loadable) m := marshaler.New(loadable)
return &AccountUserDataCache{cache: m} return &AccountUserDataCache{cache: m, loadable: loadable}
} }
return &AccountUserDataCache{cache: &marshalerWraper{loadable}} return &AccountUserDataCache{cache: &marshalerWraper{loadable}, loadable: loadable}
} }
+11 -7
View File
@@ -6,8 +6,8 @@ import (
"testing" "testing"
"time" "time"
"go.uber.org/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
nbdns "github.com/netbirdio/netbird/dns" nbdns "github.com/netbirdio/netbird/dns"
"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller" "github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
@@ -363,6 +363,7 @@ func initTestDNSAccount(t *testing.T, am *DefaultAccountManager) (*types.Account
} }
func TestDNSAccountPeersUpdate(t *testing.T) { func TestDNSAccountPeersUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
err := manager.CreateGroups(context.Background(), account.Id, userID, []*types.Group{ err := manager.CreateGroups(context.Background(), account.Id, userID, []*types.Group{
@@ -385,7 +386,9 @@ func TestDNSAccountPeersUpdate(t *testing.T) {
}) })
// Saving DNS settings with groups that have no peers should not trigger updates to account peers or send peer updates // Saving DNS settings with groups that have no peers should not trigger updates to account peers or send peer updates
t.Run("saving dns setting with unused groups", func(t *testing.T) { step(t, "saving dns setting with unused groups", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -405,7 +408,7 @@ func TestDNSAccountPeersUpdate(t *testing.T) {
}) })
// Creating DNS settings with groups that have no peers should not update account peers or send peer update // Creating DNS settings with groups that have no peers should not update account peers or send peer update
t.Run("creating dns setting with unused groups", func(t *testing.T) { step(t, "creating dns setting with unused groups", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -431,7 +434,7 @@ func TestDNSAccountPeersUpdate(t *testing.T) {
}) })
// Creating DNS settings with groups that have peers should update account peers and send peer update // Creating DNS settings with groups that have peers should update account peers and send peer update
t.Run("creating dns setting with used groups", func(t *testing.T) { step(t, "creating dns setting with used groups", func(t *testing.T) {
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{ err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupA", ID: "groupA",
Name: "GroupA", Name: "GroupA",
@@ -464,7 +467,7 @@ func TestDNSAccountPeersUpdate(t *testing.T) {
}) })
// Saving DNS settings with groups that have peers should update account peers and send peer update // Saving DNS settings with groups that have peers should update account peers and send peer update
t.Run("saving dns setting with used groups", func(t *testing.T) { step(t, "saving dns setting with used groups", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -484,7 +487,7 @@ func TestDNSAccountPeersUpdate(t *testing.T) {
}) })
// Removing group with no peers from DNS settings should not trigger updates to account peers or send peer updates // Removing group with no peers from DNS settings should not trigger updates to account peers or send peer updates
t.Run("removing group with no peers from dns settings", func(t *testing.T) { step(t, "removing group with no peers from dns settings", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -504,7 +507,7 @@ func TestDNSAccountPeersUpdate(t *testing.T) {
}) })
// Removing group with peers from DNS settings should trigger updates to account peers and send peer updates // Removing group with peers from DNS settings should trigger updates to account peers and send peer updates
t.Run("removing group with peers from dns settings", func(t *testing.T) { step(t, "removing group with peers from dns settings", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -522,4 +525,5 @@ func TestDNSAccountPeersUpdate(t *testing.T) {
t.Error("timeout waiting for peerShouldReceiveUpdate") t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
}) })
})
} }
+38 -11
View File
@@ -23,6 +23,7 @@ import (
"github.com/netbirdio/netbird/management/server/groups" "github.com/netbirdio/netbird/management/server/groups"
"github.com/netbirdio/netbird/management/server/networks" "github.com/netbirdio/netbird/management/server/networks"
"github.com/netbirdio/netbird/management/server/networks/resources" "github.com/netbirdio/netbird/management/server/networks/resources"
resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types"
"github.com/netbirdio/netbird/management/server/networks/routers" "github.com/netbirdio/netbird/management/server/networks/routers"
routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types" routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types"
networkTypes "github.com/netbirdio/netbird/management/server/networks/types" networkTypes "github.com/netbirdio/netbird/management/server/networks/types"
@@ -685,6 +686,7 @@ func initTestGroupAccount(am *DefaultAccountManager) (*DefaultAccountManager, *t
} }
func TestGroupAccountPeersUpdate(t *testing.T) { func TestGroupAccountPeersUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
g := []*types.Group{ g := []*types.Group{
@@ -725,7 +727,9 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
}) })
// Saving a group that is not linked to any resource should not update account peers // Saving a group that is not linked to any resource should not update account peers
t.Run("saving unlinked group", func(t *testing.T) { step(t, "saving unlinked group", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -748,7 +752,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
// Adding a peer to a group that is not linked to any resource should not update account peers // Adding a peer to a group that is not linked to any resource should not update account peers
// and not send peer update // and not send peer update
t.Run("adding peer to unlinked group", func(t *testing.T) { step(t, "adding peer to unlinked group", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -767,7 +771,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
// Removing a peer from a group that is not linked to any resource should not update account peers // Removing a peer from a group that is not linked to any resource should not update account peers
// and not send peer update // and not send peer update
t.Run("removing peer from unliked group", func(t *testing.T) { step(t, "removing peer from unliked group", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -785,7 +789,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
}) })
// Deleting group should not update account peers and not send peer update // Deleting group should not update account peers and not send peer update
t.Run("deleting group", func(t *testing.T) { step(t, "deleting group", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -818,7 +822,9 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
// Saving a group linked to policy should update account peers and send peer update // Saving a group linked to policy should update account peers and send peer update
t.Run("saving linked group to policy", func(t *testing.T) { step(t, "saving linked group to policy", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -840,7 +846,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
}) })
// adding peer to a used group should update account peers and send peer update // adding peer to a used group should update account peers and send peer update
t.Run("adding peer to linked group", func(t *testing.T) { step(t, "adding peer to linked group", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -858,7 +864,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
}) })
// removing peer from a linked group should update account peers and send peer update // removing peer from a linked group should update account peers and send peer update
t.Run("removing peer from linked group", func(t *testing.T) { step(t, "removing peer from linked group", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -876,7 +882,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
}) })
// Saving a group linked to name server group should update account peers and send peer update // Saving a group linked to name server group should update account peers and send peer update
t.Run("saving group linked to name server group", func(t *testing.T) { step(t, "saving group linked to name server group", func(t *testing.T) {
_, err = manager.CreateNameServerGroup( _, err = manager.CreateNameServerGroup(
context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{ context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{
IP: netip.MustParseAddr("1.1.1.1"), IP: netip.MustParseAddr("1.1.1.1"),
@@ -888,6 +894,8 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
) )
assert.NoError(t, err) assert.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -909,7 +917,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
}) })
// Saving a group linked to route should update account peers and send peer update // Saving a group linked to route should update account peers and send peer update
t.Run("saving group linked to route", func(t *testing.T) { step(t, "saving group linked to route", func(t *testing.T) {
newRoute := route.Route{ newRoute := route.Route{
ID: "route", ID: "route",
Network: netip.MustParsePrefix("192.168.0.0/16"), Network: netip.MustParsePrefix("192.168.0.0/16"),
@@ -929,6 +937,8 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
) )
require.NoError(t, err) require.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -950,12 +960,14 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
}) })
// Saving a group linked to dns settings should update account peers and send peer update // Saving a group linked to dns settings should update account peers and send peer update
t.Run("saving group linked to dns settings", func(t *testing.T) { step(t, "saving group linked to dns settings", func(t *testing.T) {
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{ err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
DisabledManagementGroups: []string{"groupD"}, DisabledManagementGroups: []string{"groupD"},
}) })
assert.NoError(t, err) assert.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -977,7 +989,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
}) })
// Saving a group linked to network router should update account peers and send peer update // Saving a group linked to network router should update account peers and send peer update
t.Run("saving group linked to network router", func(t *testing.T) { step(t, "saving group linked to network router", func(t *testing.T) {
permissionsManager := permissions.NewManager(manager.Store) permissionsManager := permissions.NewManager(manager.Store)
groupsManager := groups.NewManager(manager.Store, permissionsManager, manager) groupsManager := groups.NewManager(manager.Store, permissionsManager, manager)
resourcesManager := resources.NewManager(manager.Store, permissionsManager, groupsManager, manager, manager.serviceManager) resourcesManager := resources.NewManager(manager.Store, permissionsManager, groupsManager, manager, manager.serviceManager)
@@ -1003,6 +1015,20 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
}) })
require.NoError(t, err) require.NoError(t, err)
resource, err := resourcesManager.CreateResource(context.Background(), userID, &resourceTypes.NetworkResource{
AccountID: account.Id,
NetworkID: network.ID,
Name: "resource_test",
Address: "10.20.30.0/24",
Enabled: true,
})
require.NoError(t, err)
_, err = manager.SavePolicy(context.Background(), account.Id, userID, peerToResourcePolicyByResource("groupA", resource.ID), true)
require.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1022,6 +1048,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
t.Error("timeout waiting for peerShouldReceiveUpdate") t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
}) })
})
} }
func Test_AddPeerToGroup(t *testing.T) { func Test_AddPeerToGroup(t *testing.T) {
+12 -8
View File
@@ -6,9 +6,9 @@ import (
"testing" "testing"
"time" "time"
"go.uber.org/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
nbdns "github.com/netbirdio/netbird/dns" nbdns "github.com/netbirdio/netbird/dns"
"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller" "github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
@@ -966,6 +966,7 @@ func TestValidateDomain(t *testing.T) {
} }
func TestNameServerAccountPeersUpdate(t *testing.T) { func TestNameServerAccountPeersUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
var newNameServerGroupA *nbdns.NameServerGroup var newNameServerGroupA *nbdns.NameServerGroup
@@ -992,7 +993,9 @@ func TestNameServerAccountPeersUpdate(t *testing.T) {
// Creating a nameserver group with a distribution group no peers should not update account peers // Creating a nameserver group with a distribution group no peers should not update account peers
// and not send peer update // and not send peer update
t.Run("creating nameserver group with distribution group no peers", func(t *testing.T) { step(t, "creating nameserver group with distribution group no peers", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -1019,7 +1022,7 @@ func TestNameServerAccountPeersUpdate(t *testing.T) {
// saving a nameserver group with a distribution group with no peers should not update account peers // saving a nameserver group with a distribution group with no peers should not update account peers
// and not send peer update // and not send peer update
t.Run("saving nameserver group with distribution group no peers", func(t *testing.T) { step(t, "saving nameserver group with distribution group no peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -1037,7 +1040,7 @@ func TestNameServerAccountPeersUpdate(t *testing.T) {
}) })
// Creating a nameserver group with a distribution group no peers should update account peers and send peer update // Creating a nameserver group with a distribution group no peers should update account peers and send peer update
t.Run("creating nameserver group with distribution group has peers", func(t *testing.T) { step(t, "creating nameserver group with distribution group has peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1057,13 +1060,13 @@ func TestNameServerAccountPeersUpdate(t *testing.T) {
select { select {
case <-done: case <-done:
case <-time.After(time.Second): case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldNotReceiveUpdate") t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
}) })
// saving a nameserver group with a distribution group with peers should update account peers and send peer update // saving a nameserver group with a distribution group with peers should update account peers and send peer update
t.Run("saving nameserver group with distribution group has peers", func(t *testing.T) { step(t, "saving nameserver group with distribution group has peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1093,7 +1096,7 @@ func TestNameServerAccountPeersUpdate(t *testing.T) {
}) })
// Deleting a nameserver group should update account peers and send peer update // Deleting a nameserver group should update account peers and send peer update
t.Run("deleting nameserver group", func(t *testing.T) { step(t, "deleting nameserver group", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1109,4 +1112,5 @@ func TestNameServerAccountPeersUpdate(t *testing.T) {
t.Error("timeout waiting for peerShouldReceiveUpdate") t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
}) })
})
} }
+19 -55
View File
@@ -1844,6 +1844,7 @@ func Test_LoginPeer(t *testing.T) {
} }
func TestPeerAccountPeersUpdate(t *testing.T) { func TestPeerAccountPeersUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
err := manager.DeletePolicy(context.Background(), account.Id, account.Policies[0].ID, userID) err := manager.DeletePolicy(context.Background(), account.Id, account.Policies[0].ID, userID)
@@ -1906,27 +1907,9 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
updateManager.CloseChannel(context.Background(), peer1.ID) updateManager.CloseChannel(context.Background(), peer1.ID)
}) })
// Updating not expired peer and peer expiration is enabled should not update account peers and not send peer update
t.Run("updating not expired peer and peer expiration is enabled", func(t *testing.T) {
t.Skip("Currently all updates will trigger a network map")
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
_, err := manager.UpdatePeer(context.Background(), account.Id, userID, peer2)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Adding peer to unlinked group should not update account peers and not send peer update // Adding peer to unlinked group should not update account peers and not send peer update
t.Run("adding peer to unlinked group", func(t *testing.T) { step(t, "adding peer to unlinked group", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -1951,7 +1934,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
}) })
// Deleting peer with unlinked group should not update account peers and not send peer update // Deleting peer with unlinked group should not update account peers and not send peer update
t.Run("deleting peer with unlinked group", func(t *testing.T) { step(t, "deleting peer with unlinked group", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -1969,7 +1952,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
}) })
// Updating peer label should update account peers and send peer update // Updating peer label should update account peers and send peer update
t.Run("updating peer label", func(t *testing.T) { step(t, "updating peer label", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1987,7 +1970,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
} }
}) })
t.Run("validator requires update", func(t *testing.T) { step(t, "validator requires update", func(t *testing.T) {
requireUpdateFunc := func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) { requireUpdateFunc := func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) {
return update, true, nil return update, true, nil
} }
@@ -2009,32 +1992,8 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
} }
}) })
t.Run("validator requires no update", func(t *testing.T) {
t.Skip("Currently all updates will trigger a network map")
requireNoUpdateFunc := func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) {
return update, false, nil
}
manager.integratedPeerValidator = MockIntegratedValidator{ValidatePeerFunc: requireNoUpdateFunc}
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
_, err = manager.UpdatePeer(context.Background(), account.Id, userID, peer1)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Adding peer to group linked with policy should update account peers and send peer update // Adding peer to group linked with policy should update account peers and send peer update
t.Run("adding peer to group linked with policy", func(t *testing.T) { step(t, "adding peer to group linked with policy", func(t *testing.T) {
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{ _, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
AccountID: account.Id, AccountID: account.Id,
Enabled: true, Enabled: true,
@@ -2075,7 +2034,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
}) })
// Deleting peer with linked group to policy should update account peers and send peer update // Deleting peer with linked group to policy should update account peers and send peer update
t.Run("deleting peer with linked group to policy", func(t *testing.T) { step(t, "deleting peer with linked group to policy", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -2096,7 +2055,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
drainPeerUpdates(updMsg) drainPeerUpdates(updMsg)
// Adding peer to group linked with route should update peers in that group, not unrelated peers // Adding peer to group linked with route should update peers in that group, not unrelated peers
t.Run("adding peer to group linked with route", func(t *testing.T) { step(t, "adding peer to group linked with route", func(t *testing.T) {
route := nbroute.Route{ route := nbroute.Route{
ID: "testingRoute1", ID: "testingRoute1",
Network: netip.MustParsePrefix("100.65.250.202/32"), Network: netip.MustParsePrefix("100.65.250.202/32"),
@@ -2117,6 +2076,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
) )
require.NoError(t, err) require.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -2142,7 +2102,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
}) })
// Deleting peer with linked group to route should update peers in that group, not unrelated peers // Deleting peer with linked group to route should update peers in that group, not unrelated peers
t.Run("deleting peer with linked group to route", func(t *testing.T) { step(t, "deleting peer with linked group to route", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -2160,7 +2120,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
}) })
// Adding peer to group linked with name server group should update peers in that group, not unrelated peers // Adding peer to group linked with name server group should update peers in that group, not unrelated peers
t.Run("adding peer to group linked with name server group", func(t *testing.T) { step(t, "adding peer to group linked with name server group", func(t *testing.T) {
_, err = manager.CreateNameServerGroup( _, err = manager.CreateNameServerGroup(
context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{ context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{
IP: netip.MustParseAddr("1.1.1.1"), IP: netip.MustParseAddr("1.1.1.1"),
@@ -2172,6 +2132,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
) )
require.NoError(t, err) require.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -2197,7 +2158,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
}) })
// Deleting peer with linked group to name server group should update peers in that group, not unrelated peers // Deleting peer with linked group to name server group should update peers in that group, not unrelated peers
t.Run("deleting peer with linked group to route", func(t *testing.T) { step(t, "deleting peer with linked group to name server group", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -2213,6 +2174,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
t.Error("timeout waiting for peerShouldNotReceiveUpdate") t.Error("timeout waiting for peerShouldNotReceiveUpdate")
} }
}) })
})
} }
func Test_DeletePeer(t *testing.T) { func Test_DeletePeer(t *testing.T) {
@@ -2859,6 +2821,7 @@ func TestPeerWillHaveIPv6(t *testing.T) {
// flipping --disable-ipv6) without bumping its WtVersion, other account peers // flipping --disable-ipv6) without bumping its WtVersion, other account peers
// receive a fresh network map so their AAAA records for it become unstale. // receive a fresh network map so their AAAA records for it become unstale.
func TestSyncPeer_IPv6CapabilityChangePropagates(t *testing.T) { func TestSyncPeer_IPv6CapabilityChangePropagates(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, _, peer1, peer2, _ := setupNetworkMapTest(t) manager, updateManager, _, peer1, peer2, _ := setupNetworkMapTest(t)
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID) updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
@@ -2878,7 +2841,7 @@ func TestSyncPeer_IPv6CapabilityChangePropagates(t *testing.T) {
} }
drain() drain()
t.Run("no propagation when capabilities are unchanged", func(t *testing.T) { step(t, "no propagation when capabilities are unchanged", func(t *testing.T) {
_, _, _, _, err := manager.SyncPeer(context.Background(), types.PeerSync{ _, _, _, _, err := manager.SyncPeer(context.Background(), types.PeerSync{
WireGuardPubKey: peer2.Key, WireGuardPubKey: peer2.Key,
Meta: peer2.Meta, Meta: peer2.Meta,
@@ -2887,7 +2850,7 @@ func TestSyncPeer_IPv6CapabilityChangePropagates(t *testing.T) {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
}) })
t.Run("propagation when IPv6 capability is added", func(t *testing.T) { step(t, "propagation when IPv6 capability is added", func(t *testing.T) {
newMeta := peer2.Meta newMeta := peer2.Meta
newMeta.Capabilities = append([]int32{}, peer2.Meta.Capabilities...) newMeta.Capabilities = append([]int32{}, peer2.Meta.Capabilities...)
newMeta.Capabilities = append(newMeta.Capabilities, nbpeer.PeerCapabilityIPv6Overlay) newMeta.Capabilities = append(newMeta.Capabilities, nbpeer.PeerCapabilityIPv6Overlay)
@@ -2899,6 +2862,7 @@ func TestSyncPeer_IPv6CapabilityChangePropagates(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
}) })
})
} }
func TestUpdatePeer_DnsLabelCollisionWithFQDN(t *testing.T) { func TestUpdatePeer_DnsLabelCollisionWithFQDN(t *testing.T) {
+14 -10
View File
@@ -1135,6 +1135,7 @@ func sortFunc() func(a *types.FirewallRule, b *types.FirewallRule) int {
} }
func TestPolicyAccountPeersUpdate(t *testing.T) { func TestPolicyAccountPeersUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
g := []*types.Group{ g := []*types.Group{
@@ -1175,7 +1176,9 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
var err error var err error
// Saving policy with rule groups with no peers should not update account's peers and not send peer update // Saving policy with rule groups with no peers should not update account's peers and not send peer update
t.Run("saving policy with rule groups with no peers", func(t *testing.T) { step(t, "saving policy with rule groups with no peers", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -1206,7 +1209,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
// Saving policy with source group containing peers, but destination group without peers should // Saving policy with source group containing peers, but destination group without peers should
// update account's peers and send peer update // update account's peers and send peer update
t.Run("saving policy where source has peers but destination does not", func(t *testing.T) { step(t, "saving policy where source has peers but destination does not", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1238,7 +1241,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
// Saving policy with destination group containing peers, but source group without peers should // Saving policy with destination group containing peers, but source group without peers should
// update account's peers and send peer update // update account's peers and send peer update
t.Run("saving policy where destination has peers but source does not", func(t *testing.T) { step(t, "saving policy where destination has peers but source does not", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1270,7 +1273,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
// Saving policy with destination and source groups containing peers should update account's peers // Saving policy with destination and source groups containing peers should update account's peers
// and send peer update // and send peer update
t.Run("saving policy with source and destination groups with peers", func(t *testing.T) { step(t, "saving policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1301,7 +1304,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
// Disabling policy with destination and source groups containing peers should update account's peers // Disabling policy with destination and source groups containing peers should update account's peers
// and send peer update // and send peer update
t.Run("disabling policy with source and destination groups with peers", func(t *testing.T) { step(t, "disabling policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1321,7 +1324,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
// Updating disabled policy with destination and source groups containing peers should still update account's peers // Updating disabled policy with destination and source groups containing peers should still update account's peers
// because affected peer resolution does not filter by policy enabled state // because affected peer resolution does not filter by policy enabled state
t.Run("updating disabled policy with source and destination groups with peers", func(t *testing.T) { step(t, "updating disabled policy with source and destination groups with peers", func(t *testing.T) {
drainPeerUpdates(updMsg) drainPeerUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
@@ -1344,7 +1347,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
// Enabling policy with destination and source groups containing peers should update account's peers // Enabling policy with destination and source groups containing peers should update account's peers
// and send peer update // and send peer update
t.Run("enabling policy with source and destination groups with peers", func(t *testing.T) { step(t, "enabling policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1363,7 +1366,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
}) })
// Deleting policy should trigger account peers update and send peer update // Deleting policy should trigger account peers update and send peer update
t.Run("deleting policy with source and destination groups with peers", func(t *testing.T) { step(t, "deleting policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1383,7 +1386,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
// Deleting policy with destination group containing peers, but source group without peers should // Deleting policy with destination group containing peers, but source group without peers should
// update account's peers and send peer update // update account's peers and send peer update
t.Run("deleting policy where destination has peers but source does not", func(t *testing.T) { step(t, "deleting policy where destination has peers but source does not", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1401,7 +1404,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
}) })
// Deleting policy with no peers in groups should not update account's peers and not send peer update // Deleting policy with no peers in groups should not update account's peers and not send peer update
t.Run("deleting policy with no peers in groups", func(t *testing.T) { step(t, "deleting policy with no peers in groups", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -1418,4 +1421,5 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
} }
}) })
})
} }
+19 -9
View File
@@ -123,6 +123,7 @@ func initTestPostureChecksAccount(am *DefaultAccountManager) (*types.Account, er
} }
func TestPostureCheckAccountPeersUpdate(t *testing.T) { func TestPostureCheckAccountPeersUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
g := []*types.Group{ g := []*types.Group{
@@ -177,7 +178,9 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
} }
// Saving unused posture check should not update account peers and not send peer update // Saving unused posture check should not update account peers and not send peer update
t.Run("saving unused posture check", func(t *testing.T) { step(t, "saving unused posture check", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -195,7 +198,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
}) })
// Updating unused posture check should not update account peers and not send peer update // Updating unused posture check should not update account peers and not send peer update
t.Run("updating unused posture check", func(t *testing.T) { step(t, "updating unused posture check", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -232,7 +235,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
} }
// Linking posture check to policy should trigger update account peers and send peer update // Linking posture check to policy should trigger update account peers and send peer update
t.Run("linking posture check to policy with peers", func(t *testing.T) { step(t, "linking posture check to policy with peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -250,7 +253,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
}) })
// Updating linked posture checks should update account peers and send peer update // Updating linked posture checks should update account peers and send peer update
t.Run("updating linked to posture check with peers", func(t *testing.T) { step(t, "updating linked to posture check with peers", func(t *testing.T) {
postureCheckB.Checks = posture.ChecksDefinition{ postureCheckB.Checks = posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{ NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.29.0", MinVersion: "0.29.0",
@@ -279,7 +282,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
}) })
// Removing posture check from policy should trigger account peers update and send peer update // Removing posture check from policy should trigger account peers update and send peer update
t.Run("removing posture check from policy", func(t *testing.T) { step(t, "removing posture check from policy", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -298,7 +301,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
}) })
// Deleting unused posture check should not trigger account peers update and not send peer update // Deleting unused posture check should not trigger account peers update and not send peer update
t.Run("deleting unused posture check", func(t *testing.T) { step(t, "deleting unused posture check", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -319,7 +322,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
// Updating linked posture check to policy with no peers should not trigger account peers update and not send peer update // Updating linked posture check to policy with no peers should not trigger account peers update and not send peer update
t.Run("updating linked posture check to policy with no peers", func(t *testing.T) { step(t, "updating linked posture check to policy with no peers", func(t *testing.T) {
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{ _, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
Enabled: true, Enabled: true,
Rules: []*types.PolicyRule{ Rules: []*types.PolicyRule{
@@ -335,6 +338,8 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
}, true) }, true)
assert.NoError(t, err) assert.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -358,7 +363,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
// Updating linked posture check to policy where destination has peers but source does not // Updating linked posture check to policy where destination has peers but source does not
// should trigger account peers update and send peer update // should trigger account peers update and send peer update
t.Run("updating linked posture check to policy where destination has peers but source does not", func(t *testing.T) { step(t, "updating linked posture check to policy where destination has peers but source does not", func(t *testing.T) {
updMsg1 := updateManager.CreateChannel(context.Background(), peer2.ID) updMsg1 := updateManager.CreateChannel(context.Background(), peer2.ID)
t.Cleanup(func() { t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer2.ID) updateManager.CloseChannel(context.Background(), peer2.ID)
@@ -379,6 +384,8 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
}, true) }, true)
assert.NoError(t, err) assert.NoError(t, err)
settleAffectedUpdates(updMsg, updMsg1)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg1) peerShouldReceiveUpdate(t, updMsg1)
@@ -402,7 +409,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
// Updating linked client posture check to policy where source has peers but destination does not, // Updating linked client posture check to policy where source has peers but destination does not,
// should trigger account peers update and send peer update // should trigger account peers update and send peer update
t.Run("updating linked posture check to policy where source has peers but destination does not", func(t *testing.T) { step(t, "updating linked posture check to policy where source has peers but destination does not", func(t *testing.T) {
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{ _, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
Enabled: true, Enabled: true,
Rules: []*types.PolicyRule{ Rules: []*types.PolicyRule{
@@ -418,6 +425,8 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
}, true) }, true)
assert.NoError(t, err) assert.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -442,6 +451,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
t.Error("timeout waiting for peerShouldReceiveUpdate") t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
}) })
})
} }
func TestArePostureCheckChangesAffectPeers(t *testing.T) { func TestArePostureCheckChangesAffectPeers(t *testing.T) {
+21 -13
View File
@@ -6,10 +6,10 @@ import (
"testing" "testing"
"time" "time"
"go.uber.org/mock/gomock"
"github.com/rs/xid" "github.com/rs/xid"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller" "github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
"github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel" "github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel"
@@ -1262,7 +1262,10 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, *update_channel.
} }
eventStore := &activity.InMemoryEventStore{} eventStore := &activity.InMemoryEventStore{}
metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
metrics, err := telemetry.NewDefaultAppMetrics(ctx)
require.NoError(t, err) require.NoError(t, err)
ctrl := gomock.NewController(t) ctrl := gomock.NewController(t)
@@ -1290,9 +1293,8 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, *update_channel.
permissionsManager := permissions.NewManager(store) permissionsManager := permissions.NewManager(store)
peersManager := peers.NewManager(store, permissionsManager) peersManager := peers.NewManager(store, permissionsManager)
ctx := context.Background() // A go-cache janitor only stops through a GC finalizer, which would leave synctest bubbles with a goroutine that never exits.
cacheStore, err := cache.NewStore(ctx, 100*time.Millisecond, 0, 100)
cacheStore, err := cache.NewStore(ctx, 100*time.Millisecond, 300*time.Millisecond, 100)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -1301,10 +1303,12 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, *update_channel.
requestBuffer := NewAccountRequestBuffer(ctx, store) requestBuffer := NewAccountRequestBuffer(ctx, store)
networkMapController := controller.NewController(ctx, store, metrics, updateManager, requestBuffer, MockIntegratedValidator{}, settingsMockManager, "netbird.selfhosted", port_forwarding.NewControllerMock(), ephemeral_manager.NewEphemeralManager(store, peers.NewManager(store, permissionsManager)), &config.Config{}, nil) networkMapController := controller.NewController(ctx, store, metrics, updateManager, requestBuffer, MockIntegratedValidator{}, settingsMockManager, "netbird.selfhosted", port_forwarding.NewControllerMock(), ephemeral_manager.NewEphemeralManager(store, peers.NewManager(store, permissionsManager)), &config.Config{}, nil)
am, err := BuildManager(context.Background(), nil, store, networkMapController, job.NewJobManager(nil, store, peersManager), nil, "", eventStore, nil, false, MockIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false, cacheStore) am, err := BuildManager(ctx, nil, store, networkMapController, job.NewJobManager(nil, store, peersManager), nil, "", eventStore, nil, false, MockIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager, false, cacheStore)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
cacheManager := am.cacheManager
t.Cleanup(func() { _ = cacheManager.Close() })
return am, updateManager, nil return am, updateManager, nil
} }
@@ -1893,6 +1897,7 @@ func TestAccount_getPeersRoutesFirewall(t *testing.T) {
} }
func TestRouteAccountPeersUpdate(t *testing.T) { func TestRouteAccountPeersUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, err := createRouterManager(t) manager, updateManager, err := createRouterManager(t)
require.NoError(t, err, "failed to create account manager") require.NoError(t, err, "failed to create account manager")
@@ -1927,7 +1932,9 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
}) })
// Creating a route with no routing peer and no peers in PeerGroups or Groups should not update account peers and not send peer update // Creating a route with no routing peer and no peers in PeerGroups or Groups should not update account peers and not send peer update
t.Run("creating route no routing peer and no peers in groups", func(t *testing.T) { step(t, "creating route no routing peer and no peers in groups", func(t *testing.T) {
settleAffectedUpdates(updMsg)
route := route.Route{ route := route.Route{
ID: "testingRoute1", ID: "testingRoute1",
Network: netip.MustParsePrefix("100.65.250.202/32"), Network: netip.MustParsePrefix("100.65.250.202/32"),
@@ -1963,7 +1970,7 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
}) })
// Creating a route with no routing peer and having peers in groups that don't include peer1 should not send peer1 an update // Creating a route with no routing peer and having peers in groups that don't include peer1 should not send peer1 an update
t.Run("creating a route with peers in PeerGroups and Groups", func(t *testing.T) { step(t, "creating a route with peers in PeerGroups and Groups", func(t *testing.T) {
drainPeerUpdates(updMsg) drainPeerUpdates(updMsg)
route := route.Route{ route := route.Route{
@@ -2014,7 +2021,7 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
} }
// Creating route should update account peers and send peer update // Creating route should update account peers and send peer update
t.Run("creating route with a routing peer", func(t *testing.T) { step(t, "creating route with a routing peer", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -2037,7 +2044,7 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
}) })
// Updating the route should update account peers and send peer update when there is peers in group // Updating the route should update account peers and send peer update when there is peers in group
t.Run("updating route", func(t *testing.T) { step(t, "updating route", func(t *testing.T) {
baseRoute.Groups = []string{routeGroup1, routeGroup2} baseRoute.Groups = []string{routeGroup1, routeGroup2}
done := make(chan struct{}) done := make(chan struct{})
@@ -2057,7 +2064,7 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
}) })
// Deleting the route should update account peers and send peer update // Deleting the route should update account peers and send peer update
t.Run("deleting route", func(t *testing.T) { step(t, "deleting route", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -2075,7 +2082,7 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
}) })
// Adding peer to route peer groups that do not have any peers should update account peers and send peer update // Adding peer to route peer groups that do not have any peers should update account peers and send peer update
t.Run("adding peer to route peer groups that do not have any peers", func(t *testing.T) { step(t, "adding peer to route peer groups that do not have any peers", func(t *testing.T) {
newRoute := route.Route{ newRoute := route.Route{
Network: netip.MustParsePrefix("192.168.12.0/16"), Network: netip.MustParsePrefix("192.168.12.0/16"),
NetID: "superNet", NetID: "superNet",
@@ -2115,7 +2122,7 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
}) })
// Adding peer to route groups that do not have any peers should update account peers and send peer update // Adding peer to route groups that do not have any peers should update account peers and send peer update
t.Run("adding peer to route groups that do not have any peers", func(t *testing.T) { step(t, "adding peer to route groups that do not have any peers", func(t *testing.T) {
newRoute := route.Route{ newRoute := route.Route{
Network: netip.MustParsePrefix("192.168.13.0/16"), Network: netip.MustParsePrefix("192.168.13.0/16"),
NetID: "superNet", NetID: "superNet",
@@ -2153,6 +2160,7 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
t.Error("timeout waiting for peerShouldReceiveUpdate") t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
}) })
})
} }
func TestAccount_GetPeerNetworkResourceFirewallRules(t *testing.T) { func TestAccount_GetPeerNetworkResourceFirewallRules(t *testing.T) {
+4 -2
View File
@@ -397,6 +397,7 @@ func TestSetupKey_Copy(t *testing.T) {
} }
func TestSetupKeyAccountPeersUpdate(t *testing.T) { func TestSetupKeyAccountPeersUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
err := manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{ err := manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
@@ -433,7 +434,7 @@ func TestSetupKeyAccountPeersUpdate(t *testing.T) {
var setupKey *types.SetupKey var setupKey *types.SetupKey
// Creating setup key should not update account peers and not send peer update // Creating setup key should not update account peers and not send peer update
t.Run("creating setup key", func(t *testing.T) { step(t, "creating setup key", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -451,7 +452,7 @@ func TestSetupKeyAccountPeersUpdate(t *testing.T) {
}) })
// Saving setup key should not update account peers and not send peer update // Saving setup key should not update account peers and not send peer update
t.Run("saving setup key", func(t *testing.T) { step(t, "saving setup key", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -467,6 +468,7 @@ func TestSetupKeyAccountPeersUpdate(t *testing.T) {
t.Error("timeout waiting for peerShouldNotReceiveUpdate") t.Error("timeout waiting for peerShouldNotReceiveUpdate")
} }
}) })
})
} }
func TestDefaultAccountManager_CreateSetupKey_ShouldNotAllowToUpdateRevokedKey(t *testing.T) { func TestDefaultAccountManager_CreateSetupKey_ShouldNotAllowToUpdateRevokedKey(t *testing.T) {
+13 -9
View File
@@ -1544,6 +1544,7 @@ func TestDefaultAccountManager_SaveUser(t *testing.T) {
} }
func TestUserAccountPeersUpdate(t *testing.T) { func TestUserAccountPeersUpdate(t *testing.T) {
runPeerUpdateTest(t, func(t *testing.T) {
// account groups propagation is enabled // account groups propagation is enabled
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
@@ -1575,7 +1576,9 @@ func TestUserAccountPeersUpdate(t *testing.T) {
}) })
// Creating a new regular user should send peer update (as users are not filtered yet) // Creating a new regular user should send peer update (as users are not filtered yet)
t.Run("creating new regular user with no groups", func(t *testing.T) { step(t, "creating new regular user with no groups", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1592,16 +1595,16 @@ func TestUserAccountPeersUpdate(t *testing.T) {
select { select {
case <-done: case <-done:
case <-time.After(time.Second): case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldNotReceiveUpdate") t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
}) })
// updating user with no linked peers should update account peers and send peer update (as users are not filtered yet) // saving an unchanged user with no linked peers should not update account peers and not send peer update
t.Run("updating user with no linked peers", func(t *testing.T) { step(t, "updating user with no linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
close(done) close(done)
}() }()
@@ -1624,7 +1627,7 @@ func TestUserAccountPeersUpdate(t *testing.T) {
drainPeerUpdates(updMsg) drainPeerUpdates(updMsg)
// deleting user with no linked peers should not update account peers and not send peer update // deleting user with no linked peers should not update account peers and not send peer update
t.Run("deleting user with no linked peers", func(t *testing.T) { step(t, "deleting user with no linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldNotReceiveUpdate(t, updMsg) peerShouldNotReceiveUpdate(t, updMsg)
@@ -1661,7 +1664,7 @@ func TestUserAccountPeersUpdate(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// updating user with linked peers should update account peers and send peer update // updating user with linked peers should update account peers and send peer update
t.Run("updating user with linked peers", func(t *testing.T) { step(t, "updating user with linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
@@ -1689,7 +1692,7 @@ func TestUserAccountPeersUpdate(t *testing.T) {
}) })
// deleting user with linked peers should update account peers and send peer update // deleting user with linked peers should update account peers and send peer update
t.Run("deleting user with linked peers", func(t *testing.T) { step(t, "deleting user with linked peers", func(t *testing.T) {
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
peerShouldReceiveUpdate(t, peer4UpdMsg) peerShouldReceiveUpdate(t, peer4UpdMsg)
@@ -1705,6 +1708,7 @@ func TestUserAccountPeersUpdate(t *testing.T) {
t.Error("timeout waiting for peerShouldReceiveUpdate") t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
}) })
})
} }
func TestSaveOrAddUser_PreventAccountSwitch(t *testing.T) { func TestSaveOrAddUser_PreventAccountSwitch(t *testing.T) {