github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/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  	gc "launchpad.net/gocheck"
    13  
    14  	"launchpad.net/juju-core/instance"
    15  	"launchpad.net/juju-core/juju/testing"
    16  	"launchpad.net/juju-core/provider/dummy"
    17  	"launchpad.net/juju-core/state"
    18  	coretesting "launchpad.net/juju-core/testing"
    19  	jc "launchpad.net/juju-core/testing/checkers"
    20  	"launchpad.net/juju-core/worker"
    21  )
    22  
    23  var _ = gc.Suite(&workerSuite{})
    24  
    25  type workerSuite struct {
    26  	testing.JujuConnSuite
    27  }
    28  
    29  func (*workerSuite) instId(i int) instance.Id {
    30  	return instance.Id(fmt.Sprint(i))
    31  }
    32  
    33  func (*workerSuite) addressesForIndex(i int) []instance.Address {
    34  	return []instance.Address{
    35  		instance.NewAddress(fmt.Sprintf("127.0.0.%d", i)),
    36  	}
    37  }
    38  
    39  func (s *workerSuite) TestWorker(c *gc.C) {
    40  	// Most functionality is already tested in detail - we
    41  	// just need to test that things are wired together
    42  	// correctly.
    43  	s.PatchValue(&ShortPoll, 10*time.Millisecond)
    44  	s.PatchValue(&LongPoll, 10*time.Millisecond)
    45  	machines, insts := s.setupScenario(c)
    46  	s.State.StartSync()
    47  	w := NewWorker(s.State)
    48  	defer func() {
    49  		c.Assert(worker.Stop(w), gc.IsNil)
    50  	}()
    51  
    52  	checkInstanceInfo := func(index int, m machine, expectedStatus string) bool {
    53  		isProvisioned := true
    54  		status, err := m.InstanceStatus()
    55  		if state.IsNotProvisionedError(err) {
    56  			isProvisioned = false
    57  		} else {
    58  			c.Assert(err, gc.IsNil)
    59  		}
    60  		return reflect.DeepEqual(m.Addresses(), s.addressesForIndex(index)) && (!isProvisioned || status == expectedStatus)
    61  	}
    62  
    63  	// Wait for the odd numbered machines in the
    64  	// first half of the machine slice to be given their
    65  	// addresses and status.
    66  	for a := coretesting.LongAttempt.Start(); a.Next(); {
    67  		if !a.HasNext() {
    68  			c.Fatalf("timed out waiting for instance info")
    69  		}
    70  
    71  		if machinesSatisfy(c, machines, func(i int, m *state.Machine) bool {
    72  			if i < len(machines)/2 && i%2 == 1 {
    73  				return checkInstanceInfo(i, m, "running")
    74  			}
    75  			status, err := m.InstanceStatus()
    76  			if i%2 == 0 {
    77  				// Even machines not provisioned yet.
    78  				c.Assert(err, jc.Satisfies, state.IsNotProvisionedError)
    79  			} else {
    80  				c.Assert(status, gc.Equals, "")
    81  			}
    82  			return len(m.Addresses()) == 0
    83  		}) {
    84  			break
    85  		}
    86  	}
    87  	// Now provision the even machines in the first half and watch them get addresses.
    88  	for i := 0; i < len(insts)/2; i += 2 {
    89  		m := machines[i]
    90  		err := m.SetProvisioned(insts[i].Id(), "nonce", nil)
    91  		c.Assert(err, gc.IsNil)
    92  		dummy.SetInstanceAddresses(insts[i], s.addressesForIndex(i))
    93  		dummy.SetInstanceStatus(insts[i], "running")
    94  	}
    95  	for a := coretesting.LongAttempt.Start(); a.Next(); {
    96  		if !a.HasNext() {
    97  			c.Fatalf("timed out waiting for machine instance info")
    98  		}
    99  		if machinesSatisfy(c, machines, func(i int, m *state.Machine) bool {
   100  			if i < len(machines)/2 {
   101  				return checkInstanceInfo(i, m, "running")
   102  			}
   103  			// Machines in second half still have no addresses, nor status.
   104  			status, err := m.InstanceStatus()
   105  			if i%2 == 0 {
   106  				// Even machines not provisioned yet.
   107  				c.Assert(err, jc.Satisfies, state.IsNotProvisionedError)
   108  			} else {
   109  				c.Assert(status, gc.Equals, "")
   110  			}
   111  			return len(m.Addresses()) == 0
   112  		}) {
   113  			break
   114  		}
   115  	}
   116  
   117  	// Provision the remaining machines and check the address and status.
   118  	for i := len(insts) / 2; i < len(insts); i++ {
   119  		if i%2 == 0 {
   120  			m := machines[i]
   121  			err := m.SetProvisioned(insts[i].Id(), "nonce", nil)
   122  			c.Assert(err, gc.IsNil)
   123  		}
   124  		dummy.SetInstanceAddresses(insts[i], s.addressesForIndex(i))
   125  		dummy.SetInstanceStatus(insts[i], "running")
   126  	}
   127  	for a := coretesting.LongAttempt.Start(); a.Next(); {
   128  		if !a.HasNext() {
   129  			c.Fatalf("timed out waiting for machine instance info")
   130  		}
   131  		if machinesSatisfy(c, machines, func(i int, m *state.Machine) bool {
   132  			return checkInstanceInfo(i, m, "running")
   133  		}) {
   134  			break
   135  		}
   136  	}
   137  }
   138  
   139  // TODO(rog)
   140  // - check that the environment observer is actually hooked up.
   141  // - check that the environment observer is stopped.
   142  // - check that the errors propagate correctly.
   143  
   144  func machinesSatisfy(c *gc.C, machines []*state.Machine, f func(i int, m *state.Machine) bool) bool {
   145  	for i, m := range machines {
   146  		err := m.Refresh()
   147  		c.Assert(err, gc.IsNil)
   148  		if !f(i, m) {
   149  			return false
   150  		}
   151  	}
   152  	return true
   153  }
   154  
   155  func (s *workerSuite) setupScenario(c *gc.C) ([]*state.Machine, []instance.Instance) {
   156  	var machines []*state.Machine
   157  	var insts []instance.Instance
   158  	for i := 0; i < 10; i++ {
   159  		m, err := s.State.AddMachine("series", state.JobHostUnits)
   160  		c.Assert(err, gc.IsNil)
   161  		machines = append(machines, m)
   162  		inst, _ := testing.AssertStartInstance(c, s.Conn.Environ, m.Id())
   163  		insts = append(insts, inst)
   164  	}
   165  	// Associate the odd-numbered machines with an instance.
   166  	for i := 1; i < len(machines); i += 2 {
   167  		m := machines[i]
   168  		err := m.SetProvisioned(insts[i].Id(), "nonce", nil)
   169  		c.Assert(err, gc.IsNil)
   170  	}
   171  	// Associate the first half of the instances with an address and status.
   172  	for i := 0; i < len(machines)/2; i++ {
   173  		dummy.SetInstanceAddresses(insts[i], s.addressesForIndex(i))
   174  		dummy.SetInstanceStatus(insts[i], "running")
   175  	}
   176  	return machines, insts
   177  }