github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/relationunitswatcher_test.go (about) 1 // Copyright 2019 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common_test 5 6 import ( 7 "time" 8 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 "gopkg.in/tomb.v2" 12 13 "github.com/juju/juju/apiserver/common" 14 "github.com/juju/juju/core/watcher" 15 "github.com/juju/juju/rpc/params" 16 "github.com/juju/juju/testing" 17 ) 18 19 type relationUnitsWatcherSuite struct{} 20 21 var _ = gc.Suite(&relationUnitsWatcherSuite{}) 22 23 func (s *relationUnitsWatcherSuite) TestRelationUnitsWatcherFromState(c *gc.C) { 24 25 source := &mockRUWatcher{ 26 changes: make(chan watcher.RelationUnitsChange), 27 } 28 // Ensure the watcher tomb thinks it's still going. 29 source.Tomb.Go(func() error { 30 <-source.Tomb.Dying() 31 return nil 32 }) 33 w, err := common.RelationUnitsWatcherFromState(source) 34 c.Assert(err, jc.ErrorIsNil) 35 36 c.Assert(source.Err(), gc.Equals, tomb.ErrStillAlive) 37 c.Assert(w.Err(), gc.Equals, tomb.ErrStillAlive) 38 39 event := watcher.RelationUnitsChange{ 40 Changed: map[string]watcher.UnitSettings{ 41 "joni/1": {Version: 23}, 42 }, 43 AppChanged: map[string]int64{ 44 "mitchell": 42, 45 }, 46 Departed: []string{"urge", "for", "going"}, 47 } 48 select { 49 case source.changes <- event: 50 case <-time.After(testing.LongWait): 51 c.Fatalf("timed out waiting to send event") 52 } 53 54 // The running loop of the watcher is effectively a 1-event 55 // buffer. 56 57 select { 58 case result := <-w.Changes(): 59 c.Assert(result, gc.DeepEquals, params.RelationUnitsChange{ 60 Changed: map[string]params.UnitSettings{ 61 "joni/1": {Version: 23}, 62 }, 63 AppChanged: map[string]int64{ 64 "mitchell": 42, 65 }, 66 Departed: []string{"urge", "for", "going"}, 67 }) 68 case <-time.After(testing.LongWait): 69 c.Fatalf("timed out waiting for output event") 70 } 71 72 c.Assert(w.Stop(), jc.ErrorIsNil) 73 // Ensure that stopping the watcher has stopped the source. 74 c.Assert(source.Err(), jc.ErrorIsNil) 75 76 select { 77 case _, ok := <-w.Changes(): 78 c.Assert(ok, gc.Equals, false) 79 default: 80 c.Fatalf("didn't close output channel") 81 } 82 } 83 84 func (s *relationUnitsWatcherSuite) TestCanStopWithAPendingSend(c *gc.C) { 85 source := &mockRUWatcher{ 86 changes: make(chan watcher.RelationUnitsChange), 87 } 88 // Ensure the watcher tomb thinks it's still going. 89 source.Tomb.Go(func() error { 90 <-source.Tomb.Dying() 91 return nil 92 }) 93 w, err := common.RelationUnitsWatcherFromState(source) 94 c.Assert(err, jc.ErrorIsNil) 95 defer w.Kill() 96 97 event := watcher.RelationUnitsChange{ 98 Changed: map[string]watcher.UnitSettings{ 99 "joni/1": {Version: 23}, 100 }, 101 } 102 s.send(c, source.changes, event) 103 104 // Stop without accepting the output event. 105 stopped := make(chan error) 106 go func() { 107 err := w.Stop() 108 stopped <- err 109 }() 110 111 select { 112 case err := <-stopped: 113 c.Assert(err, jc.ErrorIsNil) 114 case <-time.After(testing.LongWait): 115 c.Fatalf("timed out waiting for watcher to stop with pending send") 116 } 117 } 118 119 func (s *relationUnitsWatcherSuite) TestNilChanged(c *gc.C) { 120 source := &mockRUWatcher{ 121 changes: make(chan watcher.RelationUnitsChange), 122 } 123 // Ensure the watcher tomb thinks it's still going. 124 source.Tomb.Go(func() error { 125 <-source.Tomb.Dying() 126 return nil 127 }) 128 w, err := common.RelationUnitsWatcherFromState(source) 129 c.Assert(err, jc.ErrorIsNil) 130 131 event := watcher.RelationUnitsChange{ 132 Departed: []string{"happy", "birthday"}, 133 } 134 135 s.send(c, source.changes, event) 136 result := s.receive(c, w) 137 c.Assert(result, gc.DeepEquals, params.RelationUnitsChange{ 138 Departed: []string{"happy", "birthday"}, 139 }) 140 } 141 142 func (s *relationUnitsWatcherSuite) send(c *gc.C, ch chan watcher.RelationUnitsChange, event watcher.RelationUnitsChange) { 143 select { 144 case ch <- event: 145 case <-time.After(testing.LongWait): 146 c.Fatalf("timed out waiting to send event") 147 } 148 } 149 150 func (s *relationUnitsWatcherSuite) receive(c *gc.C, w common.RelationUnitsWatcher) params.RelationUnitsChange { 151 select { 152 case result := <-w.Changes(): 153 return result 154 case <-time.After(testing.LongWait): 155 c.Fatalf("timed out waiting for output event") 156 } 157 // Can't actually happen, but the go compiler can't tell that 158 // c.Fatalf panics. 159 return params.RelationUnitsChange{} 160 } 161 162 type mockRUWatcher struct { 163 tomb.Tomb 164 changes chan watcher.RelationUnitsChange 165 } 166 167 func (w *mockRUWatcher) Changes() watcher.RelationUnitsChannel { 168 return w.changes 169 } 170 171 func (w *mockRUWatcher) Kill() { 172 w.Tomb.Kill(nil) 173 } 174 175 func (w *mockRUWatcher) Stop() error { 176 w.Tomb.Kill(nil) 177 return w.Tomb.Wait() 178 } 179 180 func (w *mockRUWatcher) Err() error { 181 return w.Tomb.Err() 182 }