k3s/pkg/nodepassword/nodepassword_test.go
Hussein Galal af50e1b096
Update to v1.28.0-k3s1 (#8199)
* Update to v1.28.0

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

* Update golang to v1.20.7

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

* more changes

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

* update wrangler

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

* update wrangler

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

* fix nodepassword test

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

* fix nodepassword test

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

* disable CGO before running golangci-lint

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

* execlude CGO Enabled checks

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

* Ignore reapply change error with logging

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

* Update google api client

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>

---------

Signed-off-by: galal-hussein <hussein.galal.ahmed.11@gmail.com>
2023-08-23 00:09:31 +03:00

273 lines
7.7 KiB
Go

package nodepassword
import (
"errors"
"fmt"
"log"
"os"
"runtime"
"testing"
"github.com/rancher/wrangler/pkg/generic"
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/rest"
)
const migrateNumNodes = 10
const createNumNodes = 3
func Test_UnitAsserts(t *testing.T) {
assertEqual(t, 1, 1)
assertNotEqual(t, 1, 0)
}
func Test_UnitEnsureDelete(t *testing.T) {
logMemUsage(t)
secretClient := &mockSecretClient{}
assertEqual(t, Ensure(secretClient, "node1", "Hello World"), nil)
assertEqual(t, Ensure(secretClient, "node1", "Hello World"), nil)
assertNotEqual(t, Ensure(secretClient, "node1", "Goodbye World"), nil)
assertEqual(t, secretClient.created, 1)
assertEqual(t, Delete(secretClient, "node1"), nil)
assertNotEqual(t, Delete(secretClient, "node1"), nil)
assertEqual(t, secretClient.deleted, 1)
assertEqual(t, Ensure(secretClient, "node1", "Hello Universe"), nil)
assertNotEqual(t, Ensure(secretClient, "node1", "Hello World"), nil)
assertEqual(t, Ensure(secretClient, "node1", "Hello Universe"), nil)
assertEqual(t, secretClient.created, 2)
logMemUsage(t)
}
func Test_UnitMigrateFile(t *testing.T) {
nodePasswordFile := generateNodePasswordFile(migrateNumNodes)
defer os.Remove(nodePasswordFile)
secretClient := &mockSecretClient{}
nodeClient := &mockNodeClient{}
logMemUsage(t)
if err := MigrateFile(secretClient, nodeClient, nodePasswordFile); err != nil {
log.Fatal(err)
}
logMemUsage(t)
assertEqual(t, secretClient.created, migrateNumNodes)
assertNotEqual(t, Ensure(secretClient, "node1", "Hello World"), nil)
assertEqual(t, Ensure(secretClient, "node1", "node1"), nil)
}
func Test_UnitMigrateFileNodes(t *testing.T) {
nodePasswordFile := generateNodePasswordFile(migrateNumNodes)
defer os.Remove(nodePasswordFile)
secretClient := &mockSecretClient{}
nodeClient := &mockNodeClient{}
nodeClient.nodes = make([]v1.Node, createNumNodes, createNumNodes)
for i := range nodeClient.nodes {
nodeClient.nodes[i].Name = fmt.Sprintf("node%d", i+1)
}
logMemUsage(t)
if err := MigrateFile(secretClient, nodeClient, nodePasswordFile); err != nil {
log.Fatal(err)
}
logMemUsage(t)
assertEqual(t, secretClient.created, createNumNodes)
for _, node := range nodeClient.nodes {
assertNotEqual(t, Ensure(secretClient, node.Name, "wrong-password"), nil)
assertEqual(t, Ensure(secretClient, node.Name, node.Name), nil)
}
newNode := fmt.Sprintf("node%d", createNumNodes+1)
assertEqual(t, Ensure(secretClient, newNode, "new-password"), nil)
assertNotEqual(t, Ensure(secretClient, newNode, "wrong-password"), nil)
}
func Test_PasswordError(t *testing.T) {
err := &passwordError{node: "test", err: fmt.Errorf("inner error")}
assertEqual(t, errors.Is(err, ErrVerifyFailed), true)
assertEqual(t, errors.Is(err, fmt.Errorf("different error")), false)
assertNotEqual(t, errors.Unwrap(err), nil)
}
// --------------------------
// mock secret client interface
type mockSecretClient struct {
entries map[string]map[string]v1.Secret
created int
deleted int
}
func (m *mockSecretClient) Create(secret *v1.Secret) (*v1.Secret, error) {
if m.entries == nil {
m.entries = map[string]map[string]v1.Secret{}
}
if _, ok := m.entries[secret.Namespace]; !ok {
m.entries[secret.Namespace] = map[string]v1.Secret{}
}
if _, ok := m.entries[secret.Namespace][secret.Name]; ok {
return nil, errorAlreadyExists()
}
m.created++
m.entries[secret.Namespace][secret.Name] = *secret
return secret, nil
}
func (m *mockSecretClient) Update(secret *v1.Secret) (*v1.Secret, error) {
return nil, errorNotImplemented()
}
func (m *mockSecretClient) Delete(namespace, name string, options *metav1.DeleteOptions) error {
if m.entries == nil {
return errorNotFound()
}
if _, ok := m.entries[namespace]; !ok {
return errorNotFound()
}
if _, ok := m.entries[namespace][name]; !ok {
return errorNotFound()
}
m.deleted++
delete(m.entries[namespace], name)
return nil
}
func (m *mockSecretClient) Get(namespace, name string, options metav1.GetOptions) (*v1.Secret, error) {
if m.entries == nil {
return nil, errorNotFound()
}
if _, ok := m.entries[namespace]; !ok {
return nil, errorNotFound()
}
if secret, ok := m.entries[namespace][name]; ok {
return &secret, nil
}
return nil, errorNotFound()
}
func (m *mockSecretClient) List(namespace string, opts metav1.ListOptions) (*v1.SecretList, error) {
return nil, errorNotImplemented()
}
func (m *mockSecretClient) Watch(namespace string, opts metav1.ListOptions) (watch.Interface, error) {
return nil, errorNotImplemented()
}
func (m *mockSecretClient) Patch(namespace, name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Secret, err error) {
return nil, errorNotImplemented()
}
func (m *mockSecretClient) UpdateStatus(secret *v1.Secret) (*v1.Secret, error) {
return nil, errorNotImplemented()
}
func (m *mockSecretClient) WithImpersonation(rest.ImpersonationConfig) (generic.ClientInterface[*v1.Secret, *v1.SecretList], error) {
return nil, errorNotImplemented()
}
// --------------------------
// mock node client interface
type mockNodeClient struct {
nodes []v1.Node
}
func (m *mockNodeClient) Create(node *v1.Node) (*v1.Node, error) {
return nil, errorNotImplemented()
}
func (m *mockNodeClient) Update(node *v1.Node) (*v1.Node, error) {
return nil, errorNotImplemented()
}
func (m *mockNodeClient) UpdateStatus(node *v1.Node) (*v1.Node, error) {
return nil, errorNotImplemented()
}
func (m *mockNodeClient) Delete(name string, options *metav1.DeleteOptions) error {
return errorNotImplemented()
}
func (m *mockNodeClient) Get(name string, options metav1.GetOptions) (*v1.Node, error) {
return nil, errorNotImplemented()
}
func (m *mockNodeClient) List(opts metav1.ListOptions) (*v1.NodeList, error) {
return &v1.NodeList{Items: m.nodes}, nil
}
func (m *mockNodeClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
return nil, errorNotImplemented()
}
func (m *mockNodeClient) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Node, err error) {
return nil, errorNotImplemented()
}
func (m *mockNodeClient) WithImpersonation(rest.ImpersonationConfig) (generic.NonNamespacedClientInterface[*v1.Node, *v1.NodeList], error) {
return nil, errorNotImplemented()
}
// --------------------------
// utility functions
func assertEqual(t *testing.T, a interface{}, b interface{}) {
if a != b {
t.Fatalf("[ %v != %v ]", a, b)
}
}
func assertNotEqual(t *testing.T, a interface{}, b interface{}) {
if a == b {
t.Fatalf("[ %v == %v ]", a, b)
}
}
func generateNodePasswordFile(migrateNumNodes int) string {
tempFile, err := os.CreateTemp("", "node-password-test.*")
if err != nil {
log.Fatal(err)
}
tempFile.Close()
var passwordEntries string
for i := 1; i <= migrateNumNodes; i++ {
passwordEntries += fmt.Sprintf("node%d,node%d\n", i, i)
}
if err := os.WriteFile(tempFile.Name(), []byte(passwordEntries), 0600); err != nil {
log.Fatal(err)
}
return tempFile.Name()
}
func errorNotFound() error {
return apierrors.NewNotFound(schema.GroupResource{}, "not-found")
}
func errorAlreadyExists() error {
return apierrors.NewAlreadyExists(schema.GroupResource{}, "already-exists")
}
func errorNotImplemented() error {
log.Fatal("not implemented")
return apierrors.NewMethodNotSupported(schema.GroupResource{}, "not-implemented")
}
func logMemUsage(t *testing.T) {
var stats runtime.MemStats
runtime.ReadMemStats(&stats)
t.Logf("Memory Usage: Alloc=%d MB, Sys=%d MB, NumGC=%d",
toMB(stats.Alloc), toMB(stats.Sys), stats.NumGC)
}
func toMB(bytes uint64) uint64 {
return bytes / (1024 * 1024)
}