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