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  })