github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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 watcher.StringsChannel(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, preAssert func()) StringsWatcherC { 60 if preAssert == nil { 61 preAssert = func() {} 62 } 63 return StringsWatcherC{ 64 C: c, 65 Watcher: watcher, 66 PreAssert: preAssert, 67 } 68 } 69 70 type StringsWatcherC struct { 71 *gc.C 72 Watcher watcher.StringsWatcher 73 PreAssert func() 74 } 75 76 // AssertChanges fails if it cannot read a value from Changes despite waiting a 77 // long time. It logs, but does not check, the received changes; but will fail 78 // if the Changes chan is closed. 79 func (c StringsWatcherC) AssertChanges() { 80 c.PreAssert() 81 select { 82 case change, ok := <-c.Watcher.Changes(): 83 c.Logf("received change: %#v", change) 84 c.Assert(ok, jc.IsTrue) 85 case <-time.After(testing.LongWait): 86 c.Fatalf("watcher did not send change") 87 } 88 c.AssertNoChange() 89 } 90 91 // AssertNoChange fails if it manages to read a value from Changes before a 92 // short time has passed. 93 func (c StringsWatcherC) AssertNoChange() { 94 c.PreAssert() 95 select { 96 case change, ok := <-c.Watcher.Changes(): 97 c.Fatalf("watcher sent unexpected change: (%#v, %v)", change, ok) 98 case <-time.After(testing.ShortWait): 99 } 100 } 101 102 // AssertStops Kills the watcher and asserts (1) that Wait completes without 103 // error before a long time has passed; and (2) that Changes remains open but 104 // no values are being sent. 105 func (c StringsWatcherC) AssertStops() { 106 c.Watcher.Kill() 107 wait := make(chan error) 108 go func() { 109 c.PreAssert() 110 wait <- c.Watcher.Wait() 111 }() 112 select { 113 case <-time.After(testing.LongWait): 114 c.Fatalf("watcher never stopped") 115 case err := <-wait: 116 c.Assert(err, jc.ErrorIsNil) 117 } 118 119 c.PreAssert() 120 select { 121 case change, ok := <-c.Watcher.Changes(): 122 c.Fatalf("watcher sent unexpected change: (%#v, %v)", change, ok) 123 default: 124 } 125 } 126 127 func (c StringsWatcherC) AssertChange(expect ...string) { 128 c.assertChange(false, expect...) 129 } 130 131 func (c StringsWatcherC) AssertChangeInSingleEvent(expect ...string) { 132 c.assertChange(true, expect...) 133 } 134 135 // AssertChangeMaybeIncluding verifies that there is a change that may 136 // contain zero to all of the passed in strings, and no other changes. 137 func (c StringsWatcherC) AssertChangeMaybeIncluding(expect ...string) { 138 maxCount := len(expect) 139 actual := c.collectChanges(true, maxCount) 140 141 if maxCount == 0 { 142 c.Assert(actual, gc.HasLen, 0) 143 } else { 144 actualCount := len(actual) 145 c.Assert(actualCount <= maxCount, jc.IsTrue, gc.Commentf("expected at most %d, got %d", maxCount, actualCount)) 146 unexpected := set.NewStrings(actual...).Difference(set.NewStrings(expect...)) 147 c.Assert(unexpected.Values(), gc.HasLen, 0) 148 } 149 } 150 151 // assertChange asserts the given list of changes was reported by 152 // the watcher, but does not assume there are no following changes. 153 func (c StringsWatcherC) assertChange(single bool, expect ...string) { 154 actual := c.collectChanges(single, len(expect)) 155 if len(expect) == 0 { 156 c.Assert(actual, gc.HasLen, 0) 157 } else { 158 c.Assert(actual, jc.SameContents, expect) 159 } 160 } 161 162 // collectChanges gets up to the max number of changes within the 163 // testing.LongWait period. 164 func (c StringsWatcherC) collectChanges(single bool, max int) []string { 165 timeout := time.After(testing.LongWait) 166 var actual []string 167 gotOneChange := false 168 loop: 169 for { 170 c.PreAssert() 171 select { 172 case changes, ok := <-c.Watcher.Changes(): 173 c.Assert(ok, jc.IsTrue) 174 gotOneChange = true 175 actual = append(actual, changes...) 176 if single || len(actual) >= max { 177 break loop 178 } 179 case <-timeout: 180 if !gotOneChange { 181 c.Fatalf("watcher did not send change") 182 } 183 break loop 184 } 185 } 186 return actual 187 }