launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/apiserver/server_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package apiserver_test
     5  
     6  import (
     7  	"launchpad.net/errgo/errors"
     8  	gc "launchpad.net/gocheck"
     9  	stdtesting "testing"
    10  	"time"
    11  
    12  	jujutesting "launchpad.net/juju-core/juju/testing"
    13  	"launchpad.net/juju-core/state"
    14  	"launchpad.net/juju-core/state/api"
    15  	"launchpad.net/juju-core/state/api/params"
    16  	"launchpad.net/juju-core/state/apiserver"
    17  	coretesting "launchpad.net/juju-core/testing"
    18  	jc "launchpad.net/juju-core/testing/checkers"
    19  	"launchpad.net/juju-core/utils"
    20  )
    21  
    22  func TestAll(t *stdtesting.T) {
    23  	coretesting.MgoTestPackage(t)
    24  }
    25  
    26  var fastDialOpts = api.DialOpts{}
    27  
    28  type serverSuite struct {
    29  	jujutesting.JujuConnSuite
    30  }
    31  
    32  var _ = gc.Suite(&serverSuite{})
    33  
    34  func (s *serverSuite) TestStop(c *gc.C) {
    35  	// Start our own instance of the server so we have
    36  	// a handle on it to stop it.
    37  	srv, err := apiserver.NewServer(s.State, "localhost:0", []byte(coretesting.ServerCert), []byte(coretesting.ServerKey), "")
    38  	c.Assert(err, gc.IsNil)
    39  	defer srv.Stop()
    40  
    41  	stm, err := s.State.AddMachine("quantal", state.JobHostUnits)
    42  	c.Assert(err, gc.IsNil)
    43  	err = stm.SetProvisioned("foo", "fake_nonce", nil)
    44  	c.Assert(err, gc.IsNil)
    45  	password, err := utils.RandomPassword()
    46  	c.Assert(err, gc.IsNil)
    47  	err = stm.SetPassword(password)
    48  	c.Assert(err, gc.IsNil)
    49  
    50  	// Note we can't use openAs because we're not connecting to
    51  	// s.APIConn.
    52  	apiInfo := &api.Info{
    53  		Tag:      stm.Tag(),
    54  		Password: password,
    55  		Nonce:    "fake_nonce",
    56  		Addrs:    []string{srv.Addr()},
    57  		CACert:   []byte(coretesting.CACert),
    58  	}
    59  	st, err := api.Open(apiInfo, fastDialOpts)
    60  	c.Assert(err, gc.IsNil)
    61  	defer st.Close()
    62  
    63  	_, err = st.Machiner().Machine(stm.Tag())
    64  	c.Assert(err, gc.IsNil)
    65  
    66  	err = srv.Stop()
    67  	c.Assert(err, gc.IsNil)
    68  
    69  	_, err = st.Machiner().Machine(stm.Tag())
    70  	if errors.Cause(err) != params.CodeServerShutdown {
    71  		c.Fatalf("unexpected error from request: %#v", err)
    72  	}
    73  
    74  	// Check it can be stopped twice.
    75  	err = srv.Stop()
    76  	c.Assert(err, gc.IsNil)
    77  }
    78  
    79  func (s *serverSuite) TestOpenAsMachineErrors(c *gc.C) {
    80  	assertNotProvisioned := func(err error) {
    81  		c.Assert(err, gc.NotNil)
    82  		c.Assert(err, jc.Satisfies, params.IsCodeNotProvisioned)
    83  		c.Assert(err, gc.ErrorMatches, `machine \d+ is not provisioned`)
    84  	}
    85  	stm, err := s.State.AddMachine("quantal", state.JobHostUnits)
    86  	c.Assert(err, gc.IsNil)
    87  	err = stm.SetProvisioned("foo", "fake_nonce", nil)
    88  	c.Assert(err, gc.IsNil)
    89  	password, err := utils.RandomPassword()
    90  	c.Assert(err, gc.IsNil)
    91  	err = stm.SetPassword(password)
    92  	c.Assert(err, gc.IsNil)
    93  
    94  	// This does almost exactly the same as OpenAPIAsMachine but checks
    95  	// for failures instead.
    96  	_, info, err := s.APIConn.Environ.StateInfo()
    97  	info.Tag = stm.Tag()
    98  	info.Password = password
    99  	info.Nonce = "invalid-nonce"
   100  	st, err := api.Open(info, fastDialOpts)
   101  	assertNotProvisioned(err)
   102  	c.Assert(st, gc.IsNil)
   103  
   104  	// Try with empty nonce as well.
   105  	info.Nonce = ""
   106  	st, err = api.Open(info, fastDialOpts)
   107  	assertNotProvisioned(err)
   108  	c.Assert(st, gc.IsNil)
   109  
   110  	// Finally, with the correct one succeeds.
   111  	info.Nonce = "fake_nonce"
   112  	st, err = api.Open(info, fastDialOpts)
   113  	c.Assert(err, gc.IsNil)
   114  	c.Assert(st, gc.NotNil)
   115  	st.Close()
   116  
   117  	// Now add another machine, intentionally unprovisioned.
   118  	stm1, err := s.State.AddMachine("quantal", state.JobHostUnits)
   119  	c.Assert(err, gc.IsNil)
   120  	err = stm1.SetPassword(password)
   121  	c.Assert(err, gc.IsNil)
   122  
   123  	// Try connecting, it will fail.
   124  	info.Tag = stm1.Tag()
   125  	info.Nonce = ""
   126  	st, err = api.Open(info, fastDialOpts)
   127  	assertNotProvisioned(err)
   128  	c.Assert(st, gc.IsNil)
   129  }
   130  
   131  func (s *serverSuite) TestMachineLoginStartsPinger(c *gc.C) {
   132  	// This is the same steps as OpenAPIAsNewMachine but we need to assert
   133  	// the agent is not alive before we actually open the API.
   134  	// Create a new machine to verify "agent alive" behavior.
   135  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
   136  	c.Assert(err, gc.IsNil)
   137  	err = machine.SetProvisioned("foo", "fake_nonce", nil)
   138  	c.Assert(err, gc.IsNil)
   139  	password, err := utils.RandomPassword()
   140  	c.Assert(err, gc.IsNil)
   141  	err = machine.SetPassword(password)
   142  	c.Assert(err, gc.IsNil)
   143  
   144  	// Not alive yet.
   145  	s.assertAlive(c, machine, false)
   146  
   147  	// Login as the machine agent of the created machine.
   148  	st := s.OpenAPIAsMachine(c, machine.Tag(), password, "fake_nonce")
   149  
   150  	// Make sure the pinger has started.
   151  	s.assertAlive(c, machine, true)
   152  
   153  	// Now make sure it stops when connection is closed.
   154  	c.Assert(st.Close(), gc.IsNil)
   155  
   156  	// Sync, then wait for a bit to make sure the state is updated.
   157  	s.State.StartSync()
   158  	<-time.After(coretesting.ShortWait)
   159  	s.State.StartSync()
   160  
   161  	s.assertAlive(c, machine, false)
   162  }
   163  
   164  func (s *serverSuite) TestUnitLoginStartsPinger(c *gc.C) {
   165  	// Create a new service and unit to verify "agent alive" behavior.
   166  	service := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   167  	unit, err := service.AddUnit()
   168  	c.Assert(err, gc.IsNil)
   169  	password, err := utils.RandomPassword()
   170  	c.Assert(err, gc.IsNil)
   171  	err = unit.SetPassword(password)
   172  	c.Assert(err, gc.IsNil)
   173  
   174  	// Not alive yet.
   175  	s.assertAlive(c, unit, false)
   176  
   177  	// Login as the unit agent of the created unit.
   178  	st := s.OpenAPIAs(c, unit.Tag(), password)
   179  
   180  	// Make sure the pinger has started.
   181  	s.assertAlive(c, unit, true)
   182  
   183  	// Now make sure it stops when connection is closed.
   184  	c.Assert(st.Close(), gc.IsNil)
   185  
   186  	// Sync, then wait for a bit to make sure the state is updated.
   187  	s.State.StartSync()
   188  	<-time.After(coretesting.ShortWait)
   189  	s.State.StartSync()
   190  
   191  	s.assertAlive(c, unit, false)
   192  }
   193  
   194  type agentAliver interface {
   195  	AgentAlive() (bool, error)
   196  }
   197  
   198  func (s *serverSuite) assertAlive(c *gc.C, entity agentAliver, isAlive bool) {
   199  	s.State.StartSync()
   200  	alive, err := entity.AgentAlive()
   201  	c.Assert(err, gc.IsNil)
   202  	c.Assert(alive, gc.Equals, isAlive)
   203  }