github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/machiner/machiner_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package machiner_test
     5  
     6  import (
     7  	"io/ioutil"
     8  	"net"
     9  	"path/filepath"
    10  	stdtesting "testing"
    11  	"time"
    12  
    13  	"github.com/juju/names"
    14  	gitjujutesting "github.com/juju/testing"
    15  	jc "github.com/juju/testing/checkers"
    16  	gc "gopkg.in/check.v1"
    17  
    18  	"github.com/juju/juju/agent"
    19  	"github.com/juju/juju/api"
    20  	apimachiner "github.com/juju/juju/api/machiner"
    21  	"github.com/juju/juju/apiserver/params"
    22  	"github.com/juju/juju/juju/testing"
    23  	"github.com/juju/juju/network"
    24  	"github.com/juju/juju/state"
    25  	coretesting "github.com/juju/juju/testing"
    26  	"github.com/juju/juju/worker"
    27  	"github.com/juju/juju/worker/machiner"
    28  )
    29  
    30  type MachinerSuite struct {
    31  	coretesting.BaseSuite
    32  	accessor    *mockMachineAccessor
    33  	agentConfig agent.Config
    34  	addresses   []net.Addr
    35  }
    36  
    37  var _ = gc.Suite(&MachinerSuite{})
    38  
    39  func (s *MachinerSuite) SetUpTest(c *gc.C) {
    40  	s.BaseSuite.SetUpTest(c)
    41  	s.accessor = &mockMachineAccessor{}
    42  	s.accessor.machine.watcher.changes = make(chan struct{})
    43  	s.accessor.machine.life = params.Alive
    44  	s.agentConfig = agentConfig(names.NewMachineTag("123"))
    45  	s.addresses = []net.Addr{ // anything will do
    46  		&net.IPAddr{IP: net.IPv4bcast},
    47  		&net.IPAddr{IP: net.IPv4zero},
    48  	}
    49  	s.PatchValue(machiner.InterfaceAddrs, func() ([]net.Addr, error) {
    50  		return s.addresses, nil
    51  	})
    52  }
    53  
    54  func (s *MachinerSuite) TestMachinerStorageAttached(c *gc.C) {
    55  	// Machine is dying. We'll respond to "EnsureDead" by
    56  	// saying that there are still storage attachments;
    57  	// this should not cause an error.
    58  	s.accessor.machine.life = params.Dying
    59  	s.accessor.machine.SetErrors(
    60  		nil, // SetMachineAddresses
    61  		nil, // SetStatus
    62  		nil, // Watch
    63  		nil, // Refresh
    64  		nil, // SetStatus
    65  		&params.Error{Code: params.CodeMachineHasAttachedStorage},
    66  	)
    67  
    68  	worker := machiner.NewMachiner(s.accessor, s.agentConfig)
    69  	s.accessor.machine.watcher.changes <- struct{}{}
    70  	worker.Kill()
    71  	c.Check(worker.Wait(), jc.ErrorIsNil)
    72  
    73  	s.accessor.CheckCalls(c, []gitjujutesting.StubCall{{
    74  		FuncName: "Machine",
    75  		Args:     []interface{}{s.agentConfig.Tag()},
    76  	}})
    77  
    78  	s.accessor.machine.watcher.CheckCalls(c, []gitjujutesting.StubCall{
    79  		{FuncName: "Changes"}, {FuncName: "Changes"}, {FuncName: "Stop"},
    80  	})
    81  
    82  	s.accessor.machine.CheckCalls(c, []gitjujutesting.StubCall{{
    83  		FuncName: "SetMachineAddresses",
    84  		Args: []interface{}{
    85  			network.NewAddresses(
    86  				"255.255.255.255",
    87  				"0.0.0.0",
    88  			),
    89  		},
    90  	}, {
    91  		FuncName: "SetStatus",
    92  		Args: []interface{}{
    93  			params.StatusStarted,
    94  			"",
    95  			map[string]interface{}(nil),
    96  		},
    97  	}, {
    98  		FuncName: "Watch",
    99  	}, {
   100  		FuncName: "Refresh",
   101  	}, {
   102  		FuncName: "Life",
   103  	}, {
   104  		FuncName: "SetStatus",
   105  		Args: []interface{}{
   106  			params.StatusStopped,
   107  			"",
   108  			map[string]interface{}(nil),
   109  		},
   110  	}, {
   111  		FuncName: "EnsureDead",
   112  	}})
   113  }
   114  
   115  // worstCase is used for timeouts when timing out
   116  // will fail the test. Raising this value should
   117  // not affect the overall running time of the tests
   118  // unless they fail.
   119  const worstCase = 5 * time.Second
   120  
   121  func TestPackage(t *stdtesting.T) {
   122  	coretesting.MgoTestPackage(t)
   123  }
   124  
   125  type MachinerStateSuite struct {
   126  	testing.JujuConnSuite
   127  
   128  	st            *api.State
   129  	machinerState *apimachiner.State
   130  	machine       *state.Machine
   131  	apiMachine    *apimachiner.Machine
   132  }
   133  
   134  var _ = gc.Suite(&MachinerStateSuite{})
   135  
   136  func (s *MachinerStateSuite) SetUpTest(c *gc.C) {
   137  	s.JujuConnSuite.SetUpTest(c)
   138  	s.st, s.machine = s.OpenAPIAsNewMachine(c)
   139  
   140  	// Create the machiner API facade.
   141  	s.machinerState = s.st.Machiner()
   142  	c.Assert(s.machinerState, gc.NotNil)
   143  
   144  	// Get the machine through the facade.
   145  	var err error
   146  	s.apiMachine, err = s.machinerState.Machine(s.machine.Tag().(names.MachineTag))
   147  	c.Assert(err, jc.ErrorIsNil)
   148  	c.Assert(s.apiMachine.Tag(), gc.Equals, s.machine.Tag())
   149  	// Isolate tests better by not using real interface addresses.
   150  	s.PatchValue(machiner.InterfaceAddrs, func() ([]net.Addr, error) {
   151  		return nil, nil
   152  	})
   153  	s.PatchValue(&network.InterfaceByNameAddrs, func(string) ([]net.Addr, error) {
   154  		return nil, nil
   155  	})
   156  	s.PatchValue(&network.LXCNetDefaultConfig, "")
   157  
   158  }
   159  
   160  func (s *MachinerStateSuite) waitMachineStatus(c *gc.C, m *state.Machine, expectStatus state.Status) {
   161  	timeout := time.After(worstCase)
   162  	for {
   163  		select {
   164  		case <-timeout:
   165  			c.Fatalf("timeout while waiting for machine status to change")
   166  		case <-time.After(10 * time.Millisecond):
   167  			statusInfo, err := m.Status()
   168  			c.Assert(err, jc.ErrorIsNil)
   169  			if statusInfo.Status != expectStatus {
   170  				c.Logf("machine %q status is %s, still waiting", m, statusInfo.Status)
   171  				continue
   172  			}
   173  			return
   174  		}
   175  	}
   176  }
   177  
   178  var _ worker.NotifyWatchHandler = (*machiner.Machiner)(nil)
   179  
   180  type mockConfig struct {
   181  	agent.Config
   182  	tag names.Tag
   183  }
   184  
   185  func (mock *mockConfig) Tag() names.Tag {
   186  	return mock.tag
   187  }
   188  
   189  func agentConfig(tag names.Tag) agent.Config {
   190  	return &mockConfig{tag: tag}
   191  }
   192  
   193  func (s *MachinerStateSuite) TestNotFoundOrUnauthorized(c *gc.C) {
   194  	mr := machiner.NewMachiner(
   195  		machiner.APIMachineAccessor{s.machinerState},
   196  		agentConfig(names.NewMachineTag("99")),
   197  	)
   198  	c.Assert(mr.Wait(), gc.Equals, worker.ErrTerminateAgent)
   199  }
   200  
   201  func (s *MachinerStateSuite) makeMachiner() worker.Worker {
   202  	return machiner.NewMachiner(
   203  		machiner.APIMachineAccessor{s.machinerState},
   204  		agentConfig(s.apiMachine.Tag()),
   205  	)
   206  }
   207  
   208  func (s *MachinerStateSuite) TestRunStop(c *gc.C) {
   209  	mr := s.makeMachiner()
   210  	c.Assert(worker.Stop(mr), gc.IsNil)
   211  	c.Assert(s.apiMachine.Refresh(), gc.IsNil)
   212  	c.Assert(s.apiMachine.Life(), gc.Equals, params.Alive)
   213  }
   214  
   215  func (s *MachinerStateSuite) TestStartSetsStatus(c *gc.C) {
   216  	statusInfo, err := s.machine.Status()
   217  	c.Assert(err, jc.ErrorIsNil)
   218  	c.Assert(statusInfo.Status, gc.Equals, state.StatusPending)
   219  	c.Assert(statusInfo.Message, gc.Equals, "")
   220  
   221  	mr := s.makeMachiner()
   222  	defer worker.Stop(mr)
   223  
   224  	s.waitMachineStatus(c, s.machine, state.StatusStarted)
   225  }
   226  
   227  func (s *MachinerStateSuite) TestSetsStatusWhenDying(c *gc.C) {
   228  	mr := s.makeMachiner()
   229  	defer worker.Stop(mr)
   230  	c.Assert(s.machine.Destroy(), gc.IsNil)
   231  	s.waitMachineStatus(c, s.machine, state.StatusStopped)
   232  }
   233  
   234  func (s *MachinerStateSuite) TestSetDead(c *gc.C) {
   235  	mr := s.makeMachiner()
   236  	defer worker.Stop(mr)
   237  	c.Assert(s.machine.Destroy(), gc.IsNil)
   238  	s.State.StartSync()
   239  	c.Assert(mr.Wait(), gc.Equals, worker.ErrTerminateAgent)
   240  	c.Assert(s.machine.Refresh(), gc.IsNil)
   241  	c.Assert(s.machine.Life(), gc.Equals, state.Dead)
   242  }
   243  
   244  func (s *MachinerStateSuite) TestSetDeadWithDyingUnit(c *gc.C) {
   245  	mr := s.makeMachiner()
   246  	defer worker.Stop(mr)
   247  
   248  	// Add a service, assign to machine.
   249  	wordpress := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress"))
   250  	unit, err := wordpress.AddUnit()
   251  	c.Assert(err, jc.ErrorIsNil)
   252  	err = unit.AssignToMachine(s.machine)
   253  	c.Assert(err, jc.ErrorIsNil)
   254  
   255  	// Service alive, can't destroy machine.
   256  	err = s.machine.Destroy()
   257  	c.Assert(err, jc.Satisfies, state.IsHasAssignedUnitsError)
   258  
   259  	err = wordpress.Destroy()
   260  	c.Assert(err, jc.ErrorIsNil)
   261  
   262  	// With dying unit, machine can now be marked as dying.
   263  	c.Assert(s.machine.Destroy(), gc.IsNil)
   264  	s.State.StartSync()
   265  	c.Assert(s.machine.Refresh(), gc.IsNil)
   266  	c.Assert(s.machine.Life(), gc.Equals, state.Dying)
   267  
   268  	// When the unit is ultimately destroyed, the machine becomes dead.
   269  	err = unit.Destroy()
   270  	c.Assert(err, jc.ErrorIsNil)
   271  	s.State.StartSync()
   272  	c.Assert(mr.Wait(), gc.Equals, worker.ErrTerminateAgent)
   273  
   274  }
   275  
   276  func (s *MachinerStateSuite) TestMachineAddresses(c *gc.C) {
   277  	lxcFakeNetConfig := filepath.Join(c.MkDir(), "lxc-net")
   278  	netConf := []byte(`
   279    # comments ignored
   280  LXC_BR= ignored
   281  LXC_ADDR = "fooo"
   282  LXC_BRIDGE="foobar" # detected
   283  anything else ignored
   284  LXC_BRIDGE="ignored"`[1:])
   285  	err := ioutil.WriteFile(lxcFakeNetConfig, netConf, 0644)
   286  	c.Assert(err, jc.ErrorIsNil)
   287  	s.PatchValue(machiner.InterfaceAddrs, func() ([]net.Addr, error) {
   288  		addrs := []net.Addr{
   289  			&net.IPAddr{IP: net.IPv4(10, 0, 0, 1)},
   290  			&net.IPAddr{IP: net.IPv4(127, 0, 0, 1)},
   291  			&net.IPAddr{IP: net.IPv4(10, 0, 3, 1)}, // lxc bridge address ignored
   292  			&net.IPAddr{IP: net.IPv6loopback},
   293  			&net.UnixAddr{},                        // not IP, ignored
   294  			&net.IPAddr{IP: net.IPv4(10, 0, 3, 4)}, // lxc bridge address ignored
   295  			&net.IPNet{IP: net.ParseIP("2001:db8::1")},
   296  			&net.IPAddr{IP: net.IPv4(169, 254, 1, 20)}, // LinkLocal Ignored
   297  			&net.IPNet{IP: net.ParseIP("fe80::1")},     // LinkLocal Ignored
   298  		}
   299  		return addrs, nil
   300  	})
   301  	s.PatchValue(&network.InterfaceByNameAddrs, func(name string) ([]net.Addr, error) {
   302  		c.Assert(name, gc.Equals, "foobar")
   303  		return []net.Addr{
   304  			&net.IPAddr{IP: net.IPv4(10, 0, 3, 1)},
   305  			&net.IPAddr{IP: net.IPv4(10, 0, 3, 4)},
   306  		}, nil
   307  	})
   308  	s.PatchValue(&network.LXCNetDefaultConfig, lxcFakeNetConfig)
   309  
   310  	mr := s.makeMachiner()
   311  	defer worker.Stop(mr)
   312  	c.Assert(s.machine.Destroy(), gc.IsNil)
   313  	s.State.StartSync()
   314  	c.Assert(mr.Wait(), gc.Equals, worker.ErrTerminateAgent)
   315  	c.Assert(s.machine.Refresh(), gc.IsNil)
   316  	c.Assert(s.machine.MachineAddresses(), jc.DeepEquals, []network.Address{
   317  		network.NewAddress("2001:db8::1"),
   318  		network.NewScopedAddress("10.0.0.1", network.ScopeCloudLocal),
   319  		network.NewScopedAddress("::1", network.ScopeMachineLocal),
   320  		network.NewScopedAddress("127.0.0.1", network.ScopeMachineLocal),
   321  	})
   322  }