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