github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/state/statetracker_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"time"
     8  
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/state"
    13  	statetesting "github.com/juju/juju/state/testing"
    14  	"github.com/juju/juju/testing"
    15  	workerstate "github.com/juju/juju/worker/state"
    16  )
    17  
    18  type StateTrackerSuite struct {
    19  	statetesting.StateSuite
    20  	pool         *state.State
    21  	stateTracker workerstate.StateTracker
    22  }
    23  
    24  var _ = gc.Suite(&StateTrackerSuite{})
    25  
    26  func (s *StateTrackerSuite) SetUpTest(c *gc.C) {
    27  	s.StateSuite.SetUpTest(c)
    28  	s.stateTracker = workerstate.NewStateTracker(s.StatePool)
    29  }
    30  
    31  func (s *StateTrackerSuite) TestDoneWithNoUse(c *gc.C) {
    32  	err := s.stateTracker.Done()
    33  	c.Assert(err, jc.ErrorIsNil)
    34  	assertStatePoolClosed(c, s.StatePool)
    35  }
    36  
    37  func (s *StateTrackerSuite) TestTooManyDones(c *gc.C) {
    38  	err := s.stateTracker.Done()
    39  	c.Assert(err, jc.ErrorIsNil)
    40  	assertStatePoolClosed(c, s.StatePool)
    41  
    42  	err = s.stateTracker.Done()
    43  	c.Assert(err, gc.Equals, workerstate.ErrStateClosed)
    44  	assertStatePoolClosed(c, s.StatePool)
    45  }
    46  
    47  func (s *StateTrackerSuite) TestUse(c *gc.C) {
    48  	pool, err := s.stateTracker.Use()
    49  	c.Check(pool.SystemState(), gc.Equals, s.State)
    50  	c.Check(err, jc.ErrorIsNil)
    51  
    52  	pool, err = s.stateTracker.Use()
    53  	c.Check(pool.SystemState(), gc.Equals, s.State)
    54  	c.Check(err, jc.ErrorIsNil)
    55  }
    56  
    57  func (s *StateTrackerSuite) TestUseAndDone(c *gc.C) {
    58  	// Ref count starts at 1 (the creator/owner)
    59  
    60  	_, err := s.stateTracker.Use()
    61  	// 2
    62  	c.Check(err, jc.ErrorIsNil)
    63  
    64  	_, err = s.stateTracker.Use()
    65  	// 3
    66  	c.Check(err, jc.ErrorIsNil)
    67  
    68  	c.Check(s.stateTracker.Done(), jc.ErrorIsNil)
    69  	// 2
    70  	assertStatePoolNotClosed(c, s.StatePool)
    71  
    72  	_, err = s.stateTracker.Use()
    73  	// 3
    74  	c.Check(err, jc.ErrorIsNil)
    75  
    76  	c.Check(s.stateTracker.Done(), jc.ErrorIsNil)
    77  	// 2
    78  	assertStatePoolNotClosed(c, s.StatePool)
    79  
    80  	c.Check(s.stateTracker.Done(), jc.ErrorIsNil)
    81  	// 1
    82  	assertStatePoolNotClosed(c, s.StatePool)
    83  
    84  	c.Check(s.stateTracker.Done(), jc.ErrorIsNil)
    85  	// 0
    86  	assertStatePoolClosed(c, s.StatePool)
    87  }
    88  
    89  func (s *StateTrackerSuite) TestUseWhenClosed(c *gc.C) {
    90  	c.Assert(s.stateTracker.Done(), jc.ErrorIsNil)
    91  
    92  	pool, err := s.stateTracker.Use()
    93  	c.Check(pool, gc.IsNil)
    94  	c.Check(err, gc.Equals, workerstate.ErrStateClosed)
    95  }
    96  
    97  func assertStatePoolNotClosed(c *gc.C, pool *state.StatePool) {
    98  	c.Assert(pool.SystemState(), gc.NotNil)
    99  	err := pool.SystemState().Ping()
   100  	c.Assert(err, jc.ErrorIsNil)
   101  }
   102  
   103  func assertStatePoolClosed(c *gc.C, pool *state.StatePool) {
   104  	c.Assert(pool.SystemState(), gc.IsNil)
   105  }
   106  
   107  func isTxnLogStarted(report map[string]interface{}) bool {
   108  	// Sometimes when we call pool.Report() not all the workers have started yet, so we check
   109  	next := report
   110  	var ok bool
   111  	for _, p := range []string{"txn-watcher", "workers", "txnlog"} {
   112  		if child, ok := next[p]; !ok {
   113  			return false
   114  		} else {
   115  			next = child.(map[string]interface{})
   116  		}
   117  	}
   118  	state, ok := next["state"]
   119  	return ok && state == "started"
   120  }
   121  
   122  func (s *StateTrackerSuite) TestReport(c *gc.C) {
   123  	pool, err := s.stateTracker.Use()
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	start := time.Now()
   126  	report := pool.Report()
   127  	for !isTxnLogStarted(report) {
   128  		if time.Since(start) >= testing.LongWait {
   129  			c.Fatalf("txlog worker did not start after %v", testing.LongWait)
   130  		}
   131  		time.Sleep(time.Millisecond)
   132  		report = pool.Report()
   133  	}
   134  	c.Check(report, gc.NotNil)
   135  	// We don't have any State models in the pool, but we do have the
   136  	// txn-watcher report and the system state.
   137  	c.Check(report, gc.HasLen, 3)
   138  	c.Check(report["pool-size"], gc.Equals, 0)
   139  
   140  	// Calling Report increments the request count in the system
   141  	// state's hubwatcher stats, so zero that out before comparing.
   142  	removeRequestCount := func(report map[string]interface{}) map[string]interface{} {
   143  		next := report
   144  		for _, p := range []string{"system", "workers", "txnlog", "report"} {
   145  			child, ok := next[p]
   146  			if !ok {
   147  				c.Fatalf("couldn't find system.workers.txnlog.report")
   148  			}
   149  			next = child.(map[string]interface{})
   150  		}
   151  		delete(next, "request-count")
   152  		return report
   153  	}
   154  	report = removeRequestCount(report)
   155  	c.Check(removeRequestCount(s.stateTracker.Report()), gc.DeepEquals, report)
   156  	c.Check(removeRequestCount(s.stateTracker.Report()), gc.DeepEquals, report)
   157  	c.Check(removeRequestCount(s.stateTracker.Report()), gc.DeepEquals, report)
   158  }