github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/unitstatus_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common_test
     5  
     6  import (
     7  	"errors"
     8  
     9  	"github.com/juju/names/v5"
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/apiserver/common"
    15  	"github.com/juju/juju/core/status"
    16  	"github.com/juju/juju/state"
    17  )
    18  
    19  type UnitStatusSuite struct {
    20  	testing.IsolationSuite
    21  	ctx  common.ModelPresenceContext
    22  	unit *fakeStatusUnit
    23  }
    24  
    25  var _ = gc.Suite(&UnitStatusSuite{})
    26  
    27  func (s *UnitStatusSuite) SetUpTest(c *gc.C) {
    28  	s.unit = &fakeStatusUnit{
    29  		app: "foo",
    30  		agentStatus: status.StatusInfo{
    31  			Status:  status.Started,
    32  			Message: "agent ok",
    33  		},
    34  		status: status.StatusInfo{
    35  			Status:  status.Idle,
    36  			Message: "unit ok",
    37  		},
    38  		presence:         true,
    39  		shouldBeAssigned: true,
    40  	}
    41  	s.ctx = common.ModelPresenceContext{
    42  		Presence: agentAlive(names.NewUnitTag(s.unit.Name()).String()),
    43  	}
    44  }
    45  
    46  func (s *UnitStatusSuite) checkUntouched(c *gc.C) {
    47  	agent, workload := s.ctx.UnitStatus(s.unit)
    48  	c.Check(agent.Status, jc.DeepEquals, s.unit.agentStatus)
    49  	c.Check(agent.Err, jc.ErrorIsNil)
    50  	c.Check(workload.Status, jc.DeepEquals, s.unit.status)
    51  	c.Check(workload.Err, jc.ErrorIsNil)
    52  }
    53  
    54  func (s *UnitStatusSuite) checkLost(c *gc.C) {
    55  	agent, workload := s.ctx.UnitStatus(s.unit)
    56  	c.Check(agent.Status, jc.DeepEquals, status.StatusInfo{
    57  		Status:  status.Lost,
    58  		Message: "agent is not communicating with the server",
    59  	})
    60  	c.Check(agent.Err, jc.ErrorIsNil)
    61  	c.Check(workload.Status, jc.DeepEquals, status.StatusInfo{
    62  		Status:  status.Unknown,
    63  		Message: "agent lost, see 'juju show-status-log foo/2'",
    64  	})
    65  	c.Check(workload.Err, jc.ErrorIsNil)
    66  }
    67  
    68  func (s *UnitStatusSuite) TestNormal(c *gc.C) {
    69  	s.checkUntouched(c)
    70  }
    71  
    72  func (s *UnitStatusSuite) TestCAASNormal(c *gc.C) {
    73  	s.unit.shouldBeAssigned = false
    74  	s.ctx.Presence = agentAlive(names.NewApplicationTag(s.unit.app).String())
    75  	s.checkUntouched(c)
    76  }
    77  
    78  func (s *UnitStatusSuite) TestErrors(c *gc.C) {
    79  	s.unit.agentStatusErr = errors.New("agent status error")
    80  	s.unit.statusErr = errors.New("status error")
    81  
    82  	agent, workload := s.ctx.UnitStatus(s.unit)
    83  	c.Check(agent.Err, gc.ErrorMatches, "agent status error")
    84  	c.Check(workload.Err, gc.ErrorMatches, "status error")
    85  }
    86  
    87  func (s *UnitStatusSuite) TestLost(c *gc.C) {
    88  	s.ctx.Presence = agentDown(s.unit.Tag().String())
    89  	s.checkLost(c)
    90  }
    91  
    92  func (s *UnitStatusSuite) TestCAASLost(c *gc.C) {
    93  	s.unit.shouldBeAssigned = false
    94  	s.ctx.Presence = agentDown(names.NewApplicationTag(s.unit.app).String())
    95  	s.checkLost(c)
    96  }
    97  
    98  func (s *UnitStatusSuite) TestLostTerminated(c *gc.C) {
    99  	s.unit.status.Status = status.Terminated
   100  	s.unit.status.Message = ""
   101  
   102  	s.ctx.Presence = agentDown(s.unit.Tag().String())
   103  
   104  	agent, workload := s.ctx.UnitStatus(s.unit)
   105  	c.Check(agent.Status, jc.DeepEquals, status.StatusInfo{
   106  		Status:  status.Lost,
   107  		Message: "agent is not communicating with the server",
   108  	})
   109  	c.Check(agent.Err, jc.ErrorIsNil)
   110  	c.Check(workload.Status, jc.DeepEquals, status.StatusInfo{
   111  		Status:  status.Terminated,
   112  		Message: "",
   113  	})
   114  	c.Check(workload.Err, jc.ErrorIsNil)
   115  }
   116  
   117  func (s *UnitStatusSuite) TestCAASLostTerminated(c *gc.C) {
   118  	s.unit.shouldBeAssigned = false
   119  	s.unit.status.Status = status.Terminated
   120  	s.unit.status.Message = ""
   121  
   122  	s.ctx.Presence = agentDown(names.NewApplicationTag(s.unit.app).String())
   123  
   124  	agent, workload := s.ctx.UnitStatus(s.unit)
   125  	c.Check(agent.Status, jc.DeepEquals, status.StatusInfo{
   126  		Status:  status.Lost,
   127  		Message: "agent is not communicating with the server",
   128  	})
   129  	c.Check(agent.Err, jc.ErrorIsNil)
   130  	c.Check(workload.Status, jc.DeepEquals, status.StatusInfo{
   131  		Status:  status.Terminated,
   132  		Message: "",
   133  	})
   134  	c.Check(workload.Err, jc.ErrorIsNil)
   135  }
   136  func (s *UnitStatusSuite) TestLostAndDead(c *gc.C) {
   137  	s.ctx.Presence = agentDown(s.unit.Tag().String())
   138  	s.unit.life = state.Dead
   139  	// Status is untouched if unit is Dead.
   140  	s.checkUntouched(c)
   141  }
   142  
   143  func (s *UnitStatusSuite) TestPresenceError(c *gc.C) {
   144  	s.ctx.Presence = presenceError(s.unit.Tag().String())
   145  	// Presence error gets ignored, so no output is unchanged.
   146  	s.checkUntouched(c)
   147  }
   148  
   149  func (s *UnitStatusSuite) TestNotLostIfAllocating(c *gc.C) {
   150  	s.ctx.Presence = agentDown(s.unit.Tag().String())
   151  	s.unit.agentStatus.Status = status.Allocating
   152  	s.checkUntouched(c)
   153  }
   154  
   155  func (s *UnitStatusSuite) TestCantBeLostDuringInstall(c *gc.C) {
   156  	s.ctx.Presence = agentDown(s.unit.Tag().String())
   157  	s.unit.agentStatus.Status = status.Executing
   158  	s.unit.agentStatus.Message = "running install hook"
   159  	s.checkUntouched(c)
   160  }
   161  
   162  func (s *UnitStatusSuite) TestCantBeLostDuringWorkloadInstall(c *gc.C) {
   163  	s.ctx.Presence = agentDown(s.unit.Tag().String())
   164  	s.unit.status.Status = status.Maintenance
   165  	s.unit.status.Message = "installing charm software"
   166  	s.checkUntouched(c)
   167  }
   168  
   169  type fakeStatusUnit struct {
   170  	app              string
   171  	agentStatus      status.StatusInfo
   172  	agentStatusErr   error
   173  	status           status.StatusInfo
   174  	statusErr        error
   175  	presence         bool
   176  	life             state.Life
   177  	shouldBeAssigned bool
   178  }
   179  
   180  func (u *fakeStatusUnit) Name() string {
   181  	return u.app + "/2"
   182  }
   183  
   184  func (u *fakeStatusUnit) Tag() names.Tag {
   185  	return names.NewUnitTag(u.Name())
   186  }
   187  
   188  func (u *fakeStatusUnit) AgentStatus() (status.StatusInfo, error) {
   189  	return u.agentStatus, u.agentStatusErr
   190  }
   191  
   192  func (u *fakeStatusUnit) Status() (status.StatusInfo, error) {
   193  	return u.status, u.statusErr
   194  }
   195  
   196  func (u *fakeStatusUnit) Life() state.Life {
   197  	return u.life
   198  }
   199  
   200  func (u *fakeStatusUnit) ShouldBeAssigned() bool {
   201  	return u.shouldBeAssigned
   202  }
   203  
   204  func (u *fakeStatusUnit) IsSidecar() (bool, error) {
   205  	return false, nil
   206  }