github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/instancepoller/machine_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package instancepoller_test 5 6 import ( 7 "reflect" 8 "time" 9 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 "gopkg.in/juju/names.v2" 13 14 apitesting "github.com/juju/juju/api/base/testing" 15 "github.com/juju/juju/api/instancepoller" 16 "github.com/juju/juju/apiserver/params" 17 apiservertesting "github.com/juju/juju/apiserver/testing" 18 "github.com/juju/juju/core/instance" 19 "github.com/juju/juju/core/status" 20 "github.com/juju/juju/network" 21 coretesting "github.com/juju/juju/testing" 22 ) 23 24 type MachineSuite struct { 25 coretesting.BaseSuite 26 27 tag names.MachineTag 28 } 29 30 var _ = gc.Suite(&MachineSuite{}) 31 32 func (s *MachineSuite) SetUpTest(c *gc.C) { 33 s.BaseSuite.SetUpTest(c) 34 s.tag = names.NewMachineTag("42") 35 } 36 37 func (s *MachineSuite) TestNonFacadeMethods(c *gc.C) { 38 nopCaller := apitesting.APICallerFunc( 39 func(_ string, _ int, _, _ string, _, _ interface{}) error { 40 c.Fatalf("facade call was not expected") 41 return nil 42 }, 43 ) 44 machine := instancepoller.NewMachine(nopCaller, s.tag, params.Dying) 45 46 c.Assert(machine.Id(), gc.Equals, "42") 47 c.Assert(machine.Tag(), jc.DeepEquals, s.tag) 48 c.Assert(machine.String(), gc.Equals, "42") 49 c.Assert(machine.Life(), gc.Equals, params.Dying) 50 } 51 52 // methodWrapper wraps a Machine method call and returns the error, 53 // ignoring the result (if any). 54 type methodWrapper func(*instancepoller.Machine) error 55 56 // machineErrorTests contains all the necessary information to test 57 // how each Machine method handles client- and server-side API errors, 58 // as well as the case when the server-side API returns more results 59 // than expected. 60 var machineErrorTests = []struct { 61 method string // only for logging 62 wrapper methodWrapper 63 resultsRef interface{} // an instance of the server-side method's result type 64 }{{ 65 method: "Refresh", 66 wrapper: (*instancepoller.Machine).Refresh, 67 resultsRef: params.LifeResults{}, 68 }, { 69 method: "IsManual", 70 wrapper: func(m *instancepoller.Machine) error { 71 _, err := m.IsManual() 72 return err 73 }, 74 resultsRef: params.BoolResults{}, 75 }, { 76 method: "InstanceId", 77 wrapper: func(m *instancepoller.Machine) error { 78 _, err := m.InstanceId() 79 return err 80 }, 81 resultsRef: params.StringResults{}, 82 }, { 83 method: "Status", 84 wrapper: func(m *instancepoller.Machine) error { 85 _, err := m.Status() 86 return err 87 }, 88 resultsRef: params.StatusResults{}, 89 }, { 90 method: "InstanceStatus", 91 wrapper: func(m *instancepoller.Machine) error { 92 _, err := m.InstanceStatus() 93 return err 94 }, 95 resultsRef: params.StatusResults{}, 96 }, { 97 method: "SetInstanceStatus", 98 wrapper: func(m *instancepoller.Machine) error { 99 return m.SetInstanceStatus("", "", nil) 100 }, 101 resultsRef: params.ErrorResults{}, 102 }, { 103 method: "ProviderAddresses", 104 wrapper: func(m *instancepoller.Machine) error { 105 _, err := m.ProviderAddresses() 106 return err 107 }, 108 resultsRef: params.MachineAddressesResults{}, 109 }, { 110 method: "SetProviderAddresses", 111 wrapper: func(m *instancepoller.Machine) error { 112 return m.SetProviderAddresses() 113 }, 114 resultsRef: params.ErrorResults{}, 115 }} 116 117 func (s *MachineSuite) TestClientError(c *gc.C) { 118 for i, test := range machineErrorTests { 119 c.Logf("test #%d: %s", i, test.method) 120 s.CheckClientError(c, test.wrapper) 121 } 122 } 123 124 func (s *MachineSuite) TestServerError(c *gc.C) { 125 err := apiservertesting.ServerError("server error!") 126 expected := err.Error() 127 for i, test := range machineErrorTests { 128 c.Logf("test #%d: %s", i, test.method) 129 results := MakeResultsWithErrors(test.resultsRef, err, 1) 130 s.CheckServerError(c, test.wrapper, expected, results) 131 } 132 } 133 134 func (s *MachineSuite) TestTooManyResultsServerError(c *gc.C) { 135 err := apiservertesting.ServerError("some error") 136 expected := "expected 1 result, got 2" 137 for i, test := range machineErrorTests { 138 c.Logf("test #%d: %s", i, test.method) 139 results := MakeResultsWithErrors(test.resultsRef, err, 2) 140 s.CheckServerError(c, test.wrapper, expected, results) 141 } 142 } 143 144 func (s *MachineSuite) TestRefreshSuccess(c *gc.C) { 145 results := params.LifeResults{ 146 Results: []params.LifeResult{{Life: params.Dying}}, 147 } 148 apiCaller := successAPICaller(c, "Life", entitiesArgs, results) 149 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 150 c.Check(machine.Refresh(), jc.ErrorIsNil) 151 c.Check(machine.Life(), gc.Equals, params.Dying) 152 c.Check(apiCaller.CallCount, gc.Equals, 1) 153 } 154 155 func (s *MachineSuite) TestStatusSuccess(c *gc.C) { 156 now := time.Now() 157 expectStatus := params.StatusResult{ 158 Status: "foo", 159 Info: "bar", 160 Data: map[string]interface{}{ 161 "int": 42, 162 "bool": true, 163 "float": 3.14, 164 "slice": []string{"a", "b"}, 165 "map": map[int]string{5: "five"}, 166 "string": "argh", 167 }, 168 Since: &now, 169 } 170 results := params.StatusResults{Results: []params.StatusResult{expectStatus}} 171 apiCaller := successAPICaller(c, "Status", entitiesArgs, results) 172 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 173 status, err := machine.Status() 174 c.Check(err, jc.ErrorIsNil) 175 c.Check(status, jc.DeepEquals, expectStatus) 176 c.Check(apiCaller.CallCount, gc.Equals, 1) 177 } 178 179 func (s *MachineSuite) TestIsManualSuccess(c *gc.C) { 180 results := params.BoolResults{ 181 Results: []params.BoolResult{{Result: true}}, 182 } 183 apiCaller := successAPICaller(c, "AreManuallyProvisioned", entitiesArgs, results) 184 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 185 isManual, err := machine.IsManual() 186 c.Check(err, jc.ErrorIsNil) 187 c.Check(isManual, jc.IsTrue) 188 c.Check(apiCaller.CallCount, gc.Equals, 1) 189 } 190 191 func (s *MachineSuite) TestInstanceIdSuccess(c *gc.C) { 192 results := params.StringResults{ 193 Results: []params.StringResult{{Result: "i-foo"}}, 194 } 195 apiCaller := successAPICaller(c, "InstanceId", entitiesArgs, results) 196 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 197 instId, err := machine.InstanceId() 198 c.Check(err, jc.ErrorIsNil) 199 c.Check(instId, gc.Equals, instance.Id("i-foo")) 200 c.Check(apiCaller.CallCount, gc.Equals, 1) 201 } 202 203 func (s *MachineSuite) TestInstanceStatusSuccess(c *gc.C) { 204 results := params.StatusResults{ 205 Results: []params.StatusResult{{ 206 Status: status.Provisioning.String(), 207 }}, 208 } 209 apiCaller := successAPICaller(c, "InstanceStatus", entitiesArgs, results) 210 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 211 statusResult, err := machine.InstanceStatus() 212 c.Check(err, jc.ErrorIsNil) 213 c.Check(statusResult.Status, gc.DeepEquals, status.Provisioning.String()) 214 c.Check(apiCaller.CallCount, gc.Equals, 1) 215 } 216 217 func (s *MachineSuite) TestSetInstanceStatusSuccess(c *gc.C) { 218 expectArgs := params.SetStatus{ 219 Entities: []params.EntityStatusArgs{{ 220 Tag: "machine-42", 221 Status: "RUNNING", 222 }}} 223 results := params.ErrorResults{ 224 Results: []params.ErrorResult{{Error: nil}}, 225 } 226 apiCaller := successAPICaller(c, "SetInstanceStatus", expectArgs, results) 227 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 228 err := machine.SetInstanceStatus("RUNNING", "", nil) 229 c.Check(err, jc.ErrorIsNil) 230 c.Check(apiCaller.CallCount, gc.Equals, 1) 231 } 232 233 func (s *MachineSuite) TestProviderAddressesSuccess(c *gc.C) { 234 addresses := network.NewAddresses("2001:db8::1", "0.1.2.3") 235 results := params.MachineAddressesResults{ 236 Results: []params.MachineAddressesResult{{ 237 Addresses: params.FromNetworkAddresses(addresses...), 238 }}} 239 apiCaller := successAPICaller(c, "ProviderAddresses", entitiesArgs, results) 240 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 241 addrs, err := machine.ProviderAddresses() 242 c.Check(err, jc.ErrorIsNil) 243 c.Check(addrs, jc.DeepEquals, addresses) 244 c.Check(apiCaller.CallCount, gc.Equals, 1) 245 } 246 247 func (s *MachineSuite) TestSetProviderAddressesSuccess(c *gc.C) { 248 addresses := network.NewAddresses("2001:db8::1", "0.1.2.3") 249 expectArgs := params.SetMachinesAddresses{ 250 MachineAddresses: []params.MachineAddresses{{ 251 Tag: "machine-42", 252 Addresses: params.FromNetworkAddresses(addresses...), 253 }}} 254 results := params.ErrorResults{ 255 Results: []params.ErrorResult{{Error: nil}}, 256 } 257 apiCaller := successAPICaller(c, "SetProviderAddresses", expectArgs, results) 258 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 259 err := machine.SetProviderAddresses(addresses...) 260 c.Check(err, jc.ErrorIsNil) 261 c.Check(apiCaller.CallCount, gc.Equals, 1) 262 } 263 264 func (s *MachineSuite) CheckClientError(c *gc.C, wf methodWrapper) { 265 apiCaller := clientErrorAPICaller(c, "", nil) 266 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 267 c.Check(wf(machine), gc.ErrorMatches, "client error!") 268 c.Check(apiCaller.CallCount, gc.Equals, 1) 269 } 270 271 func (s *MachineSuite) CheckServerError(c *gc.C, wf methodWrapper, expectErr string, serverResults interface{}) { 272 apiCaller := successAPICaller(c, "", nil, serverResults) 273 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 274 c.Check(wf(machine), gc.ErrorMatches, expectErr) 275 c.Check(apiCaller.CallCount, gc.Equals, 1) 276 } 277 278 var entitiesArgs = params.Entities{ 279 Entities: []params.Entity{{Tag: "machine-42"}}, 280 } 281 282 // MakeResultsWithErrors constructs a new instance of the results type 283 // (from apiserver/params), matching the given resultsRef, finds its 284 // first field (expected to be a slice, usually "Results") and adds 285 // howMany elements to it, setting the Error field of each element to 286 // err. 287 // 288 // This helper makes a few assumptions: 289 // - resultsRef's type is a struct and has a single field (commonly - "Results") 290 // - that field is a slice of structs, which have an Error field 291 // - the Error field is of type *params.Error 292 // 293 // Example: 294 // err := apiservertesting.ServerError("foo") 295 // r := MakeResultsWithErrors(params.LifeResults{}, err, 2) 296 // is equvalent to: 297 // r := params.LifeResults{Results: []params.LifeResult{{Error: err}, {Error: err}}} 298 // 299 func MakeResultsWithErrors(resultsRef interface{}, err *params.Error, howMany int) interface{} { 300 // Make a new instance of the same type as resultsRef. 301 resultsType := reflect.TypeOf(resultsRef) 302 newResults := reflect.New(resultsType).Elem() 303 304 // Make a new empty slice for the results. 305 sliceField := newResults.Field(0) 306 newSlice := reflect.New(sliceField.Type()).Elem() 307 308 // Make a new result of the slice's element type and set it to err. 309 newResult := reflect.New(newSlice.Type().Elem()).Elem() 310 newResult.FieldByName("Error").Set(reflect.ValueOf(err)) 311 312 // Append howMany copies of newResult to the slice. 313 for howMany > 0 { 314 sliceField.Set(reflect.Append(sliceField, newResult)) 315 howMany-- 316 } 317 318 return newResults.Interface() 319 } 320 321 // TODO(dimitern): Move this and MakeResultsWithErrors in params/testing ? 322 func (MachineSuite) TestMakeResultsWithErrors(c *gc.C) { 323 err := apiservertesting.ServerError("foo") 324 r1 := MakeResultsWithErrors(params.LifeResults{}, err, 2) 325 r2 := params.LifeResults{Results: []params.LifeResult{{Error: err}, {Error: err}}} 326 c.Assert(r1, jc.DeepEquals, r2) 327 }