github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/client/statushistory_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package client_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/names"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/apiserver/client"
    15  	"github.com/juju/juju/apiserver/params"
    16  	apiservertesting "github.com/juju/juju/apiserver/testing"
    17  	"github.com/juju/juju/status"
    18  	"github.com/juju/juju/testing"
    19  )
    20  
    21  var _ = gc.Suite(&statusHistoryTestSuite{})
    22  
    23  type statusHistoryTestSuite struct {
    24  	testing.BaseSuite
    25  	st  *mockState
    26  	api *client.Client
    27  }
    28  
    29  func (s *statusHistoryTestSuite) SetUpTest(c *gc.C) {
    30  	s.st = &mockState{}
    31  	client.PatchState(s, s.st)
    32  	tag := names.NewUserTag("user")
    33  	authorizer := &apiservertesting.FakeAuthorizer{Tag: tag}
    34  	var err error
    35  	s.api, err = client.NewClient(nil, nil, authorizer)
    36  	c.Assert(err, jc.ErrorIsNil)
    37  }
    38  
    39  func statusInfoWithDates(si []status.StatusInfo) []status.StatusInfo {
    40  	// Add timestamps to input status info records.
    41  	// Timestamps will be in descending order so that we can
    42  	// check that sorting has occurred and the output should
    43  	// be in ascending order.
    44  	result := make([]status.StatusInfo, len(si))
    45  	for i, s := range si {
    46  		t := time.Unix(int64(1000-i), 0)
    47  		s.Since = &t
    48  		result[i] = s
    49  	}
    50  	return result
    51  }
    52  
    53  func reverseStatusInfo(si []status.StatusInfo) []status.StatusInfo {
    54  	result := make([]status.StatusInfo, len(si))
    55  	for i, s := range si {
    56  		result[len(si)-i-1] = s
    57  	}
    58  	return result
    59  }
    60  
    61  func checkStatusInfo(c *gc.C, obtained []params.DetailedStatus, expected []status.StatusInfo) {
    62  	c.Assert(len(obtained), gc.Equals, len(expected))
    63  	lastTimestamp := int64(0)
    64  	for i, obtainedInfo := range obtained {
    65  		c.Logf("Checking status %q with info %q", obtainedInfo.Status, obtainedInfo.Info)
    66  		thisTimeStamp := obtainedInfo.Since.Unix()
    67  		c.Assert(thisTimeStamp >= lastTimestamp, jc.IsTrue)
    68  		lastTimestamp = thisTimeStamp
    69  		obtainedInfo.Since = nil
    70  		c.Assert(obtainedInfo.Status, gc.Equals, status.Status(expected[i].Status))
    71  		c.Assert(obtainedInfo.Info, gc.Equals, expected[i].Message)
    72  	}
    73  }
    74  
    75  func (s *statusHistoryTestSuite) TestSizeRequired(c *gc.C) {
    76  	_, err := s.api.StatusHistory(params.StatusHistoryArgs{
    77  		Name: "unit",
    78  		Kind: params.KindUnit,
    79  		Size: 0,
    80  	})
    81  	c.Assert(err, gc.ErrorMatches, "invalid history size: 0")
    82  }
    83  
    84  func (s *statusHistoryTestSuite) TestStatusHistoryUnitOnly(c *gc.C) {
    85  	s.st.unitHistory = statusInfoWithDates([]status.StatusInfo{
    86  		{
    87  			Status:  status.StatusMaintenance,
    88  			Message: "working",
    89  		},
    90  		{
    91  			Status:  status.StatusActive,
    92  			Message: "running",
    93  		},
    94  	})
    95  	s.st.agentHistory = statusInfoWithDates([]status.StatusInfo{
    96  		{
    97  			Status: status.StatusIdle,
    98  		},
    99  	})
   100  	h, err := s.api.StatusHistory(params.StatusHistoryArgs{
   101  		Name: "unit/0",
   102  		Kind: params.KindWorkload,
   103  		Size: 10,
   104  	})
   105  	c.Assert(err, jc.ErrorIsNil)
   106  	checkStatusInfo(c, h.Statuses, reverseStatusInfo(s.st.unitHistory))
   107  }
   108  
   109  func (s *statusHistoryTestSuite) TestStatusHistoryAgentOnly(c *gc.C) {
   110  	s.st.unitHistory = statusInfoWithDates([]status.StatusInfo{
   111  		{
   112  			Status:  status.StatusMaintenance,
   113  			Message: "working",
   114  		},
   115  		{
   116  			Status:  status.StatusActive,
   117  			Message: "running",
   118  		},
   119  	})
   120  	s.st.agentHistory = statusInfoWithDates([]status.StatusInfo{
   121  		{
   122  			Status: status.StatusExecuting,
   123  		},
   124  		{
   125  			Status: status.StatusIdle,
   126  		},
   127  	})
   128  	h, err := s.api.StatusHistory(params.StatusHistoryArgs{
   129  		Name: "unit/0",
   130  		Kind: params.KindUnitAgent,
   131  		Size: 10,
   132  	})
   133  	c.Assert(err, jc.ErrorIsNil)
   134  	checkStatusInfo(c, h.Statuses, reverseStatusInfo(s.st.agentHistory))
   135  }
   136  
   137  func (s *statusHistoryTestSuite) TestStatusHistoryCombined(c *gc.C) {
   138  	s.st.unitHistory = statusInfoWithDates([]status.StatusInfo{
   139  		{
   140  			Status:  status.StatusMaintenance,
   141  			Message: "working",
   142  		},
   143  		{
   144  			Status:  status.StatusActive,
   145  			Message: "running",
   146  		},
   147  		{
   148  			Status:  status.StatusBlocked,
   149  			Message: "waiting",
   150  		},
   151  	})
   152  	s.st.agentHistory = statusInfoWithDates([]status.StatusInfo{
   153  		{
   154  			Status: status.StatusExecuting,
   155  		},
   156  		{
   157  			Status: status.StatusIdle,
   158  		},
   159  	})
   160  	h, err := s.api.StatusHistory(params.StatusHistoryArgs{
   161  		Name: "unit/0",
   162  		Kind: params.KindUnit,
   163  		Size: 3,
   164  	})
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	expected := []status.StatusInfo{
   167  		s.st.agentHistory[1],
   168  		s.st.unitHistory[0],
   169  		s.st.agentHistory[0],
   170  	}
   171  	checkStatusInfo(c, h.Statuses, expected)
   172  }
   173  
   174  type mockState struct {
   175  	client.StateInterface
   176  	unitHistory  []status.StatusInfo
   177  	agentHistory []status.StatusInfo
   178  }
   179  
   180  func (m *mockState) ModelUUID() string {
   181  	return "uuid"
   182  }
   183  
   184  func (m *mockState) Unit(name string) (client.Unit, error) {
   185  	if name != "unit/0" {
   186  		return nil, errors.NotFoundf("%v", name)
   187  	}
   188  	return &mockUnit{
   189  		status: m.unitHistory,
   190  		agent:  &mockUnitAgent{m.agentHistory},
   191  	}, nil
   192  }
   193  
   194  type mockUnit struct {
   195  	status statuses
   196  	agent  *mockUnitAgent
   197  	client.Unit
   198  }
   199  
   200  func (m *mockUnit) StatusHistory(size int) ([]status.StatusInfo, error) {
   201  	return m.status.StatusHistory(size)
   202  }
   203  
   204  func (m *mockUnit) AgentHistory() status.StatusHistoryGetter {
   205  	return m.agent
   206  }
   207  
   208  type mockUnitAgent struct {
   209  	statuses
   210  }
   211  
   212  type statuses []status.StatusInfo
   213  
   214  func (s statuses) StatusHistory(size int) ([]status.StatusInfo, error) {
   215  	if size > len(s) {
   216  		size = len(s)
   217  	}
   218  	return s[:size], nil
   219  }