github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/watcher/watchertest/strings.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package watchertest 5 6 import ( 7 "time" 8 9 "github.com/juju/collections/set" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 tomb "gopkg.in/tomb.v2" 13 14 "github.com/juju/juju/core/watcher" 15 "github.com/juju/juju/testing" 16 ) 17 18 type MockStringsWatcher struct { 19 tomb tomb.Tomb 20 ch <-chan []string 21 } 22 23 func NewMockStringsWatcher(ch <-chan []string) *MockStringsWatcher { 24 w := &MockStringsWatcher{ch: ch} 25 w.tomb.Go(func() error { 26 <-w.tomb.Dying() 27 return tomb.ErrDying 28 }) 29 return w 30 } 31 32 func (w *MockStringsWatcher) Changes() watcher.StringsChannel { 33 return w.ch 34 } 35 36 func (w *MockStringsWatcher) Stop() error { 37 w.Kill() 38 return w.Wait() 39 } 40 41 func (w *MockStringsWatcher) Kill() { 42 w.tomb.Kill(nil) 43 } 44 45 // KillErr can be used to kill the worker with 46 // an error, to simulate a failing watcher. 47 func (w *MockStringsWatcher) KillErr(err error) { 48 w.tomb.Kill(err) 49 } 50 51 func (w *MockStringsWatcher) Err() error { 52 return w.tomb.Err() 53 } 54 55 func (w *MockStringsWatcher) Wait() error { 56 return w.tomb.Wait() 57 } 58 59 func NewStringsWatcherC(c *gc.C, watcher watcher.StringsWatcher) StringsWatcherC { 60 return StringsWatcherC{ 61 C: c, 62 Watcher: watcher, 63 } 64 } 65 66 type StringsWatcherC struct { 67 *gc.C 68 Watcher watcher.StringsWatcher 69 } 70 71 // AssertChanges fails if it cannot read a value from Changes despite waiting a 72 // long time. It logs, but does not check, the received changes; but will fail 73 // if the Changes chan is closed. 74 func (c StringsWatcherC) AssertChanges() { 75 select { 76 case change, ok := <-c.Watcher.Changes(): 77 c.Logf("received change: %#v", change) 78 c.Assert(ok, jc.IsTrue) 79 case <-time.After(testing.LongWait): 80 c.Fatalf("watcher did not send change") 81 } 82 c.AssertNoChange() 83 } 84 85 // AssertNoChange fails if it manages to read a value from Changes before a 86 // short time has passed. 87 func (c StringsWatcherC) AssertNoChange() { 88 select { 89 case change, ok := <-c.Watcher.Changes(): 90 if !ok { 91 c.Fatalf("watcher closed Changes channel") 92 } else { 93 c.Fatalf("watcher sent unexpected change: %#v", change) 94 } 95 case <-time.After(testing.ShortWait): 96 } 97 } 98 99 // AssertStops Kills the watcher and asserts (1) that Wait completes without 100 // error before a long time has passed; and (2) that Changes remains open but 101 // no values are being sent. 102 func (c StringsWatcherC) AssertStops() { 103 c.Watcher.Kill() 104 wait := make(chan error) 105 go func() { 106 wait <- c.Watcher.Wait() 107 }() 108 select { 109 case <-time.After(testing.LongWait): 110 c.Fatalf("watcher never stopped") 111 case err := <-wait: 112 c.Assert(err, jc.ErrorIsNil) 113 } 114 115 select { 116 case change, ok := <-c.Watcher.Changes(): 117 c.Fatalf("watcher sent unexpected change: (%#v, %v)", change, ok) 118 default: 119 } 120 } 121 122 func (c StringsWatcherC) AssertChange(expect ...string) { 123 c.assertChange(false, expect...) 124 } 125 126 func (c StringsWatcherC) AssertChangeInSingleEvent(expect ...string) { 127 c.assertChange(true, expect...) 128 } 129 130 // AssertChangeMaybeIncluding verifies that there is a change that may 131 // contain zero to all of the passed in strings, and no other changes. 132 func (c StringsWatcherC) AssertChangeMaybeIncluding(expect ...string) { 133 maxCount := len(expect) 134 actual := c.collectChanges(true, maxCount) 135 136 if maxCount == 0 { 137 c.Assert(actual, gc.HasLen, 0) 138 } else { 139 actualCount := len(actual) 140 c.Assert(actualCount <= maxCount, jc.IsTrue, gc.Commentf("expected at most %d, got %d", maxCount, actualCount)) 141 unexpected := set.NewStrings(actual...).Difference(set.NewStrings(expect...)) 142 c.Assert(unexpected.Values(), gc.HasLen, 0) 143 } 144 } 145 146 // assertChange asserts the given list of changes was reported by 147 // the watcher, but does not assume there are no following changes. 148 func (c StringsWatcherC) assertChange(single bool, expect ...string) { 149 actual := c.collectChanges(single, len(expect)) 150 if len(expect) == 0 { 151 c.Assert(actual, gc.HasLen, 0) 152 } else { 153 c.Assert(actual, jc.SameContents, expect) 154 } 155 } 156 157 // collectChanges gets up to the max number of changes within the 158 // testing.LongWait period. 159 func (c StringsWatcherC) collectChanges(single bool, max int) []string { 160 timeout := time.After(testing.LongWait) 161 var actual []string 162 gotOneChange := false 163 loop: 164 for { 165 select { 166 case changes, ok := <-c.Watcher.Changes(): 167 c.Assert(ok, jc.IsTrue) 168 gotOneChange = true 169 actual = append(actual, changes...) 170 if single || len(actual) >= max { 171 break loop 172 } 173 case <-timeout: 174 if !gotOneChange { 175 c.Fatalf("watcher did not send change") 176 } 177 break loop 178 } 179 } 180 return actual 181 }