github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/db/notifications_bus_test.go (about) 1 package db_test 2 3 import ( 4 "errors" 5 6 "github.com/pf-qiu/concourse/v6/atc/db" 7 "github.com/pf-qiu/concourse/v6/atc/db/dbfakes" 8 "github.com/lib/pq" 9 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 ) 13 14 var _ = Describe("NotificationBus", func() { 15 16 var ( 17 c chan *pq.Notification 18 fakeExecutor *dbfakes.FakeExecutor 19 fakeListener *dbfakes.FakeListener 20 21 bus db.NotificationsBus 22 ) 23 24 BeforeEach(func() { 25 c = make(chan *pq.Notification, 1) 26 27 fakeExecutor = new(dbfakes.FakeExecutor) 28 fakeListener = new(dbfakes.FakeListener) 29 fakeListener.NotificationChannelReturns(c) 30 31 bus = db.NewNotificationsBus(fakeListener, fakeExecutor) 32 }) 33 34 Context("Notify", func() { 35 var ( 36 err error 37 ) 38 39 JustBeforeEach(func() { 40 err = bus.Notify("some-channel") 41 }) 42 43 It("notifies the channel", func() { 44 Expect(fakeExecutor.ExecCallCount()).To(Equal(1)) 45 msg, _ := fakeExecutor.ExecArgsForCall(0) 46 Expect(msg).To(Equal("NOTIFY some-channel")) 47 }) 48 49 Context("when the executor errors", func() { 50 BeforeEach(func() { 51 fakeExecutor.ExecReturns(nil, errors.New("nope")) 52 }) 53 54 It("errors", func() { 55 Expect(err).To(HaveOccurred()) 56 }) 57 }) 58 59 Context("when the executor succeeds", func() { 60 BeforeEach(func() { 61 fakeExecutor.ExecReturns(nil, nil) 62 }) 63 64 It("succeeds", func() { 65 Expect(err).NotTo(HaveOccurred()) 66 }) 67 }) 68 }) 69 70 Context("Listen", func() { 71 var ( 72 err error 73 ) 74 75 JustBeforeEach(func() { 76 _, err = bus.Listen("some-channel") 77 }) 78 79 Context("when not already listening on channel", func() { 80 It("listens on the given channel", func() { 81 Expect(fakeListener.ListenCallCount()).To(Equal(1)) 82 channel := fakeListener.ListenArgsForCall(0) 83 Expect(channel).To(Equal("some-channel")) 84 }) 85 86 Context("when listening errors", func() { 87 BeforeEach(func() { 88 fakeListener.ListenReturns(errors.New("nope")) 89 }) 90 91 It("errors", func() { 92 Expect(err).To(HaveOccurred()) 93 }) 94 }) 95 96 Context("when listening succeeds", func() { 97 BeforeEach(func() { 98 fakeListener.ListenReturns(nil) 99 }) 100 101 It("succeeds", func() { 102 Expect(err).NotTo(HaveOccurred()) 103 }) 104 }) 105 }) 106 107 Context("when already listening on the channel", func() { 108 BeforeEach(func() { 109 _, err := bus.Listen("some-channel") 110 Expect(err).NotTo(HaveOccurred()) 111 }) 112 113 It("only listens once", func() { 114 Expect(fakeListener.ListenCallCount()).To(Equal(1)) 115 }) 116 }) 117 }) 118 119 Context("Unlisten", func() { 120 var ( 121 err error 122 c chan bool 123 ) 124 125 JustBeforeEach(func() { 126 err = bus.Unlisten("some-channel", c) 127 }) 128 129 Context("when there's only one listener", func() { 130 BeforeEach(func() { 131 c, err = bus.Listen("some-channel") 132 Expect(err).NotTo(HaveOccurred()) 133 }) 134 135 It("unlistens on the given channel", func() { 136 Expect(fakeListener.UnlistenCallCount()).To(Equal(1)) 137 channel := fakeListener.UnlistenArgsForCall(0) 138 Expect(channel).To(Equal("some-channel")) 139 }) 140 141 Context("when unlistening errors", func() { 142 BeforeEach(func() { 143 fakeListener.UnlistenReturns(errors.New("nope")) 144 }) 145 146 It("errors", func() { 147 Expect(err).To(HaveOccurred()) 148 }) 149 }) 150 151 Context("when unlistening succeeds", func() { 152 BeforeEach(func() { 153 fakeListener.UnlistenReturns(nil) 154 }) 155 156 It("succeeds", func() { 157 Expect(err).NotTo(HaveOccurred()) 158 }) 159 }) 160 }) 161 162 Context("when there's multiple listeners", func() { 163 BeforeEach(func() { 164 c, err = bus.Listen("some-channel") 165 Expect(err).NotTo(HaveOccurred()) 166 167 _, err = bus.Listen("some-channel") 168 Expect(err).NotTo(HaveOccurred()) 169 }) 170 171 It("succeeds", func() { 172 Expect(err).NotTo(HaveOccurred()) 173 }) 174 175 It("does not unlisten on the given channel", func() { 176 Expect(fakeListener.UnlistenCallCount()).To(Equal(0)) 177 }) 178 }) 179 }) 180 181 Describe("Receiving Notifications", func() { 182 var ( 183 err error 184 a chan bool 185 b chan bool 186 ) 187 188 Context("when there are multiple listeners for the same channel", func() { 189 BeforeEach(func() { 190 a, err = bus.Listen("some-channel") 191 Expect(err).NotTo(HaveOccurred()) 192 193 b, err = bus.Listen("some-channel") 194 Expect(err).NotTo(HaveOccurred()) 195 }) 196 197 Context("when it receives an upstream notification", func() { 198 199 BeforeEach(func() { 200 c <- &pq.Notification{Channel: "some-channel"} 201 }) 202 203 It("delivers the notification to all listeners", func() { 204 Eventually(a).Should(Receive(Equal(true))) 205 Eventually(b).Should(Receive(Equal(true))) 206 }) 207 }) 208 209 Context("when it receives an upstream disconnect notice", func() { 210 211 BeforeEach(func() { 212 c <- nil 213 }) 214 215 It("delivers the notification to all listeners", func() { 216 Eventually(a).Should(Receive(Equal(false))) 217 Eventually(b).Should(Receive(Equal(false))) 218 }) 219 }) 220 }) 221 222 Context("when there are multiple listeners on different channels", func() { 223 BeforeEach(func() { 224 a, err = bus.Listen("some-channel") 225 Expect(err).NotTo(HaveOccurred()) 226 227 b, err = bus.Listen("some-other-channel") 228 Expect(err).NotTo(HaveOccurred()) 229 }) 230 231 Context("when it receives an upstream notification", func() { 232 233 BeforeEach(func() { 234 c <- &pq.Notification{Channel: "some-channel"} 235 }) 236 237 It("delivers the notification to only specific listeners", func() { 238 Eventually(a).Should(Receive(Equal(true))) 239 Consistently(b).ShouldNot(Receive()) 240 }) 241 }) 242 243 Context("when it receives an upstream disconnect notice", func() { 244 245 BeforeEach(func() { 246 c <- nil 247 }) 248 249 It("delivers the notification to all listeners", func() { 250 Eventually(a).Should(Receive(Equal(false))) 251 Eventually(b).Should(Receive(Equal(false))) 252 }) 253 }) 254 }) 255 256 Context("when the notification channel fills up while listening", func() { 257 258 BeforeEach(func() { 259 fakeListener.ListenCalls(func(_ string) error { 260 c <- &pq.Notification{Channel: "some-channel"} 261 c <- &pq.Notification{Channel: "some-channel"} 262 c <- &pq.Notification{Channel: "some-channel"} 263 return nil 264 }) 265 }) 266 267 It("should still be able to listen for notifications", func(done Done) { 268 269 _, err := bus.Listen("some-channel") 270 Expect(err).NotTo(HaveOccurred()) 271 272 _, err = bus.Listen("some-other-channel") 273 Expect(err).NotTo(HaveOccurred()) 274 275 _, err = bus.Listen("some-new-channel") 276 Expect(err).NotTo(HaveOccurred()) 277 278 close(done) 279 }, 5) 280 281 }) 282 283 Context("when the notification channel fills up while unlistening", func() { 284 285 BeforeEach(func() { 286 fakeListener.UnlistenCalls(func(_ string) error { 287 c <- &pq.Notification{Channel: "some-channel"} 288 c <- &pq.Notification{Channel: "some-channel"} 289 c <- &pq.Notification{Channel: "some-channel"} 290 return nil 291 }) 292 }) 293 294 It("should still be able to unlisten for notifications", func(done Done) { 295 296 err := bus.Unlisten("some-channel", a) 297 Expect(err).NotTo(HaveOccurred()) 298 299 err = bus.Unlisten("some-other-channel", b) 300 Expect(err).NotTo(HaveOccurred()) 301 302 close(done) 303 }, 5) 304 }) 305 }) 306 })