github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/worker/instancepoller/worker_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // TODO(wallyworld) - move to instancepoller_test
     5  package instancepoller
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"time"
    11  
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/utils/clock"
    14  	gc "gopkg.in/check.v1"
    15  	"gopkg.in/juju/names.v2"
    16  
    17  	"github.com/juju/juju/api"
    18  	apiinstancepoller "github.com/juju/juju/api/instancepoller"
    19  	"github.com/juju/juju/apiserver/params"
    20  	"github.com/juju/juju/instance"
    21  	"github.com/juju/juju/juju/testing"
    22  	"github.com/juju/juju/network"
    23  	"github.com/juju/juju/provider/dummy"
    24  	"github.com/juju/juju/state"
    25  	"github.com/juju/juju/status"
    26  	coretesting "github.com/juju/juju/testing"
    27  	"github.com/juju/juju/worker"
    28  )
    29  
    30  var _ = gc.Suite(&workerSuite{})
    31  
    32  type workerSuite struct {
    33  	testing.JujuConnSuite
    34  
    35  	apiSt api.Connection
    36  	api   *apiinstancepoller.API
    37  }
    38  
    39  func (s *workerSuite) SetUpTest(c *gc.C) {
    40  	s.JujuConnSuite.SetUpTest(c)
    41  	s.apiSt, _ = s.OpenAPIAsNewMachine(c, state.JobManageModel)
    42  	s.api = s.apiSt.InstancePoller()
    43  }
    44  
    45  func (*workerSuite) instId(i int) instance.Id {
    46  	return instance.Id(fmt.Sprint(i))
    47  }
    48  
    49  func (*workerSuite) addressesForIndex(i int) []network.Address {
    50  	return network.NewAddresses(fmt.Sprintf("127.0.0.%d", i))
    51  }
    52  
    53  func (s *workerSuite) TestWorker(c *gc.C) {
    54  	// Most functionality is already tested in detail - we
    55  	// just need to test that things are wired together
    56  	// correctly.
    57  
    58  	// TODO(redir): per fwereade these should be in the worker config.
    59  	s.PatchValue(&ShortPoll, 10*time.Millisecond)
    60  	s.PatchValue(&LongPoll, 10*time.Millisecond)
    61  
    62  	machines, insts := s.setupScenario(c)
    63  	s.State.StartSync()
    64  	w, err := NewWorker(Config{
    65  		Delay:   time.Millisecond * 10,
    66  		Clock:   clock.WallClock,
    67  		Facade:  s.api,
    68  		Environ: s.Environ,
    69  	})
    70  	c.Assert(err, jc.ErrorIsNil)
    71  	defer func() {
    72  		c.Assert(worker.Stop(w), gc.IsNil)
    73  	}()
    74  
    75  	// TODO(perrito666) make this dependent on a juju status
    76  	checkInstanceInfo := func(index int, m machine, expectedStatus string) bool {
    77  		isProvisioned := true
    78  		instanceStatus, err := m.InstanceStatus()
    79  		if params.IsCodeNotProvisioned(err) {
    80  			isProvisioned = false
    81  		} else {
    82  			c.Assert(err, jc.ErrorIsNil)
    83  		}
    84  		providerAddresses, err := m.ProviderAddresses()
    85  		c.Assert(err, jc.ErrorIsNil)
    86  		// TODO(perrito666) all providers should use juju statuses instead of message.
    87  		return reflect.DeepEqual(providerAddresses, s.addressesForIndex(index)) && (!isProvisioned || instanceStatus.Info == expectedStatus)
    88  	}
    89  
    90  	// Wait for the odd numbered machines in the
    91  	// first half of the machine slice to be given their
    92  	// addresses and status.
    93  	for a := coretesting.LongAttempt.Start(); a.Next(); {
    94  		if !a.HasNext() {
    95  			c.Fatalf("timed out waiting for instance info")
    96  		}
    97  
    98  		if machinesSatisfy(c, machines, func(i int, m *apiinstancepoller.Machine) bool {
    99  			if i < len(machines)/2 && i%2 == 1 {
   100  				return checkInstanceInfo(i, m, "running")
   101  			}
   102  			instanceStatus, err := m.InstanceStatus()
   103  			c.Logf("instance message is: %q", instanceStatus.Info)
   104  			c.Assert(instanceStatus.Status, gc.Equals, status.Pending.String())
   105  			stm, err := s.State.Machine(m.Id())
   106  			c.Assert(err, jc.ErrorIsNil)
   107  			return len(stm.Addresses()) == 0
   108  		}) {
   109  			break
   110  		}
   111  	}
   112  	// Now provision the even machines in the first half and watch them get addresses.
   113  	for i := 0; i < len(insts)/2; i += 2 {
   114  		m, err := s.State.Machine(machines[i].Id())
   115  		c.Assert(err, jc.ErrorIsNil)
   116  		err = m.SetProvisioned(insts[i].Id(), "nonce", nil)
   117  		c.Assert(err, jc.ErrorIsNil)
   118  		dummy.SetInstanceAddresses(insts[i], s.addressesForIndex(i))
   119  		dummy.SetInstanceStatus(insts[i], "running")
   120  	}
   121  	for a := coretesting.LongAttempt.Start(); a.Next(); {
   122  		if !a.HasNext() {
   123  			c.Fatalf("timed out waiting for machine instance info")
   124  		}
   125  		if machinesSatisfy(c, machines, func(i int, m *apiinstancepoller.Machine) bool {
   126  			if i < len(machines)/2 {
   127  				return checkInstanceInfo(i, m, "running")
   128  			}
   129  			// Machines in second half still have no addresses, nor status.
   130  			instanceStatus, err := m.InstanceStatus()
   131  			c.Assert(instanceStatus.Status, gc.Equals, status.Pending.String())
   132  			stm, err := s.State.Machine(m.Id())
   133  			c.Assert(err, jc.ErrorIsNil)
   134  			return len(stm.Addresses()) == 0
   135  		}) {
   136  			break
   137  		}
   138  	}
   139  
   140  	// Provision the remaining machines and check the address and status.
   141  	for i := len(insts) / 2; i < len(insts); i++ {
   142  		if i%2 == 0 {
   143  			m, err := s.State.Machine(machines[i].Id())
   144  			c.Assert(err, jc.ErrorIsNil)
   145  			err = m.SetProvisioned(insts[i].Id(), "nonce", nil)
   146  			c.Assert(err, jc.ErrorIsNil)
   147  		}
   148  		dummy.SetInstanceAddresses(insts[i], s.addressesForIndex(i))
   149  		dummy.SetInstanceStatus(insts[i], "running")
   150  	}
   151  	for a := coretesting.LongAttempt.Start(); a.Next(); {
   152  		if !a.HasNext() {
   153  			c.Fatalf("timed out waiting for machine instance info")
   154  		}
   155  		if machinesSatisfy(c, machines, func(i int, m *apiinstancepoller.Machine) bool {
   156  			return checkInstanceInfo(i, m, "running")
   157  		}) {
   158  			break
   159  		}
   160  	}
   161  }
   162  
   163  // TODO(rog)
   164  // - check that the environment observer is actually hooked up.
   165  // - check that the environment observer is stopped.
   166  // - check that the errors propagate correctly.
   167  
   168  func machinesSatisfy(c *gc.C, machines []*apiinstancepoller.Machine, f func(i int, m *apiinstancepoller.Machine) bool) bool {
   169  	for i, m := range machines {
   170  		err := m.Refresh()
   171  		c.Assert(err, jc.ErrorIsNil)
   172  		if !f(i, m) {
   173  			return false
   174  		}
   175  	}
   176  	return true
   177  }
   178  
   179  func (s *workerSuite) setupScenario(c *gc.C) ([]*apiinstancepoller.Machine, []instance.Instance) {
   180  	var machines []*apiinstancepoller.Machine
   181  	var insts []instance.Instance
   182  	for i := 0; i < 10; i++ {
   183  		m, err := s.State.AddMachine("series", state.JobHostUnits)
   184  		c.Assert(err, jc.ErrorIsNil)
   185  		apiMachine, err := s.api.Machine(names.NewMachineTag(m.Id()))
   186  		c.Assert(err, jc.ErrorIsNil)
   187  		machines = append(machines, apiMachine)
   188  		inst, _ := testing.AssertStartInstance(c, s.Environ, s.ControllerConfig.ControllerUUID(), m.Id())
   189  		insts = append(insts, inst)
   190  	}
   191  	// Associate the odd-numbered machines with an instance.
   192  	for i := 1; i < len(machines); i += 2 {
   193  		apiMachine := machines[i]
   194  		m, err := s.State.Machine(apiMachine.Id())
   195  		c.Assert(err, jc.ErrorIsNil)
   196  		err = m.SetProvisioned(insts[i].Id(), "nonce", nil)
   197  		c.Assert(err, jc.ErrorIsNil)
   198  	}
   199  	// Associate the first half of the instances with an address and status.
   200  	for i := 0; i < len(machines)/2; i++ {
   201  		dummy.SetInstanceAddresses(insts[i], s.addressesForIndex(i))
   202  		dummy.SetInstanceStatus(insts[i], "running")
   203  	}
   204  	// Make sure the second half of the instances have no addresses.
   205  	for i := len(machines) / 2; i < len(machines); i++ {
   206  		dummy.SetInstanceAddresses(insts[i], nil)
   207  	}
   208  	return machines, insts
   209  }