github.com/docker/compose-on-kubernetes@v0.5.0/internal/controller/stacklistener_test.go (about) 1 package controller 2 3 import ( 4 "sync" 5 "testing" 6 7 "github.com/docker/compose-on-kubernetes/api/compose/latest" 8 "github.com/stretchr/testify/assert" 9 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 "k8s.io/client-go/rest" 11 "k8s.io/client-go/tools/cache" 12 ) 13 14 type dummyOwnerCache struct { 15 mut sync.Mutex 16 data map[string]stackOwnerCacheEntry 17 } 18 19 func (s *dummyOwnerCache) remove(key string) { 20 s.mut.Lock() 21 defer s.mut.Unlock() 22 delete(s.data, key) 23 } 24 25 func (s *dummyOwnerCache) setDirty(key string) { 26 s.mut.Lock() 27 defer s.mut.Unlock() 28 if entry, ok := s.data[key]; ok { 29 entry.dirty = true 30 s.data[key] = entry 31 } 32 } 33 34 func (s *dummyOwnerCache) getWithRetries(stack *latest.Stack, acceptDirty bool) (rest.ImpersonationConfig, error) { 35 return rest.ImpersonationConfig{}, nil 36 } 37 func TestStackListenerCacheInvalidation(t *testing.T) { 38 cache := &dummyOwnerCache{ 39 data: map[string]stackOwnerCacheEntry{ 40 "ns/test-add": {config: rest.ImpersonationConfig{UserName: "test"}}, 41 "ns/test-update": {config: rest.ImpersonationConfig{UserName: "test"}}, 42 "ns/test-delete": {config: rest.ImpersonationConfig{UserName: "test"}}, 43 }, 44 } 45 reconcileQueue := make(chan string) 46 defer close(reconcileQueue) 47 deleteQueue := make(chan *latest.Stack) 48 defer close(deleteQueue) 49 go func() { 50 for range reconcileQueue { 51 } 52 }() 53 go func() { 54 for range deleteQueue { 55 } 56 }() 57 testee := &StackListener{ 58 reconcileQueue: reconcileQueue, 59 reconcileDeletionQueue: deleteQueue, 60 ownerCache: cache, 61 } 62 testee.onAdd(&latest.Stack{ 63 ObjectMeta: metav1.ObjectMeta{ 64 Namespace: "ns", 65 Name: "test-add", 66 }, 67 }) 68 testee.onUpdate(nil, &latest.Stack{ 69 ObjectMeta: metav1.ObjectMeta{ 70 Namespace: "ns", 71 Name: "test-update", 72 }, 73 }) 74 testee.onDelete(&latest.Stack{ 75 ObjectMeta: metav1.ObjectMeta{ 76 Namespace: "ns", 77 Name: "test-delete", 78 }, 79 }) 80 81 // delete should not invalidate cache (to make children deletion possible) 82 // add and update should 83 84 addEntry, hasAdd := cache.data["ns/test-add"] 85 updateEntry, hasUpdate := cache.data["ns/test-update"] 86 deleteEntry, hasDelete := cache.data["ns/test-delete"] 87 assert.True(t, hasAdd) 88 assert.True(t, addEntry.dirty) 89 assert.True(t, hasUpdate) 90 assert.True(t, updateEntry.dirty) 91 assert.True(t, hasDelete) 92 assert.False(t, deleteEntry.dirty) 93 } 94 95 type testStore struct { 96 store cache.Store 97 } 98 99 func (s *testStore) GetStore() cache.Store { 100 return s.store 101 } 102 103 func (s *testStore) Run(<-chan struct{}) { 104 } 105 106 func TestStackListenerGetByKey(t *testing.T) { 107 storeMock := &testStore{store: cache.NewStore(cache.DeletionHandlingMetaNamespaceKeyFunc)} 108 storeMock.store.Add(&latest.Stack{ 109 ObjectMeta: metav1.ObjectMeta{ 110 Namespace: "test-ns", 111 Name: "test-name", 112 }, 113 }) 114 testee := &StackListener{stacks: storeMock} 115 116 v, err := testee.get("test-ns/test-name") 117 assert.NoError(t, err) 118 assert.NotNil(t, v) 119 _, err = testee.get("test-ns/no-exists") 120 assert.EqualError(t, err, "not found: test-ns/no-exists") 121 }