Files
netmaker/controllers/network_test.go
T
Abhishek Kondur edda2868fc NM-163: Users, Groups, Roles, Networks and Hosts Table Migration (#3910)
* feat(go): add user schema;

* feat(go): migrate to user schema;

* feat(go): add audit fields;

* feat(go): remove unused fields from the network model;

* feat(go): add network schema;

* feat(go): migrate to network schema;

* refactor(go): add comment to clarify migration logic;

* fix(go): test failures;

* fix(go): test failures;

* feat(go): change membership table to store memberships at all scopes;

* feat(go): add schema for access grants;

* feat(go): remove nameservers from new networks table; ensure db passed for schema functions;

* feat(go): set max conns for sqlite to 1;

* fix(go): issues updating user account status;

* refactor(go): remove converters and access grants;

* refactor(go): add json tags in schema models;

* refactor(go): rename file to migrate_v1_6_0.go;

* refactor(go): add user groups and user roles tables; use schema tables;

* refactor(go): inline get and list from schema package;

* refactor(go): inline get network and list users from schema package;

* fix(go): staticcheck issues;

* fix(go): remove test not in use; fix test case;

* fix(go): validate network;

* fix(go): resolve static checks;

* fix(go): new models errors;

* fix(go): test errors;

* fix(go): handle no records;

* fix(go): add validations for user object;

* fix(go): set correct extclient status;

* fix(go): test error;

* feat(go): make schema the base package;

* feat(go): add host schema;

* feat(go): use schema host everywhere;

* feat(go): inline get host, list hosts and delete host;

* feat(go): use non-ptr value;

* feat(go): use save to upsert all fields;

* feat(go): use save to upsert all fields;

* feat(go): save turn endpoint as string;

* feat(go): check for gorm error record not found;

* fix(go): test failures;

* fix(go): update all network fields;

* fix(go): update all network fields;

* feat(go): add paginated list networks api;

* feat(go): add paginated list users api;

* feat(go): add paginated list hosts api;

* feat(go): add pagination to list groups api;

* fix(go): comment;

* fix(go): implement marshal and unmarshal text for custom types;

* fix(go): implement marshal and unmarshal json for custom types;

* fix(go): just use the old model for unmarshalling;

* fix(go): implement marshal and unmarshal json for custom types;

* feat(go): remove paginated list networks api;

* feat(go): use custom paginated response object;

* fix(go): ensure default values for page and per_page are used when not passed;

* fix(go): rename v1.6.0 to v1.5.1;

* fix(go): check for gorm.ErrRecordNotFound instead of database.IsEmptyRecord;

* fix(go): use host id, not pending host id;

* feat(go): add filters to paginated apis;

* feat(go): add filters to paginated apis;

* feat(go): remove check for max username length;

* feat(go): add filters to count as well;

* feat(go): use library to check email address validity;

* feat(go): ignore pagination if params not passed;

* fix(go): pagination issues;

* fix(go): check exists before using;

* fix(go): remove debug log;

* fix(go): use gorm err record not found;

* fix(go): use gorm err record not found;

* fix(go): use user principal name when creating pending user;

* fix(go): use schema package for consts;

* fix(go): prevent disabling superadmin user;

Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>

* fix(go): swap is admin and is superadmin;

Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>

* fix(go): remove dead code block;

https://github.com/gravitl/netmaker/pull/3910#discussion_r2928837937

* fix(go): incorrect message when trying to disable self;

https://github.com/gravitl/netmaker/pull/3910#discussion_r2928837934

* fix(go): use correct header;

Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>

* fix(go): return after error response;

Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>

* fix(go): use correct order of params;

https://github.com/gravitl/netmaker/pull/3910#discussion_r2929593036

* fix(go): set default values for page and page size; use v2 instead of /list;

* Update logic/auth.go

Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>

* Update schema/user_roles.go

Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>

* fix(go): syntax error;

* fix(go): set default values when page and per_page are not passed or 0;

* fix(go): use uuid.parse instead of uuid.must parse;

* fix(go): review errors;

* fix(go): review errors;

* Update controllers/user.go

Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>

* Update controllers/user.go

Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>

* NM-163: fix errors:

* Update db/types/options.go

Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>

* fix(go): persist return user in event;

* Update db/types/options.go

Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>

* NM-163: duplicate lines of code

* NM-163: fix(go): fix missing return and filter parsing in user controller

- Add missing return after error response in updateUserAccountStatus
  to prevent double-response and spurious ext-client side-effects
- Use switch statements in listUsers to skip unrecognized
  account_status and mfa_status filter values

* fix(go): check for both min and max page size;

* fix(go): enclose transfer superadmin in transaction;

* fix(go): review errors;

* fix(go): remove free tier checks;

* fix(go): review fixes;

---------

Co-authored-by: VishalDalwadi <dalwadivishal26@gmail.com>
Co-authored-by: Vishal Dalwadi <51291657+VishalDalwadi@users.noreply.github.com>
Co-authored-by: tenki-reviewer[bot] <262613592+tenki-reviewer[bot]@users.noreply.github.com>
2026-03-17 19:36:52 +05:30

254 lines
6.4 KiB
Go

package controller
import (
"context"
"os"
"testing"
"github.com/gravitl/netmaker/db"
"github.com/gravitl/netmaker/schema"
"gorm.io/gorm"
"github.com/google/uuid"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
"github.com/stretchr/testify/assert"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
type NetworkValidationTestCase struct {
testname string
network schema.Network
errMessage string
}
var netHost schema.Host
func TestMain(m *testing.M) {
db.InitializeDB(schema.ListModels()...)
defer db.CloseDB()
database.InitializeDatabase()
defer database.CloseDB()
logic.CreateSuperAdmin(&schema.User{
Username: "admin",
Password: "password",
PlatformRoleID: schema.SuperAdminRole,
})
peerUpdate := make(chan *models.Node)
go logic.ManageZombies(context.Background())
go func() {
for update := range peerUpdate {
//do nothing
logger.Log(3, "received node update", update.Action)
}
}()
os.Exit(m.Run())
}
func TestCreateNetwork(t *testing.T) {
deleteAllNetworks()
var network schema.Network
network.Name = "skynet1"
network.AddressRange = "10.10.0.1/24"
// if tests break - check here (removed displayname)
//network.DisplayName = "mynetwork"
err := logic.CreateNetwork(&network)
assert.Nil(t, err)
}
func TestGetNetwork(t *testing.T) {
createNet()
t.Run("GetExistingNetwork", func(t *testing.T) {
network := &schema.Network{Name: "skynet"}
err := network.Get(db.WithContext(context.TODO()))
assert.Nil(t, err)
assert.Equal(t, "skynet", network.Name)
})
t.Run("GetNonExistantNetwork", func(t *testing.T) {
network := &schema.Network{Name: "doesnotexist"}
err := network.Get(db.WithContext(context.TODO()))
assert.EqualError(t, err, gorm.ErrRecordNotFound.Error())
assert.Equal(t, "", network.ID)
})
}
func TestDeleteNetwork(t *testing.T) {
createNet()
//create nodes
t.Run("NetworkwithNodes", func(t *testing.T) {
})
t.Run("DeleteExistingNetwork", func(t *testing.T) {
doneCh := make(chan struct{}, 1)
err := logic.DeleteNetwork("skynet", false, doneCh)
assert.Nil(t, err)
})
t.Run("NonExistentNetwork", func(t *testing.T) {
doneCh := make(chan struct{}, 1)
err := logic.DeleteNetwork("skynet", false, doneCh)
assert.Nil(t, err)
})
createNetv1("test")
t.Run("ForceDeleteNetwork", func(t *testing.T) {
doneCh := make(chan struct{}, 1)
err := logic.DeleteNetwork("test", true, doneCh)
assert.Nil(t, err)
})
}
func TestSecurityCheck(t *testing.T) {
//these seem to work but not sure it the tests are really testing the functionality
os.Setenv("MASTER_KEY", "secretkey")
t.Run("NoNetwork", func(t *testing.T) {
username, err := logic.UserPermissions(false, "Bearer secretkey")
assert.Nil(t, err)
t.Log(username)
})
t.Run("BadToken", func(t *testing.T) {
username, err := logic.UserPermissions(false, "Bearer badkey")
assert.NotNil(t, err)
t.Log(err)
t.Log(username)
})
}
func TestValidateNetwork(t *testing.T) {
//t.Skip()
//This functions is not called by anyone
//it panics as validation function 'display_name_valid' is not defined
//yes := true
//no := false
//deleteNet(t)
//DeleteNetworks
cases := []NetworkValidationTestCase{
{
testname: "InvalidAddress",
network: schema.Network{
Name: "skynet",
AddressRange: "10.0.0.256",
},
errMessage: "invalid CIDR address: 10.0.0.256",
},
{
testname: "InvalidAddress6",
network: schema.Network{
Name: "skynet1",
AddressRange6: "2607::ffff/130",
},
errMessage: "invalid CIDR address: 2607::ffff/130",
},
{
testname: "InvalidNetID",
network: schema.Network{
Name: "with spaces",
},
errMessage: "invalid character(s) in network name",
},
{
testname: "NetIDTooLong",
network: schema.Network{
Name: "LongNetIDNameForMaxCharactersTest",
},
errMessage: "network name cannot be longer than 32 characters",
},
{
testname: "KeepAliveTooBig",
network: schema.Network{
Name: "skynet",
DefaultKeepAlive: 1010,
},
errMessage: "default keep alive must be less than 1000",
},
}
for _, tc := range cases {
t.Run(tc.testname, func(t *testing.T) {
t.Log(tc.testname)
network := tc.network
err := logic.ValidateNetwork(&network, false)
assert.NotNil(t, err)
assert.Contains(t, err.Error(), tc.errMessage) // test passes if err.Error() contains the expected errMessage.
})
}
}
func TestIpv6Network(t *testing.T) {
//these seem to work but not sure it the tests are really testing the functionality
os.Setenv("MASTER_KEY", "secretkey")
deleteAllNetworks()
createNet()
createNetDualStack()
network := &schema.Network{Name: "skynet6"}
err := network.Get(db.WithContext(context.TODO()))
t.Run("Test Network Create IPv6", func(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, network.AddressRange6, "fde6:be04:fa5e:d076::/64")
})
node1 := createNodeWithParams("skynet6", "")
createNetHost()
nodeErr := logic.AssociateNodeToHost(node1, &netHost)
t.Run("Test node on network IPv6", func(t *testing.T) {
assert.Nil(t, nodeErr)
assert.Equal(t, "fde6:be04:fa5e:d076::1", node1.Address6.IP.String())
})
}
func deleteAllNetworks() {
deleteAllNodes()
_networks, _ := (&schema.Network{}).ListAll(db.WithContext(context.TODO()))
for _, _network := range _networks {
_ = _network.Delete(db.WithContext(context.TODO()))
}
}
func createNet() {
var network schema.Network
network.Name = "skynet"
network.AddressRange = "10.0.0.1/24"
err := (&schema.Network{Name: "skynet"}).Get(db.WithContext(context.TODO()))
if err != nil {
logic.CreateNetwork(&network)
}
}
func createNetv1(netId string) {
var network schema.Network
network.Name = netId
network.AddressRange = "100.0.0.1/24"
err := (&schema.Network{Name: netId}).Get(db.WithContext(context.TODO()))
if err != nil {
logic.CreateNetwork(&network)
}
}
func createNetDualStack() {
var network schema.Network
network.Name = "skynet6"
network.AddressRange = "10.1.2.0/24"
network.AddressRange6 = "fde6:be04:fa5e:d076::/64"
err := (&schema.Network{Name: "skynet6"}).Get(db.WithContext(context.TODO()))
if err != nil {
logic.CreateNetwork(&network)
}
}
func createNetHost() {
k, _ := wgtypes.ParseKey("DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=")
netHost = schema.Host{
ID: uuid.New(),
PublicKey: schema.WgKey{Key: k.PublicKey()},
HostPass: "password",
OS: "linux",
Name: "nethost",
}
_ = logic.CreateHost(&netHost)
}