github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/api/monitor_internal_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package api
     5  
     6  import (
     7  	"errors"
     8  	"time"
     9  
    10  	"github.com/juju/clock/testclock"
    11  	"github.com/juju/testing"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	jtesting "github.com/juju/juju/testing"
    15  )
    16  
    17  var _ = gc.Suite(&MonitorSuite{})
    18  
    19  type MonitorSuite struct {
    20  	testing.IsolationSuite
    21  	clock   *testclock.Clock
    22  	closed  chan struct{}
    23  	dead    chan struct{}
    24  	broken  chan struct{}
    25  	monitor *monitor
    26  }
    27  
    28  const testPingPeriod = 30 * time.Second
    29  const testPingTimeout = time.Second
    30  
    31  func (s *MonitorSuite) SetUpTest(c *gc.C) {
    32  	s.IsolationSuite.SetUpTest(c)
    33  	s.clock = testclock.NewClock(time.Time{})
    34  	s.closed = make(chan struct{})
    35  	s.dead = make(chan struct{})
    36  	s.broken = make(chan struct{})
    37  	s.monitor = &monitor{
    38  		clock:       s.clock,
    39  		ping:        func() error { return nil },
    40  		pingPeriod:  testPingPeriod,
    41  		pingTimeout: testPingTimeout,
    42  		closed:      s.closed,
    43  		dead:        s.dead,
    44  		broken:      s.broken,
    45  	}
    46  }
    47  
    48  func (s *MonitorSuite) TestClose(c *gc.C) {
    49  	go s.monitor.run()
    50  	s.waitForClock(c)
    51  	close(s.closed)
    52  	assertEvent(c, s.broken)
    53  }
    54  
    55  func (s *MonitorSuite) TestDead(c *gc.C) {
    56  	go s.monitor.run()
    57  	s.waitForClock(c)
    58  	close(s.dead)
    59  	assertEvent(c, s.broken)
    60  }
    61  
    62  func (s *MonitorSuite) TestFirstPingFails(c *gc.C) {
    63  	s.monitor.ping = func() error { return errors.New("boom") }
    64  	go s.monitor.run()
    65  
    66  	s.waitThenAdvance(c, testPingPeriod)
    67  	assertEvent(c, s.broken)
    68  }
    69  
    70  func (s *MonitorSuite) TestLaterPingFails(c *gc.C) {
    71  	pings := 0
    72  	s.monitor.ping = func() error {
    73  		if pings > 0 {
    74  			return errors.New("boom")
    75  		}
    76  		pings++
    77  		return nil
    78  	}
    79  	go s.monitor.run()
    80  
    81  	s.waitThenAdvance(c, testPingPeriod) // in run
    82  	s.waitForClock(c)                    // in pingWithTimeout
    83  	s.waitThenAdvance(c, testPingPeriod) // in run
    84  	s.waitForClock(c)                    // in pingWithTimeout
    85  	assertEvent(c, s.broken)
    86  }
    87  
    88  func (s *MonitorSuite) TestPingsTimesOut(c *gc.C) {
    89  	s.monitor.ping = func() error {
    90  		// Advance the clock only once this ping call is being waited on.
    91  		s.waitThenAdvance(c, testPingTimeout)
    92  		return nil
    93  	}
    94  	go s.monitor.run()
    95  
    96  	s.waitThenAdvance(c, testPingPeriod)
    97  	assertEvent(c, s.broken)
    98  }
    99  
   100  func (s *MonitorSuite) waitForClock(c *gc.C) {
   101  	assertEvent(c, s.clock.Alarms())
   102  }
   103  
   104  func (s *MonitorSuite) waitThenAdvance(c *gc.C, d time.Duration) {
   105  	s.waitForClock(c)
   106  	s.clock.Advance(d)
   107  }
   108  
   109  func assertEvent(c *gc.C, ch <-chan struct{}) {
   110  	select {
   111  	case <-ch:
   112  	case <-time.After(jtesting.LongWait):
   113  		c.Fatal("timed out waiting for channel event")
   114  	}
   115  }