github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/instance" 19 "github.com/juju/juju/network" 20 "github.com/juju/juju/status" 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 var called int 146 results := params.LifeResults{ 147 Results: []params.LifeResult{{Life: params.Dying}}, 148 } 149 apiCaller := successAPICaller(c, "Life", entitiesArgs, results, &called) 150 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 151 c.Check(machine.Refresh(), jc.ErrorIsNil) 152 c.Check(machine.Life(), gc.Equals, params.Dying) 153 c.Check(called, gc.Equals, 1) 154 } 155 156 func (s *MachineSuite) TestStatusSuccess(c *gc.C) { 157 var called int 158 now := time.Now() 159 expectStatus := params.StatusResult{ 160 Status: "foo", 161 Info: "bar", 162 Data: map[string]interface{}{ 163 "int": 42, 164 "bool": true, 165 "float": 3.14, 166 "slice": []string{"a", "b"}, 167 "map": map[int]string{5: "five"}, 168 "string": "argh", 169 }, 170 Since: &now, 171 } 172 results := params.StatusResults{Results: []params.StatusResult{expectStatus}} 173 apiCaller := successAPICaller(c, "Status", entitiesArgs, results, &called) 174 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 175 status, err := machine.Status() 176 c.Check(err, jc.ErrorIsNil) 177 c.Check(status, jc.DeepEquals, expectStatus) 178 c.Check(called, gc.Equals, 1) 179 } 180 181 func (s *MachineSuite) TestIsManualSuccess(c *gc.C) { 182 var called int 183 results := params.BoolResults{ 184 Results: []params.BoolResult{{Result: true}}, 185 } 186 apiCaller := successAPICaller(c, "AreManuallyProvisioned", entitiesArgs, results, &called) 187 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 188 isManual, err := machine.IsManual() 189 c.Check(err, jc.ErrorIsNil) 190 c.Check(isManual, jc.IsTrue) 191 c.Check(called, gc.Equals, 1) 192 } 193 194 func (s *MachineSuite) TestInstanceIdSuccess(c *gc.C) { 195 var called int 196 results := params.StringResults{ 197 Results: []params.StringResult{{Result: "i-foo"}}, 198 } 199 apiCaller := successAPICaller(c, "InstanceId", entitiesArgs, results, &called) 200 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 201 instId, err := machine.InstanceId() 202 c.Check(err, jc.ErrorIsNil) 203 c.Check(instId, gc.Equals, instance.Id("i-foo")) 204 c.Check(called, gc.Equals, 1) 205 } 206 207 func (s *MachineSuite) TestInstanceStatusSuccess(c *gc.C) { 208 var called int 209 results := params.StatusResults{ 210 Results: []params.StatusResult{{ 211 Status: status.Provisioning.String(), 212 }}, 213 } 214 apiCaller := successAPICaller(c, "InstanceStatus", entitiesArgs, results, &called) 215 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 216 statusResult, err := machine.InstanceStatus() 217 c.Check(err, jc.ErrorIsNil) 218 c.Check(statusResult.Status, gc.DeepEquals, status.Provisioning.String()) 219 c.Check(called, gc.Equals, 1) 220 } 221 222 func (s *MachineSuite) TestSetInstanceStatusSuccess(c *gc.C) { 223 var called int 224 expectArgs := params.SetStatus{ 225 Entities: []params.EntityStatusArgs{{ 226 Tag: "machine-42", 227 Status: "RUNNING", 228 }}} 229 results := params.ErrorResults{ 230 Results: []params.ErrorResult{{Error: nil}}, 231 } 232 apiCaller := successAPICaller(c, "SetInstanceStatus", expectArgs, results, &called) 233 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 234 err := machine.SetInstanceStatus("RUNNING", "", nil) 235 c.Check(err, jc.ErrorIsNil) 236 c.Check(called, gc.Equals, 1) 237 } 238 239 func (s *MachineSuite) TestProviderAddressesSuccess(c *gc.C) { 240 var called int 241 addresses := network.NewAddresses("2001:db8::1", "0.1.2.3") 242 results := params.MachineAddressesResults{ 243 Results: []params.MachineAddressesResult{{ 244 Addresses: params.FromNetworkAddresses(addresses...), 245 }}} 246 apiCaller := successAPICaller(c, "ProviderAddresses", entitiesArgs, results, &called) 247 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 248 addrs, err := machine.ProviderAddresses() 249 c.Check(err, jc.ErrorIsNil) 250 c.Check(addrs, jc.DeepEquals, addresses) 251 c.Check(called, gc.Equals, 1) 252 } 253 254 func (s *MachineSuite) TestSetProviderAddressesSuccess(c *gc.C) { 255 var called int 256 addresses := network.NewAddresses("2001:db8::1", "0.1.2.3") 257 expectArgs := params.SetMachinesAddresses{ 258 MachineAddresses: []params.MachineAddresses{{ 259 Tag: "machine-42", 260 Addresses: params.FromNetworkAddresses(addresses...), 261 }}} 262 results := params.ErrorResults{ 263 Results: []params.ErrorResult{{Error: nil}}, 264 } 265 apiCaller := successAPICaller(c, "SetProviderAddresses", expectArgs, results, &called) 266 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 267 err := machine.SetProviderAddresses(addresses...) 268 c.Check(err, jc.ErrorIsNil) 269 c.Check(called, gc.Equals, 1) 270 } 271 272 func (s *MachineSuite) CheckClientError(c *gc.C, wf methodWrapper) { 273 var called int 274 apiCaller := clientErrorAPICaller(c, "", nil, &called) 275 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 276 c.Check(wf(machine), gc.ErrorMatches, "client error!") 277 c.Check(called, gc.Equals, 1) 278 } 279 280 func (s *MachineSuite) CheckServerError(c *gc.C, wf methodWrapper, expectErr string, serverResults interface{}) { 281 var called int 282 apiCaller := successAPICaller(c, "", nil, serverResults, &called) 283 machine := instancepoller.NewMachine(apiCaller, s.tag, params.Alive) 284 c.Check(wf(machine), gc.ErrorMatches, expectErr) 285 c.Check(called, gc.Equals, 1) 286 } 287 288 var entitiesArgs = params.Entities{ 289 Entities: []params.Entity{{Tag: "machine-42"}}, 290 } 291 292 // MakeResultsWithErrors constructs a new instance of the results type 293 // (from apiserver/params), matching the given resultsRef, finds its 294 // first field (expected to be a slice, usually "Results") and adds 295 // howMany elements to it, setting the Error field of each element to 296 // err. 297 // 298 // This helper makes a few assumptions: 299 // - resultsRef's type is a struct and has a single field (commonly - "Results") 300 // - that field is a slice of structs, which have an Error field 301 // - the Error field is of type *params.Error 302 // 303 // Example: 304 // err := apiservertesting.ServerError("foo") 305 // r := MakeResultsWithErrors(params.LifeResults{}, err, 2) 306 // is equvalent to: 307 // r := params.LifeResults{Results: []params.LifeResult{{Error: err}, {Error: err}}} 308 // 309 func MakeResultsWithErrors(resultsRef interface{}, err *params.Error, howMany int) interface{} { 310 // Make a new instance of the same type as resultsRef. 311 resultsType := reflect.TypeOf(resultsRef) 312 newResults := reflect.New(resultsType).Elem() 313 314 // Make a new empty slice for the results. 315 sliceField := newResults.Field(0) 316 newSlice := reflect.New(sliceField.Type()).Elem() 317 318 // Make a new result of the slice's element type and set it to err. 319 newResult := reflect.New(newSlice.Type().Elem()).Elem() 320 newResult.FieldByName("Error").Set(reflect.ValueOf(err)) 321 322 // Append howMany copies of newResult to the slice. 323 for howMany > 0 { 324 sliceField.Set(reflect.Append(sliceField, newResult)) 325 howMany-- 326 } 327 328 return newResults.Interface() 329 } 330 331 // TODO(dimitern): Move this and MakeResultsWithErrors in params/testing ? 332 func (MachineSuite) TestMakeResultsWithErrors(c *gc.C) { 333 err := apiservertesting.ServerError("foo") 334 r1 := MakeResultsWithErrors(params.LifeResults{}, err, 2) 335 r2 := params.LifeResults{Results: []params.LifeResult{{Error: err}, {Error: err}}} 336 c.Assert(r1, jc.DeepEquals, r2) 337 }