github.com/fafucoder/cilium@v1.6.11/pkg/controller/controller_test.go (about) 1 // Copyright 2018 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build !privileged_tests 16 17 package controller 18 19 import ( 20 "context" 21 "fmt" 22 "sync/atomic" 23 "testing" 24 "time" 25 26 "github.com/cilium/cilium/pkg/testutils" 27 28 . "gopkg.in/check.v1" 29 ) 30 31 // Hook up gocheck into the "go test" runner. 32 func Test(t *testing.T) { 33 TestingT(t) 34 } 35 36 type ControllerSuite struct{} 37 38 var _ = Suite(&ControllerSuite{}) 39 40 func (b *ControllerSuite) TestUpdateRemoveController(c *C) { 41 mngr := NewManager() 42 mngr.UpdateController("test", ControllerParams{}) 43 c.Assert(mngr.RemoveController("test"), IsNil) 44 c.Assert(mngr.RemoveController("not-exist"), Not(IsNil)) 45 } 46 47 func (b *ControllerSuite) TestStopFunc(c *C) { 48 stopFuncRan := false 49 waitChan := make(chan bool) 50 51 mngr := Manager{} 52 mngr.UpdateController("test", ControllerParams{ 53 RunInterval: time.Second, 54 DoFunc: NoopFunc, 55 StopFunc: func(ctx context.Context) error { 56 stopFuncRan = true 57 close(waitChan) 58 return nil 59 }, 60 }) 61 c.Assert(mngr.RemoveController("test"), IsNil) 62 select { 63 case <-waitChan: 64 case <-time.After(2 * time.Second): 65 c.Error("StopFunc did not run") 66 } 67 c.Assert(stopFuncRan, Equals, true) 68 } 69 70 func (b *ControllerSuite) TestSelfExit(c *C) { 71 var iterations uint32 72 waitChan := make(chan bool) 73 74 mngr := Manager{} 75 mngr.UpdateController("test", ControllerParams{ 76 RunInterval: 100 * time.Millisecond, 77 DoFunc: func(ctx context.Context) error { 78 atomic.AddUint32(&iterations, 1) 79 return NewExitReason("test exit") 80 }, 81 StopFunc: func(ctx context.Context) error { 82 close(waitChan) 83 return nil 84 }, 85 }) 86 select { 87 case <-waitChan: 88 c.Error("Controller exited") 89 case <-time.After(time.Second): 90 } 91 c.Assert(atomic.LoadUint32(&iterations), Equals, uint32(1)) 92 93 // The controller is inactive, and waiting for the next update or stop. 94 // A controller will only stop when explicitly removed and stopped. 95 mngr.RemoveController("test") 96 select { 97 case <-waitChan: 98 case <-time.After(time.Second): 99 c.Error("Controller did not exit") 100 } 101 } 102 103 func (b *ControllerSuite) TestRemoveAll(c *C) { 104 mngr := NewManager() 105 // create 106 mngr.UpdateController("test1", ControllerParams{}) 107 mngr.UpdateController("test2", ControllerParams{}) 108 mngr.UpdateController("test3", ControllerParams{}) 109 // update 110 mngr.UpdateController("test1", ControllerParams{}) 111 mngr.UpdateController("test2", ControllerParams{}) 112 mngr.UpdateController("test3", ControllerParams{}) 113 mngr.RemoveAll() 114 } 115 116 type testObj struct { 117 cnt int 118 } 119 120 func (b *ControllerSuite) TestRunController(c *C) { 121 mngr := NewManager() 122 o := &testObj{} 123 124 ctrl := mngr.UpdateController("test", ControllerParams{ 125 DoFunc: func(ctx context.Context) error { 126 // after two failed attempts, start succeeding 127 if o.cnt >= 2 { 128 return nil 129 } 130 131 o.cnt++ 132 return fmt.Errorf("temporary error") 133 }, 134 RunInterval: time.Duration(1) * time.Millisecond, // short interval 135 ErrorRetryBaseDuration: time.Duration(1) * time.Millisecond, // short error retry 136 }) 137 138 for n := 0; ctrl.GetSuccessCount() < 2; n++ { 139 if n > 100 { 140 c.Fatalf("time out while waiting for controller to succeed, last error: %s", ctrl.GetLastError()) 141 } 142 143 time.Sleep(time.Duration(100) * time.Millisecond) 144 } 145 146 c.Assert(GetGlobalStatus(), Not(IsNil)) 147 148 c.Assert(ctrl.GetSuccessCount(), Not(Equals), 0) 149 c.Assert(ctrl.GetFailureCount(), Equals, 2) 150 c.Assert(ctrl.GetLastError(), IsNil) 151 c.Assert(mngr.RemoveController("test"), IsNil) 152 } 153 154 func (b *ControllerSuite) TestCancellation(c *C) { 155 mngr := NewManager() 156 157 started := make(chan struct{}) 158 cancelled := make(chan struct{}) 159 160 mngr.UpdateController("test", ControllerParams{ 161 DoFunc: func(ctx context.Context) error { 162 close(started) 163 <-ctx.Done() 164 close(cancelled) 165 return nil 166 }, 167 }) 168 169 // wait for the controller to be running 170 select { 171 case <-started: 172 case <-time.After(time.Minute): 173 c.Fatalf("timeout while waiting for controller to start") 174 } 175 176 mngr.RemoveAll() 177 178 // wait for the controller to be cancelled 179 select { 180 case <-cancelled: 181 case <-time.After(time.Minute): 182 c.Fatalf("timeout while waiting for controller to be cancelled") 183 } 184 } 185 186 func (b *ControllerSuite) TestWaitForTermination(c *C) { 187 mngr := NewManager() 188 mngr.UpdateController("test1", ControllerParams{}) 189 mngr.UpdateController("test1", ControllerParams{}) 190 191 // Ensure that the channel does not get closed while the controller is 192 // still running 193 c.Assert(testutils.WaitUntil(func() bool { 194 select { 195 case <-mngr.TerminationChannel("test1"): 196 return false 197 default: 198 return true 199 } 200 }, 20*time.Millisecond), IsNil) 201 202 c.Assert(mngr.RemoveControllerAndWait("test1"), IsNil) 203 204 // The controller must have been terminated already due to AndWait above 205 select { 206 case <-mngr.TerminationChannel("test1"): 207 default: 208 c.Fail() 209 } 210 }