github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/pinger_test.go (about)

     1  // Copyright 2012-2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package apiserver_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"github.com/juju/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/api"
    17  	"github.com/juju/juju/apiserver"
    18  	"github.com/juju/juju/rpc"
    19  	coretesting "github.com/juju/juju/testing"
    20  )
    21  
    22  // pingerSuite exercises the apiserver's ping timeout functionality
    23  // from the outside. Ping API requests are made (or not) to a running
    24  // API server to ensure that the server shuts down the API connection
    25  // as expected once there's been no pings within the timeout period.
    26  type pingerSuite struct {
    27  	apiserverBaseSuite
    28  }
    29  
    30  var _ = gc.Suite(&pingerSuite{})
    31  
    32  func (s *pingerSuite) newServerWithTestClock(c *gc.C) (*apiserver.Server, *testing.Clock) {
    33  	clock := testing.NewClock(time.Now())
    34  	config := s.sampleConfig(c)
    35  	config.PingClock = clock
    36  	server := s.newServer(c, config)
    37  	return server, clock
    38  }
    39  
    40  func (s *pingerSuite) TestConnectionBrokenDetection(c *gc.C) {
    41  	server, clock := s.newServerWithTestClock(c)
    42  	conn, _ := s.OpenAPIAsNewMachine(c, server)
    43  
    44  	clock.Advance(api.PingPeriod)
    45  	// Connection still alive
    46  	select {
    47  	case <-conn.Broken():
    48  		c.Fatalf("connection should be alive still")
    49  	case <-time.After(coretesting.ShortWait):
    50  		// all good, connection still there
    51  	}
    52  
    53  	conn.Close()
    54  
    55  	clock.Advance(api.PingPeriod + time.Second)
    56  	// Check it's detected
    57  	select {
    58  	case <-time.After(coretesting.ShortWait):
    59  		c.Fatalf("connection not closed as expected")
    60  	case <-conn.Broken():
    61  		return
    62  	}
    63  }
    64  
    65  func (s *pingerSuite) TestPing(c *gc.C) {
    66  	tw := &loggo.TestWriter{}
    67  	c.Assert(loggo.RegisterWriter("ping-tester", tw), gc.IsNil)
    68  
    69  	server, _ := s.newServerWithTestClock(c)
    70  	conn, _ := s.OpenAPIAsNewMachine(c, server)
    71  
    72  	c.Assert(pingConn(conn), jc.ErrorIsNil)
    73  	c.Assert(conn.Close(), jc.ErrorIsNil)
    74  	c.Assert(errors.Cause(pingConn(conn)), gc.Equals, rpc.ErrShutdown)
    75  
    76  	// Make sure that ping messages have not been logged.
    77  	for _, m := range tw.Log() {
    78  		c.Logf("checking %q", m.Message)
    79  		c.Check(m.Message, gc.Not(gc.Matches), `.*"Request":"Ping".*`)
    80  	}
    81  }
    82  
    83  func (s *pingerSuite) TestClientNoNeedToPing(c *gc.C) {
    84  	server, clock := s.newServerWithTestClock(c)
    85  	conn := s.OpenAPIAsAdmin(c, server)
    86  
    87  	// Here we have a conundrum, we can't wait for a clock alarm because
    88  	// one isn't set because we don't have pingers for clients. So just
    89  	// a short wait then.
    90  	time.Sleep(coretesting.ShortWait)
    91  
    92  	clock.Advance(apiserver.MaxClientPingInterval * 2)
    93  	c.Assert(pingConn(conn), jc.ErrorIsNil)
    94  }
    95  
    96  func (s *pingerSuite) TestAgentConnectionShutsDownWithNoPing(c *gc.C) {
    97  	server, clock := s.newServerWithTestClock(c)
    98  	conn, _ := s.OpenAPIAsNewMachine(c, server)
    99  
   100  	waitAndAdvance(c, clock, apiserver.MaxClientPingInterval)
   101  	checkConnectionDies(c, conn)
   102  }
   103  
   104  func (s *pingerSuite) TestAgentConnectionDelaysShutdownWithPing(c *gc.C) {
   105  	server, clock := s.newServerWithTestClock(c)
   106  	conn, _ := s.OpenAPIAsNewMachine(c, server)
   107  
   108  	// As long as we don't wait too long, the connection stays open
   109  	attemptDelay := apiserver.MaxClientPingInterval / 2
   110  	for i := 0; i < 10; i++ {
   111  		waitAndAdvance(c, clock, attemptDelay)
   112  		c.Assert(pingConn(conn), jc.ErrorIsNil)
   113  	}
   114  
   115  	// However, once we stop pinging for too long, the connection dies
   116  	waitAndAdvance(c, clock, apiserver.MaxClientPingInterval)
   117  	checkConnectionDies(c, conn)
   118  }
   119  
   120  func (s *pingerSuite) TestAgentConnectionsShutDownWhenAPIServerDies(c *gc.C) {
   121  	clock := testing.NewClock(time.Now())
   122  	config := s.sampleConfig(c)
   123  	config.Clock = clock
   124  	server := s.newServerDirtyKill(c, config)
   125  	conn, _ := s.OpenAPIAsNewMachine(c, server)
   126  
   127  	err := pingConn(conn)
   128  	c.Assert(err, jc.ErrorIsNil)
   129  	server.Kill()
   130  
   131  	// We know this is less than the client ping interval.
   132  	clock.Advance(apiserver.MongoPingInterval)
   133  	checkConnectionDies(c, conn)
   134  }
   135  
   136  func waitAndAdvance(c *gc.C, clock *testing.Clock, delta time.Duration) {
   137  	waitForClock(c, clock)
   138  	clock.Advance(delta)
   139  }
   140  
   141  func waitForClock(c *gc.C, clock *testing.Clock) {
   142  	select {
   143  	case <-clock.Alarms():
   144  	case <-time.After(coretesting.LongWait):
   145  		c.Fatal("timed out waiting for clock")
   146  	}
   147  }
   148  
   149  func checkConnectionDies(c *gc.C, conn api.Connection) {
   150  	attempt := utils.AttemptStrategy{
   151  		Total: coretesting.LongWait,
   152  		Delay: coretesting.ShortWait,
   153  	}
   154  	for a := attempt.Start(); a.Next(); {
   155  		err := pingConn(conn)
   156  		if err != nil {
   157  			c.Assert(err, gc.ErrorMatches, "connection is shut down")
   158  			return
   159  		}
   160  	}
   161  	c.Fatal("connection didn't get shut down")
   162  }
   163  
   164  func pingConn(conn api.Connection) error {
   165  	version := conn.BestFacadeVersion("Pinger")
   166  	return conn.APICall("Pinger", version, "", "Ping", nil, nil)
   167  }