github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/hk/housekeeper_test.go (about) 1 // Package hk provides mechanism for registering cleanup 2 // functions which are invoked at specified intervals. 3 /* 4 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 5 */ 6 package hk_test 7 8 import ( 9 "math/rand" 10 "strconv" 11 "time" 12 13 "github.com/NVIDIA/aistore/cmn/atomic" 14 "github.com/NVIDIA/aistore/hk" 15 . "github.com/onsi/ginkgo/v2" 16 . "github.com/onsi/gomega" 17 ) 18 19 var _ = Describe("Housekeeper", func() { 20 It("should register the callback and fire it", func() { 21 fired := false 22 hk.Reg("foo", func() time.Duration { 23 fired = true 24 return time.Second 25 }, 0) 26 defer hk.Unreg("foo") 27 time.Sleep(20 * time.Millisecond) 28 Expect(fired).To(BeTrue()) // callback should be fired at the start 29 fired = false 30 31 time.Sleep(500 * time.Millisecond) 32 Expect(fired).To(BeFalse()) 33 34 time.Sleep(600 * time.Millisecond) 35 Expect(fired).To(BeTrue()) 36 }) 37 38 It("should register the callback and fire it after initial interval", func() { 39 fired := false 40 hk.Reg("foo", func() time.Duration { 41 fired = true 42 return time.Second 43 }, time.Second) 44 defer hk.Unreg("foo") 45 46 time.Sleep(500 * time.Millisecond) 47 Expect(fired).To(BeFalse()) 48 49 time.Sleep(600 * time.Millisecond) 50 Expect(fired).To(BeTrue()) 51 }) 52 53 It("should register multiple callbacks and fire it in correct order", func() { 54 fired := make([]bool, 2) 55 hk.Reg("foo", func() time.Duration { 56 fired[0] = true 57 return 2 * time.Second 58 }, 0) 59 defer hk.Unreg("foo") 60 hk.Reg("bar", func() time.Duration { 61 fired[1] = true 62 return time.Second + 500*time.Millisecond 63 }, 0) 64 defer hk.Unreg("bar") 65 66 time.Sleep(20 * time.Millisecond) 67 // "foo" and "bar" should fire at the start (no initial interval) 68 for idx := range len(fired) { 69 Expect(fired[idx]).To(BeTrue()) 70 fired[idx] = false 71 } 72 73 time.Sleep(600 * time.Millisecond) // ~600ms 74 75 // "foo" nor "bar" should fire 76 Expect(fired[0] || fired[1]).To(BeFalse()) 77 78 time.Sleep(time.Second) // ~1.6s 79 80 // "bar" should fire 81 Expect(fired[0]).To(BeFalse()) 82 Expect(fired[1]).To(BeTrue()) 83 fired[1] = false 84 85 time.Sleep(500 * time.Millisecond) // ~2.1s 86 87 // "foo" should fire 88 Expect(fired[0]).To(BeTrue()) 89 Expect(fired[1]).To(BeFalse()) 90 91 time.Sleep(time.Second) // ~3.1s 92 93 // "bar" should fire once again 94 Expect(fired[0] && fired[1]).To(BeTrue()) 95 }) 96 97 It("should unregister callback", func() { 98 fired := make([]bool, 2) 99 hk.Reg("bar", func() time.Duration { 100 fired[0] = true 101 return 400 * time.Millisecond 102 }, 400*time.Millisecond) 103 hk.Reg("foo", func() time.Duration { 104 fired[1] = true 105 return 200 * time.Millisecond 106 }, 200*time.Millisecond) 107 108 time.Sleep(500 * time.Millisecond) 109 Expect(fired[0] && fired[1]).To(BeTrue()) 110 111 fired[0], fired[1] = false, false 112 hk.Unreg("foo") 113 114 time.Sleep(time.Second) 115 Expect(fired[1]).To(BeFalse()) 116 Expect(fired[0]).To(BeTrue()) 117 118 hk.Unreg("bar") 119 }) 120 121 It("should unregister callback that returns UnregInterval", func() { 122 for range 3 { 123 fired := make([]bool, 2) 124 hk.Reg("bar", func() time.Duration { 125 fired[0] = true 126 return 400 * time.Millisecond 127 }, 400*time.Millisecond) 128 hk.Reg("foo", func() time.Duration { 129 fired[1] = true 130 return hk.UnregInterval 131 }, 100*time.Millisecond) 132 133 time.Sleep(500 * time.Millisecond) 134 Expect(fired[0] && fired[1]).To(BeTrue()) 135 136 fired[0], fired[1] = false, false 137 138 time.Sleep(500 * time.Millisecond) 139 Expect(fired[1]).To(BeFalse()) // foo 140 Expect(fired[0]).To(BeTrue()) // bar 141 142 hk.Unreg("bar") 143 } 144 }) 145 146 It("should register and unregister multiple callbacks", func() { 147 var fired bool 148 f := func(name string) { 149 Expect(fired).To(BeFalse()) 150 hk.Reg(name, func() time.Duration { 151 fired = true 152 return 100 * time.Millisecond 153 }, 100*time.Millisecond) 154 155 time.Sleep(110 * time.Millisecond) 156 Expect(fired).To(BeTrue()) 157 158 hk.Unreg(name) 159 fired = false 160 } 161 162 f("foo") 163 f("bar") 164 f("baz") 165 166 time.Sleep(time.Second) 167 Expect(fired).To(BeFalse()) 168 }) 169 170 It("should correctly call multiple callbacks", func() { 171 type action struct { 172 d time.Duration 173 origIdx int 174 } 175 const ( 176 actionCnt = 30 177 ) 178 var ( 179 counter atomic.Int32 180 durs = make([]action, 0, actionCnt) 181 fired = make([]int32, actionCnt) 182 ) 183 184 for i := range actionCnt { 185 durs = append(durs, action{ 186 d: 50*time.Millisecond + time.Duration(40*i)*time.Millisecond, 187 origIdx: i, 188 }) 189 fired[i] = -1 190 } 191 192 rand.Shuffle(actionCnt, func(i, j int) { 193 durs[i], durs[j] = durs[j], durs[i] 194 }) 195 196 for i := range actionCnt { 197 index := i 198 hk.Reg(strconv.Itoa(index), func() time.Duration { 199 if fired[index] == -1 { 200 fired[index] = counter.Inc() - 1 201 } 202 return durs[index].d 203 }, durs[index].d) 204 } 205 206 time.Sleep(100 * actionCnt * time.Millisecond) 207 208 for i := range actionCnt { 209 Expect(durs[i].origIdx).To(BeEquivalentTo(fired[i])) 210 } 211 }) 212 })