1package diodes_test 2 3import ( 4 "code.cloudfoundry.org/go-diodes" 5 6 . "github.com/onsi/ginkgo" 7 . "github.com/onsi/gomega" 8) 9 10var _ = Describe("OneToOne", func() { 11 var ( 12 d *diodes.OneToOne 13 data []byte 14 15 spy *spyAlerter 16 ) 17 18 BeforeEach(func() { 19 spy = newSpyAlerter() 20 21 d = diodes.NewOneToOne(5, spy) 22 23 data = []byte("some-data") 24 d.Set(diodes.GenericDataType(&data)) 25 }) 26 27 Context("multiple data slices", func() { 28 var ( 29 secondData []byte 30 ) 31 32 BeforeEach(func() { 33 secondData = []byte("some-other-data") 34 d.Set(diodes.GenericDataType(&secondData)) 35 }) 36 37 Describe("TryNext()", func() { 38 It("returns true", func() { 39 _, ok := d.TryNext() 40 41 Expect(ok).To(BeTrue()) 42 }) 43 44 Context("reads exceed writes", func() { 45 BeforeEach(func() { 46 d.TryNext() 47 d.TryNext() 48 }) 49 50 It("returns false", func() { 51 _, ok := d.TryNext() 52 53 Expect(ok).To(BeFalse()) 54 }) 55 }) 56 }) 57 58 Context("buffer size exceeded", func() { 59 BeforeEach(func() { 60 for i := 0; i < 4; i++ { 61 d.Set(diodes.GenericDataType(&secondData)) 62 } 63 }) 64 65 It("wraps", func() { 66 data, _ := d.TryNext() 67 Expect(*(*[]byte)(data)).To(Equal(secondData)) 68 }) 69 70 It("alerts for each dropped point", func() { 71 d.TryNext() 72 Expect(spy.AlertInput.Missed).To(Receive(Equal(5))) 73 }) 74 75 It("it updates the read index", func() { 76 d.TryNext() 77 Expect(spy.AlertInput.Missed).To(Receive(Equal(5))) 78 79 for i := 0; i < 6; i++ { 80 d.Set(diodes.GenericDataType(&secondData)) 81 } 82 83 d.TryNext() 84 Expect(spy.AlertInput.Missed).To(Receive(Equal(5))) 85 }) 86 87 Context("read catches up with write", func() { 88 BeforeEach(func() { 89 d.TryNext() 90 <-spy.AlertInput.Missed 91 }) 92 93 It("does not alert", func() { 94 d.TryNext() 95 Expect(spy.AlertInput.Missed).To(Not(Receive())) 96 }) 97 }) 98 99 Context("writer laps reader", func() { 100 BeforeEach(func() { 101 for i := 0; i < 5; i++ { 102 d.Set(diodes.GenericDataType(&secondData)) 103 } 104 d.TryNext() 105 }) 106 107 It("sends an alert for each set", func() { 108 Expect(spy.AlertInput.Missed).To(Receive(Equal(10))) 109 }) 110 }) 111 112 Context("writer laps reader with nil alerter", func() { 113 It("drops the alert", func() { 114 d = diodes.NewOneToOne(5, nil) 115 for i := 0; i < 10; i++ { 116 d.Set(diodes.GenericDataType(&secondData)) 117 } 118 119 Expect(func() { 120 d.TryNext() 121 }).ToNot(Panic()) 122 }) 123 }) 124 }) 125 }) 126 127}) 128 129var _ = Describe("reader ahead of writer", func() { 130 It("must not occur after alerting", func() { 131 length := 4 132 spy := newSpyAlerter() 133 d := diodes.NewOneToOne(length, spy) 134 data := []byte("some-data") 135 genData := diodes.GenericDataType(&data) 136 137 By("filling up the buffer") 138 for i := 0; i < length; i++ { 139 d.Set(genData) 140 } 141 142 By("overwriting the first index") 143 d.Set(genData) 144 145 By("having reader fast forward") 146 Expect(spy.AlertInput.Missed).To(BeEmpty()) 147 _, ok := d.TryNext() 148 Expect(ok).To(BeTrue()) 149 Expect(spy.AlertInput.Missed).To(Receive(Equal(4))) 150 151 By("failing reads until the writer writes over skipped values") 152 _, ok = d.TryNext() 153 Expect(ok).To(BeFalse()) 154 d.Set(genData) 155 _, ok = d.TryNext() 156 Expect(ok).To(BeTrue()) 157 }) 158}) 159 160type spyAlerter struct { 161 AlertCalled chan bool 162 AlertInput struct { 163 Missed chan int 164 } 165} 166 167func newSpyAlerter() *spyAlerter { 168 m := &spyAlerter{} 169 m.AlertCalled = make(chan bool, 100) 170 m.AlertInput.Missed = make(chan int, 100) 171 return m 172} 173func (m *spyAlerter) Alert(missed int) { 174 m.AlertCalled <- true 175 m.AlertInput.Missed <- missed 176} 177