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  }