github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/prechecker_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "fmt" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/agent" 14 "github.com/juju/juju/constraints" 15 "github.com/juju/juju/environs/config" 16 "github.com/juju/juju/instance" 17 "github.com/juju/juju/state" 18 ) 19 20 type PrecheckerSuite struct { 21 ConnSuite 22 prechecker mockPrechecker 23 } 24 25 var _ = gc.Suite(&PrecheckerSuite{}) 26 27 type mockPrechecker struct { 28 precheckInstanceError error 29 precheckInstanceSeries string 30 precheckInstanceConstraints constraints.Value 31 precheckInstancePlacement string 32 } 33 34 func (p *mockPrechecker) PrecheckInstance(series string, cons constraints.Value, placement string) error { 35 p.precheckInstanceSeries = series 36 p.precheckInstanceConstraints = cons 37 p.precheckInstancePlacement = placement 38 return p.precheckInstanceError 39 } 40 41 func (s *PrecheckerSuite) SetUpTest(c *gc.C) { 42 s.ConnSuite.SetUpTest(c) 43 s.prechecker = mockPrechecker{} 44 s.policy.GetPrechecker = func(*config.Config) (state.Prechecker, error) { 45 return &s.prechecker, nil 46 } 47 } 48 49 func (s *PrecheckerSuite) TestPrecheckInstance(c *gc.C) { 50 // PrecheckInstance should be called with the specified 51 // series and placement, and the specified constraints 52 // merged with the model constraints, when attempting 53 // to create an instance. 54 envCons := constraints.MustParse("mem=4G") 55 placement := "abc123" 56 template, err := s.addOneMachine(c, envCons, placement) 57 c.Assert(err, jc.ErrorIsNil) 58 c.Assert(s.prechecker.precheckInstanceSeries, gc.Equals, template.Series) 59 c.Assert(s.prechecker.precheckInstancePlacement, gc.Equals, placement) 60 validator := constraints.NewValidator() 61 cons, err := validator.Merge(envCons, template.Constraints) 62 c.Assert(err, jc.ErrorIsNil) 63 c.Assert(s.prechecker.precheckInstanceConstraints, gc.DeepEquals, cons) 64 } 65 66 func (s *PrecheckerSuite) TestPrecheckErrors(c *gc.C) { 67 // Ensure that AddOneMachine fails when PrecheckInstance returns an error. 68 s.prechecker.precheckInstanceError = fmt.Errorf("no instance for you") 69 _, err := s.addOneMachine(c, constraints.Value{}, "placement") 70 c.Assert(err, gc.ErrorMatches, ".*no instance for you") 71 72 // If the policy's Prechecker method fails, that will be returned first. 73 s.policy.GetPrechecker = func(*config.Config) (state.Prechecker, error) { 74 return nil, fmt.Errorf("no prechecker for you") 75 } 76 _, err = s.addOneMachine(c, constraints.Value{}, "placement") 77 c.Assert(err, gc.ErrorMatches, ".*no prechecker for you") 78 } 79 80 func (s *PrecheckerSuite) TestPrecheckPrecheckerUnimplemented(c *gc.C) { 81 var precheckerErr error 82 s.policy.GetPrechecker = func(*config.Config) (state.Prechecker, error) { 83 return nil, precheckerErr 84 } 85 _, err := s.addOneMachine(c, constraints.Value{}, "placement") 86 c.Assert(err, gc.ErrorMatches, "cannot add a new machine: policy returned nil prechecker without an error") 87 precheckerErr = errors.NotImplementedf("Prechecker") 88 _, err = s.addOneMachine(c, constraints.Value{}, "placement") 89 c.Assert(err, jc.ErrorIsNil) 90 } 91 92 func (s *PrecheckerSuite) TestPrecheckNoPolicy(c *gc.C) { 93 s.policy.GetPrechecker = func(*config.Config) (state.Prechecker, error) { 94 c.Errorf("should not have been invoked") 95 return nil, nil 96 } 97 state.SetPolicy(s.State, nil) 98 _, err := s.addOneMachine(c, constraints.Value{}, "placement") 99 c.Assert(err, jc.ErrorIsNil) 100 } 101 102 func (s *PrecheckerSuite) addOneMachine(c *gc.C, envCons constraints.Value, placement string) (state.MachineTemplate, error) { 103 err := s.State.SetModelConstraints(envCons) 104 c.Assert(err, jc.ErrorIsNil) 105 oneJob := []state.MachineJob{state.JobHostUnits} 106 extraCons := constraints.MustParse("cpu-cores=4") 107 template := state.MachineTemplate{ 108 Series: "precise", 109 Constraints: extraCons, 110 Jobs: oneJob, 111 Placement: placement, 112 } 113 _, err = s.State.AddOneMachine(template) 114 return template, err 115 } 116 117 func (s *PrecheckerSuite) TestPrecheckInstanceInjectMachine(c *gc.C) { 118 template := state.MachineTemplate{ 119 InstanceId: instance.Id("bootstrap"), 120 Series: "precise", 121 Nonce: agent.BootstrapNonce, 122 Jobs: []state.MachineJob{state.JobManageModel}, 123 Placement: "anyoldthing", 124 } 125 _, err := s.State.AddOneMachine(template) 126 c.Assert(err, jc.ErrorIsNil) 127 // PrecheckInstance should not have been called, as we've 128 // injected a machine with an existing instance. 129 c.Assert(s.prechecker.precheckInstanceSeries, gc.Equals, "") 130 c.Assert(s.prechecker.precheckInstancePlacement, gc.Equals, "") 131 } 132 133 func (s *PrecheckerSuite) TestPrecheckContainerNewMachine(c *gc.C) { 134 // Attempting to add a container to a new machine should cause 135 // PrecheckInstance to be called. 136 template := state.MachineTemplate{ 137 Series: "precise", 138 Jobs: []state.MachineJob{state.JobHostUnits}, 139 Placement: "intertubes", 140 } 141 _, err := s.State.AddMachineInsideNewMachine(template, template, instance.LXC) 142 c.Assert(err, jc.ErrorIsNil) 143 c.Assert(s.prechecker.precheckInstanceSeries, gc.Equals, template.Series) 144 c.Assert(s.prechecker.precheckInstancePlacement, gc.Equals, template.Placement) 145 }