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 }