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