Skip to content

Commit

Permalink
[YUNIKORN-2623] Create unit tests for Clients (#839)
Browse files Browse the repository at this point in the history
Closes: #839

Signed-off-by: Peter Bacsko <pbacsko@cloudera.com>
  • Loading branch information
pbacsko committed May 14, 2024
1 parent 4f8da23 commit d5d70e3
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 22 deletions.
61 changes: 52 additions & 9 deletions pkg/client/apifactory_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,13 @@ func NewMockedAPIProvider(showError bool) *MockedAPIProvider {
PodInformer: test.NewMockedPodInformer(),
NodeInformer: test.NewMockedNodeInformer(),
ConfigMapInformer: test.NewMockedConfigMapInformer(),
PVInformer: &MockedPersistentVolumeInformer{},
PVCInformer: &MockedPersistentVolumeClaimInformer{},
StorageInformer: &MockedStorageClassInformer{},
PVInformer: NewMockedPersistentVolumeInformer(),
PVCInformer: NewMockedPersistentVolumeClaimInformer(),
StorageInformer: NewMockedStorageClassInformer(),
VolumeBinder: test.NewVolumeBinderMock(),
NamespaceInformer: test.NewMockNamespaceInformer(false),
PriorityClassInformer: test.NewMockPriorityClassInformer(),
CSINodeInformer: NewMockedCSINodeInformer(),
InformerFactory: informers.NewSharedInformerFactory(k8fake.NewSimpleClientset(), time.Second*60),
},
events: make(chan informerEvent),
Expand Down Expand Up @@ -416,38 +417,80 @@ func (m *MockedAPIProvider) GetBoundPods(clear bool) []BoundPod {
}

// MockedPersistentVolumeInformer implements PersistentVolumeInformer interface
type MockedPersistentVolumeInformer struct{}
type MockedPersistentVolumeInformer struct {
informer cache.SharedIndexInformer
}

func NewMockedPersistentVolumeInformer() *MockedPersistentVolumeInformer {
return &MockedPersistentVolumeInformer{
informer: &test.SharedInformerMock{},
}
}

func (m *MockedPersistentVolumeInformer) Informer() cache.SharedIndexInformer {
return nil
return m.informer
}

func (m *MockedPersistentVolumeInformer) Lister() corev1.PersistentVolumeLister {
return nil
}

// MockedPersistentVolumeClaimInformer implements PersistentVolumeClaimInformer interface
type MockedPersistentVolumeClaimInformer struct{}
type MockedPersistentVolumeClaimInformer struct {
informer cache.SharedIndexInformer
}

func NewMockedPersistentVolumeClaimInformer() *MockedPersistentVolumeClaimInformer {
return &MockedPersistentVolumeClaimInformer{
informer: &test.SharedInformerMock{},
}
}

func (m *MockedPersistentVolumeClaimInformer) Informer() cache.SharedIndexInformer {
return nil
return m.informer
}

func (m *MockedPersistentVolumeClaimInformer) Lister() corev1.PersistentVolumeClaimLister {
return nil
}

// MockedStorageClassInformer implements StorageClassInformer interface
type MockedStorageClassInformer struct{}
type MockedStorageClassInformer struct {
informer cache.SharedIndexInformer
}

func NewMockedStorageClassInformer() *MockedStorageClassInformer {
return &MockedStorageClassInformer{
informer: &test.SharedInformerMock{},
}
}

func (m *MockedStorageClassInformer) Informer() cache.SharedIndexInformer {
return nil
return m.informer
}

func (m *MockedStorageClassInformer) Lister() storagev1.StorageClassLister {
return nil
}

type MockedCSINodeInformer struct {
informer cache.SharedIndexInformer
}

func NewMockedCSINodeInformer() *MockedCSINodeInformer {
return &MockedCSINodeInformer{
informer: &test.SharedInformerMock{},
}
}

func (m *MockedCSINodeInformer) Informer() cache.SharedIndexInformer {
return m.informer
}

func (m *MockedCSINodeInformer) Lister() storagev1.CSINodeLister {
return nil
}

func (m *MockedAPIProvider) SetVolumeBinder(binder volumebinding.SchedulerVolumeBinder) {
m.clients.VolumeBinder = binder
}
86 changes: 86 additions & 0 deletions pkg/client/clients_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package client

import (
"testing"
"time"

"gotest.tools/v3/assert"

"github.com/apache/yunikorn-core/pkg/common"
"github.com/apache/yunikorn-k8shim/pkg/common/test"
)

const (
noOfInformers = 9 // total number of active informers
)

func TestWaitForSync(t *testing.T) {
clients := getClients()
test.SyncDone.Store(false)
go func() {
time.Sleep(500 * time.Millisecond)
test.SyncDone.Store(true)
}()

start := time.Now()
clients.WaitForSync()
diff := time.Since(start)
assert.Equal(t, int64(1000), diff.Truncate(time.Second).Milliseconds(), "WaitForSync() didn't block for 1 second")
}

func TestRun(t *testing.T) {
stopped := false
clients := getClients()
test.RunningInformers.Store(0)
stop := make(chan struct{})
defer func() {
if !stopped {
close(stop)
}
}()

clients.Run(stop)
err := common.WaitForCondition(func() bool {
return test.RunningInformers.Load() == noOfInformers
}, 10*time.Millisecond, time.Second)
assert.NilError(t, err, "number of running informers: expected %d got %d", noOfInformers, test.RunningInformers.Load())

close(stop)
stopped = true
err = common.WaitForCondition(func() bool {
return test.RunningInformers.Load() == 0
}, 10*time.Millisecond, time.Second)
assert.NilError(t, err, "no. of informers still running: %d", test.RunningInformers.Load())
}

func getClients() *Clients {
return &Clients{
PodInformer: test.NewMockedPodInformer(),
NodeInformer: test.NewMockedNodeInformer(),
ConfigMapInformer: test.NewMockedConfigMapInformer(),
PVInformer: NewMockedPersistentVolumeInformer(),
PVCInformer: NewMockedPersistentVolumeClaimInformer(),
StorageInformer: NewMockedStorageClassInformer(),
CSINodeInformer: NewMockedCSINodeInformer(),
NamespaceInformer: test.NewMockNamespaceInformer(false),
PriorityClassInformer: test.NewMockPriorityClassInformer(),
}
}
12 changes: 7 additions & 5 deletions pkg/common/test/configmap_informer_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,21 @@ import (
)

type ConfigMapInformerMock struct {
lister v1.ConfigMapLister
lister v1.ConfigMapLister
informer cache.SharedIndexInformer
}

func NewMockedConfigMapInformer() *ConfigMapInformerMock {
return &ConfigMapInformerMock{
lister: NewConfigMapListerMock(),
lister: NewConfigMapListerMock(),
informer: &SharedInformerMock{},
}
}

func (c ConfigMapInformerMock) Informer() cache.SharedIndexInformer {
return nil
func (c *ConfigMapInformerMock) Informer() cache.SharedIndexInformer {
return c.informer
}

func (c ConfigMapInformerMock) Lister() v1.ConfigMapLister {
func (c *ConfigMapInformerMock) Lister() v1.ConfigMapLister {
return c.lister
}
8 changes: 5 additions & 3 deletions pkg/common/test/namespaceinformer_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@ import (
)

type MockNamespaceInformer struct {
lister listersV1.NamespaceLister
lister listersV1.NamespaceLister
informer cache.SharedIndexInformer
}

func NewMockNamespaceInformer(errIfNotFound bool) informersV1.NamespaceInformer {
return &MockNamespaceInformer{
lister: NewMockNamespaceLister(errIfNotFound),
lister: NewMockNamespaceLister(errIfNotFound),
informer: &SharedInformerMock{},
}
}

func (nsi *MockNamespaceInformer) Informer() cache.SharedIndexInformer {
return nil
return nsi.informer
}

func (nsi *MockNamespaceInformer) Lister() listersV1.NamespaceLister {
Expand Down
4 changes: 3 additions & 1 deletion pkg/common/test/nodeinformer_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ import (

type MockedNodeInformer struct {
nodeLister v1.NodeLister
informer cache.SharedIndexInformer
}

func NewMockedNodeInformer() *MockedNodeInformer {
return &MockedNodeInformer{
nodeLister: NewNodeListerMock(),
informer: &SharedInformerMock{},
}
}

func (m *MockedNodeInformer) Informer() cache.SharedIndexInformer {
return nil
return m.informer
}

func (m *MockedNodeInformer) Lister() v1.NodeLister {
Expand Down
4 changes: 3 additions & 1 deletion pkg/common/test/podinformer_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ import (

type MockedPodInformer struct {
podLister v1.PodLister
informer cache.SharedIndexInformer
}

func NewMockedPodInformer() *MockedPodInformer {
return &MockedPodInformer{
podLister: NewPodListerMock(),
informer: &SharedInformerMock{},
}
}

func (m *MockedPodInformer) Informer() cache.SharedIndexInformer {
return nil
return m.informer
}

func (m *MockedPodInformer) Lister() v1.PodLister {
Expand Down
8 changes: 5 additions & 3 deletions pkg/common/test/priorityclass_informer_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@ import (
)

type MockPriorityClassInformer struct {
lister listersV1.PriorityClassLister
lister listersV1.PriorityClassLister
informer cache.SharedIndexInformer
}

func NewMockPriorityClassInformer() informersV1.PriorityClassInformer {
return &MockPriorityClassInformer{
lister: NewMockPriorityClassLister(),
lister: NewMockPriorityClassLister(),
informer: &SharedInformerMock{},
}
}

func (nsi *MockPriorityClassInformer) Informer() cache.SharedIndexInformer {
return nil
return nsi.informer
}

func (nsi *MockPriorityClassInformer) Lister() listersV1.PriorityClassLister {
Expand Down
94 changes: 94 additions & 0 deletions pkg/common/test/shared_informer_mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package test

import (
"sync/atomic"
"time"

"k8s.io/client-go/tools/cache"
)

func init() {
SyncDone.Store(true) // shouldn't block by default
}

var (
SyncDone atomic.Bool
RunningInformers atomic.Int64

_ cache.SharedIndexInformer = &SharedInformerMock{}
)

type SharedInformerMock struct {
}

func (s *SharedInformerMock) AddEventHandler(_ cache.ResourceEventHandler) (cache.ResourceEventHandlerRegistration, error) {
return nil, nil
}

func (s *SharedInformerMock) AddEventHandlerWithResyncPeriod(_ cache.ResourceEventHandler, _ time.Duration) (cache.ResourceEventHandlerRegistration, error) {
return nil, nil
}

func (s *SharedInformerMock) RemoveEventHandler(handle cache.ResourceEventHandlerRegistration) error {
return nil
}

func (s *SharedInformerMock) GetStore() cache.Store {
return nil
}

func (s *SharedInformerMock) GetController() cache.Controller {
return nil
}

func (s *SharedInformerMock) Run(stopCh <-chan struct{}) {
RunningInformers.Add(1)
<-stopCh
RunningInformers.Add(-1)
}

func (s *SharedInformerMock) HasSynced() bool {
return SyncDone.Load()
}

func (s *SharedInformerMock) LastSyncResourceVersion() string {
return ""
}

func (s *SharedInformerMock) SetWatchErrorHandler(_ cache.WatchErrorHandler) error {
return nil
}

func (s *SharedInformerMock) SetTransform(_ cache.TransformFunc) error {
return nil
}

func (s *SharedInformerMock) IsStopped() bool {
return false
}

func (s *SharedInformerMock) AddIndexers(_ cache.Indexers) error {
return nil
}

func (s *SharedInformerMock) GetIndexer() cache.Indexer {
return nil
}

0 comments on commit d5d70e3

Please sign in to comment.