github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/params/params_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package params_test 5 6 import ( 7 "encoding/json" 8 stdtesting "testing" 9 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 "gopkg.in/juju/charm.v6-unstable" 13 14 "github.com/juju/juju/apiserver/params" 15 "github.com/juju/juju/constraints" 16 "github.com/juju/juju/instance" 17 "github.com/juju/juju/network" 18 "github.com/juju/juju/state" 19 "github.com/juju/juju/state/multiwatcher" 20 "github.com/juju/juju/status" 21 "github.com/juju/juju/testing" 22 ) 23 24 // TestPackage integrates the tests into gotest. 25 func TestPackage(t *stdtesting.T) { 26 gc.TestingT(t) 27 } 28 29 type MarshalSuite struct{} 30 31 var _ = gc.Suite(&MarshalSuite{}) 32 33 var marshalTestCases = []struct { 34 about string 35 // Value holds a real Go struct. 36 value multiwatcher.Delta 37 // JSON document. 38 json string 39 }{{ 40 about: "MachineInfo Delta", 41 value: multiwatcher.Delta{ 42 Entity: &multiwatcher.MachineInfo{ 43 ModelUUID: "uuid", 44 Id: "Benji", 45 InstanceId: "Shazam", 46 JujuStatus: multiwatcher.StatusInfo{ 47 Current: status.StatusError, 48 Message: "foo", 49 }, 50 MachineStatus: multiwatcher.StatusInfo{ 51 Current: status.StatusPending, 52 }, 53 Life: multiwatcher.Life("alive"), 54 Series: "trusty", 55 SupportedContainers: []instance.ContainerType{instance.LXC}, 56 Jobs: []multiwatcher.MachineJob{state.JobManageModel.ToParams()}, 57 Addresses: []network.Address{}, 58 HardwareCharacteristics: &instance.HardwareCharacteristics{}, 59 }, 60 }, 61 json: `["machine","change",{"ModelUUID":"uuid","Id":"Benji","InstanceId":"Shazam","JujuStatus":{"Err":null,"Current":"error","Message":"foo","Since":null,"Version":"","Data":null},"MachineStatus":{"Err":null,"Current":"pending","Message":"","Since":null,"Version":"","Data":null},"Life":"alive","Series":"trusty","SupportedContainers":["lxc"],"SupportedContainersKnown":false,"HardwareCharacteristics":{},"Jobs":["JobManageModel"],"Addresses":[],"HasVote":false,"WantsVote":false}]`, 62 }, { 63 about: "ServiceInfo Delta", 64 value: multiwatcher.Delta{ 65 Entity: &multiwatcher.ServiceInfo{ 66 ModelUUID: "uuid", 67 Name: "Benji", 68 Exposed: true, 69 CharmURL: "cs:quantal/name", 70 Life: multiwatcher.Life("dying"), 71 OwnerTag: "test-owner", 72 MinUnits: 42, 73 Constraints: constraints.MustParse("arch=armhf mem=1024M"), 74 Config: charm.Settings{ 75 "hello": "goodbye", 76 "foo": false, 77 }, 78 Status: multiwatcher.StatusInfo{ 79 Current: status.StatusActive, 80 Message: "all good", 81 }, 82 }, 83 }, 84 json: `["service","change",{"ModelUUID": "uuid", "CharmURL": "cs:quantal/name","Name":"Benji","Exposed":true,"Life":"dying","OwnerTag":"test-owner","MinUnits":42,"Constraints":{"arch":"armhf", "mem": 1024},"Config": {"hello":"goodbye","foo":false},"Subordinate":false,"Status":{"Current":"active", "Message":"all good", "Version": "", "Err": null, "Data": null, "Since": null}}]`, 85 }, { 86 about: "UnitInfo Delta", 87 value: multiwatcher.Delta{ 88 Entity: &multiwatcher.UnitInfo{ 89 ModelUUID: "uuid", 90 Name: "Benji", 91 Service: "Shazam", 92 Series: "precise", 93 CharmURL: "cs:~user/precise/wordpress-42", 94 Ports: []network.Port{{ 95 Protocol: "http", 96 Number: 80, 97 }}, 98 PortRanges: []network.PortRange{{ 99 FromPort: 80, 100 ToPort: 80, 101 Protocol: "http", 102 }}, 103 PublicAddress: "testing.invalid", 104 PrivateAddress: "10.0.0.1", 105 MachineId: "1", 106 WorkloadStatus: multiwatcher.StatusInfo{ 107 Current: status.StatusActive, 108 Message: "all good", 109 }, 110 JujuStatus: multiwatcher.StatusInfo{ 111 Current: status.StatusIdle, 112 }, 113 }, 114 }, 115 json: `["unit","change",{"ModelUUID":"uuid","Name":"Benji","Service":"Shazam","Series":"precise","CharmURL":"cs:~user/precise/wordpress-42","PublicAddress":"testing.invalid","PrivateAddress":"10.0.0.1","MachineId":"1","Ports":[{"Protocol":"http","Number":80}],"PortRanges":[{"FromPort":80,"ToPort":80,"Protocol":"http"}],"Subordinate":false,"WorkloadStatus":{"Err":null,"Current":"active","Message":"all good","Since":null,"Version":"","Data":null},"JujuStatus":{"Err":null,"Current":"idle","Message":"","Since":null,"Version":"","Data":null}}]`, 116 }, { 117 about: "RelationInfo Delta", 118 value: multiwatcher.Delta{ 119 Entity: &multiwatcher.RelationInfo{ 120 ModelUUID: "uuid", 121 Key: "Benji", 122 Id: 4711, 123 Endpoints: []multiwatcher.Endpoint{ 124 {ServiceName: "logging", Relation: charm.Relation{Name: "logging-directory", Role: "requirer", Interface: "logging", Optional: false, Limit: 1, Scope: "container"}}, 125 {ServiceName: "wordpress", Relation: charm.Relation{Name: "logging-dir", Role: "provider", Interface: "logging", Optional: false, Limit: 0, Scope: "container"}}}, 126 }, 127 }, 128 json: `["relation","change",{"ModelUUID": "uuid", "Key":"Benji", "Id": 4711, "Endpoints": [{"ServiceName":"logging", "Relation":{"Name":"logging-directory", "Role":"requirer", "Interface":"logging", "Optional":false, "Limit":1, "Scope":"container"}}, {"ServiceName":"wordpress", "Relation":{"Name":"logging-dir", "Role":"provider", "Interface":"logging", "Optional":false, "Limit":0, "Scope":"container"}}]}]`, 129 }, { 130 about: "AnnotationInfo Delta", 131 value: multiwatcher.Delta{ 132 Entity: &multiwatcher.AnnotationInfo{ 133 ModelUUID: "uuid", 134 Tag: "machine-0", 135 Annotations: map[string]string{ 136 "foo": "bar", 137 "arble": "2 4", 138 }, 139 }, 140 }, 141 json: `["annotation","change",{"ModelUUID": "uuid", "Tag":"machine-0","Annotations":{"foo":"bar","arble":"2 4"}}]`, 142 }, { 143 about: "Delta Removed True", 144 value: multiwatcher.Delta{ 145 Removed: true, 146 Entity: &multiwatcher.RelationInfo{ 147 ModelUUID: "uuid", 148 Key: "Benji", 149 }, 150 }, 151 json: `["relation","remove",{"ModelUUID": "uuid", "Key":"Benji", "Id": 0, "Endpoints": null}]`, 152 }} 153 154 func (s *MarshalSuite) TestDeltaMarshalJSON(c *gc.C) { 155 for _, t := range marshalTestCases { 156 c.Log(t.about) 157 output, err := t.value.MarshalJSON() 158 c.Check(err, jc.ErrorIsNil) 159 // We check unmarshalled output both to reduce the fragility of the 160 // tests (because ordering in the maps can change) and to verify that 161 // the output is well-formed. 162 var unmarshalledOutput interface{} 163 err = json.Unmarshal(output, &unmarshalledOutput) 164 c.Check(err, jc.ErrorIsNil) 165 var expected interface{} 166 err = json.Unmarshal([]byte(t.json), &expected) 167 c.Check(err, jc.ErrorIsNil) 168 c.Check(unmarshalledOutput, jc.DeepEquals, expected) 169 } 170 } 171 172 func (s *MarshalSuite) TestDeltaUnmarshalJSON(c *gc.C) { 173 for i, t := range marshalTestCases { 174 c.Logf("test %d. %s", i, t.about) 175 var unmarshalled multiwatcher.Delta 176 err := json.Unmarshal([]byte(t.json), &unmarshalled) 177 c.Check(err, jc.ErrorIsNil) 178 c.Check(unmarshalled, gc.DeepEquals, t.value) 179 } 180 } 181 182 func (s *MarshalSuite) TestDeltaMarshalJSONCardinality(c *gc.C) { 183 err := json.Unmarshal([]byte(`[1,2]`), new(multiwatcher.Delta)) 184 c.Check(err, gc.ErrorMatches, "Expected 3 elements in top-level of JSON but got 2") 185 } 186 187 func (s *MarshalSuite) TestDeltaMarshalJSONUnknownOperation(c *gc.C) { 188 err := json.Unmarshal([]byte(`["relation","masticate",{}]`), new(multiwatcher.Delta)) 189 c.Check(err, gc.ErrorMatches, `Unexpected operation "masticate"`) 190 } 191 192 func (s *MarshalSuite) TestDeltaMarshalJSONUnknownEntity(c *gc.C) { 193 err := json.Unmarshal([]byte(`["qwan","change",{}]`), new(multiwatcher.Delta)) 194 c.Check(err, gc.ErrorMatches, `Unexpected entity name "qwan"`) 195 } 196 197 type ErrorResultsSuite struct{} 198 199 var _ = gc.Suite(&ErrorResultsSuite{}) 200 201 func (s *ErrorResultsSuite) TestOneError(c *gc.C) { 202 for i, test := range []struct { 203 results params.ErrorResults 204 errMatch string 205 }{ 206 { 207 errMatch: "expected 1 result, got 0", 208 }, { 209 results: params.ErrorResults{ 210 []params.ErrorResult{{nil}}, 211 }, 212 }, { 213 results: params.ErrorResults{ 214 []params.ErrorResult{{nil}, {nil}}, 215 }, 216 errMatch: "expected 1 result, got 2", 217 }, { 218 results: params.ErrorResults{ 219 []params.ErrorResult{ 220 {¶ms.Error{Message: "test error"}}, 221 }, 222 }, 223 errMatch: "test error", 224 }, 225 } { 226 c.Logf("test %d", i) 227 err := test.results.OneError() 228 if test.errMatch == "" { 229 c.Check(err, jc.ErrorIsNil) 230 } else { 231 c.Check(err, gc.ErrorMatches, test.errMatch) 232 } 233 } 234 } 235 236 func (s *ErrorResultsSuite) TestCombine(c *gc.C) { 237 for i, test := range []struct { 238 msg string 239 results params.ErrorResults 240 errMatch string 241 }{ 242 { 243 msg: "no results, no error", 244 }, { 245 msg: "single nil result", 246 results: params.ErrorResults{ 247 []params.ErrorResult{{nil}}, 248 }, 249 }, { 250 msg: "multiple nil results", 251 results: params.ErrorResults{ 252 []params.ErrorResult{{nil}, {nil}}, 253 }, 254 }, { 255 msg: "one error result", 256 results: params.ErrorResults{ 257 []params.ErrorResult{ 258 {¶ms.Error{Message: "test error"}}, 259 }, 260 }, 261 errMatch: "test error", 262 }, { 263 msg: "mixed error results", 264 results: params.ErrorResults{ 265 []params.ErrorResult{ 266 {¶ms.Error{Message: "test error"}}, 267 {nil}, 268 {¶ms.Error{Message: "second error"}}, 269 }, 270 }, 271 errMatch: "test error\nsecond error", 272 }, 273 } { 274 c.Logf("test %d: %s", i, test.msg) 275 err := test.results.Combine() 276 if test.errMatch == "" { 277 c.Check(err, jc.ErrorIsNil) 278 } else { 279 c.Check(err, gc.ErrorMatches, test.errMatch) 280 } 281 } 282 } 283 284 type importSuite struct{} 285 286 var _ = gc.Suite(&importSuite{}) 287 288 func (*importSuite) TestParamsDoesNotDependOnState(c *gc.C) { 289 imports := testing.FindJujuCoreImports(c, "github.com/juju/juju/apiserver/params") 290 for _, i := range imports { 291 c.Assert(i, gc.Not(gc.Equals), "state") 292 } 293 }