Add credentials manager unit test in vSphere Cloud Provider
This commit is contained in:
		
							
								
								
									
										322
									
								
								pkg/cloudprovider/providers/vsphere/credentialmanager_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								pkg/cloudprovider/providers/vsphere/credentialmanager_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,322 @@
 | 
			
		||||
package vsphere
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	corev1 "k8s.io/api/core/v1"
 | 
			
		||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		||||
	"k8s.io/apimachinery/pkg/labels"
 | 
			
		||||
	"k8s.io/client-go/informers"
 | 
			
		||||
	"k8s.io/client-go/kubernetes/fake"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/controller"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestSecretCredentialManager_GetCredential(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		userKey             = "username"
 | 
			
		||||
		passwordKey         = "password"
 | 
			
		||||
		testUser            = "user"
 | 
			
		||||
		testPassword        = "password"
 | 
			
		||||
		testServer          = "0.0.0.0"
 | 
			
		||||
		testServer2         = "0.0.1.1"
 | 
			
		||||
		testUserServer2     = "user1"
 | 
			
		||||
		testPasswordServer2 = "password1"
 | 
			
		||||
		testIncorrectServer = "1.1.1.1"
 | 
			
		||||
	)
 | 
			
		||||
	var (
 | 
			
		||||
		secretName      = "vsconf"
 | 
			
		||||
		secretNamespace = "kube-system"
 | 
			
		||||
	)
 | 
			
		||||
	var (
 | 
			
		||||
		addSecretOp      = "ADD_SECRET_OP"
 | 
			
		||||
		getCredentialsOp = "GET_CREDENTIAL_OP"
 | 
			
		||||
		deleteSecretOp   = "DELETE_SECRET_OP"
 | 
			
		||||
	)
 | 
			
		||||
	type GetCredentialsTest struct {
 | 
			
		||||
		server   string
 | 
			
		||||
		username string
 | 
			
		||||
		password string
 | 
			
		||||
		err      error
 | 
			
		||||
	}
 | 
			
		||||
	type OpSecretTest struct {
 | 
			
		||||
		secret *corev1.Secret
 | 
			
		||||
	}
 | 
			
		||||
	type testEnv struct {
 | 
			
		||||
		testName       string
 | 
			
		||||
		ops            []string
 | 
			
		||||
		expectedValues []interface{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client := &fake.Clientset{}
 | 
			
		||||
	metaObj := metav1.ObjectMeta{
 | 
			
		||||
		Name:      secretName,
 | 
			
		||||
		Namespace: secretNamespace,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defaultSecret := &corev1.Secret{
 | 
			
		||||
		ObjectMeta: metaObj,
 | 
			
		||||
		Data: map[string][]byte{
 | 
			
		||||
			testServer + "." + userKey:     []byte(testUser),
 | 
			
		||||
			testServer + "." + passwordKey: []byte(testPassword),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	multiVCSecret := &corev1.Secret{
 | 
			
		||||
		ObjectMeta: metaObj,
 | 
			
		||||
		Data: map[string][]byte{
 | 
			
		||||
			testServer + "." + userKey:      []byte(testUser),
 | 
			
		||||
			testServer + "." + passwordKey:  []byte(testPassword),
 | 
			
		||||
			testServer2 + "." + userKey:     []byte(testUserServer2),
 | 
			
		||||
			testServer2 + "." + passwordKey: []byte(testPasswordServer2),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	emptySecret := &corev1.Secret{
 | 
			
		||||
		ObjectMeta: metaObj,
 | 
			
		||||
		Data:       map[string][]byte{},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tests := []testEnv{
 | 
			
		||||
		{
 | 
			
		||||
			testName: "Deleting secret should give the credentials from cache",
 | 
			
		||||
			ops:      []string{addSecretOp, getCredentialsOp, deleteSecretOp, getCredentialsOp},
 | 
			
		||||
			expectedValues: []interface{}{
 | 
			
		||||
				OpSecretTest{
 | 
			
		||||
					secret: defaultSecret,
 | 
			
		||||
				},
 | 
			
		||||
				GetCredentialsTest{
 | 
			
		||||
					username: testUser,
 | 
			
		||||
					password: testPassword,
 | 
			
		||||
					server:   testServer,
 | 
			
		||||
				},
 | 
			
		||||
				OpSecretTest{
 | 
			
		||||
					secret: defaultSecret,
 | 
			
		||||
				},
 | 
			
		||||
				GetCredentialsTest{
 | 
			
		||||
					username: testUser,
 | 
			
		||||
					password: testPassword,
 | 
			
		||||
					server:   testServer,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			testName: "Add secret and get credentials",
 | 
			
		||||
			ops:      []string{addSecretOp, getCredentialsOp},
 | 
			
		||||
			expectedValues: []interface{}{
 | 
			
		||||
				OpSecretTest{
 | 
			
		||||
					secret: defaultSecret,
 | 
			
		||||
				},
 | 
			
		||||
				GetCredentialsTest{
 | 
			
		||||
					username: testUser,
 | 
			
		||||
					password: testPassword,
 | 
			
		||||
					server:   testServer,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			testName: "Getcredentials should fail by not adding at secret at first time",
 | 
			
		||||
			ops:      []string{getCredentialsOp},
 | 
			
		||||
			expectedValues: []interface{}{
 | 
			
		||||
				GetCredentialsTest{
 | 
			
		||||
					username: testUser,
 | 
			
		||||
					password: testPassword,
 | 
			
		||||
					server:   testServer,
 | 
			
		||||
					err:      ErrCredentialsNotFound,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			testName: "GetCredential should fail to get credentials from empty secrets",
 | 
			
		||||
			ops:      []string{addSecretOp, getCredentialsOp},
 | 
			
		||||
			expectedValues: []interface{}{
 | 
			
		||||
				OpSecretTest{
 | 
			
		||||
					secret: emptySecret,
 | 
			
		||||
				},
 | 
			
		||||
				GetCredentialsTest{
 | 
			
		||||
					server: testServer,
 | 
			
		||||
					err:    ErrCredentialMissing,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			testName: "GetCredential should fail to get credentials for invalid server",
 | 
			
		||||
			ops:      []string{addSecretOp, getCredentialsOp},
 | 
			
		||||
			expectedValues: []interface{}{
 | 
			
		||||
				OpSecretTest{
 | 
			
		||||
					secret: defaultSecret,
 | 
			
		||||
				},
 | 
			
		||||
				GetCredentialsTest{
 | 
			
		||||
					server: testIncorrectServer,
 | 
			
		||||
					err:    ErrCredentialsNotFound,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			testName: "GetCredential for multi-vc",
 | 
			
		||||
			ops:      []string{addSecretOp, getCredentialsOp},
 | 
			
		||||
			expectedValues: []interface{}{
 | 
			
		||||
				OpSecretTest{
 | 
			
		||||
					secret: multiVCSecret,
 | 
			
		||||
				},
 | 
			
		||||
				GetCredentialsTest{
 | 
			
		||||
					server:   testServer2,
 | 
			
		||||
					username: testUserServer2,
 | 
			
		||||
					password: testPasswordServer2,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
 | 
			
		||||
	secretInformer := informerFactory.Core().V1().Secrets()
 | 
			
		||||
	secretCredentialManager := &SecretCredentialManager{
 | 
			
		||||
		SecretName:      secretName,
 | 
			
		||||
		SecretNamespace: secretNamespace,
 | 
			
		||||
		SecretLister:    secretInformer.Lister(),
 | 
			
		||||
		Cache: &SecretCache{
 | 
			
		||||
			VirtualCenter: make(map[string]*Credential),
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	cleanupSecretCredentialManager := func() {
 | 
			
		||||
		secretCredentialManager.Cache.Secret = nil
 | 
			
		||||
		for key := range secretCredentialManager.Cache.VirtualCenter {
 | 
			
		||||
			delete(secretCredentialManager.Cache.VirtualCenter, key)
 | 
			
		||||
		}
 | 
			
		||||
		secrets, err := secretCredentialManager.SecretLister.List(labels.Everything())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatal("Failed to get all secrets from sharedInformer. error: ", err)
 | 
			
		||||
		}
 | 
			
		||||
		for _, secret := range secrets {
 | 
			
		||||
			secretInformer.Informer().GetIndexer().Delete(secret)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, test := range tests {
 | 
			
		||||
		t.Logf("Executing Testcase: %s", test.testName)
 | 
			
		||||
		for ntest, op := range test.ops {
 | 
			
		||||
			switch op {
 | 
			
		||||
			case addSecretOp:
 | 
			
		||||
				expected := test.expectedValues[ntest].(OpSecretTest)
 | 
			
		||||
				t.Logf("Adding secret: %s", expected.secret)
 | 
			
		||||
				err := secretInformer.Informer().GetIndexer().Add(expected.secret)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					t.Fatalf("Failed to add secret to internal cache: %v", err)
 | 
			
		||||
				}
 | 
			
		||||
			case getCredentialsOp:
 | 
			
		||||
				expected := test.expectedValues[ntest].(GetCredentialsTest)
 | 
			
		||||
				credential, err := secretCredentialManager.GetCredential(expected.server)
 | 
			
		||||
				t.Logf("Retrieving credentials for server %s", expected.server)
 | 
			
		||||
				if err != expected.err {
 | 
			
		||||
					t.Fatalf("Fail to get credentials with error: %v", err)
 | 
			
		||||
				}
 | 
			
		||||
				if expected.err == nil {
 | 
			
		||||
					if expected.username != credential.User ||
 | 
			
		||||
						expected.password != credential.Password {
 | 
			
		||||
						t.Fatalf("Recieved credentials %v "+
 | 
			
		||||
							"are diffrent than actual credential user:%s password:%s", credential, expected.username,
 | 
			
		||||
							expected.password)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			case deleteSecretOp:
 | 
			
		||||
				expected := test.expectedValues[ntest].(OpSecretTest)
 | 
			
		||||
				t.Logf("Deleting secret: %s", expected.secret)
 | 
			
		||||
				err := secretInformer.Informer().GetIndexer().Delete(expected.secret)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					t.Fatalf("Failed to delete secret to internal cache: %v", err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		cleanupSecretCredentialManager()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseSecretConfig(t *testing.T) {
 | 
			
		||||
	var (
 | 
			
		||||
		testUsername = "Admin"
 | 
			
		||||
		testPassword = "Password"
 | 
			
		||||
		testIP       = "10.20.30.40"
 | 
			
		||||
	)
 | 
			
		||||
	var testcases = []struct {
 | 
			
		||||
		testName      string
 | 
			
		||||
		data          map[string][]byte
 | 
			
		||||
		config        map[string]*Credential
 | 
			
		||||
		expectedError error
 | 
			
		||||
	}{
 | 
			
		||||
		{
 | 
			
		||||
			testName: "Valid username and password",
 | 
			
		||||
			data: map[string][]byte{
 | 
			
		||||
				"10.20.30.40.username": []byte(testUsername),
 | 
			
		||||
				"10.20.30.40.password": []byte(testPassword),
 | 
			
		||||
			},
 | 
			
		||||
			config: map[string]*Credential{
 | 
			
		||||
				testIP: {
 | 
			
		||||
					User:     testUsername,
 | 
			
		||||
					Password: testPassword,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedError: nil,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			testName: "Invalid username key with valid password key",
 | 
			
		||||
			data: map[string][]byte{
 | 
			
		||||
				"10.20.30.40.usernam":  []byte(testUsername),
 | 
			
		||||
				"10.20.30.40.password": []byte(testPassword),
 | 
			
		||||
			},
 | 
			
		||||
			config:        nil,
 | 
			
		||||
			expectedError: ErrUnknownSecretKey,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			testName: "Missing username",
 | 
			
		||||
			data: map[string][]byte{
 | 
			
		||||
				"10.20.30.40.password": []byte(testPassword),
 | 
			
		||||
			},
 | 
			
		||||
			config: map[string]*Credential{
 | 
			
		||||
				testIP: {
 | 
			
		||||
					Password: testPassword,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedError: ErrCredentialMissing,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			testName: "Missing password",
 | 
			
		||||
			data: map[string][]byte{
 | 
			
		||||
				"10.20.30.40.username": []byte(testUsername),
 | 
			
		||||
			},
 | 
			
		||||
			config: map[string]*Credential{
 | 
			
		||||
				testIP: {
 | 
			
		||||
					User: testUsername,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
			expectedError: ErrCredentialMissing,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			testName: "IP with unknown key",
 | 
			
		||||
			data: map[string][]byte{
 | 
			
		||||
				"10.20.30.40": []byte(testUsername),
 | 
			
		||||
			},
 | 
			
		||||
			config:        nil,
 | 
			
		||||
			expectedError: ErrUnknownSecretKey,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resultConfig := make(map[string]*Credential)
 | 
			
		||||
	cleanupResultConfig := func(config map[string]*Credential) {
 | 
			
		||||
		for k := range config {
 | 
			
		||||
			delete(config, k)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, testcase := range testcases {
 | 
			
		||||
		err := parseConfig(testcase.data, resultConfig)
 | 
			
		||||
		t.Logf("Executing Testcase: %s", testcase.testName)
 | 
			
		||||
		if err != testcase.expectedError {
 | 
			
		||||
			t.Fatalf("Parsing Secret failed for data %+v: %s", testcase.data, err)
 | 
			
		||||
		}
 | 
			
		||||
		if testcase.config != nil && !reflect.DeepEqual(testcase.config, resultConfig) {
 | 
			
		||||
			t.Fatalf("Parsing Secret failed for data %+v expected config %+v and actual config %+v",
 | 
			
		||||
				testcase.data, resultConfig, testcase.config)
 | 
			
		||||
		}
 | 
			
		||||
		cleanupResultConfig(resultConfig)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user