added tests to cover GetNetworkMapData() call

Signed-off-by: Dmitri Dolguikh <dmitri.external@netbird.io>
This commit is contained in:
Dmitri Dolguikh
2026-08-14 16:45:33 +02:00
parent 14f976bade
commit 84e4b08056
7 changed files with 985 additions and 45 deletions
@@ -40,6 +40,7 @@ func TestMain(m *testing.M) {
case string(types.PostgresStoreEngine):
engine = string(types.PostgresStoreEngine)
pgstore, cleanup = createPGTestStore(baseData, pgData)
pgstore.UsingTimeZone(time.UTC)
case "", string(types.SqliteStoreEngine):
engine = string(types.SqliteStoreEngine)
sqlitestore, cleanup = createSqliteTestStore(baseData, sqliteData)
@@ -67,6 +68,18 @@ func conn(t *testing.T, ctx context.Context) networkmapdb.NetworkMapDBStoreConn
return nil
}
func store(t *testing.T) networkmapdb.NetworkMapDBStore {
t.Helper()
switch engine {
case string(types.PostgresStoreEngine):
return pgstore
case string(types.SqliteStoreEngine):
return sqlitestore
}
log.Fatalf("unknown db engine kind %s", engine)
return nil
}
func execQuery(t *testing.T, ctx context.Context, q string) {
t.Helper()
switch engine {
@@ -80,20 +93,13 @@ func execQuery(t *testing.T, ctx context.Context, q string) {
}
// use to parse time in time.RFC3339Nano format
// returns the time in the local time zone, as that's what being returned from sql queries
// pgx returns time in the "local" timezone
// sql with sqlite driver returns time in UTC timezone
// returns the time in the UTC time zone
func mustParseTime(t string) *time.Time {
tt, err := time.Parse(time.RFC3339Nano, t)
if err != nil {
panic(err)
}
if engine == string(types.SqliteStoreEngine) {
utc := tt.UTC()
return &utc
}
local := tt.Local()
return &local
utc := tt.UTC()
return &utc
}
@@ -0,0 +1,372 @@
{
"Peers": {
"peer-id-1": {
"ID": "peer-id-1",
"Key": "key-1",
"SSHKey": "ssh-key-1",
"DNSLabel": "peer-1",
"UserID": "user-id-1",
"SSHEnabled": true,
"LoginExpirationEnabled": true,
"LastLogin": "2026-08-06T13:25:59.12999Z",
"IP": "10.10.10.1",
"IPv6": "fdf4:ba80:6aa5:89f1:44d7:8701:8699:4940",
"RequiresApproval": false,
"ExtraDNSLabels": [
"extra-peer-1"
],
"Meta": {
"WtVersion": "0.76.0",
"GoOS": "linux",
"OSVersion": "26.4.1",
"KernelVersion": "6.8.0-134-generic",
"NetworkAddresses": [
{
"NetIP": "fe80::8b4c:973f:a76b:3771/64"
},
{
"NetIP": "192.168.16.1/20"
}
],
"Files": [
{
"Path": "/usr/bin/netbird",
"ProcessIsRunning": false
}
],
"Capabilities": [
1,
2
],
"Flags": {
"ServerSSHAllowed": true,
"DisableIPv6": false
},
"SyncMessageVersion": 1
},
"ProxyMeta": {
"Embedded": true
},
"Location": {
"CountryCode": "DE",
"CityName": "Berlin",
"ConnectionIP": "46.201.148.187"
}
},
"peer-id-2": {
"ID": "peer-id-2",
"Key": "key-2",
"SSHKey": "ssh-key-2",
"DNSLabel": "peer-2",
"UserID": "user-id-2",
"SSHEnabled": true,
"LoginExpirationEnabled": true,
"LastLogin": "2026-08-06T14:25:59.12999Z",
"IP": "10.10.100.1",
"IPv6": "fdf5:ba80:6aa5:89f1:44d7:8701:8699:4940",
"RequiresApproval": false,
"ExtraDNSLabels": [
"extra-peer-2"
],
"Meta": {
"WtVersion": "0.76.1",
"GoOS": "linux",
"OSVersion": "26.4.2",
"KernelVersion": "6.8.0-135-generic",
"NetworkAddresses": [
{
"NetIP": "fe81::8b4c:973f:a76b:3771/64"
},
{
"NetIP": "192.168.17.1/20"
}
],
"Files": [
{
"Path": "/usr/bin/netbird",
"ProcessIsRunning": false
}
],
"Capabilities": [
1,
2
],
"Flags": {
"ServerSSHAllowed": true,
"DisableIPv6": false
},
"SyncMessageVersion": 0
},
"ProxyMeta": {
"Embedded": true
},
"Location": {
"CountryCode": "DE",
"CityName": "Berlin",
"ConnectionIP": "46.201.149.187"
}
},
"peer-id-3": {
"ID": "peer-id-3",
"Key": "key-3",
"SSHKey": "ssh-key-3",
"DNSLabel": "peer-3",
"UserID": "user-id-3",
"SSHEnabled": true,
"LoginExpirationEnabled": true,
"LastLogin": "2026-08-06T12:25:59.12999Z",
"IP": "10.10.200.1",
"IPv6": "fdf6:ba80:6aa5:89f1:44d7:8701:8699:4940",
"RequiresApproval": false,
"ExtraDNSLabels": [
"extra-peer-3"
],
"Meta": {
"WtVersion": "0.76.2",
"GoOS": "linux",
"OSVersion": "26.4.3",
"KernelVersion": "6.8.0-136-generic",
"NetworkAddresses": [
{
"NetIP": "fe82::8b4c:973f:a76b:3771/64"
},
{
"NetIP": "192.168.18.1/20"
}
],
"Files": [
{
"Path": "/usr/bin/netbird",
"ProcessIsRunning": false
}
],
"Capabilities": [
1,
2
],
"Flags": {
"ServerSSHAllowed": true,
"DisableIPv6": false
},
"SyncMessageVersion": 1
},
"ProxyMeta": {
"Embedded": true
},
"Location": {
"CountryCode": "DE",
"CityName": "Berlin",
"ConnectionIP": "46.201.150.187"
}
}
},
"Groups": {
"group-no-resources-id": {
"ID": "group-no-resources-id",
"Name": "group-3-name",
"PublicID": "group-no-resources-id-public",
"Peers": null,
"Resources": null
},
"group-one-resource-id": {
"ID": "group-one-resource-id",
"Name": "group-1-name",
"PublicID": "group-one-resource-id-public",
"Peers": [
"peer-id-1"
],
"Resources": [
{
"ID": "host-id-1",
"Type": "host"
}
]
},
"group-two-resources-id": {
"ID": "group-two-resources-id",
"Name": "group-2-name",
"PublicID": "group-two-resources-id-public",
"Peers": [
"peer-id-2",
"peer-id-3"
],
"Resources": [
{
"ID": "subnet-id-1",
"Type": "subnet"
},
{
"ID": "host-id-2",
"Type": "host"
}
]
}
},
"Policies": [],
"Routes": [],
"NameServerGroups": [
{
"ID": "nsgroup-1",
"PublicID": "nsgroup-1-public",
"Name": "nsgroup-1",
"Description": "nsgroup-1",
"NameServers": [
{
"IP": "192.168.31.2",
"NSType": 1,
"Port": 53
}
],
"Groups": [
"group-one-resource-id"
],
"Primary": true,
"Domains": [
"test-1.com"
],
"Enabled": true,
"SearchDomainsEnabled": false
},
{
"ID": "nsgroup-2",
"PublicID": "nsgroup-2-public",
"Name": "nsgroup-2",
"Description": "nsgroup-2",
"NameServers": [
{
"IP": "192.168.32.3",
"NSType": 1,
"Port": 53
}
],
"Groups": [
"group-one-resource-id",
"group-no-resources-id"
],
"Primary": true,
"Domains": [
"test-1.com",
"test-2.com"
],
"Enabled": true,
"SearchDomainsEnabled": false
},
{
"ID": "nsgroup-3",
"PublicID": "nsgroup-3-public",
"Name": "",
"Description": "",
"NameServers": null,
"Groups": null,
"Primary": false,
"Domains": null,
"Enabled": true,
"SearchDomainsEnabled": false
}
],
"NetworkResources": [],
"Network": {
"Identifier": "network-1",
"Net": {
"IP": "100.103.0.0",
"Mask": "//8AAA=="
},
"NetV6": {
"IP": "fdde:e995:fd38:a465::",
"Mask": "//////////8AAAAAAAAAAA=="
},
"Dns": "",
"Serial": 1
},
"DNSSettings": {
"DisabledManagementGroups": [
"disabled-group-1",
"disabled-group-2"
]
},
"AccountSettings": {
"PeerLoginExpirationEnabled": true,
"PeerLoginExpiration": 86400000000000,
"PeerInactivityExpirationEnabled": false,
"PeerInactivityExpiration": 86400000000000,
"DNSDomain": "",
"IPv6EnabledGroups": [
"group-one-resource-id"
],
"RoutingPeerDNSResolutionEnabled": false,
"LazyConnectionEnabled": false,
"AutoUpdateVersion": "disabled",
"AutoUpdateAlways": false,
"MetricsPushEnabled": false
},
"PostureChecks": {},
"PostureValidation": null,
"AllowedUserIDs": {},
"NetworkXIDToPublicID": {},
"PostureCheckXIDToPublicID": {},
"ValidatedPeers": {
"peer-id-1": {},
"peer-id-2": {},
"peer-id-3": {}
},
"ResourcePolicies": {},
"Routers": {},
"GroupIDToUserIDs": {},
"DNSDomain": "",
"ProxyTargetedDomainResourceIDs": {},
"AppliedZoneCandidates": [
{
"DistributionGroups": [
"group-one-resource-id"
],
"Zone": {
"Domain": "test-1.com",
"Records": [
{
"Name": "test.test-1.com",
"Type": 1,
"Class": "IN",
"TTL": 1800,
"RData": "1.1.1.1"
},
{
"Name": "test2.test-1.com",
"Type": 1,
"Class": "IN",
"TTL": 1800,
"RData": "1.1.1.2"
},
{
"Name": "test3.test-1.com",
"Type": 5,
"Class": "IN",
"TTL": 1800,
"RData": "test4.test-1.com."
}
],
"SearchDomainDisabled": false,
"NonAuthoritative": false
}
},
{
"DistributionGroups": [
"group-two-resources-id"
],
"Zone": {
"Domain": "test-2.com",
"Records": [
{
"Name": "test2.test-2.com",
"Type": 5,
"Class": "IN",
"TTL": 1800,
"RData": "test3.test-2.com."
}
],
"SearchDomainDisabled": true,
"NonAuthoritative": false
}
}
],
"PrivateServiceCandidates": null
}
@@ -0,0 +1,103 @@
//go:build integration
package networkmap_pgsql
import (
"context"
_ "embed"
"encoding/json"
"net/netip"
"os"
"path/filepath"
"runtime"
"testing"
networkmapdb "github.com/netbirdio/netbird/management/internals/network_map_db"
"github.com/netbirdio/netbird/management/server/integrations/extra_settings"
nbpeer "github.com/netbirdio/netbird/management/server/peer"
"github.com/netbirdio/netbird/management/server/types"
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
"github.com/netbirdio/netbird/shared/management/proto"
"github.com/stretchr/testify/assert"
)
//go:embed network_map_data_golden.json
var goldenNMap string
const EnvUpdateGoldenData = "NMAP_UPDATE_GOLDEN_DATA"
func TestGetNetworkMapData(t *testing.T) {
ctx := context.TODO()
storeImpl := networkmapdb.NetworkMapDBStoreImpl{
Store: store(t),
ExtraSettingsManager: &extraSettingsManagerForTesting{},
IntegratedPeerValidator: &peerValidatorForTesting{},
}
nmap, err := storeImpl.GetNetworkMapData(ctx, "account-1")
assert.NoError(t, err)
serializedNMap, err := json.MarshalIndent(nmap, "", " ")
assert.NoError(t, err)
if _, ok := os.LookupEnv(EnvUpdateGoldenData); ok {
_, filename, _, _ := runtime.Caller(0)
tosavepath := filepath.Join(filepath.Dir(filename), "network_map_data_golden.json")
err = os.WriteFile(tosavepath, serializedNMap, 0644)
assert.NoError(t, err)
goldenNMap = string(serializedNMap)
}
assert.Equal(t, goldenNMap, string(serializedNMap))
}
// need these calls for the test
func (*extraSettingsManagerForTesting) GetExtraSettings(ctx context.Context, accountID string) (*types.ExtraSettings, error) {
return &types.ExtraSettings{}, nil
}
func (*peerValidatorForTesting) GetValidatedPeers(ctx context.Context, accountID string, groups []*nmdata.Group, peers []*nmdata.Peer, extraSettings *types.ExtraSettings) (map[string]struct{}, error) {
return map[string]struct{}{
"peer-id-1": {},
"peer-id-2": {},
"peer-id-3": {},
}, nil
}
type extraSettingsManagerForTesting struct{}
func (*extraSettingsManagerForTesting) GetExtraSettingsManager() extra_settings.Manager { return nil }
func (*extraSettingsManagerForTesting) GetSettings(ctx context.Context, accountID string, userID string) (*types.Settings, error) {
return nil, nil
}
func (*extraSettingsManagerForTesting) UpdateExtraSettings(ctx context.Context, accountID, userID string, extraSettings *types.ExtraSettings) (bool, error) {
return false, nil
}
func (*extraSettingsManagerForTesting) GetEffectiveNetworkRanges(ctx context.Context, accountID string) (v4, v6 netip.Prefix, err error) {
return netip.Prefix{}, netip.Prefix{}, nil
}
type peerValidatorForTesting struct{}
func (*peerValidatorForTesting) ValidateExtraSettings(ctx context.Context, newExtraSettings *types.ExtraSettings, oldExtraSettings *types.ExtraSettings, userID string, accountID string) error {
return nil
}
func (*peerValidatorForTesting) ValidatePeer(ctx context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) {
return nil, false, nil
}
func (*peerValidatorForTesting) PreparePeer(ctx context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *types.ExtraSettings, temporary bool) *nbpeer.Peer {
return nil
}
func (*peerValidatorForTesting) IsNotValidPeer(ctx context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *types.ExtraSettings) (bool, bool, error) {
return false, false, nil
}
func (*peerValidatorForTesting) GetInvalidPeers(ctx context.Context, accountID string, extraSettings *types.ExtraSettings) (map[string]string, error) {
return nil, nil
}
func (*peerValidatorForTesting) PeerDeleted(ctx context.Context, accountID, peerID string, extraSettings *types.ExtraSettings) error {
return nil
}
func (*peerValidatorForTesting) SetPeerInvalidationListener(fn func(accountID string, peerIDs []string)) {
}
func (*peerValidatorForTesting) Stop(ctx context.Context) {}
func (*peerValidatorForTesting) ValidateFlowResponse(ctx context.Context, peerKey string, flowResponse *proto.PKCEAuthorizationFlow) *proto.PKCEAuthorizationFlow {
return nil
}