agones.dev/agones@v1.54.0/pkg/util/workerqueue/workerqueue_test.go (about) 1 // Copyright 2018 Google LLC All Rights Reserved. 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 package workerqueue 16 17 import ( 18 "context" 19 "io" 20 "net/http" 21 "net/http/httptest" 22 "testing" 23 "time" 24 25 "github.com/heptiolabs/healthcheck" 26 "github.com/pkg/errors" 27 "github.com/sirupsen/logrus" 28 "github.com/stretchr/testify/assert" 29 "k8s.io/apimachinery/pkg/util/wait" 30 "k8s.io/client-go/tools/cache" 31 ) 32 33 func TestWorkerQueueRun(t *testing.T) { 34 t.Parallel() 35 36 received := make(chan string) 37 defer close(received) 38 39 syncHandler := func(_ context.Context, name string) error { 40 assert.Equal(t, "default/test", name) 41 received <- name 42 return nil 43 } 44 45 wq := NewWorkerQueue(syncHandler, logrus.WithField("source", "test"), "testKey", "test") 46 stop := make(chan struct{}) 47 defer close(stop) 48 49 go wq.Run(context.Background(), 1) 50 51 // no change, should be no value 52 select { 53 case <-received: 54 assert.Fail(t, "should not have received value") 55 case <-time.After(1 * time.Second): 56 } 57 58 wq.Enqueue(cache.ExplicitKey("default/test")) 59 60 select { 61 case <-received: 62 case <-time.After(5 * time.Second): 63 assert.Fail(t, "should have received value") 64 } 65 } 66 67 func TestWorkerQueueHealthy(t *testing.T) { 68 t.Parallel() 69 70 done := make(chan struct{}) 71 handler := func(context.Context, string) error { 72 <-done 73 return nil 74 } 75 wq := NewWorkerQueue(handler, logrus.WithField("source", "test"), "testKey", "test") 76 wq.Enqueue(cache.ExplicitKey("default/test")) 77 78 ctx, cancel := context.WithCancel(context.Background()) 79 go wq.Run(ctx, 1) 80 81 // Yield to the scheduler to ensure the worker queue goroutine can run. 82 err := wait.PollUntilContextTimeout(context.Background(), 100*time.Millisecond, 3*time.Second, true, func(_ context.Context) (done bool, err error) { 83 if (wq.RunCount() == 1) && wq.Healthy() == nil { 84 return true, nil 85 } 86 87 return false, nil 88 }) 89 assert.Nil(t, err) 90 91 close(done) // Ensure the handler no longer blocks. 92 cancel() // Stop the worker queue. 93 94 // Yield to the scheduler again to ensure the worker queue goroutine can 95 // finish. 96 err = wait.PollUntilContextTimeout(context.Background(), 100*time.Millisecond, 3*time.Second, true, func(_ context.Context) (done bool, err error) { 97 if (wq.RunCount() == 0) && wq.Healthy() != nil { 98 return true, nil 99 } 100 101 return false, nil 102 }) 103 assert.Nil(t, err) 104 } 105 106 func TestWorkQueueHealthCheck(t *testing.T) { 107 t.Parallel() 108 109 health := healthcheck.NewHandler() 110 handler := func(context.Context, string) error { 111 return nil 112 } 113 wq := NewWorkerQueue(handler, logrus.WithField("source", "test"), "testKey", "test") 114 health.AddLivenessCheck("test", wq.Healthy) 115 116 server := httptest.NewServer(health) 117 defer server.Close() 118 119 const workersCount = 1 120 ctx, cancel := context.WithCancel(context.Background()) 121 go wq.Run(ctx, workersCount) 122 123 // Wait for worker to actually start 124 err := wait.PollUntilContextTimeout(context.Background(), 100*time.Millisecond, 5*time.Second, true, func(_ context.Context) (bool, error) { 125 rc := wq.RunCount() 126 logrus.WithField("runcount", rc).Info("Checking run count before liveness check") 127 return rc == workersCount, nil 128 }) 129 assert.Nil(t, err) 130 131 f := func(t *testing.T, url string, status int) { 132 // sometimes the http server takes a bit to start up 133 err := wait.PollUntilContextTimeout(context.Background(), time.Second, 5*time.Second, true, func(_ context.Context) (done bool, err error) { 134 resp, err := http.Get(url) 135 assert.Nil(t, err) 136 defer resp.Body.Close() // nolint: errcheck 137 138 if status != resp.StatusCode { 139 return false, nil 140 } 141 142 body, err := io.ReadAll(resp.Body) 143 assert.Nil(t, err) 144 assert.Equal(t, status, resp.StatusCode) 145 assert.Equal(t, []byte("{}\n"), body) 146 147 return true, nil 148 }) 149 150 assert.Nil(t, err) 151 } 152 153 url := server.URL + "/live" 154 f(t, url, http.StatusOK) 155 156 cancel() 157 // closing can take a short while 158 err = wait.PollUntilContextTimeout(context.Background(), time.Second, 5*time.Second, true, func(_ context.Context) (bool, error) { 159 rc := wq.RunCount() 160 logrus.WithField("runcount", rc).Info("Checking run count") 161 return rc == 0, nil 162 }) 163 assert.Nil(t, err) 164 165 // gate 166 assert.Error(t, wq.Healthy()) 167 f(t, url, http.StatusServiceUnavailable) 168 } 169 170 func TestWorkerQueueEnqueueAfter(t *testing.T) { 171 t.Parallel() 172 173 updated := make(chan bool) 174 syncHandler := func(_ context.Context, _ string) error { 175 updated <- true 176 return nil 177 } 178 wq := NewWorkerQueue(syncHandler, logrus.WithField("source", "test"), "testKey", "test") 179 stop := make(chan struct{}) 180 defer close(stop) 181 182 go wq.Run(context.Background(), 1) 183 184 wq.EnqueueAfter(cache.ExplicitKey("default/test"), 2*time.Second) 185 186 select { 187 case <-updated: 188 assert.FailNow(t, "should not be a result in queue yet") 189 case <-time.After(time.Second): 190 } 191 192 select { 193 case <-updated: 194 case <-time.After(2 * time.Second): 195 assert.Fail(t, "should have got a queue'd message by now") 196 } 197 } 198 199 func TestDebugError(t *testing.T) { 200 err := errors.New("not a debug error") 201 assert.False(t, isTraceError(err)) 202 203 err = NewTraceError(err) 204 assert.True(t, isTraceError(err)) 205 assert.EqualError(t, err, "not a debug error") 206 207 err = NewTraceError(nil) 208 assert.True(t, isTraceError(err)) 209 assert.EqualError(t, err, "<nil>") 210 }