launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/cmd/jujud/unit_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package main
     5  
     6  import (
     7  	"time"
     8  
     9  	gc "launchpad.net/gocheck"
    10  
    11  	"launchpad.net/juju-core/agent"
    12  	"launchpad.net/juju-core/cmd"
    13  	jujutesting "launchpad.net/juju-core/juju/testing"
    14  	"launchpad.net/juju-core/names"
    15  	"launchpad.net/juju-core/state"
    16  	"launchpad.net/juju-core/state/api/params"
    17  	coretesting "launchpad.net/juju-core/testing"
    18  	"launchpad.net/juju-core/tools"
    19  	"launchpad.net/juju-core/worker"
    20  )
    21  
    22  type UnitSuite struct {
    23  	coretesting.GitSuite
    24  	agentSuite
    25  }
    26  
    27  var _ = gc.Suite(&UnitSuite{})
    28  
    29  func (s *UnitSuite) SetUpTest(c *gc.C) {
    30  	s.GitSuite.SetUpTest(c)
    31  	s.agentSuite.SetUpTest(c)
    32  }
    33  
    34  func (s *UnitSuite) TearDownTest(c *gc.C) {
    35  	s.agentSuite.TearDownTest(c)
    36  	s.GitSuite.TearDownTest(c)
    37  }
    38  
    39  const initialUnitPassword = "unit-password-1234567890"
    40  
    41  // primeAgent creates a unit, and sets up the unit agent's directory.
    42  // It returns the new unit and the agent's configuration.
    43  func (s *UnitSuite) primeAgent(c *gc.C) (*state.Unit, agent.Config, *tools.Tools) {
    44  	jujutesting.AddStateServerMachine(c, s.State)
    45  	svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
    46  	unit, err := svc.AddUnit()
    47  	c.Assert(err, gc.IsNil)
    48  	err = unit.SetPassword(initialUnitPassword)
    49  	c.Assert(err, gc.IsNil)
    50  	conf, tools := s.agentSuite.primeAgent(c, unit.Tag(), initialUnitPassword)
    51  	return unit, conf, tools
    52  }
    53  
    54  func (s *UnitSuite) newAgent(c *gc.C, unit *state.Unit) *UnitAgent {
    55  	a := &UnitAgent{}
    56  	s.initAgent(c, a, "--unit-name", unit.Name())
    57  	return a
    58  }
    59  
    60  func (s *UnitSuite) TestParseSuccess(c *gc.C) {
    61  	create := func() (cmd.Command, *AgentConf) {
    62  		a := &UnitAgent{}
    63  		return a, &a.Conf
    64  	}
    65  	uc := CheckAgentCommand(c, create, []string{"--unit-name", "w0rd-pre55/1"})
    66  	c.Assert(uc.(*UnitAgent).UnitName, gc.Equals, "w0rd-pre55/1")
    67  }
    68  
    69  func (s *UnitSuite) TestParseMissing(c *gc.C) {
    70  	uc := &UnitAgent{}
    71  	err := ParseAgentCommand(uc, []string{})
    72  	c.Assert(err, gc.ErrorMatches, "--unit-name option must be set")
    73  }
    74  
    75  func (s *UnitSuite) TestParseNonsense(c *gc.C) {
    76  	for _, args := range [][]string{
    77  		{"--unit-name", "wordpress"},
    78  		{"--unit-name", "wordpress/seventeen"},
    79  		{"--unit-name", "wordpress/-32"},
    80  		{"--unit-name", "wordpress/wild/9"},
    81  		{"--unit-name", "20/20"},
    82  	} {
    83  		err := ParseAgentCommand(&UnitAgent{}, args)
    84  		c.Assert(err, gc.ErrorMatches, `--unit-name option expects "<service>/<n>" argument`)
    85  	}
    86  }
    87  
    88  func (s *UnitSuite) TestParseUnknown(c *gc.C) {
    89  	uc := &UnitAgent{}
    90  	err := ParseAgentCommand(uc, []string{"--unit-name", "wordpress/1", "thundering typhoons"})
    91  	c.Assert(err, gc.ErrorMatches, `unrecognized args: \["thundering typhoons"\]`)
    92  }
    93  
    94  func waitForUnitStarted(stateConn *state.State, unit *state.Unit, c *gc.C) {
    95  	timeout := time.After(5 * time.Second)
    96  
    97  	for {
    98  		select {
    99  		case <-timeout:
   100  			c.Fatalf("no activity detected")
   101  		case <-time.After(coretesting.ShortWait):
   102  			err := unit.Refresh()
   103  			c.Assert(err, gc.IsNil)
   104  			st, info, data, err := unit.Status()
   105  			c.Assert(err, gc.IsNil)
   106  			switch st {
   107  			case params.StatusPending, params.StatusInstalled:
   108  				c.Logf("waiting...")
   109  				continue
   110  			case params.StatusStarted:
   111  				c.Logf("started!")
   112  				return
   113  			case params.StatusDown:
   114  				stateConn.StartSync()
   115  				c.Logf("unit is still down")
   116  			default:
   117  				c.Fatalf("unexpected status %s %s %v", st, info, data)
   118  			}
   119  		}
   120  	}
   121  }
   122  
   123  func (s *UnitSuite) TestRunStop(c *gc.C) {
   124  	unit, _, _ := s.primeAgent(c)
   125  	a := s.newAgent(c, unit)
   126  	go func() { c.Check(a.Run(nil), gc.IsNil) }()
   127  	defer func() { c.Check(a.Stop(), gc.IsNil) }()
   128  	waitForUnitStarted(s.State, unit, c)
   129  }
   130  
   131  func (s *UnitSuite) TestUpgrade(c *gc.C) {
   132  	unit, _, currentTools := s.primeAgent(c)
   133  	a := s.newAgent(c, unit)
   134  	s.testUpgrade(c, a, unit.Tag(), currentTools)
   135  }
   136  
   137  func (s *UnitSuite) TestWithDeadUnit(c *gc.C) {
   138  	unit, _, _ := s.primeAgent(c)
   139  	err := unit.EnsureDead()
   140  	c.Assert(err, gc.IsNil)
   141  	a := s.newAgent(c, unit)
   142  	err = runWithTimeout(a)
   143  	c.Assert(err, gc.IsNil)
   144  
   145  	// try again when the unit has been removed.
   146  	err = unit.Remove()
   147  	c.Assert(err, gc.IsNil)
   148  	a = s.newAgent(c, unit)
   149  	err = runWithTimeout(a)
   150  	c.Assert(err, gc.IsNil)
   151  }
   152  
   153  func (s *UnitSuite) TestOpenAPIState(c *gc.C) {
   154  	unit, _, _ := s.primeAgent(c)
   155  	s.testOpenAPIState(c, unit, s.newAgent(c, unit), initialUnitPassword)
   156  }
   157  
   158  func (s *UnitSuite) TestOpenAPIStateWithBadCredsTerminates(c *gc.C) {
   159  	conf, _ := s.agentSuite.primeAgent(c, "unit-missing-0", "no-password")
   160  	_, _, err := openAPIState(conf, nil)
   161  	c.Assert(err, gc.Equals, worker.ErrTerminateAgent)
   162  }
   163  
   164  type fakeUnitAgent struct {
   165  	unitName string
   166  }
   167  
   168  func (f *fakeUnitAgent) Entity(st *state.State) (AgentState, error) {
   169  	return st.Unit(f.unitName)
   170  }
   171  
   172  func (f *fakeUnitAgent) Tag() string {
   173  	return names.UnitTag(f.unitName)
   174  }
   175  
   176  func (s *UnitSuite) TestOpenAPIStateWithDeadEntityTerminates(c *gc.C) {
   177  	unit, conf, _ := s.primeAgent(c)
   178  	err := unit.EnsureDead()
   179  	c.Assert(err, gc.IsNil)
   180  	_, _, err = openAPIState(conf, &fakeUnitAgent{"wordpress/0"})
   181  	c.Assert(err, gc.Equals, worker.ErrTerminateAgent)
   182  }
   183  
   184  func (s *UnitSuite) TestOpenStateFails(c *gc.C) {
   185  	// Start a unit agent and make sure it doesn't set a mongo password
   186  	// we can use to connect to state with.
   187  	unit, conf, _ := s.primeAgent(c)
   188  	a := s.newAgent(c, unit)
   189  	go func() { c.Check(a.Run(nil), gc.IsNil) }()
   190  	defer func() { c.Check(a.Stop(), gc.IsNil) }()
   191  	waitForUnitStarted(s.State, unit, c)
   192  
   193  	s.assertCannotOpenState(c, conf.Tag(), conf.DataDir())
   194  }