Skip to content
Snippets Groups Projects
test_util_test.go 8.05 KiB
Newer Older
  • Learn to ignore specific revisions
  • package server
    
    import (
    	"bytes"
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	"encoding/base64"
    
    	"log"
    	"testing"
    
    
    	spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
    
    	"code.fbi.h-da.de/danet/gosdn/controller/conflict"
    
    	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain"
    
    	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkelement"
    
    	rbacInterfaces "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac"
    	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
    	"code.fbi.h-da.de/danet/gosdn/controller/mocks"
    	"code.fbi.h-da.de/danet/gosdn/controller/nucleus"
    	"code.fbi.h-da.de/danet/gosdn/models/generated/openconfig"
    
    
    	"code.fbi.h-da.de/danet/gosdn/controller/rbac"
    	"code.fbi.h-da.de/danet/gosdn/controller/store"
    	"github.com/google/uuid"
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	"github.com/sethvargo/go-password/password"
    
    	"github.com/stretchr/testify/mock"
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	"golang.org/x/crypto/argon2"
    
    const pndID = "2043519e-46d1-4963-9a8e-d99007e104b8"
    const pendingChangeID = "0992d600-f7d4-4906-9559-409b04d59a5f"
    const committedChangeID = "804787d6-e5a8-4dba-a1e6-e73f96b0119e"
    const sbiID = "f6fd4b35-f039-4111-9156-5e4501bb8a5a"
    
    const mneID = "7e0ed8cc-ebf5-46fa-9794-741494914883"
    
    
    var hostname = "manfred"
    var domainname = "uwe"
    var pndUUID uuid.UUID
    var sbiUUID uuid.UUID
    var pendingChangeUUID uuid.UUID
    var committedChangeUUID uuid.UUID
    
    var mockPnd *mocks.NetworkDomain
    
    var mockNetworkElement networkelement.NetworkElement
    
    var sbiStore southbound.Store
    
    
    // Name of this file requires _test at the end, because of how the availability of varibales is handled in test files of go packages.
    // Does not include actual file tests!
    
    const adminID = "5c248a22-8eb7-48cf-b392-45680a1863a5"
    const userID = "57005d13-7a4d-493d-a02b-50ca51c40197"
    const adminRoleID = "126683ae-5ff2-43ee-92f7-0e2b936f8c77"
    const randomRoleName = "bertram"
    
    var adminRoleMap = map[string]string{pndID: "adminTestRole"}
    var userRoleMap = map[string]string{pndID: "userTestRole"}
    
    
    func clearAndCreateAuthTestSetup(userService rbacInterfaces.UserService, roleService rbacInterfaces.RoleService) error {
    
    	//clear setup if changed
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	storedUsers, err := userService.GetAll()
    
    	if err != nil {
    		return err
    	}
    	for _, u := range storedUsers {
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    		err = userService.Delete(u)
    
    		if err != nil {
    			return err
    		}
    	}
    
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	storedRoles, err := roleService.GetAll()
    
    	if err != nil {
    		return err
    	}
    	for _, r := range storedRoles {
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    		err = roleService.Delete(r)
    
    		if err != nil {
    			return err
    		}
    	}
    
    	// create dataset
    
    	err = createTestUsers(userService)
    
    	if err != nil {
    		return err
    	}
    
    
    	err = createTestRoles(roleService)
    
    	if err != nil {
    		return err
    	}
    
    	return nil
    }
    
    
    func createTestUsers(userService rbacInterfaces.UserService) error {
    
    	randomRoleMap := map[string]string{pndID: randomRoleName}
    
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    	// Generate a salt that is 16 characters long with 3 digits, 0 symbols,
    	// allowing upper and lower case letters, disallowing repeat characters.
    	salt, err := password.Generate(16, 3, 0, true, false)
    	if err != nil {
    		return err
    	}
    
    	testAdminPWD := createHashedAndSaltedPassword("admin", salt)
    	testUserPWD := createHashedAndSaltedPassword("user", salt)
    	testRandPWD := createHashedAndSaltedPassword("aurelius", salt)
    
    
    	users := []rbac.User{
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    		{UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: testAdminPWD},
    		{UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: testUserPWD},
    		{UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: testRandPWD, Token: "wrong token"},
    
    	}
    
    	for _, u := range users {
    
    		err := userService.Add(rbac.NewUser(u.ID(), u.Name(), u.Roles, u.Password, "", salt, conflict.Metadata{ResourceVersion: 0}))
    
    		if err != nil {
    			return err
    		}
    	}
    
    	return nil
    }
    
    
    func createTestRoles(roleService rbacInterfaces.RoleService) error {
    
    	roles := []rbac.Role{
    		{
    			RoleID:      uuid.MustParse(adminRoleID),
    			RoleName:    "adminTestRole",
    			Description: "Admin",
    			Permissions: []string{
    				"/gosdn.core.CoreService/GetPnd",
    				"/gosdn.core.CoreService/GetPndList",
    				"/gosdn.rbac.UserService/GetUsers",
    				"/gosdn.southbound.SbiService/GetSchema",
    			},
    		},
    		{
    			RoleID:      uuid.New(),
    			RoleName:    "userTestRole",
    			Description: "User",
    			Permissions: []string{
    				"/gosdn.pnd.PndService/GetChangeList",
    			},
    		},
    		{
    			RoleID:      uuid.New(),
    			RoleName:    randomRoleName,
    			Description: "Not a role",
    			Permissions: []string{
    				"nope",
    			},
    		},
    	}
    
    	for _, r := range roles {
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    		err := roleService.Add(rbac.NewRole(r.ID(), r.Name(), r.Description, r.Permissions))
    
    		if err != nil {
    			return err
    		}
    	}
    
    	return nil
    }
    
    // This is needed as a workaround for a bug where the output of the getUser test falsely was
    
    // that it failed while actually passing. Apparently, this can happen when loggers write
    
    // the output of test cases.
    // Solution found here: https://github.com/gotestyourself/gotestsum/issues/141#issuecomment-686243110
    func patchLogger(t *testing.T) {
    	orig := log.Writer()
    	buf := new(bytes.Buffer)
    	log.SetOutput(buf)
    
    	t.Cleanup(func() {
    		// optionally check t.Failed here if you only want to print logs on failure
    
    		t.Log(buf.String())
    		log.SetOutput(orig)
    	})
    }
    
    // Creates a token to be used in auth interceptor tests. If validTokenRequired is set as true, the generated token will also
    // be attached to the provided user. Else the user won't have the token and can not be authorized.
    
    func createTestUserToken(userName string, validTokenRequired bool, userService rbacInterfaces.UserService, jwt *rbac.JWTManager) (string, error) {
    
    	token, err := jwt.GenerateToken(rbac.User{UserName: userName})
    	if err != nil {
    		return token, err
    	}
    
    	if validTokenRequired {
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    		user, err := userService.Get(store.Query{Name: userName})
    
    		if err != nil {
    			return token, err
    		}
    		user.SetToken(token)
    
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    		err = userService.Update(user)
    
    		if err != nil {
    			return token, err
    		}
    	}
    
    	return token, nil
    }
    
    Fabian Seidl's avatar
    Fabian Seidl committed
    
    func createHashedAndSaltedPassword(plainPWD, salt string) string {
    	return base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(plainPWD), []byte(salt), 1, 64*1024, 4, 32))
    }
    
    
    func getMockPnd(t *testing.T) networkdomain.NetworkDomain {
    
    	mockNetworkElement = &nucleus.CommonNetworkElement{
    
    		Model: &openconfig.Device{
    			System: &openconfig.OpenconfigSystem_System{
    				Config: &openconfig.OpenconfigSystem_System_Config{
    					Hostname:   &hostname,
    					DomainName: &domainname,
    				},
    			},
    		},
    
    	}
    
    	sbi, err := nucleus.NewSBI(spb.Type_TYPE_OPENCONFIG, sbiUUID)
    	if err != nil {
    		t.Fatal(err)
    	}
    
    	mockNetworkElement.(*nucleus.CommonNetworkElement).SetSBI(sbi)
    	mockNetworkElement.(*nucleus.CommonNetworkElement).SetTransport(&mocks.Transport{})
    	mockNetworkElement.(*nucleus.CommonNetworkElement).SetName(hostname)
    
    	sbiStore = nucleus.NewSbiStore(pndUUID)
    
    	if err := sbiStore.Add(mockNetworkElement.SBI()); err != nil {
    
    		t.Fatal(err)
    	}
    
    	mockPnd = &mocks.NetworkDomain{}
    	mockPnd.On("ID").Return(pndUUID)
    	mockPnd.On("GetName").Return("test")
    	mockPnd.On("GetDescription").Return("test")
    	mockPnd.On("GetSBIs").Return(sbiStore)
    
    	mockPnd.On("GetSBI", mock.Anything).Return(mockNetworkElement.SBI(), nil)
    	mockPnd.On("NetworkElements").Return([]uuid.UUID{mneUUID})
    
    	mockPnd.On("PendingChanges").Return([]uuid.UUID{pendingChangeUUID})
    	mockPnd.On("CommittedChanges").Return([]uuid.UUID{committedChangeUUID})
    
    	mockPnd.On("AddNetworkElement", mock.Anything, mock.Anything, mock.Anything).Return(nil)
    	mockPnd.On("GetNetworkElement", mock.Anything).Return(mockNetworkElement, nil)
    
    	mockPnd.On("Commit", mock.Anything).Return(nil)
    	mockPnd.On("Confirm", mock.Anything).Return(nil)
    
    	mockPnd.On("ChangeMNE", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(uuid.Nil, nil)
    
    	mockPnd.On("Request", mock.Anything, mock.Anything).Return(nil, nil)
    
    	return mockPnd
    }
    
    func initUUIDs(t *testing.T) {
    	var err error
    	pndUUID, err = uuid.Parse(pndID)
    	if err != nil {
    		t.Fatal(err)
    	}
    
    	sbiUUID, err = uuid.Parse(sbiID)
    	if err != nil {
    		t.Fatal(err)
    	}
    
    	pendingChangeUUID, err = uuid.Parse(pendingChangeID)
    	if err != nil {
    		t.Fatal(err)
    	}
    
    	committedChangeUUID, err = uuid.Parse(committedChangeID)
    	if err != nil {
    		t.Fatal(err)
    	}
    
    
    	mneUUID, err = uuid.Parse(mneID)