[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
+74 -13
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) {
testAccountManager_NetworkUpdates_SaveGroup(t) runPeerUpdateTest(t, func(t *testing.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) {
testAccountManager_NetworkUpdates_DeletePolicy(t) runPeerUpdateTest(t, func(t *testing.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) {
testAccountManager_NetworkUpdates_SavePolicy(t) runPeerUpdateTest(t, func(t *testing.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) {
testAccountManager_NetworkUpdates_DeletePeer(t) runPeerUpdateTest(t, func(t *testing.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) {
testAccountManager_NetworkUpdates_DeleteGroup(t) runPeerUpdateTest(t, func(t *testing.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 {
+77 -77
View File
@@ -87,93 +87,93 @@ 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) {
manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t)
accountID := account.Id ctx := context.Background()
accountID := account.Id
key, err := wgtypes.GeneratePrivateKey() key, err := wgtypes.GeneratePrivateKey()
require.NoError(t, err) require.NoError(t, err)
userPeer, _, _, _, err := manager.AddPeer(ctx, accountID, "", userID, &nbpeer.Peer{ userPeer, _, _, _, err := manager.AddPeer(ctx, accountID, "", userID, &nbpeer.Peer{
Key: key.PublicKey().String(), Key: key.PublicKey().String(),
Meta: nbpeer.PeerSystemMeta{Hostname: "user-peer"}, Meta: nbpeer.PeerSystemMeta{Hostname: "user-peer"},
}, false) }, false)
require.NoError(t, err) require.NoError(t, err)
policies, err := manager.Store.GetAccountPolicies(ctx, store.LockingStrengthNone, accountID) policies, err := manager.Store.GetAccountPolicies(ctx, store.LockingStrengthNone, accountID)
require.NoError(t, err) require.NoError(t, err)
for _, p := range policies { for _, p := range policies {
require.NoError(t, manager.Store.DeletePolicy(ctx, accountID, p.ID)) require.NoError(t, manager.Store.DeletePolicy(ctx, accountID, p.ID))
} }
account, err = manager.Store.GetAccount(ctx, accountID) account, err = manager.Store.GetAccount(ctx, accountID)
require.NoError(t, err) require.NoError(t, err)
account.Settings.JWTGroupsEnabled = true account.Settings.JWTGroupsEnabled = true
account.Settings.JWTGroupsClaimName = "groups" account.Settings.JWTGroupsClaimName = "groups"
account.Settings.GroupsPropagationEnabled = true account.Settings.GroupsPropagationEnabled = true
require.NoError(t, manager.Store.SaveAccount(ctx, account)) require.NoError(t, manager.Store.SaveAccount(ctx, account))
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "jwt-grp", Name: "jwt-linked", Issued: types.GroupIssuedJWT, Peers: []string{}})) require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "jwt-grp", Name: "jwt-linked", Issued: types.GroupIssuedJWT, Peers: []string{}}))
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "jwt-dest", Name: "jwt-dest", Peers: []string{peer2.ID}})) require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "jwt-dest", Name: "jwt-dest", Peers: []string{peer2.ID}}))
_, err = manager.SavePolicy(ctx, accountID, userID, &types.Policy{ _, err = manager.SavePolicy(ctx, accountID, userID, &types.Policy{
Enabled: true, Enabled: true,
Rules: []*types.PolicyRule{ Rules: []*types.PolicyRule{
{ {
Enabled: true, Enabled: true,
Sources: []string{"jwt-grp"}, Sources: []string{"jwt-grp"},
Destinations: []string{"jwt-dest"}, Destinations: []string{"jwt-dest"},
Bidirectional: true, Bidirectional: true,
Action: types.PolicyTrafficActionAccept, Action: types.PolicyTrafficActionAccept,
},
}, },
}, }, true)
}, true)
require.NoError(t, err)
updUser := updateManager.CreateChannel(ctx, userPeer.ID)
upd2 := updateManager.CreateChannel(ctx, peer2.ID)
upd3 := updateManager.CreateChannel(ctx, peer3.ID)
t.Cleanup(func() {
updateManager.CloseChannel(ctx, userPeer.ID)
updateManager.CloseChannel(ctx, peer2.ID)
updateManager.CloseChannel(ctx, peer3.ID)
})
userAuth := auth.UserAuth{
AccountId: accountID,
UserId: userID,
Groups: []string{"jwt-linked"},
}
t.Run("adding JWT group updates only linked peers", func(t *testing.T) {
drainPeerUpdates(updUser)
drainPeerUpdates(upd2)
drainPeerUpdates(upd3)
require.NoError(t, manager.SyncUserJWTGroups(ctx, userAuth))
peerShouldReceiveUpdate(t, updUser)
peerShouldReceiveUpdate(t, upd2)
peerShouldNotReceiveUpdate(t, upd3)
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, userID)
require.NoError(t, err) require.NoError(t, err)
assert.Contains(t, user.AutoGroups, "jwt-grp")
})
t.Run("removing JWT group updates only linked peers", func(t *testing.T) { updUser := updateManager.CreateChannel(ctx, userPeer.ID)
drainPeerUpdates(updUser) upd2 := updateManager.CreateChannel(ctx, peer2.ID)
drainPeerUpdates(upd2) upd3 := updateManager.CreateChannel(ctx, peer3.ID)
drainPeerUpdates(upd3) t.Cleanup(func() {
updateManager.CloseChannel(ctx, userPeer.ID)
updateManager.CloseChannel(ctx, peer2.ID)
updateManager.CloseChannel(ctx, peer3.ID)
})
userAuth.Groups = nil userAuth := auth.UserAuth{
require.NoError(t, manager.SyncUserJWTGroups(ctx, userAuth)) AccountId: accountID,
UserId: userID,
Groups: []string{"jwt-linked"},
}
peerShouldReceiveUpdate(t, updUser) step(t, "adding JWT group updates only linked peers", func(t *testing.T) {
peerShouldReceiveUpdate(t, upd2) settleAffectedUpdates(updUser, upd2, upd3)
peerShouldNotReceiveUpdate(t, upd3)
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, userID) require.NoError(t, manager.SyncUserJWTGroups(ctx, userAuth))
require.NoError(t, err)
assert.NotContains(t, user.AutoGroups, "jwt-grp") peerShouldReceiveUpdate(t, updUser)
peerShouldReceiveUpdate(t, upd2)
peerShouldNotReceiveUpdate(t, upd3)
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, userID)
require.NoError(t, err)
assert.Contains(t, user.AutoGroups, "jwt-grp")
})
step(t, "removing JWT group updates only linked peers", func(t *testing.T) {
drainPeerUpdates(updUser)
drainPeerUpdates(upd2)
drainPeerUpdates(upd3)
userAuth.Groups = nil
require.NoError(t, manager.SyncUserJWTGroups(ctx, userAuth))
peerShouldReceiveUpdate(t, updUser)
peerShouldReceiveUpdate(t, upd2)
peerShouldNotReceiveUpdate(t, upd3)
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, userID)
require.NoError(t, err)
assert.NotContains(t, user.AutoGroups, "jwt-grp")
})
}) })
} }
+101 -97
View File
@@ -24,120 +24,124 @@ 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) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, true)
ctx := context.Background()
// A second resource group + a second source group/peer that reaches the // A second resource group + a second source group/peer that reaches the
// resource only through that second group. // resource only through that second group.
const detachGroupID = "rs-detach-grp" const detachGroupID = "rs-detach-grp"
require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{ID: detachGroupID, Name: "rs-detach"})) require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{ID: detachGroupID, Name: "rs-detach"}))
const secondSourceGroupID = "rs-source-grp-2" const secondSourceGroupID = "rs-source-grp-2"
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-detach-key", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false) setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-detach-key", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
require.NoError(t, err) require.NoError(t, err)
secondSourcePeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key) secondSourcePeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{ require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{
ID: secondSourceGroupID, Name: "rs-source-2", Peers: []string{secondSourcePeer.ID}, ID: secondSourceGroupID, Name: "rs-source-2", Peers: []string{secondSourcePeer.ID},
})) }))
resourcesManager, _, _ := s.managers() resourcesManager, _, _ := s.managers()
// Attach the resource to the detach group as well: now in [resourceGroup, detachGroup]. // Attach the resource to the detach group as well: now in [resourceGroup, detachGroup].
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{ _, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
ID: s.resourceID, ID: s.resourceID,
AccountID: s.accountID, AccountID: s.accountID,
NetworkID: s.networkID, NetworkID: s.networkID,
Name: "rs-resource-host", Name: "rs-resource-host",
Address: "10.20.30.0/24", Address: "10.20.30.0/24",
GroupIDs: []string{s.resourceGroupID, detachGroupID}, GroupIDs: []string{s.resourceGroupID, detachGroupID},
Enabled: true, Enabled: true,
})
require.NoError(t, err)
// Policy granting the second source group access via the detach group.
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(secondSourceGroupID, detachGroupID), true)
require.NoError(t, err)
secondSrcCh := s.updateManager.CreateChannel(ctx, secondSourcePeer.ID)
t.Cleanup(func() { s.updateManager.CloseChannel(ctx, secondSourcePeer.ID) })
settleAffectedUpdates(secondSrcCh)
done := make(chan struct{})
go func() {
// Detaching the resource from detachGroup removes the second source's
// access; that source peer must be refreshed even though the post-update
// resource no longer maps to detachGroup.
peerShouldReceiveUpdate(t, secondSrcCh)
close(done)
}()
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
ID: s.resourceID,
AccountID: s.accountID,
NetworkID: s.networkID,
Name: "rs-resource-host",
Address: "10.20.30.0/24",
GroupIDs: []string{s.resourceGroupID}, // detached detachGroup
Enabled: true,
})
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: detaching a resource group did not refresh the old group's policy source peer")
}
}) })
require.NoError(t, err)
// Policy granting the second source group access via the detach group.
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(secondSourceGroupID, detachGroupID), true)
require.NoError(t, err)
secondSrcCh := s.updateManager.CreateChannel(ctx, secondSourcePeer.ID)
t.Cleanup(func() { s.updateManager.CloseChannel(ctx, secondSourcePeer.ID) })
settleAffectedUpdates(secondSrcCh)
done := make(chan struct{})
go func() {
// Detaching the resource from detachGroup removes the second source's
// access; that source peer must be refreshed even though the post-update
// resource no longer maps to detachGroup.
peerShouldReceiveUpdate(t, secondSrcCh)
close(done)
}()
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
ID: s.resourceID,
AccountID: s.accountID,
NetworkID: s.networkID,
Name: "rs-resource-host",
Address: "10.20.30.0/24",
GroupIDs: []string{s.resourceGroupID}, // detached detachGroup
Enabled: true,
})
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, true)
ctx := context.Background()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true) _, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
require.NoError(t, err) require.NoError(t, err)
_, routersManager, _ := s.managers() _, routersManager, _ := s.managers()
routers, err := s.manager.Store.GetNetworkRoutersByNetID(ctx, store.LockingStrengthNone, s.accountID, s.networkID) routers, err := s.manager.Store.GetNetworkRoutersByNetID(ctx, store.LockingStrengthNone, s.accountID, s.networkID)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, routers, 1) require.Len(t, routers, 1)
router := routers[0] router := routers[0]
oldRoutingPeer := router.Peer oldRoutingPeer := router.Peer
require.NotEmpty(t, oldRoutingPeer) require.NotEmpty(t, oldRoutingPeer)
// A new peer to become the routing peer in place of the old one. // A new peer to become the routing peer in place of the old one.
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-newrouter-key", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false) setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-newrouter-key", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
require.NoError(t, err) require.NoError(t, err)
newRoutingPeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key) newRoutingPeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
oldCh := s.updateManager.CreateChannel(ctx, oldRoutingPeer) oldCh := s.updateManager.CreateChannel(ctx, oldRoutingPeer)
t.Cleanup(func() { s.updateManager.CloseChannel(ctx, oldRoutingPeer) }) t.Cleanup(func() { s.updateManager.CloseChannel(ctx, oldRoutingPeer) })
settleAffectedUpdates(oldCh) settleAffectedUpdates(oldCh)
done := make(chan struct{}) done := make(chan struct{})
go func() { go func() {
// The old routing peer stops serving the resource and must be refreshed. // The old routing peer stops serving the resource and must be refreshed.
peerShouldReceiveUpdate(t, oldCh) peerShouldReceiveUpdate(t, oldCh)
close(done) close(done)
}() }()
_, err = routersManager.UpdateRouter(ctx, userID, &routerTypes.NetworkRouter{ _, err = routersManager.UpdateRouter(ctx, userID, &routerTypes.NetworkRouter{
ID: router.ID, ID: router.ID,
NetworkID: s.networkID, NetworkID: s.networkID,
AccountID: s.accountID, AccountID: s.accountID,
Peer: newRoutingPeer.ID, // repoint within the same network Peer: newRoutingPeer.ID, // repoint within the same network
Masquerade: true, Masquerade: true,
Metric: 9999, Metric: 9999,
Enabled: true, Enabled: true,
})
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: re-pointing the router peer did not refresh the old routing peer")
}
}) })
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: re-pointing the router peer did not refresh the old routing peer")
}
} }
@@ -165,148 +165,154 @@ 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) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, true)
ctx := context.Background()
checkID := s.createPostureCheckGatedPolicy(t, ctx, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID)) checkID := s.createPostureCheckGatedPolicy(t, ctx, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID))
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID) srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID) routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID) unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID)
t.Cleanup(func() { t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, s.sourcePeerID) s.updateManager.CloseChannel(ctx, s.sourcePeerID)
s.updateManager.CloseChannel(ctx, s.routerPeerID) s.updateManager.CloseChannel(ctx, s.routerPeerID)
s.updateManager.CloseChannel(ctx, s.unrelatedPeerID) s.updateManager.CloseChannel(ctx, s.unrelatedPeerID)
})
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
peerShouldNotReceiveUpdate(t, unrelatedCh)
close(done)
}()
_, err := s.manager.SavePostureChecks(ctx, s.accountID, userID, &posture.Checks{
ID: checkID,
Name: "rs-min-version",
Checks: posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{MinVersion: "0.31.0"},
},
}, false)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: editing a posture check did not refresh source + routing peers")
}
}) })
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
peerShouldNotReceiveUpdate(t, unrelatedCh)
close(done)
}()
_, err := s.manager.SavePostureChecks(ctx, s.accountID, userID, &posture.Checks{
ID: checkID,
Name: "rs-min-version",
Checks: posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{MinVersion: "0.31.0"},
},
}, false)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, true)
ctx := context.Background()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true) _, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
require.NoError(t, err) require.NoError(t, err)
resourcesManager, _, _ := s.managers() resourcesManager, _, _ := s.managers()
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID) srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID) routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID) unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID)
t.Cleanup(func() { t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, s.sourcePeerID) s.updateManager.CloseChannel(ctx, s.sourcePeerID)
s.updateManager.CloseChannel(ctx, s.routerPeerID) s.updateManager.CloseChannel(ctx, s.routerPeerID)
s.updateManager.CloseChannel(ctx, s.unrelatedPeerID) s.updateManager.CloseChannel(ctx, s.unrelatedPeerID)
})
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
peerShouldNotReceiveUpdate(t, unrelatedCh)
close(done)
}()
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
ID: s.resourceID,
AccountID: s.accountID,
NetworkID: s.networkID,
Name: "rs-resource-host",
Address: "10.20.30.0/25",
GroupIDs: []string{s.resourceGroupID},
Enabled: true,
})
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: updating a DestinationResource-targeted resource did not refresh its policy source peer")
}
}) })
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
peerShouldNotReceiveUpdate(t, unrelatedCh)
close(done)
}()
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
ID: s.resourceID,
AccountID: s.accountID,
NetworkID: s.networkID,
Name: "rs-resource-host",
Address: "10.20.30.0/25",
GroupIDs: []string{s.resourceGroupID},
Enabled: true,
})
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, true)
ctx := context.Background()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true) _, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
require.NoError(t, err) require.NoError(t, err)
resourcesManager, routersManager, _ := s.managers() resourcesManager, routersManager, _ := s.managers()
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-key-disabled", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false) setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-key-disabled", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
require.NoError(t, err) require.NoError(t, err)
disabledRouterPeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key) disabledRouterPeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
_, err = routersManager.CreateRouter(ctx, userID, &routerTypes.NetworkRouter{ _, err = routersManager.CreateRouter(ctx, userID, &routerTypes.NetworkRouter{
NetworkID: s.networkID, NetworkID: s.networkID,
AccountID: s.accountID, AccountID: s.accountID,
Peer: disabledRouterPeer.ID, Peer: disabledRouterPeer.ID,
Masquerade: true, Masquerade: true,
Metric: 9000, Metric: 9000,
Enabled: false, Enabled: false,
})
require.NoError(t, err)
disabledCh := s.updateManager.CreateChannel(ctx, disabledRouterPeer.ID)
enabledCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, disabledRouterPeer.ID)
s.updateManager.CloseChannel(ctx, s.routerPeerID)
})
settleAffectedUpdates(disabledCh, enabledCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, enabledCh)
peerShouldNotReceiveUpdate(t, disabledCh)
close(done)
}()
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
ID: s.resourceID,
AccountID: s.accountID,
NetworkID: s.networkID,
Name: "rs-resource-host",
Address: "10.20.30.0/25",
GroupIDs: []string{s.resourceGroupID},
Enabled: true,
})
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout")
}
}) })
require.NoError(t, err)
disabledCh := s.updateManager.CreateChannel(ctx, disabledRouterPeer.ID)
enabledCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, disabledRouterPeer.ID)
s.updateManager.CloseChannel(ctx, s.routerPeerID)
})
settleAffectedUpdates(disabledCh, enabledCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, enabledCh)
peerShouldNotReceiveUpdate(t, disabledCh)
close(done)
}()
_, err = resourcesManager.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
ID: s.resourceID,
AccountID: s.accountID,
NetworkID: s.networkID,
Name: "rs-resource-host",
Address: "10.20.30.0/25",
GroupIDs: []string{s.resourceGroupID},
Enabled: true,
})
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout")
}
} }
func TestAffectedPeers_GroupChange_RouterInOtherNetworkNotAffected(t *testing.T) { func TestAffectedPeers_GroupChange_RouterInOtherNetworkNotAffected(t *testing.T) {
@@ -346,8 +352,10 @@ 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) {
runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy { runPeerUpdateTest(t, func(t *testing.T) {
return peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID) runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy {
return peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID)
})
}) })
} }
@@ -355,8 +363,10 @@ func TestAffectedPeers_E2E_PostureFlip_RefreshesRoutingPeer(t *testing.T) {
// 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) {
runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy { runPeerUpdateTest(t, func(t *testing.T) {
return peerToResourcePolicyByPeer(s.sourcePeerID, s.resourceGroupID) runPostureFlipRefreshesRoutingPeer(t, func(s *routerScenario) *types.Policy {
return peerToResourcePolicyByPeer(s.sourcePeerID, s.resourceGroupID)
})
}) })
} }
+256 -252
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,190 +319,189 @@ func TestAffectedPeers_PolicyToResource_UnrelatedPeerNotAffected(t *testing.T) {
} }
func TestAffectedPeers_ResourceSideBridgesToRoutingPeer_DirectRouter(t *testing.T) { func TestAffectedPeers_ResourceSideBridgesToRoutingPeer_DirectRouter(t *testing.T) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, true)
ctx := context.Background()
// A pre-existing policy grants the source group access to the resource. // A pre-existing policy grants the source group access to the resource.
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true) _, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
require.NoError(t, err) require.NoError(t, err)
// Drive an update through the resource manager and assert the routing peer // Drive an update through the resource manager and assert the routing peer
// is among the affected set by observing the channel. This path walks // is among the affected set by observing the channel. This path walks
// policies whose destinations reference the resource's groups, folds in the // policies whose destinations reference the resource's groups, folds in the
// source groups, and loads the network's routers, so it reaches both the // source groups, and loads the network's routers, so it reaches both the
// source peer and the routing peer. // source peer and the routing peer.
permissionsManager := permissions.NewManager(s.manager.Store) permissionsManager := permissions.NewManager(s.manager.Store)
groupsManager := groups.NewManager(s.manager.Store, permissionsManager, s.manager) groupsManager := groups.NewManager(s.manager.Store, permissionsManager, s.manager)
rm := resources.NewManager(s.manager.Store, permissionsManager, groupsManager, s.manager, s.manager.serviceManager) rm := resources.NewManager(s.manager.Store, permissionsManager, groupsManager, s.manager, s.manager.serviceManager)
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID) srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID) routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
t.Cleanup(func() { t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, s.sourcePeerID) s.updateManager.CloseChannel(ctx, s.sourcePeerID)
s.updateManager.CloseChannel(ctx, s.routerPeerID) s.updateManager.CloseChannel(ctx, s.routerPeerID)
})
settleAffectedUpdates(srcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
_, err = rm.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
ID: s.resourceID,
AccountID: s.accountID,
NetworkID: s.networkID,
Name: "rs-resource-host",
Address: "10.20.30.0/24",
GroupIDs: []string{s.resourceGroupID},
Enabled: true,
})
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: resource update did not refresh source peer + routing peer")
}
}) })
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
_, err = rm.UpdateResource(ctx, userID, &resourceTypes.NetworkResource{
ID: s.resourceID,
AccountID: s.accountID,
NetworkID: s.networkID,
Name: "rs-resource-host",
Address: "10.20.30.0/24",
GroupIDs: []string{s.resourceGroupID},
Enabled: true,
})
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, true)
ctx := context.Background()
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID) srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID) routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID) unrelatedCh := s.updateManager.CreateChannel(ctx, s.unrelatedPeerID)
t.Cleanup(func() { t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, s.sourcePeerID) s.updateManager.CloseChannel(ctx, s.sourcePeerID)
s.updateManager.CloseChannel(ctx, s.routerPeerID) s.updateManager.CloseChannel(ctx, s.routerPeerID)
s.updateManager.CloseChannel(ctx, s.unrelatedPeerID) s.updateManager.CloseChannel(ctx, s.unrelatedPeerID)
})
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
peerShouldNotReceiveUpdate(t, unrelatedCh)
close(done)
}()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: creating peer->resource policy did not refresh the routing peer")
}
}) })
settleAffectedUpdates(srcCh, routerCh, unrelatedCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
peerShouldNotReceiveUpdate(t, unrelatedCh)
close(done)
}()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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) {
s := setupRouterScenario(t, false) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, false)
ctx := context.Background()
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID) srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
routerCh := s.updateManager.CreateChannel(ctx, s.routerGroupPeerID) routerCh := s.updateManager.CreateChannel(ctx, s.routerGroupPeerID)
t.Cleanup(func() { t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, s.sourcePeerID) s.updateManager.CloseChannel(ctx, s.sourcePeerID)
s.updateManager.CloseChannel(ctx, s.routerGroupPeerID) s.updateManager.CloseChannel(ctx, s.routerGroupPeerID)
})
settleAffectedUpdates(srcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: routing peer (PeerGroups) not refreshed on policy create")
}
}) })
settleAffectedUpdates(srcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, true)
ctx := context.Background()
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID) srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID) routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
t.Cleanup(func() { t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, s.sourcePeerID) s.updateManager.CloseChannel(ctx, s.sourcePeerID)
s.updateManager.CloseChannel(ctx, s.routerPeerID) s.updateManager.CloseChannel(ctx, s.routerPeerID)
})
settleAffectedUpdates(srcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: routing peer not refreshed when policy targets DestinationResource")
}
}) })
settleAffectedUpdates(srcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, true)
ctx := context.Background()
policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true) policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
require.NoError(t, err) require.NoError(t, err)
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID) srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID) routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
t.Cleanup(func() { t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, s.sourcePeerID) s.updateManager.CloseChannel(ctx, s.sourcePeerID)
s.updateManager.CloseChannel(ctx, s.routerPeerID) s.updateManager.CloseChannel(ctx, s.routerPeerID)
})
settleAffectedUpdates(srcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
require.NoError(t, s.manager.DeletePolicy(ctx, s.accountID, policy.ID, userID))
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: deleting peer->resource policy did not refresh the routing peer")
}
}) })
settleAffectedUpdates(srcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
require.NoError(t, s.manager.DeletePolicy(ctx, s.accountID, policy.ID, userID))
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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,113 +570,119 @@ 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) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
second := s.addSecondTopology(t, "b") s := setupRouterScenario(t, true)
ctx := context.Background() second := s.addSecondTopology(t, "b")
ctx := context.Background()
policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true) policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
require.NoError(t, err) require.NoError(t, err)
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID) srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
routerACh := s.updateManager.CreateChannel(ctx, s.routerPeerID) routerACh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
routerBCh := s.updateManager.CreateChannel(ctx, second.routerPeerID) routerBCh := s.updateManager.CreateChannel(ctx, second.routerPeerID)
t.Cleanup(func() { t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, s.sourcePeerID) s.updateManager.CloseChannel(ctx, s.sourcePeerID)
s.updateManager.CloseChannel(ctx, s.routerPeerID) s.updateManager.CloseChannel(ctx, s.routerPeerID)
s.updateManager.CloseChannel(ctx, second.routerPeerID) s.updateManager.CloseChannel(ctx, second.routerPeerID)
})
settleAffectedUpdates(srcCh, routerACh, routerBCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerACh)
peerShouldReceiveUpdate(t, routerBCh)
close(done)
}()
policy.Rules[0].Destinations = []string{second.resourceGroupID}
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, policy, false)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: re-pointing the policy destination did not refresh both routing peers")
}
}) })
settleAffectedUpdates(srcCh, routerACh, routerBCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerACh)
peerShouldReceiveUpdate(t, routerBCh)
close(done)
}()
policy.Rules[0].Destinations = []string{second.resourceGroupID}
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, policy, false)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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) {
s := setupRouterScenario(t, true) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, true)
ctx := context.Background()
const secondSourceGroupID = "rs-source-grp-2" const secondSourceGroupID = "rs-source-grp-2"
setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-key-2", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false) setupKey, err := s.manager.CreateSetupKey(ctx, s.accountID, "rs-key-2", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
require.NoError(t, err) require.NoError(t, err)
secondSourcePeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key) secondSourcePeer := addPeerToAccount(t, s.manager, s.accountID, setupKey.Key)
require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{ require.NoError(t, s.manager.CreateGroup(ctx, s.accountID, userID, &types.Group{
ID: secondSourceGroupID, Name: "rs-source-2", Peers: []string{secondSourcePeer.ID}, ID: secondSourceGroupID, Name: "rs-source-2", Peers: []string{secondSourcePeer.ID},
})) }))
policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true) policy, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByGroup(s.sourceGroupID, s.resourceGroupID), true)
require.NoError(t, err) require.NoError(t, err)
newSrcCh := s.updateManager.CreateChannel(ctx, secondSourcePeer.ID) newSrcCh := s.updateManager.CreateChannel(ctx, secondSourcePeer.ID)
routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID) routerCh := s.updateManager.CreateChannel(ctx, s.routerPeerID)
t.Cleanup(func() { t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, secondSourcePeer.ID) s.updateManager.CloseChannel(ctx, secondSourcePeer.ID)
s.updateManager.CloseChannel(ctx, s.routerPeerID) s.updateManager.CloseChannel(ctx, s.routerPeerID)
})
settleAffectedUpdates(newSrcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, newSrcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
policy.Rules[0].Sources = []string{s.sourceGroupID, secondSourceGroupID}
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, policy, false)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: adding a source group did not refresh the new source peer + routing peer")
}
}) })
settleAffectedUpdates(newSrcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, newSrcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
policy.Rules[0].Sources = []string{s.sourceGroupID, secondSourceGroupID}
_, err = s.manager.SavePolicy(ctx, s.accountID, userID, policy, false)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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) {
s := setupRouterScenario(t, false) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() s := setupRouterScenario(t, false)
ctx := context.Background()
srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID) srcCh := s.updateManager.CreateChannel(ctx, s.sourcePeerID)
routerCh := s.updateManager.CreateChannel(ctx, s.routerGroupPeerID) routerCh := s.updateManager.CreateChannel(ctx, s.routerGroupPeerID)
t.Cleanup(func() { t.Cleanup(func() {
s.updateManager.CloseChannel(ctx, s.sourcePeerID) s.updateManager.CloseChannel(ctx, s.sourcePeerID)
s.updateManager.CloseChannel(ctx, s.routerGroupPeerID) s.updateManager.CloseChannel(ctx, s.routerGroupPeerID)
})
settleAffectedUpdates(srcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout: DestinationResource policy with PeerGroups router did not refresh the routing peer")
}
}) })
settleAffectedUpdates(srcCh, routerCh)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, srcCh)
peerShouldReceiveUpdate(t, routerCh)
close(done)
}()
_, err := s.manager.SavePolicy(ctx, s.accountID, userID, peerToResourcePolicyByResource(s.sourceGroupID, s.resourceID), true)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
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) {
File diff suppressed because it is too large Load Diff
+117 -121
View File
@@ -17,156 +17,152 @@ 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) {
manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t) runPeerUpdateTest(t, func(t *testing.T) {
ctx := context.Background() manager, updateManager, account, _, peer2, peer3 := setupNetworkMapTest(t)
accountID := account.Id ctx := context.Background()
accountID := account.Id
const targetUserID = "target-user" const targetUserID = "target-user"
require.NoError(t, manager.Store.SaveUser(ctx, &types.User{ require.NoError(t, manager.Store.SaveUser(ctx, &types.User{
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser, Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
})) }))
key, err := wgtypes.GeneratePrivateKey() key, err := wgtypes.GeneratePrivateKey()
require.NoError(t, err) require.NoError(t, err)
targetPeer, _, _, _, err := manager.AddPeer(ctx, accountID, "", targetUserID, &nbpeer.Peer{ targetPeer, _, _, _, err := manager.AddPeer(ctx, accountID, "", targetUserID, &nbpeer.Peer{
Key: key.PublicKey().String(), Key: key.PublicKey().String(),
Meta: nbpeer.PeerSystemMeta{Hostname: "target-peer"}, Meta: nbpeer.PeerSystemMeta{Hostname: "target-peer"},
}, false) }, false)
require.NoError(t, err) require.NoError(t, err)
policies, err := manager.Store.GetAccountPolicies(ctx, store.LockingStrengthNone, accountID) policies, err := manager.Store.GetAccountPolicies(ctx, store.LockingStrengthNone, accountID)
require.NoError(t, err) require.NoError(t, err)
for _, p := range policies { for _, p := range policies {
require.NoError(t, manager.Store.DeletePolicy(ctx, accountID, p.ID)) require.NoError(t, manager.Store.DeletePolicy(ctx, accountID, p.ID))
} }
account, err = manager.Store.GetAccount(ctx, accountID) account, err = manager.Store.GetAccount(ctx, accountID)
require.NoError(t, err) require.NoError(t, err)
account.Settings.GroupsPropagationEnabled = true account.Settings.GroupsPropagationEnabled = true
require.NoError(t, manager.Store.SaveAccount(ctx, account)) require.NoError(t, manager.Store.SaveAccount(ctx, account))
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-linked", Name: "ug-linked"})) require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-linked", Name: "ug-linked"}))
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-dest", Name: "ug-dest", Peers: []string{peer2.ID}})) require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-dest", Name: "ug-dest", Peers: []string{peer2.ID}}))
_, err = manager.SavePolicy(ctx, accountID, userID, &types.Policy{ _, err = manager.SavePolicy(ctx, accountID, userID, &types.Policy{
Enabled: true, Enabled: true,
Rules: []*types.PolicyRule{ Rules: []*types.PolicyRule{
{ {
Enabled: true, Enabled: true,
Sources: []string{"ug-linked"}, Sources: []string{"ug-linked"},
Destinations: []string{"ug-dest"}, Destinations: []string{"ug-dest"},
Bidirectional: true, Bidirectional: true,
Action: types.PolicyTrafficActionAccept, Action: types.PolicyTrafficActionAccept,
},
}, },
}, }, true)
}, true) require.NoError(t, err)
require.NoError(t, err)
updTarget := updateManager.CreateChannel(ctx, targetPeer.ID) updTarget := updateManager.CreateChannel(ctx, targetPeer.ID)
upd2 := updateManager.CreateChannel(ctx, peer2.ID) upd2 := updateManager.CreateChannel(ctx, peer2.ID)
upd3 := updateManager.CreateChannel(ctx, peer3.ID) upd3 := updateManager.CreateChannel(ctx, peer3.ID)
t.Cleanup(func() { t.Cleanup(func() {
updateManager.CloseChannel(ctx, targetPeer.ID) updateManager.CloseChannel(ctx, targetPeer.ID)
updateManager.CloseChannel(ctx, peer2.ID) updateManager.CloseChannel(ctx, peer2.ID)
updateManager.CloseChannel(ctx, peer3.ID) updateManager.CloseChannel(ctx, peer3.ID)
})
t.Run("auto group change updates only linked peers", func(t *testing.T) {
drainPeerUpdates(updTarget)
drainPeerUpdates(upd2)
drainPeerUpdates(upd3)
_, err := manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
AutoGroups: []string{"ug-linked"},
}) })
require.NoError(t, err)
peerShouldReceiveUpdate(t, updTarget) step(t, "auto group change updates only linked peers", func(t *testing.T) {
peerShouldReceiveUpdate(t, upd2) settleAffectedUpdates(updTarget, upd2, upd3)
peerShouldNotReceiveUpdate(t, upd3)
})
t.Run("update without group changes refreshes nobody", func(t *testing.T) { _, err := manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
drainPeerUpdates(updTarget) Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
drainPeerUpdates(upd2) AutoGroups: []string{"ug-linked"},
drainPeerUpdates(upd3) })
require.NoError(t, err)
_, err := manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{ peerShouldReceiveUpdate(t, updTarget)
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser, peerShouldReceiveUpdate(t, upd2)
AutoGroups: []string{"ug-linked"}, Name: "renamed", peerShouldNotReceiveUpdate(t, upd3)
}) })
require.NoError(t, err)
peerShouldNotReceiveUpdate(t, updTarget) step(t, "update without group changes refreshes nobody", func(t *testing.T) {
peerShouldNotReceiveUpdate(t, upd2) drainPeerUpdates(updTarget)
peerShouldNotReceiveUpdate(t, upd3) drainPeerUpdates(upd2)
drainPeerUpdates(upd3)
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, targetUserID) _, err := manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
require.NoError(t, err) Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
assert.Equal(t, "renamed", user.Name) AutoGroups: []string{"ug-linked"}, Name: "renamed",
}) })
require.NoError(t, err)
t.Run("auto group change reassigning IPv6 refreshes the changed peers and their observers", func(t *testing.T) { peerShouldNotReceiveUpdate(t, updTarget)
require.NoError(t, manager.CreateGroup(ctx, accountID, userID, &types.Group{ID: "ug-v6", Name: "ug-v6"})) peerShouldNotReceiveUpdate(t, upd2)
// Apply through the settings API so the reconciliation that strips the other peerShouldNotReceiveUpdate(t, upd3)
user, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, targetUserID)
require.NoError(t, err)
assert.Equal(t, "renamed", user.Name)
})
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
// 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,
AutoGroups: []string{"ug-linked", "ug-v6"}, Name: "renamed", AutoGroups: []string{"ug-linked", "ug-v6"}, Name: "renamed",
})
require.NoError(t, err)
// The reassigned peer refreshes with everyone it can reach: peer2 via the
// policy, but not peer3, which shares no group or policy with it.
peerShouldReceiveUpdate(t, updTarget)
peerShouldReceiveUpdate(t, upd2)
peerShouldNotReceiveUpdate(t, upd3)
}) })
require.NoError(t, err)
// The reassigned peer refreshes with everyone it can reach: peer2 via the step(t, "unblocking a user refreshes only the SSH rule destinations", func(t *testing.T) {
// policy, but not peer3, which shares no group or policy with it. // An SSH rule that authorizes no group of its own ships the account's
peerShouldReceiveUpdate(t, updTarget) // allowed-user set to its destinations, so those are the peers an unblock
peerShouldReceiveUpdate(t, upd2) // reaches — not the whole account.
peerShouldNotReceiveUpdate(t, upd3) _, err := manager.SavePolicy(ctx, accountID, userID, &types.Policy{
}) Enabled: true,
Rules: []*types.PolicyRule{{
Enabled: true,
Sources: []string{"ug-linked"},
Destinations: []string{"ug-dest"},
Protocol: types.PolicyRuleProtocolNetbirdSSH,
Action: types.PolicyTrafficActionAccept,
}},
}, true)
require.NoError(t, err)
t.Run("unblocking a user refreshes only the SSH rule destinations", func(t *testing.T) { blocked, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, targetUserID)
// An SSH rule that authorizes no group of its own ships the account's require.NoError(t, err)
// allowed-user set to its destinations, so those are the peers an unblock blocked.Blocked = true
// reaches — not the whole account. require.NoError(t, manager.Store.SaveUser(ctx, blocked))
_, err := manager.SavePolicy(ctx, accountID, userID, &types.Policy{
Enabled: true,
Rules: []*types.PolicyRule{{
Enabled: true,
Sources: []string{"ug-linked"},
Destinations: []string{"ug-dest"},
Protocol: types.PolicyRuleProtocolNetbirdSSH,
Action: types.PolicyTrafficActionAccept,
}},
}, true)
require.NoError(t, err)
blocked, err := manager.Store.GetUserByUserID(ctx, store.LockingStrengthNone, targetUserID) settleAffectedUpdates(updTarget, upd2, upd3)
require.NoError(t, err)
blocked.Blocked = true
require.NoError(t, manager.Store.SaveUser(ctx, blocked))
drainPeerUpdates(updTarget) // Same auto-groups as the previous subtest left them, so no group change and
drainPeerUpdates(upd2) // no IPv6 reconciliation interferes: the unblock alone drives the refresh.
drainPeerUpdates(upd3) _, err = manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
AutoGroups: []string{"ug-linked", "ug-v6"}, Name: "renamed",
})
require.NoError(t, err)
// Same auto-groups as the previous subtest left them, so no group change and peerShouldReceiveUpdate(t, upd2)
// no IPv6 reconciliation interferes: the unblock alone drives the refresh. peerShouldNotReceiveUpdate(t, upd3)
_, err = manager.SaveUser(ctx, accountID, activity.SystemInitiator, &types.User{
Id: targetUserID, AccountID: accountID, Role: types.UserRoleUser,
AutoGroups: []string{"ug-linked", "ug-v6"}, Name: "renamed",
}) })
require.NoError(t, err)
peerShouldReceiveUpdate(t, upd2)
peerShouldNotReceiveUpdate(t, upd3)
}) })
} }
+9 -3
View File
@@ -88,7 +88,8 @@ 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}
} }
+144 -140
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,163 +363,167 @@ func initTestDNSAccount(t *testing.T, am *DefaultAccountManager) (*types.Account
} }
func TestDNSAccountPeersUpdate(t *testing.T) { func TestDNSAccountPeersUpdate(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) runPeerUpdateTest(t, func(t *testing.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{
{ {
ID: "groupA", ID: "groupA",
Name: "GroupA", Name: "GroupA",
Peers: []string{}, Peers: []string{},
}, },
{ {
ID: "groupB", ID: "groupB",
Name: "GroupB", Name: "GroupB",
Peers: []string{}, Peers: []string{},
}, },
})
assert.NoError(t, err)
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1.ID)
})
// 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) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
DisabledManagementGroups: []string{"groupA"},
}) })
assert.NoError(t, err) assert.NoError(t, err)
select { updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
case <-done: t.Cleanup(func() {
case <-time.After(time.Second): updateManager.CloseChannel(context.Background(), peer1.ID)
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// 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) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
_, err = manager.CreateNameServerGroup(
context.Background(), account.Id, "ns-group", "ns-group", []nbdns.NameServer{{
IP: netip.MustParseAddr(peer1.IP.String()),
NSType: nbdns.UDPNameServerType,
Port: nbdns.DefaultDNSPort,
}},
[]string{"groupB"},
true, []string{}, true, userID, false,
)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// 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) {
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupA",
Name: "GroupA",
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
}) })
assert.NoError(t, err)
done := make(chan struct{}) // Saving DNS settings with groups that have no peers should not trigger updates to account peers or send peer updates
go func() { step(t, "saving dns setting with unused groups", func(t *testing.T) {
peerShouldReceiveUpdate(t, updMsg) settleAffectedUpdates(updMsg)
close(done)
}()
_, err = manager.CreateNameServerGroup( done := make(chan struct{})
context.Background(), account.Id, "ns-group-1", "ns-group-1", []nbdns.NameServer{{ go func() {
IP: netip.MustParseAddr(peer1.IP.String()), peerShouldNotReceiveUpdate(t, updMsg)
NSType: nbdns.UDPNameServerType, close(done)
Port: nbdns.DefaultDNSPort, }()
}},
[]string{"groupA"},
true, []string{}, true, userID, false,
)
assert.NoError(t, err)
select { err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
case <-done: DisabledManagementGroups: []string{"groupA"},
case <-time.After(peerUpdateTimeout): })
t.Error("timeout waiting for peerShouldReceiveUpdate") assert.NoError(t, err)
}
})
// Saving DNS settings with groups that have peers should update account peers and send peer update select {
t.Run("saving dns setting with used groups", func(t *testing.T) { case <-done:
done := make(chan struct{}) case <-time.After(time.Second):
go func() { t.Error("timeout waiting for peerShouldNotReceiveUpdate")
peerShouldReceiveUpdate(t, updMsg) }
close(done)
}()
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
DisabledManagementGroups: []string{"groupA", "groupB"},
}) })
assert.NoError(t, err)
select { // Creating DNS settings with groups that have no peers should not update account peers or send peer update
case <-done: step(t, "creating dns setting with unused groups", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): done := make(chan struct{})
t.Error("timeout waiting for peerShouldReceiveUpdate") go func() {
} peerShouldNotReceiveUpdate(t, updMsg)
}) close(done)
}()
// Removing group with no peers from DNS settings should not trigger updates to account peers or send peer updates _, err = manager.CreateNameServerGroup(
t.Run("removing group with no peers from dns settings", func(t *testing.T) { context.Background(), account.Id, "ns-group", "ns-group", []nbdns.NameServer{{
done := make(chan struct{}) IP: netip.MustParseAddr(peer1.IP.String()),
go func() { NSType: nbdns.UDPNameServerType,
peerShouldNotReceiveUpdate(t, updMsg) Port: nbdns.DefaultDNSPort,
close(done) }},
}() []string{"groupB"},
true, []string{}, true, userID, false,
)
assert.NoError(t, err)
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{ select {
DisabledManagementGroups: []string{"groupA"}, case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
}) })
assert.NoError(t, err)
select { // Creating DNS settings with groups that have peers should update account peers and send peer update
case <-done: step(t, "creating dns setting with used groups", func(t *testing.T) {
case <-time.After(time.Second): err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
t.Error("timeout waiting for peerShouldNotReceiveUpdate") ID: "groupA",
} Name: "GroupA",
}) Peers: []string{peer1.ID, peer2.ID, peer3.ID},
})
assert.NoError(t, err)
// Removing group with peers from DNS settings should trigger updates to account peers and send peer updates done := make(chan struct{})
t.Run("removing group with peers from dns settings", func(t *testing.T) { go func() {
done := make(chan struct{}) peerShouldReceiveUpdate(t, updMsg)
go func() { close(done)
peerShouldReceiveUpdate(t, updMsg) }()
close(done)
}()
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{ _, err = manager.CreateNameServerGroup(
DisabledManagementGroups: []string{}, context.Background(), account.Id, "ns-group-1", "ns-group-1", []nbdns.NameServer{{
IP: netip.MustParseAddr(peer1.IP.String()),
NSType: nbdns.UDPNameServerType,
Port: nbdns.DefaultDNSPort,
}},
[]string{"groupA"},
true, []string{}, true, userID, false,
)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
}) })
assert.NoError(t, err)
select { // Saving DNS settings with groups that have peers should update account peers and send peer update
case <-done: step(t, "saving dns setting with used groups", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): done := make(chan struct{})
t.Error("timeout waiting for peerShouldReceiveUpdate") go func() {
} peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
DisabledManagementGroups: []string{"groupA", "groupB"},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Removing group with no peers from DNS settings should not trigger updates to account peers or send peer updates
step(t, "removing group with no peers from dns settings", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
DisabledManagementGroups: []string{"groupA"},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Removing group with peers from DNS settings should trigger updates to account peers and send peer updates
step(t, "removing group with peers from dns settings", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
DisabledManagementGroups: []string{},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
}) })
} }
+331 -304
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,342 +686,368 @@ func initTestGroupAccount(am *DefaultAccountManager) (*DefaultAccountManager, *t
} }
func TestGroupAccountPeersUpdate(t *testing.T) { func TestGroupAccountPeersUpdate(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
g := []*types.Group{ g := []*types.Group{
{
ID: "groupA",
Name: "GroupA",
Peers: []string{peer1.ID, peer2.ID},
},
{
ID: "groupB",
Name: "GroupB",
Peers: []string{},
},
{
ID: "groupC",
Name: "GroupC",
Peers: []string{peer1.ID, peer3.ID},
},
{
ID: "groupD",
Name: "GroupD",
Peers: []string{},
},
{
ID: "groupE",
Name: "GroupE",
Peers: []string{peer2.ID},
},
}
for _, group := range g {
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
assert.NoError(t, err)
}
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1.ID)
})
// Saving a group that is not linked to any resource should not update account peers
t.Run("saving unlinked group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupB",
Name: "GroupB",
Peers: []string{peer1.ID, peer2.ID},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Adding a peer to a group that is not linked to any resource should not update account peers
// and not send peer update
t.Run("adding peer to unlinked group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.GroupAddPeer(context.Background(), account.Id, "groupB", peer3.ID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Removing a peer from a group that is not linked to any resource should not update account peers
// and not send peer update
t.Run("removing peer from unliked group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.GroupDeletePeer(context.Background(), account.Id, "groupB", peer3.ID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Deleting group should not update account peers and not send peer update
t.Run("deleting group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeleteGroup(context.Background(), account.Id, userID, "groupB")
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// adding a group to policy
_, err := manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
Enabled: true,
Rules: []*types.PolicyRule{
{ {
Enabled: true, ID: "groupA",
Sources: []string{"groupA"}, Name: "GroupA",
Destinations: []string{"groupA"}, Peers: []string{peer1.ID, peer2.ID},
Bidirectional: true, },
Action: types.PolicyTrafficActionAccept, {
ID: "groupB",
Name: "GroupB",
Peers: []string{},
},
{
ID: "groupC",
Name: "GroupC",
Peers: []string{peer1.ID, peer3.ID},
},
{
ID: "groupD",
Name: "GroupD",
Peers: []string{},
},
{
ID: "groupE",
Name: "GroupE",
Peers: []string{peer2.ID},
}, },
},
}, true)
assert.NoError(t, err)
// 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) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupA",
Name: "GroupA",
Peers: []string{peer1.ID, peer2.ID},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
}) for _, group := range g {
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
// adding peer to a used group should update account peers and send peer update assert.NoError(t, err)
t.Run("adding peer to linked group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.GroupAddPeer(context.Background(), account.Id, "groupA", peer3.ID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
})
// removing peer from a linked group should update account peers and send peer update updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Run("removing peer from linked group", func(t *testing.T) { t.Cleanup(func() {
done := make(chan struct{}) updateManager.CloseChannel(context.Background(), peer1.ID)
go func() { })
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.GroupDeletePeer(context.Background(), account.Id, "groupA", peer3.ID) // Saving a group that is not linked to any resource should not update account peers
step(t, "saving unlinked group", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupB",
Name: "GroupB",
Peers: []string{peer1.ID, peer2.ID},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Adding a peer to a group that is not linked to any resource should not update account peers
// and not send peer update
step(t, "adding peer to unlinked group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.GroupAddPeer(context.Background(), account.Id, "groupB", peer3.ID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Removing a peer from a group that is not linked to any resource should not update account peers
// and not send peer update
step(t, "removing peer from unliked group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.GroupDeletePeer(context.Background(), account.Id, "groupB", peer3.ID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Deleting group should not update account peers and not send peer update
step(t, "deleting group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeleteGroup(context.Background(), account.Id, userID, "groupB")
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// adding a group to policy
_, err := manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupA"},
Destinations: []string{"groupA"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
}, true)
assert.NoError(t, err) assert.NoError(t, err)
select { // Saving a group linked to policy should update account peers and send peer update
case <-done: step(t, "saving linked group to policy", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): settleAffectedUpdates(updMsg)
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Saving a group linked to name server group should update account peers and send peer update done := make(chan struct{})
t.Run("saving group linked to name server group", func(t *testing.T) { go func() {
_, err = manager.CreateNameServerGroup( peerShouldReceiveUpdate(t, updMsg)
context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{ close(done)
IP: netip.MustParseAddr("1.1.1.1"), }()
NSType: nbdns.UDPNameServerType,
Port: nbdns.DefaultDNSPort,
}},
[]string{"groupC"},
true, nil, true, userID, false,
)
assert.NoError(t, err)
done := make(chan struct{}) err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
go func() { ID: "groupA",
peerShouldReceiveUpdate(t, updMsg) Name: "GroupA",
close(done) Peers: []string{peer1.ID, peer2.ID},
}() })
assert.NoError(t, err)
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{ select {
ID: "groupC", case <-done:
Name: "GroupC", case <-time.After(peerUpdateTimeout):
Peers: []string{peer1.ID, peer3.ID}, t.Error("timeout waiting for peerShouldReceiveUpdate")
}
}) })
assert.NoError(t, err)
select { // adding peer to a used group should update account peers and send peer update
case <-done: step(t, "adding peer to linked group", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): done := make(chan struct{})
t.Error("timeout waiting for peerShouldReceiveUpdate") go func() {
} peerShouldReceiveUpdate(t, updMsg)
}) close(done)
}()
// Saving a group linked to route should update account peers and send peer update err := manager.GroupAddPeer(context.Background(), account.Id, "groupA", peer3.ID)
t.Run("saving group linked to route", func(t *testing.T) { assert.NoError(t, err)
newRoute := route.Route{
ID: "route",
Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: "superNet",
NetworkType: route.IPv4Network,
PeerGroups: []string{"groupA"},
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{"groupC"},
}
_, err := manager.CreateRoute(
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, newRoute.SkipAutoApply,
)
require.NoError(t, err)
done := make(chan struct{}) select {
go func() { case <-done:
peerShouldReceiveUpdate(t, updMsg) case <-time.After(peerUpdateTimeout):
close(done) t.Error("timeout waiting for peerShouldReceiveUpdate")
}() }
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupA",
Name: "GroupA",
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
}) })
assert.NoError(t, err)
select { // removing peer from a linked group should update account peers and send peer update
case <-done: step(t, "removing peer from linked group", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): done := make(chan struct{})
t.Error("timeout waiting for peerShouldReceiveUpdate") go func() {
} peerShouldReceiveUpdate(t, updMsg)
}) close(done)
}()
// Saving a group linked to dns settings should update account peers and send peer update err := manager.GroupDeletePeer(context.Background(), account.Id, "groupA", peer3.ID)
t.Run("saving group linked to dns settings", func(t *testing.T) { assert.NoError(t, err)
err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
DisabledManagementGroups: []string{"groupD"}, select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
}) })
assert.NoError(t, err)
done := make(chan struct{}) // Saving a group linked to name server group should update account peers and send peer update
go func() { step(t, "saving group linked to name server group", func(t *testing.T) {
peerShouldReceiveUpdate(t, updMsg) _, err = manager.CreateNameServerGroup(
close(done) context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{
}() IP: netip.MustParseAddr("1.1.1.1"),
NSType: nbdns.UDPNameServerType,
Port: nbdns.DefaultDNSPort,
}},
[]string{"groupC"},
true, nil, true, userID, false,
)
assert.NoError(t, err)
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{ settleAffectedUpdates(updMsg)
ID: "groupD",
Name: "GroupD", done := make(chan struct{})
Peers: []string{peer1.ID}, go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupC",
Name: "GroupC",
Peers: []string{peer1.ID, peer3.ID},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
}) })
assert.NoError(t, err)
select { // Saving a group linked to route should update account peers and send peer update
case <-done: step(t, "saving group linked to route", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): newRoute := route.Route{
t.Error("timeout waiting for peerShouldReceiveUpdate") ID: "route",
} Network: netip.MustParsePrefix("192.168.0.0/16"),
}) NetID: "superNet",
NetworkType: route.IPv4Network,
PeerGroups: []string{"groupA"},
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{"groupC"},
}
_, err := manager.CreateRoute(
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, newRoute.SkipAutoApply,
)
require.NoError(t, err)
// Saving a group linked to network router should update account peers and send peer update settleAffectedUpdates(updMsg)
t.Run("saving group linked to network router", func(t *testing.T) {
permissionsManager := permissions.NewManager(manager.Store)
groupsManager := groups.NewManager(manager.Store, permissionsManager, manager)
resourcesManager := resources.NewManager(manager.Store, permissionsManager, groupsManager, manager, manager.serviceManager)
routersManager := routers.NewManager(manager.Store, permissionsManager, manager)
networksManager := networks.NewManager(manager.Store, permissionsManager, resourcesManager, routersManager, manager)
network, err := networksManager.CreateNetwork(context.Background(), userID, &networkTypes.Network{ done := make(chan struct{})
ID: "network_test", go func() {
AccountID: account.Id, peerShouldReceiveUpdate(t, updMsg)
Name: "network_test", close(done)
Description: "", }()
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupA",
Name: "GroupA",
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
}) })
require.NoError(t, err)
_, err = routersManager.CreateRouter(context.Background(), userID, &routerTypes.NetworkRouter{ // Saving a group linked to dns settings should update account peers and send peer update
ID: "router_test", step(t, "saving group linked to dns settings", func(t *testing.T) {
NetworkID: network.ID, err := manager.SaveDNSSettings(context.Background(), account.Id, userID, &types.DNSSettings{
AccountID: account.Id, DisabledManagementGroups: []string{"groupD"},
PeerGroups: []string{"groupE"}, })
Masquerade: true, assert.NoError(t, err)
Metric: 9999,
Enabled: true, settleAffectedUpdates(updMsg)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupD",
Name: "GroupD",
Peers: []string{peer1.ID},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
}) })
require.NoError(t, err)
done := make(chan struct{}) // Saving a group linked to network router should update account peers and send peer update
go func() { step(t, "saving group linked to network router", func(t *testing.T) {
peerShouldReceiveUpdate(t, updMsg) permissionsManager := permissions.NewManager(manager.Store)
close(done) groupsManager := groups.NewManager(manager.Store, permissionsManager, manager)
}() resourcesManager := resources.NewManager(manager.Store, permissionsManager, groupsManager, manager, manager.serviceManager)
routersManager := routers.NewManager(manager.Store, permissionsManager, manager)
networksManager := networks.NewManager(manager.Store, permissionsManager, resourcesManager, routersManager, manager)
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{ network, err := networksManager.CreateNetwork(context.Background(), userID, &networkTypes.Network{
ID: "groupE", ID: "network_test",
Name: "GroupE", AccountID: account.Id,
Peers: []string{peer2.ID, peer3.ID}, Name: "network_test",
Description: "",
})
require.NoError(t, err)
_, err = routersManager.CreateRouter(context.Background(), userID, &routerTypes.NetworkRouter{
ID: "router_test",
NetworkID: network.ID,
AccountID: account.Id,
PeerGroups: []string{"groupE"},
Masquerade: true,
Metric: 9999,
Enabled: true,
})
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{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupE",
Name: "GroupE",
Peers: []string{peer2.ID, peer3.ID},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
}) })
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
}) })
} }
+132 -128
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,147 +966,151 @@ func TestValidateDomain(t *testing.T) {
} }
func TestNameServerAccountPeersUpdate(t *testing.T) { func TestNameServerAccountPeersUpdate(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
var newNameServerGroupA *nbdns.NameServerGroup var newNameServerGroupA *nbdns.NameServerGroup
var newNameServerGroupB *nbdns.NameServerGroup var newNameServerGroupB *nbdns.NameServerGroup
err := manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{ err := manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupA", ID: "groupA",
Name: "GroupA", Name: "GroupA",
Peers: []string{}, Peers: []string{},
}) })
assert.NoError(t, err)
err = manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupB",
Name: "GroupB",
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
})
assert.NoError(t, err)
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1.ID)
})
// Creating a nameserver group with a distribution group no peers should not update account peers
// and not send peer update
t.Run("creating nameserver group with distribution group no peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
newNameServerGroupA, err = manager.CreateNameServerGroup(
context.Background(), account.Id, "nsGroupA", "nsGroupA", []nbdns.NameServer{{
IP: netip.MustParseAddr("1.1.1.1"),
NSType: nbdns.UDPNameServerType,
Port: nbdns.DefaultDNSPort,
}},
[]string{"groupA"},
true, []string{}, true, userID, false,
)
assert.NoError(t, err) assert.NoError(t, err)
select { err = manager.CreateGroup(context.Background(), account.Id, userID, &types.Group{
case <-done: ID: "groupB",
case <-time.After(time.Second): Name: "GroupB",
t.Error("timeout waiting for peerShouldNotReceiveUpdate") Peers: []string{peer1.ID, peer2.ID, peer3.ID},
} })
})
// saving a nameserver group with a distribution group with no peers should not update account peers
// and not send peer update
t.Run("saving nameserver group with distribution group no peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.SaveNameServerGroup(context.Background(), account.Id, userID, newNameServerGroupA)
assert.NoError(t, err) assert.NoError(t, err)
select { updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
case <-done: t.Cleanup(func() {
case <-time.After(time.Second): updateManager.CloseChannel(context.Background(), peer1.ID)
t.Error("timeout waiting for peerShouldNotReceiveUpdate") })
}
})
// 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 not update account peers
t.Run("creating nameserver group with distribution group has peers", func(t *testing.T) { // and not send peer update
done := make(chan struct{}) step(t, "creating nameserver group with distribution group no peers", func(t *testing.T) {
go func() { settleAffectedUpdates(updMsg)
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
newNameServerGroupB, err = manager.CreateNameServerGroup( done := make(chan struct{})
context.Background(), account.Id, "nsGroupB", "nsGroupB", []nbdns.NameServer{{ go func() {
IP: netip.MustParseAddr("1.1.1.1"), peerShouldNotReceiveUpdate(t, updMsg)
NSType: nbdns.UDPNameServerType, close(done)
Port: nbdns.DefaultDNSPort, }()
}},
[]string{"groupB"},
true, []string{}, true, userID, false,
)
assert.NoError(t, err)
select { newNameServerGroupA, err = manager.CreateNameServerGroup(
case <-done: context.Background(), account.Id, "nsGroupA", "nsGroupA", []nbdns.NameServer{{
case <-time.After(time.Second): IP: netip.MustParseAddr("1.1.1.1"),
t.Error("timeout waiting for peerShouldNotReceiveUpdate") NSType: nbdns.UDPNameServerType,
} Port: nbdns.DefaultDNSPort,
}) }},
[]string{"groupA"},
true, []string{}, true, userID, false,
)
assert.NoError(t, err)
// saving a nameserver group with a distribution group with peers should update account peers and send peer update select {
t.Run("saving nameserver group with distribution group has peers", func(t *testing.T) { case <-done:
done := make(chan struct{}) case <-time.After(time.Second):
go func() { t.Error("timeout waiting for peerShouldNotReceiveUpdate")
peerShouldReceiveUpdate(t, updMsg) }
close(done) })
}()
newNameServerGroupB.NameServers = []nbdns.NameServer{ // saving a nameserver group with a distribution group with no peers should not update account peers
{ // and not send peer update
IP: netip.MustParseAddr("1.1.1.2"), step(t, "saving nameserver group with distribution group no peers", func(t *testing.T) {
NSType: nbdns.UDPNameServerType, done := make(chan struct{})
Port: nbdns.DefaultDNSPort, go func() {
}, peerShouldNotReceiveUpdate(t, updMsg)
{ close(done)
IP: netip.MustParseAddr("8.8.8.8"), }()
NSType: nbdns.UDPNameServerType,
Port: nbdns.DefaultDNSPort,
},
}
err = manager.SaveNameServerGroup(context.Background(), account.Id, userID, newNameServerGroupB)
assert.NoError(t, err)
select { err = manager.SaveNameServerGroup(context.Background(), account.Id, userID, newNameServerGroupA)
case <-done: assert.NoError(t, err)
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Deleting a nameserver group should update account peers and send peer update select {
t.Run("deleting nameserver group", func(t *testing.T) { case <-done:
done := make(chan struct{}) case <-time.After(time.Second):
go func() { t.Error("timeout waiting for peerShouldNotReceiveUpdate")
peerShouldReceiveUpdate(t, updMsg) }
close(done) })
}()
err = manager.DeleteNameServerGroup(context.Background(), account.Id, newNameServerGroupB.ID, userID) // Creating a nameserver group with a distribution group no peers should update account peers and send peer update
assert.NoError(t, err) step(t, "creating nameserver group with distribution group has peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
select { newNameServerGroupB, err = manager.CreateNameServerGroup(
case <-done: context.Background(), account.Id, "nsGroupB", "nsGroupB", []nbdns.NameServer{{
case <-time.After(peerUpdateTimeout): IP: netip.MustParseAddr("1.1.1.1"),
t.Error("timeout waiting for peerShouldReceiveUpdate") NSType: nbdns.UDPNameServerType,
} Port: nbdns.DefaultDNSPort,
}},
[]string{"groupB"},
true, []string{}, true, userID, false,
)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// saving a nameserver group with a distribution group with peers should update account peers and send peer update
step(t, "saving nameserver group with distribution group has peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
newNameServerGroupB.NameServers = []nbdns.NameServer{
{
IP: netip.MustParseAddr("1.1.1.2"),
NSType: nbdns.UDPNameServerType,
Port: nbdns.DefaultDNSPort,
},
{
IP: netip.MustParseAddr("8.8.8.8"),
NSType: nbdns.UDPNameServerType,
Port: nbdns.DefaultDNSPort,
},
}
err = manager.SaveNameServerGroup(context.Background(), account.Id, userID, newNameServerGroupB)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Deleting a nameserver group should update account peers and send peer update
step(t, "deleting nameserver group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.DeleteNameServerGroup(context.Background(), account.Id, newNameServerGroupB.ID, userID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
}) })
} }
+330 -366
View File
@@ -1844,374 +1844,336 @@ func Test_LoginPeer(t *testing.T) {
} }
func TestPeerAccountPeersUpdate(t *testing.T) { func TestPeerAccountPeersUpdate(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) runPeerUpdateTest(t, func(t *testing.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)
require.NoError(t, err)
g := []*types.Group{
{
ID: "groupA",
Name: "GroupA",
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
},
{
ID: "groupB",
Name: "GroupB",
Peers: []string{},
},
{
ID: "groupC",
Name: "GroupC",
Peers: []string{},
},
}
for _, group := range g {
err = manager.CreateGroup(context.Background(), account.Id, userID, group)
require.NoError(t, err)
}
// create a user with auto groups
_, err = manager.SaveOrAddUsers(context.Background(), account.Id, userID, []*types.User{
{
Id: "regularUser1",
AccountID: account.Id,
Role: types.UserRoleAdmin,
Issued: types.UserIssuedAPI,
AutoGroups: []string{"groupA"},
},
{
Id: "regularUser2",
AccountID: account.Id,
Role: types.UserRoleAdmin,
Issued: types.UserIssuedAPI,
AutoGroups: []string{"groupB"},
},
{
Id: "regularUser3",
AccountID: account.Id,
Role: types.UserRoleAdmin,
Issued: types.UserIssuedAPI,
AutoGroups: []string{"groupC"},
},
}, true)
require.NoError(t, err)
var peer4 *nbpeer.Peer
var peer5 *nbpeer.Peer
var peer6 *nbpeer.Peer
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Cleanup(func() {
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) require.NoError(t, err)
select { g := []*types.Group{
case <-done: {
case <-time.After(time.Second): ID: "groupA",
t.Error("timeout waiting for peerShouldNotReceiveUpdate") Name: "GroupA",
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
},
{
ID: "groupB",
Name: "GroupB",
Peers: []string{},
},
{
ID: "groupC",
Name: "GroupC",
Peers: []string{},
},
} }
}) for _, group := range g {
err = manager.CreateGroup(context.Background(), account.Id, userID, group)
// Adding peer to unlinked group should not update account peers and not send peer update require.NoError(t, err)
t.Run("adding peer to unlinked group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
key, err := wgtypes.GeneratePrivateKey()
require.NoError(t, err)
expectedPeerKey := key.PublicKey().String()
peer4, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
Key: expectedPeerKey,
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
}, false)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// 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) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.DeletePeer(context.Background(), account.Id, peer4.ID, userID)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Updating peer label should update account peers and send peer update
t.Run("updating peer label", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
peer1.Name = "peer-1"
_, err = manager.UpdatePeer(context.Background(), account.Id, userID, peer1)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
t.Run("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) {
return update, true, nil
} }
manager.integratedPeerValidator = MockIntegratedValidator{ValidatePeerFunc: requireUpdateFunc} // create a user with auto groups
done := make(chan struct{}) _, err = manager.SaveOrAddUsers(context.Background(), account.Id, userID, []*types.User{
go func() { {
peerShouldReceiveUpdate(t, updMsg) Id: "regularUser1",
close(done) AccountID: account.Id,
}() Role: types.UserRoleAdmin,
Issued: types.UserIssuedAPI,
_, err = manager.UpdatePeer(context.Background(), account.Id, userID, peer1) AutoGroups: []string{"groupA"},
require.NoError(t, err) },
{
select { Id: "regularUser2",
case <-done: AccountID: account.Id,
case <-time.After(peerUpdateTimeout): Role: types.UserRoleAdmin,
t.Error("timeout waiting for peerShouldReceiveUpdate") Issued: types.UserIssuedAPI,
} AutoGroups: []string{"groupB"},
}) },
{
t.Run("validator requires no update", func(t *testing.T) { Id: "regularUser3",
t.Skip("Currently all updates will trigger a network map") AccountID: account.Id,
Role: types.UserRoleAdmin,
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) { Issued: types.UserIssuedAPI,
return update, false, nil AutoGroups: []string{"groupC"},
}
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
t.Run("adding peer to group linked with policy", func(t *testing.T) {
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
AccountID: account.Id,
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupA"},
Destinations: []string{"groupA"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
}, },
}, true) }, true)
require.NoError(t, err) require.NoError(t, err)
done := make(chan struct{}) var peer4 *nbpeer.Peer
go func() { var peer5 *nbpeer.Peer
peerShouldReceiveUpdate(t, updMsg) var peer6 *nbpeer.Peer
close(done)
}()
key, err := wgtypes.GeneratePrivateKey() updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
require.NoError(t, err) t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1.ID)
})
expectedPeerKey := key.PublicKey().String() // Adding peer to unlinked group should not update account peers and not send peer update
peer4, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{ step(t, "adding peer to unlinked group", func(t *testing.T) {
Key: expectedPeerKey, settleAffectedUpdates(updMsg)
LoginExpirationEnabled: true, done := make(chan struct{})
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey}, go func() {
}, false) peerShouldNotReceiveUpdate(t, updMsg)
require.NoError(t, err) close(done)
}()
select { key, err := wgtypes.GeneratePrivateKey()
case <-done: require.NoError(t, err)
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Deleting peer with linked group to policy should update account peers and send peer update expectedPeerKey := key.PublicKey().String()
t.Run("deleting peer with linked group to policy", func(t *testing.T) { peer4, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
done := make(chan struct{}) Key: expectedPeerKey,
go func() { Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
peerShouldReceiveUpdate(t, updMsg) }, false)
close(done) require.NoError(t, err)
}()
err = manager.DeletePeer(context.Background(), account.Id, peer4.ID, userID) select {
require.NoError(t, err) case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
select { // Deleting peer with unlinked group should not update account peers and not send peer update
case <-done: step(t, "deleting peer with unlinked group", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): done := make(chan struct{})
t.Error("timeout waiting for peerShouldReceiveUpdate") go func() {
} peerShouldNotReceiveUpdate(t, updMsg)
}) close(done)
}()
// drain any buffered updates from previous subtests err = manager.DeletePeer(context.Background(), account.Id, peer4.ID, userID)
drainPeerUpdates(updMsg) require.NoError(t, err)
// Adding peer to group linked with route should update peers in that group, not unrelated peers select {
t.Run("adding peer to group linked with route", func(t *testing.T) { case <-done:
route := nbroute.Route{ case <-time.After(time.Second):
ID: "testingRoute1", t.Error("timeout waiting for peerShouldNotReceiveUpdate")
Network: netip.MustParsePrefix("100.65.250.202/32"), }
NetID: "superNet", })
NetworkType: nbroute.IPv4Network,
PeerGroups: []string{"groupB"},
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{"groupB"},
}
_, err := manager.CreateRoute( // Updating peer label should update account peers and send peer update
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer, step(t, "updating peer label", func(t *testing.T) {
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric, done := make(chan struct{})
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply, go func() {
) peerShouldReceiveUpdate(t, updMsg)
require.NoError(t, err) close(done)
}()
done := make(chan struct{}) peer1.Name = "peer-1"
go func() { _, err = manager.UpdatePeer(context.Background(), account.Id, userID, peer1)
peerShouldNotReceiveUpdate(t, updMsg) require.NoError(t, err)
close(done)
}()
key, err := wgtypes.GeneratePrivateKey() select {
require.NoError(t, err) case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
expectedPeerKey := key.PublicKey().String() step(t, "validator requires update", func(t *testing.T) {
peer5, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{ 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) {
Key: expectedPeerKey, return update, true, nil
LoginExpirationEnabled: true, }
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
}, false)
require.NoError(t, err)
select { manager.integratedPeerValidator = MockIntegratedValidator{ValidatePeerFunc: requireUpdateFunc}
case <-done: done := make(chan struct{})
case <-time.After(time.Second): go func() {
t.Error("timeout waiting for peerShouldNotReceiveUpdate") peerShouldReceiveUpdate(t, updMsg)
} close(done)
}) }()
// Deleting peer with linked group to route should update peers in that group, not unrelated peers _, err = manager.UpdatePeer(context.Background(), account.Id, userID, peer1)
t.Run("deleting peer with linked group to route", func(t *testing.T) { require.NoError(t, err)
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.DeletePeer(context.Background(), account.Id, peer5.ID, userID) select {
require.NoError(t, err) case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
select { // Adding peer to group linked with policy should update account peers and send peer update
case <-done: step(t, "adding peer to group linked with policy", func(t *testing.T) {
case <-time.After(time.Second): _, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
t.Error("timeout waiting for peerShouldNotReceiveUpdate") AccountID: account.Id,
} Enabled: true,
}) Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupA"},
Destinations: []string{"groupA"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
}, true)
require.NoError(t, err)
// Adding peer to group linked with name server group should update peers in that group, not unrelated peers done := make(chan struct{})
t.Run("adding peer to group linked with name server group", func(t *testing.T) { go func() {
_, err = manager.CreateNameServerGroup( peerShouldReceiveUpdate(t, updMsg)
context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{ close(done)
IP: netip.MustParseAddr("1.1.1.1"), }()
NSType: nbdns.UDPNameServerType,
Port: nbdns.DefaultDNSPort,
}},
[]string{"groupC"},
true, []string{}, true, userID, false,
)
require.NoError(t, err)
done := make(chan struct{}) key, err := wgtypes.GeneratePrivateKey()
go func() { require.NoError(t, err)
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
key, err := wgtypes.GeneratePrivateKey() expectedPeerKey := key.PublicKey().String()
require.NoError(t, err) peer4, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser1", &nbpeer.Peer{
Key: expectedPeerKey,
LoginExpirationEnabled: true,
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
}, false)
require.NoError(t, err)
expectedPeerKey := key.PublicKey().String() select {
peer6, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser3", &nbpeer.Peer{ case <-done:
Key: expectedPeerKey, case <-time.After(peerUpdateTimeout):
LoginExpirationEnabled: true, t.Error("timeout waiting for peerShouldReceiveUpdate")
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey}, }
}, false) })
require.NoError(t, err)
select { // Deleting peer with linked group to policy should update account peers and send peer update
case <-done: step(t, "deleting peer with linked group to policy", func(t *testing.T) {
case <-time.After(time.Second): done := make(chan struct{})
t.Error("timeout waiting for peerShouldNotReceiveUpdate") go func() {
} peerShouldReceiveUpdate(t, updMsg)
}) close(done)
}()
// Deleting peer with linked group to name server group should update peers in that group, not unrelated peers err = manager.DeletePeer(context.Background(), account.Id, peer4.ID, userID)
t.Run("deleting peer with linked group to route", func(t *testing.T) { require.NoError(t, err)
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.DeletePeer(context.Background(), account.Id, peer6.ID, userID) select {
require.NoError(t, err) case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
select { // drain any buffered updates from previous subtests
case <-done: drainPeerUpdates(updMsg)
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate") // Adding peer to group linked with route should update peers in that group, not unrelated peers
} step(t, "adding peer to group linked with route", func(t *testing.T) {
route := nbroute.Route{
ID: "testingRoute1",
Network: netip.MustParsePrefix("100.65.250.202/32"),
NetID: "superNet",
NetworkType: nbroute.IPv4Network,
PeerGroups: []string{"groupB"},
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{"groupB"},
}
_, err := manager.CreateRoute(
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
)
require.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
key, err := wgtypes.GeneratePrivateKey()
require.NoError(t, err)
expectedPeerKey := key.PublicKey().String()
peer5, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{
Key: expectedPeerKey,
LoginExpirationEnabled: true,
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
}, false)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Deleting peer with linked group to route should update peers in that group, not unrelated peers
step(t, "deleting peer with linked group to route", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.DeletePeer(context.Background(), account.Id, peer5.ID, userID)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Adding peer to group linked with name server group should update peers in that group, not unrelated peers
step(t, "adding peer to group linked with name server group", func(t *testing.T) {
_, err = manager.CreateNameServerGroup(
context.Background(), account.Id, "nsGroup", "nsGroup", []nbdns.NameServer{{
IP: netip.MustParseAddr("1.1.1.1"),
NSType: nbdns.UDPNameServerType,
Port: nbdns.DefaultDNSPort,
}},
[]string{"groupC"},
true, []string{}, true, userID, false,
)
require.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
key, err := wgtypes.GeneratePrivateKey()
require.NoError(t, err)
expectedPeerKey := key.PublicKey().String()
peer6, _, _, _, err = manager.AddPeer(context.Background(), "", "", "regularUser3", &nbpeer.Peer{
Key: expectedPeerKey,
LoginExpirationEnabled: true,
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
}, false)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Deleting peer with linked group to name server group should update peers in that group, not unrelated peers
step(t, "deleting peer with linked group to name server group", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.DeletePeer(context.Background(), account.Id, peer6.ID, userID)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
}) })
} }
@@ -2859,45 +2821,47 @@ 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) {
manager, updateManager, _, peer1, peer2, _ := setupNetworkMapTest(t) runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, _, peer1, peer2, _ := setupNetworkMapTest(t)
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID) updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Cleanup(func() { t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1.ID) updateManager.CloseChannel(context.Background(), peer1.ID)
}) })
// Drain any initial updates from setup. // Drain any initial updates from setup.
drain := func() { drain := func() {
for { for {
select { select {
case <-updMsg: case <-updMsg:
case <-time.After(200 * time.Millisecond): case <-time.After(200 * time.Millisecond):
return return
}
} }
} }
} 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,
}, peer2.AccountID) }, peer2.AccountID)
require.NoError(t, err) require.NoError(t, err)
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)
_, _, _, _, err := manager.SyncPeer(context.Background(), types.PeerSync{ _, _, _, _, err := manager.SyncPeer(context.Background(), types.PeerSync{
WireGuardPubKey: peer2.Key, WireGuardPubKey: peer2.Key,
Meta: newMeta, Meta: newMeta,
}, peer2.AccountID) }, peer2.AccountID)
require.NoError(t, err) require.NoError(t, err)
peerShouldReceiveUpdate(t, updMsg) peerShouldReceiveUpdate(t, updMsg)
})
}) })
} }
+278 -274
View File
@@ -1135,287 +1135,291 @@ func sortFunc() func(a *types.FirewallRule, b *types.FirewallRule) int {
} }
func TestPolicyAccountPeersUpdate(t *testing.T) { func TestPolicyAccountPeersUpdate(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
g := []*types.Group{ g := []*types.Group{
{ {
ID: "groupA", ID: "groupA",
Name: "GroupA", Name: "GroupA",
Peers: []string{peer1.ID, peer3.ID}, Peers: []string{peer1.ID, peer3.ID},
},
{
ID: "groupB",
Name: "GroupB",
Peers: []string{},
},
{
ID: "groupC",
Name: "GroupC",
Peers: []string{},
},
{
ID: "groupD",
Name: "GroupD",
Peers: []string{peer1.ID, peer2.ID},
},
}
for _, group := range g {
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
assert.NoError(t, err)
}
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1.ID)
})
var policyWithGroupRulesNoPeers *types.Policy
var policyWithDestinationPeersOnly *types.Policy
var policyWithSourceAndDestinationPeers *types.Policy
var err error
// 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) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
policyWithGroupRulesNoPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
AccountID: account.Id,
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupB"},
Destinations: []string{"groupC"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
}, },
}, true) {
assert.NoError(t, err) ID: "groupB",
Name: "GroupB",
select { Peers: []string{},
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Saving policy with source group containing peers, but destination group without peers should
// update account's peers and send peer update
t.Run("saving policy where source has peers but destination does not", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
AccountID: account.Id,
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupA"},
Destinations: []string{"groupB"},
Protocol: types.PolicyRuleProtocolTCP,
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
}, },
}, true) {
assert.NoError(t, err) ID: "groupC",
Name: "GroupC",
select { Peers: []string{},
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Saving policy with destination group containing peers, but source group without peers should
// update account's peers and send peer update
t.Run("saving policy where destination has peers but source does not", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policyWithDestinationPeersOnly, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
AccountID: account.Id,
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupC"},
Destinations: []string{"groupD"},
Bidirectional: true,
Protocol: types.PolicyRuleProtocolTCP,
Action: types.PolicyTrafficActionAccept,
},
}, },
}, true) {
assert.NoError(t, err) ID: "groupD",
Name: "GroupD",
select { Peers: []string{peer1.ID, peer2.ID},
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Saving policy with destination and source groups containing peers should update account's peers
// and send peer update
t.Run("saving policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
AccountID: account.Id,
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupA"},
Destinations: []string{"groupD"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
}, },
}, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
}) for _, group := range g {
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
// Disabling policy with destination and source groups containing peers should update account's peers assert.NoError(t, err)
// and send peer update
t.Run("disabling policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policyWithSourceAndDestinationPeers.Enabled = false
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// 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
t.Run("updating disabled policy with source and destination groups with peers", func(t *testing.T) {
drainPeerUpdates(updMsg)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policyWithSourceAndDestinationPeers.Description = "updated description"
policyWithSourceAndDestinationPeers.Rules[0].Destinations = []string{"groupA"}
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Enabling policy with destination and source groups containing peers should update account's peers
// and send peer update
t.Run("enabling policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policyWithSourceAndDestinationPeers.Enabled = true
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// 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) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeletePolicy(context.Background(), account.Id, policyWithSourceAndDestinationPeers.ID, userID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1.ID)
})
var policyWithGroupRulesNoPeers *types.Policy
var policyWithDestinationPeersOnly *types.Policy
var policyWithSourceAndDestinationPeers *types.Policy
var err error
// Saving policy with rule groups with no peers should not update account's peers and not send peer update
step(t, "saving policy with rule groups with no peers", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
policyWithGroupRulesNoPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
AccountID: account.Id,
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupB"},
Destinations: []string{"groupC"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
}, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Saving policy with source group containing peers, but destination group without peers should
// update account's peers and send peer update
step(t, "saving policy where source has peers but destination does not", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
AccountID: account.Id,
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupA"},
Destinations: []string{"groupB"},
Protocol: types.PolicyRuleProtocolTCP,
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
}, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Saving policy with destination group containing peers, but source group without peers should
// update account's peers and send peer update
step(t, "saving policy where destination has peers but source does not", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policyWithDestinationPeersOnly, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
AccountID: account.Id,
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupC"},
Destinations: []string{"groupD"},
Bidirectional: true,
Protocol: types.PolicyRuleProtocolTCP,
Action: types.PolicyTrafficActionAccept,
},
},
}, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Saving policy with destination and source groups containing peers should update account's peers
// and send peer update
step(t, "saving policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
AccountID: account.Id,
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupA"},
Destinations: []string{"groupD"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
}, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Disabling policy with destination and source groups containing peers should update account's peers
// and send peer update
step(t, "disabling policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policyWithSourceAndDestinationPeers.Enabled = false
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// 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
step(t, "updating disabled policy with source and destination groups with peers", func(t *testing.T) {
drainPeerUpdates(updMsg)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policyWithSourceAndDestinationPeers.Description = "updated description"
policyWithSourceAndDestinationPeers.Rules[0].Destinations = []string{"groupA"}
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Enabling policy with destination and source groups containing peers should update account's peers
// and send peer update
step(t, "enabling policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policyWithSourceAndDestinationPeers.Enabled = true
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Deleting policy should trigger account peers update and send peer update
step(t, "deleting policy with source and destination groups with peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeletePolicy(context.Background(), account.Id, policyWithSourceAndDestinationPeers.ID, userID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Deleting policy with destination group containing peers, but source group without peers should
// update account's peers and send peer update
step(t, "deleting policy where destination has peers but source does not", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeletePolicy(context.Background(), account.Id, policyWithDestinationPeersOnly.ID, userID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Deleting policy with no peers in groups should not update account's peers and not send peer update
step(t, "deleting policy with no peers in groups", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeletePolicy(context.Background(), account.Id, policyWithGroupRulesNoPeers.ID, userID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
}) })
// Deleting policy with destination group containing peers, but source group without peers should
// update account's peers and send peer update
t.Run("deleting policy where destination has peers but source does not", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeletePolicy(context.Background(), account.Id, policyWithDestinationPeersOnly.ID, userID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// 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) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeletePolicy(context.Background(), account.Id, policyWithGroupRulesNoPeers.ID, userID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
} }
+298 -288
View File
@@ -123,324 +123,334 @@ func initTestPostureChecksAccount(am *DefaultAccountManager) (*types.Account, er
} }
func TestPostureCheckAccountPeersUpdate(t *testing.T) { func TestPostureCheckAccountPeersUpdate(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t)
g := []*types.Group{ g := []*types.Group{
{
ID: "groupA",
Name: "GroupA",
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
},
{
ID: "groupB",
Name: "GroupB",
Peers: []string{},
},
{
ID: "groupC",
Name: "GroupC",
Peers: []string{},
},
}
for _, group := range g {
err := manager.CreateGroup(context.Background(), account.Id, userID, group)
assert.NoError(t, err)
}
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1.ID)
})
postureCheckA := &posture.Checks{
Name: "postureCheckA",
AccountID: account.Id,
Checks: posture.ChecksDefinition{
ProcessCheck: &posture.ProcessCheck{
Processes: []posture.Process{
{LinuxPath: "/usr/bin/netbird", MacPath: "/usr/local/bin/netbird"},
},
},
},
}
postureCheckA, err := manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckA, true)
require.NoError(t, err)
postureCheckB := &posture.Checks{
Name: "postureCheckB",
AccountID: account.Id,
Checks: posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.28.0",
},
},
}
// Saving unused posture check should not update account peers and not send peer update
t.Run("saving unused posture check", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
postureCheckB, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Updating unused posture check should not update account peers and not send peer update
t.Run("updating unused posture check", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
postureCheckB.Checks = posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.29.0",
},
}
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
policy := &types.Policy{
Enabled: true,
Rules: []*types.PolicyRule{
{ {
Enabled: true, ID: "groupA",
Sources: []string{"groupA"}, Name: "GroupA",
Destinations: []string{"groupA"}, Peers: []string{peer1.ID, peer2.ID, peer3.ID},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
}, },
}, {
SourcePostureChecks: []string{postureCheckB.ID}, ID: "groupB",
} Name: "GroupB",
Peers: []string{},
// 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) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policy, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// 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) {
postureCheckB.Checks = posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.29.0",
}, },
ProcessCheck: &posture.ProcessCheck{ {
Processes: []posture.Process{ ID: "groupC",
{LinuxPath: "/usr/bin/netbird", MacPath: "/usr/local/bin/netbird"}, Name: "GroupC",
}, Peers: []string{},
}, },
} }
for _, group := range g {
done := make(chan struct{}) err := manager.CreateGroup(context.Background(), account.Id, userID, group)
go func() { assert.NoError(t, err)
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
} }
})
// Removing posture check from policy should trigger account peers update and send peer update updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Run("removing posture check from policy", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policy.SourcePostureChecks = []string{}
_, err := manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// 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) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeletePostureChecks(context.Background(), account.Id, postureCheckA.ID, userID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
// 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) {
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupB"},
Destinations: []string{"groupC"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
SourcePostureChecks: []string{postureCheckB.ID},
}, true)
assert.NoError(t, err)
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
postureCheckB.Checks = posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.29.0",
},
}
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Updating linked posture check to policy where destination has peers but source does not
// 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) {
updMsg1 := updateManager.CreateChannel(context.Background(), peer2.ID)
t.Cleanup(func() { t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer2.ID) updateManager.CloseChannel(context.Background(), peer1.ID)
}) })
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{ postureCheckA := &posture.Checks{
Name: "postureCheckA",
AccountID: account.Id,
Checks: posture.ChecksDefinition{
ProcessCheck: &posture.ProcessCheck{
Processes: []posture.Process{
{LinuxPath: "/usr/bin/netbird", MacPath: "/usr/local/bin/netbird"},
},
},
},
}
postureCheckA, err := manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckA, true)
require.NoError(t, err)
postureCheckB := &posture.Checks{
Name: "postureCheckB",
AccountID: account.Id,
Checks: posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.28.0",
},
},
}
// Saving unused posture check should not update account peers and not send peer update
step(t, "saving unused posture check", func(t *testing.T) {
settleAffectedUpdates(updMsg)
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
postureCheckB, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Updating unused posture check should not update account peers and not send peer update
step(t, "updating unused posture check", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
postureCheckB.Checks = posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.29.0",
},
}
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
policy := &types.Policy{
Enabled: true, Enabled: true,
Rules: []*types.PolicyRule{ Rules: []*types.PolicyRule{
{ {
Enabled: true, Enabled: true,
Sources: []string{"groupB"}, Sources: []string{"groupA"},
Destinations: []string{"groupA"}, Destinations: []string{"groupA"},
Bidirectional: true, Bidirectional: true,
Action: types.PolicyTrafficActionAccept, Action: types.PolicyTrafficActionAccept,
}, },
}, },
SourcePostureChecks: []string{postureCheckB.ID}, SourcePostureChecks: []string{postureCheckB.ID},
}, true)
assert.NoError(t, err)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg1)
close(done)
}()
postureCheckB.Checks = posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.29.0",
},
} }
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select { // Linking posture check to policy should trigger update account peers and send peer update
case <-done: step(t, "linking posture check to policy with peers", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): done := make(chan struct{})
t.Error("timeout waiting for peerShouldReceiveUpdate") go func() {
} peerShouldReceiveUpdate(t, updMsg)
}) close(done)
}()
// Updating linked client posture check to policy where source has peers but destination does not, policy, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
// should trigger account peers update and send peer update assert.NoError(t, err)
t.Run("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{ select {
Enabled: true, case <-done:
Rules: []*types.PolicyRule{ case <-time.After(peerUpdateTimeout):
{ t.Error("timeout waiting for peerShouldReceiveUpdate")
Enabled: true, }
Sources: []string{"groupA"}, })
Destinations: []string{"groupB"},
Bidirectional: true, // Updating linked posture checks should update account peers and send peer update
Action: types.PolicyTrafficActionAccept, step(t, "updating linked to posture check with peers", func(t *testing.T) {
postureCheckB.Checks = posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.29.0",
}, },
}, ProcessCheck: &posture.ProcessCheck{
SourcePostureChecks: []string{postureCheckB.ID}, Processes: []posture.Process{
}, true) {LinuxPath: "/usr/bin/netbird", MacPath: "/usr/local/bin/netbird"},
assert.NoError(t, err)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
postureCheckB.Checks = posture.ChecksDefinition{
ProcessCheck: &posture.ProcessCheck{
Processes: []posture.Process{
{
LinuxPath: "/usr/bin/netbird",
}, },
}, },
}, }
}
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Removing posture check from policy should trigger account peers update and send peer update
step(t, "removing posture check from policy", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
policy.SourcePostureChecks = []string{}
_, err := manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Deleting unused posture check should not trigger account peers update and not send peer update
step(t, "deleting unused posture check", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeletePostureChecks(context.Background(), account.Id, postureCheckA.ID, userID)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true) _, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err) assert.NoError(t, err)
select { // Updating linked posture check to policy with no peers should not trigger account peers update and not send peer update
case <-done: step(t, "updating linked posture check to policy with no peers", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): _, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
t.Error("timeout waiting for peerShouldReceiveUpdate") Enabled: true,
} Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupB"},
Destinations: []string{"groupC"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
SourcePostureChecks: []string{postureCheckB.ID},
}, true)
assert.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
postureCheckB.Checks = posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.29.0",
},
}
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Updating linked posture check to policy where destination has peers but source does not
// should trigger account peers update and send peer update
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)
t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer2.ID)
})
_, err = manager.SavePolicy(context.Background(), account.Id, userID, &types.Policy{
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupB"},
Destinations: []string{"groupA"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
SourcePostureChecks: []string{postureCheckB.ID},
}, true)
assert.NoError(t, err)
settleAffectedUpdates(updMsg, updMsg1)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg1)
close(done)
}()
postureCheckB.Checks = posture.ChecksDefinition{
NBVersionCheck: &posture.NBVersionCheck{
MinVersion: "0.29.0",
},
}
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Updating linked client posture check to policy where source has peers but destination does not,
// should trigger account peers update and send peer update
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{
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupA"},
Destinations: []string{"groupB"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
SourcePostureChecks: []string{postureCheckB.ID},
}, true)
assert.NoError(t, err)
settleAffectedUpdates(updMsg)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
postureCheckB.Checks = posture.ChecksDefinition{
ProcessCheck: &posture.ProcessCheck{
Processes: []posture.Process{
{
LinuxPath: "/usr/bin/netbird",
},
},
},
}
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
}) })
} }
+252 -244
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,265 +1897,269 @@ func TestAccount_getPeersRoutesFirewall(t *testing.T) {
} }
func TestRouteAccountPeersUpdate(t *testing.T) { func TestRouteAccountPeersUpdate(t *testing.T) {
manager, updateManager, err := createRouterManager(t) runPeerUpdateTest(t, func(t *testing.T) {
require.NoError(t, err, "failed to create account manager") manager, updateManager, err := createRouterManager(t)
require.NoError(t, err, "failed to create account manager")
account, err := initTestRouteAccount(t, manager) account, err := initTestRouteAccount(t, manager)
require.NoError(t, err, "failed to init testing account") require.NoError(t, err, "failed to init testing account")
g := []*types.Group{ g := []*types.Group{
{ {
ID: "groupA", ID: "groupA",
Name: "GroupA", Name: "GroupA",
Peers: []string{}, Peers: []string{},
}, },
{ {
ID: "groupB", ID: "groupB",
Name: "GroupB", Name: "GroupB",
Peers: []string{}, Peers: []string{},
}, },
{ {
ID: "groupC", ID: "groupC",
Name: "GroupC", Name: "GroupC",
Peers: []string{}, Peers: []string{},
}, },
} }
for _, group := range g { for _, group := range g {
err = manager.CreateGroup(context.Background(), account.Id, userID, group) err = manager.CreateGroup(context.Background(), account.Id, userID, group)
require.NoError(t, err, "failed to create group %s", group.Name) require.NoError(t, err, "failed to create group %s", group.Name)
} }
updMsg := updateManager.CreateChannel(context.Background(), peer1ID) updMsg := updateManager.CreateChannel(context.Background(), peer1ID)
t.Cleanup(func() { t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1ID) updateManager.CloseChannel(context.Background(), peer1ID)
}) })
// 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) {
route := route.Route{ settleAffectedUpdates(updMsg)
ID: "testingRoute1",
Network: netip.MustParsePrefix("100.65.250.202/32"), route := route.Route{
ID: "testingRoute1",
Network: netip.MustParsePrefix("100.65.250.202/32"),
NetID: "superNet",
NetworkType: route.IPv4Network,
PeerGroups: []string{"groupA"},
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{"groupA"},
}
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
_, err := manager.CreateRoute(
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Creating a route with no routing peer and having peers in groups that don't include peer1 should not send peer1 an update
step(t, "creating a route with peers in PeerGroups and Groups", func(t *testing.T) {
drainPeerUpdates(updMsg)
route := route.Route{
ID: "testingRoute2",
Network: netip.MustParsePrefix("192.0.2.0/32"),
NetID: "superNet",
NetworkType: route.IPv4Network,
PeerGroups: []string{routeGroup3},
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{routeGroup3},
}
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
_, err := manager.CreateRoute(
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
baseRoute := route.Route{
ID: "testingRoute3",
Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: "superNet", NetID: "superNet",
NetworkType: route.IPv4Network, NetworkType: route.IPv4Network,
PeerGroups: []string{"groupA"}, Peer: peer1ID,
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{"groupA"},
}
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
_, err := manager.CreateRoute(
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// 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) {
drainPeerUpdates(updMsg)
route := route.Route{
ID: "testingRoute2",
Network: netip.MustParsePrefix("192.0.2.0/32"),
NetID: "superNet",
NetworkType: route.IPv4Network,
PeerGroups: []string{routeGroup3},
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{routeGroup3},
}
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
_, err := manager.CreateRoute(
context.Background(), account.Id, route.Network, route.NetworkType, route.Domains, route.Peer,
route.PeerGroups, route.Description, route.NetID, route.Masquerade, route.Metric,
route.Groups, []string{}, true, userID, route.KeepRoute, route.SkipAutoApply,
)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
baseRoute := route.Route{
ID: "testingRoute3",
Network: netip.MustParsePrefix("192.168.0.0/16"),
NetID: "superNet",
NetworkType: route.IPv4Network,
Peer: peer1ID,
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{routeGroup1},
}
// Creating route should update account peers and send peer update
t.Run("creating route with a routing peer", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
newRoute, err := manager.CreateRoute(
context.Background(), account.Id, baseRoute.Network, baseRoute.NetworkType, baseRoute.Domains, baseRoute.Peer,
baseRoute.PeerGroups, baseRoute.Description, baseRoute.NetID, baseRoute.Masquerade, baseRoute.Metric,
baseRoute.Groups, []string{}, true, userID, baseRoute.KeepRoute, !baseRoute.SkipAutoApply,
)
require.NoError(t, err)
baseRoute = *newRoute
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// 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) {
baseRoute.Groups = []string{routeGroup1, routeGroup2}
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.SaveRoute(context.Background(), account.Id, userID, &baseRoute)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Deleting the route should update account peers and send peer update
t.Run("deleting route", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeleteRoute(context.Background(), account.Id, baseRoute.ID, userID)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// 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) {
newRoute := route.Route{
Network: netip.MustParsePrefix("192.168.12.0/16"),
NetID: "superNet",
NetworkType: route.IPv4Network,
PeerGroups: []string{"groupB"},
Description: "super", Description: "super",
Masquerade: false, Masquerade: false,
Metric: 9999, Metric: 9999,
Enabled: true, Enabled: true,
Groups: []string{routeGroup1}, Groups: []string{routeGroup1},
} }
_, err := manager.CreateRoute(
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, !newRoute.SkipAutoApply,
)
require.NoError(t, err)
done := make(chan struct{}) // Creating route should update account peers and send peer update
go func() { step(t, "creating route with a routing peer", func(t *testing.T) {
peerShouldReceiveUpdate(t, updMsg) done := make(chan struct{})
close(done) go func() {
}() peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{ newRoute, err := manager.CreateRoute(
ID: "groupB", context.Background(), account.Id, baseRoute.Network, baseRoute.NetworkType, baseRoute.Domains, baseRoute.Peer,
Name: "GroupB", baseRoute.PeerGroups, baseRoute.Description, baseRoute.NetID, baseRoute.Masquerade, baseRoute.Metric,
Peers: []string{peer1ID}, baseRoute.Groups, []string{}, true, userID, baseRoute.KeepRoute, !baseRoute.SkipAutoApply,
)
require.NoError(t, err)
baseRoute = *newRoute
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
}) })
assert.NoError(t, err)
select { // Updating the route should update account peers and send peer update when there is peers in group
case <-done: step(t, "updating route", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): baseRoute.Groups = []string{routeGroup1, routeGroup2}
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Adding peer to route groups that do not have any peers should update account peers and send peer update done := make(chan struct{})
t.Run("adding peer to route groups that do not have any peers", func(t *testing.T) { go func() {
newRoute := route.Route{ peerShouldReceiveUpdate(t, updMsg)
Network: netip.MustParsePrefix("192.168.13.0/16"), close(done)
NetID: "superNet", }()
NetworkType: route.IPv4Network,
PeerGroups: []string{"groupB"},
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{"groupC"},
}
_, err := manager.CreateRoute(
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, !newRoute.SkipAutoApply,
)
require.NoError(t, err)
done := make(chan struct{}) err := manager.SaveRoute(context.Background(), account.Id, userID, &baseRoute)
go func() { require.NoError(t, err)
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{ select {
ID: "groupC", case <-done:
Name: "GroupC", case <-time.After(peerUpdateTimeout):
Peers: []string{peer1ID}, t.Error("timeout waiting for peerShouldReceiveUpdate")
}
}) })
assert.NoError(t, err)
select { // Deleting the route should update account peers and send peer update
case <-done: step(t, "deleting route", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): done := make(chan struct{})
t.Error("timeout waiting for peerShouldReceiveUpdate") go func() {
} peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err := manager.DeleteRoute(context.Background(), account.Id, baseRoute.ID, userID)
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Adding peer to route peer groups that do not have any peers should update account peers and send peer update
step(t, "adding peer to route peer groups that do not have any peers", func(t *testing.T) {
newRoute := route.Route{
Network: netip.MustParsePrefix("192.168.12.0/16"),
NetID: "superNet",
NetworkType: route.IPv4Network,
PeerGroups: []string{"groupB"},
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{routeGroup1},
}
_, err := manager.CreateRoute(
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, !newRoute.SkipAutoApply,
)
require.NoError(t, err)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupB",
Name: "GroupB",
Peers: []string{peer1ID},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// Adding peer to route groups that do not have any peers should update account peers and send peer update
step(t, "adding peer to route groups that do not have any peers", func(t *testing.T) {
newRoute := route.Route{
Network: netip.MustParsePrefix("192.168.13.0/16"),
NetID: "superNet",
NetworkType: route.IPv4Network,
PeerGroups: []string{"groupB"},
Description: "super",
Masquerade: false,
Metric: 9999,
Enabled: true,
Groups: []string{"groupC"},
}
_, err := manager.CreateRoute(
context.Background(), account.Id, newRoute.Network, newRoute.NetworkType, newRoute.Domains, newRoute.Peer,
newRoute.PeerGroups, newRoute.Description, newRoute.NetID, newRoute.Masquerade, newRoute.Metric,
newRoute.Groups, []string{}, true, userID, newRoute.KeepRoute, !newRoute.SkipAutoApply,
)
require.NoError(t, err)
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
err = manager.UpdateGroup(context.Background(), account.Id, userID, &types.Group{
ID: "groupC",
Name: "GroupC",
Peers: []string{peer1ID},
})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
}) })
} }
+65 -63
View File
@@ -397,75 +397,77 @@ func TestSetupKey_Copy(t *testing.T) {
} }
func TestSetupKeyAccountPeersUpdate(t *testing.T) { func TestSetupKeyAccountPeersUpdate(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) runPeerUpdateTest(t, func(t *testing.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{
ID: "groupA", ID: "groupA",
Name: "GroupA", Name: "GroupA",
Peers: []string{peer1.ID, peer2.ID, peer3.ID}, Peers: []string{peer1.ID, peer2.ID, peer3.ID},
}) })
assert.NoError(t, err)
policy := &types.Policy{
Enabled: true,
Rules: []*types.PolicyRule{
{
Enabled: true,
Sources: []string{"groupA"},
Destinations: []string{"group"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
}
_, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
require.NoError(t, err)
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1.ID)
})
// The setup policy above dispatches affected-peer updates asynchronously; drain
// any in-flight ones so the assertions only observe the setup-key operations.
settleAffectedUpdates(updMsg)
var setupKey *types.SetupKey
// Creating setup key should not update account peers and not send peer update
t.Run("creating setup key", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
setupKey, err = manager.CreateSetupKey(context.Background(), account.Id, "key1", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
assert.NoError(t, err) assert.NoError(t, err)
select { policy := &types.Policy{
case <-done: Enabled: true,
case <-time.After(time.Second): Rules: []*types.PolicyRule{
t.Error("timeout waiting for peerShouldNotReceiveUpdate") {
Enabled: true,
Sources: []string{"groupA"},
Destinations: []string{"group"},
Bidirectional: true,
Action: types.PolicyTrafficActionAccept,
},
},
} }
}) _, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
// Saving setup key should not update account peers and not send peer update
t.Run("saving setup key", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
_, err = manager.SaveSetupKey(context.Background(), account.Id, setupKey, userID)
require.NoError(t, err) require.NoError(t, err)
select { updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
case <-done: t.Cleanup(func() {
case <-time.After(time.Second): updateManager.CloseChannel(context.Background(), peer1.ID)
t.Error("timeout waiting for peerShouldNotReceiveUpdate") })
}
// The setup policy above dispatches affected-peer updates asynchronously; drain
// any in-flight ones so the assertions only observe the setup-key operations.
settleAffectedUpdates(updMsg)
var setupKey *types.SetupKey
// Creating setup key should not update account peers and not send peer update
step(t, "creating setup key", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
setupKey, err = manager.CreateSetupKey(context.Background(), account.Id, "key1", types.SetupKeyReusable, time.Hour, nil, 999, userID, false, false)
assert.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
// Saving setup key should not update account peers and not send peer update
step(t, "saving setup key", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
_, err = manager.SaveSetupKey(context.Background(), account.Id, setupKey, userID)
require.NoError(t, err)
select {
case <-done:
case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate")
}
})
}) })
} }
+135 -131
View File
@@ -1544,166 +1544,170 @@ func TestDefaultAccountManager_SaveUser(t *testing.T) {
} }
func TestUserAccountPeersUpdate(t *testing.T) { func TestUserAccountPeersUpdate(t *testing.T) {
// account groups propagation is enabled runPeerUpdateTest(t, func(t *testing.T) {
manager, updateManager, account, peer1, peer2, peer3 := setupNetworkMapTest(t) // account groups propagation is enabled
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{
ID: "groupA", ID: "groupA",
Name: "GroupA", Name: "GroupA",
Peers: []string{peer1.ID, peer2.ID, peer3.ID}, Peers: []string{peer1.ID, peer2.ID, peer3.ID},
}) })
require.NoError(t, err) require.NoError(t, err)
policy := &types.Policy{ policy := &types.Policy{
Enabled: true, Enabled: true,
Rules: []*types.PolicyRule{ Rules: []*types.PolicyRule{
{ {
Enabled: true, Enabled: true,
Sources: []string{"groupA"}, Sources: []string{"groupA"},
Destinations: []string{"groupA"}, Destinations: []string{"groupA"},
Bidirectional: true, Bidirectional: true,
Action: types.PolicyTrafficActionAccept, Action: types.PolicyTrafficActionAccept,
},
}, },
}, }
} _, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
_, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
require.NoError(t, err)
updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer1.ID)
})
// 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) {
done := make(chan struct{})
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
Id: "regularUser1",
AccountID: account.Id,
Role: types.UserRoleUser,
Issued: types.UserIssuedAPI,
}, true)
require.NoError(t, err) require.NoError(t, err)
select { updMsg := updateManager.CreateChannel(context.Background(), peer1.ID)
case <-done: t.Cleanup(func() {
case <-time.After(time.Second): updateManager.CloseChannel(context.Background(), peer1.ID)
t.Error("timeout waiting for peerShouldNotReceiveUpdate") })
}
})
// updating user with no linked peers should update account peers and 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("updating user with no linked peers", func(t *testing.T) { step(t, "creating new regular user with no groups", func(t *testing.T) {
done := make(chan struct{}) settleAffectedUpdates(updMsg)
go func() {
peerShouldReceiveUpdate(t, updMsg)
close(done)
}()
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{ done := make(chan struct{})
Id: "regularUser1", go func() {
AccountID: account.Id, peerShouldReceiveUpdate(t, updMsg)
Role: types.UserRoleUser, close(done)
Issued: types.UserIssuedAPI, }()
}, false)
require.NoError(t, err)
select { _, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
case <-done: Id: "regularUser1",
case <-time.After(time.Second): AccountID: account.Id,
t.Error("timeout waiting for peerShouldNotReceiveUpdate") Role: types.UserRoleUser,
} Issued: types.UserIssuedAPI,
}) }, true)
require.NoError(t, err)
// drain any buffered updates from previous subtests select {
drainPeerUpdates(updMsg) case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
// deleting user with no linked peers should not update account peers and not send peer update // saving an unchanged 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, "updating 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)
close(done) close(done)
}() }()
err = manager.DeleteUser(context.Background(), account.Id, userID, "regularUser1") _, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
require.NoError(t, err) Id: "regularUser1",
AccountID: account.Id,
Role: types.UserRoleUser,
Issued: types.UserIssuedAPI,
}, false)
require.NoError(t, err)
select { select {
case <-done: case <-done:
case <-time.After(time.Second): case <-time.After(time.Second):
t.Error("timeout waiting for peerShouldNotReceiveUpdate") t.Error("timeout waiting for peerShouldNotReceiveUpdate")
} }
}) })
// create a user and add new peer with the user // drain any buffered updates from previous subtests
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{ drainPeerUpdates(updMsg)
Id: "regularUser2",
AccountID: account.Id,
Role: types.UserRoleAdmin,
Issued: types.UserIssuedAPI,
}, true)
require.NoError(t, err)
key, err := wgtypes.GeneratePrivateKey() // deleting user with no linked peers should not update account peers and not send peer update
require.NoError(t, err) step(t, "deleting user with no linked peers", func(t *testing.T) {
done := make(chan struct{})
go func() {
peerShouldNotReceiveUpdate(t, updMsg)
close(done)
}()
expectedPeerKey := key.PublicKey().String() err = manager.DeleteUser(context.Background(), account.Id, userID, "regularUser1")
peer4, _, _, _, err := manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{ require.NoError(t, err)
Key: expectedPeerKey,
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
}, false)
require.NoError(t, err)
// updating user with linked peers should update account peers and send peer update select {
t.Run("updating user with linked peers", func(t *testing.T) { case <-done:
done := make(chan struct{}) case <-time.After(time.Second):
go func() { t.Error("timeout waiting for peerShouldNotReceiveUpdate")
peerShouldReceiveUpdate(t, updMsg) }
close(done) })
}()
// create a user and add new peer with the user
_, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{ _, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
Id: "regularUser2", Id: "regularUser2",
AccountID: account.Id, AccountID: account.Id,
Role: types.UserRoleAdmin, Role: types.UserRoleAdmin,
Issued: types.UserIssuedAPI, Issued: types.UserIssuedAPI,
}, true)
require.NoError(t, err)
key, err := wgtypes.GeneratePrivateKey()
require.NoError(t, err)
expectedPeerKey := key.PublicKey().String()
peer4, _, _, _, err := manager.AddPeer(context.Background(), "", "", "regularUser2", &nbpeer.Peer{
Key: expectedPeerKey,
Meta: nbpeer.PeerSystemMeta{Hostname: expectedPeerKey},
}, false) }, false)
require.NoError(t, err) require.NoError(t, err)
select { // updating user with linked peers should update account peers and send peer update
case <-done: step(t, "updating user with linked peers", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): done := make(chan struct{})
t.Error("timeout waiting for peerShouldReceiveUpdate") go func() {
} peerShouldReceiveUpdate(t, updMsg)
}) close(done)
}()
peer4UpdMsg := updateManager.CreateChannel(context.Background(), peer4.ID) _, err = manager.SaveOrAddUser(context.Background(), account.Id, userID, &types.User{
t.Cleanup(func() { Id: "regularUser2",
updateManager.CloseChannel(context.Background(), peer4.ID) AccountID: account.Id,
}) Role: types.UserRoleAdmin,
Issued: types.UserIssuedAPI,
}, false)
require.NoError(t, err)
// deleting user with linked peers should update account peers and send peer update select {
t.Run("deleting user with linked peers", func(t *testing.T) { case <-done:
done := make(chan struct{}) case <-time.After(peerUpdateTimeout):
go func() { t.Error("timeout waiting for peerShouldReceiveUpdate")
peerShouldReceiveUpdate(t, peer4UpdMsg) }
close(done) })
}()
err = manager.DeleteUser(context.Background(), account.Id, userID, "regularUser2") peer4UpdMsg := updateManager.CreateChannel(context.Background(), peer4.ID)
require.NoError(t, err) t.Cleanup(func() {
updateManager.CloseChannel(context.Background(), peer4.ID)
})
select { // deleting user with linked peers should update account peers and send peer update
case <-done: step(t, "deleting user with linked peers", func(t *testing.T) {
case <-time.After(peerUpdateTimeout): done := make(chan struct{})
t.Error("timeout waiting for peerShouldReceiveUpdate") go func() {
} peerShouldReceiveUpdate(t, peer4UpdMsg)
close(done)
}()
err = manager.DeleteUser(context.Background(), account.Id, userID, "regularUser2")
require.NoError(t, err)
select {
case <-done:
case <-time.After(peerUpdateTimeout):
t.Error("timeout waiting for peerShouldReceiveUpdate")
}
})
}) })
} }