github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/core/description/model_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package description 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/errors" 11 "github.com/juju/names" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/version" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/yaml.v2" 16 17 "github.com/juju/juju/testing" 18 ) 19 20 type ModelSerializationSuite struct { 21 testing.BaseSuite 22 } 23 24 var _ = gc.Suite(&ModelSerializationSuite{}) 25 26 func (*ModelSerializationSuite) TestNil(c *gc.C) { 27 _, err := importModel(nil) 28 c.Check(err, gc.ErrorMatches, "version: expected int, got nothing") 29 } 30 31 func (*ModelSerializationSuite) TestMissingVersion(c *gc.C) { 32 _, err := importModel(map[string]interface{}{}) 33 c.Check(err, gc.ErrorMatches, "version: expected int, got nothing") 34 } 35 36 func (*ModelSerializationSuite) TestNonIntVersion(c *gc.C) { 37 _, err := importModel(map[string]interface{}{ 38 "version": "hello", 39 }) 40 c.Check(err.Error(), gc.Equals, `version: expected int, got string("hello")`) 41 } 42 43 func (*ModelSerializationSuite) TestUnknownVersion(c *gc.C) { 44 _, err := importModel(map[string]interface{}{ 45 "version": 42, 46 }) 47 c.Check(err.Error(), gc.Equals, `version 42 not valid`) 48 } 49 50 func (*ModelSerializationSuite) TestUpdateConfig(c *gc.C) { 51 model := NewModel(ModelArgs{Config: map[string]interface{}{ 52 "name": "awesome", 53 "uuid": "some-uuid", 54 }}) 55 model.UpdateConfig(map[string]interface{}{ 56 "name": "something else", 57 "key": "value", 58 }) 59 c.Assert(model.Config(), jc.DeepEquals, map[string]interface{}{ 60 "name": "something else", 61 "uuid": "some-uuid", 62 "key": "value", 63 }) 64 } 65 66 func (s *ModelSerializationSuite) exportImport(c *gc.C, initial Model) Model { 67 bytes, err := Serialize(initial) 68 c.Assert(err, jc.ErrorIsNil) 69 model, err := Deserialize(bytes) 70 c.Assert(err, jc.ErrorIsNil) 71 return model 72 } 73 74 func (s *ModelSerializationSuite) TestParsingYAML(c *gc.C) { 75 args := ModelArgs{ 76 Owner: names.NewUserTag("magic"), 77 Config: map[string]interface{}{ 78 "name": "awesome", 79 "uuid": "some-uuid", 80 }, 81 LatestToolsVersion: version.MustParse("2.0.1"), 82 Blocks: map[string]string{ 83 "all-changes": "locked down", 84 }, 85 } 86 initial := NewModel(args) 87 adminUser := names.NewUserTag("admin@local") 88 initial.AddUser(UserArgs{ 89 Name: adminUser, 90 CreatedBy: adminUser, 91 DateCreated: time.Date(2015, 10, 9, 12, 34, 56, 0, time.UTC), 92 }) 93 addMinimalMachine(initial, "0") 94 addMinimalService(initial) 95 model := s.exportImport(c, initial) 96 97 c.Assert(model.Owner(), gc.Equals, args.Owner) 98 c.Assert(model.Tag().Id(), gc.Equals, "some-uuid") 99 c.Assert(model.Config(), jc.DeepEquals, args.Config) 100 c.Assert(model.LatestToolsVersion(), gc.Equals, args.LatestToolsVersion) 101 c.Assert(model.Blocks(), jc.DeepEquals, args.Blocks) 102 users := model.Users() 103 c.Assert(users, gc.HasLen, 1) 104 c.Assert(users[0].Name(), gc.Equals, adminUser) 105 machines := model.Machines() 106 c.Assert(machines, gc.HasLen, 1) 107 c.Assert(machines[0].Id(), gc.Equals, "0") 108 services := model.Services() 109 c.Assert(services, gc.HasLen, 1) 110 c.Assert(services[0].Name(), gc.Equals, "ubuntu") 111 } 112 113 func (s *ModelSerializationSuite) TestParsingOptionals(c *gc.C) { 114 args := ModelArgs{ 115 Owner: names.NewUserTag("magic"), 116 Config: map[string]interface{}{ 117 "name": "awesome", 118 "uuid": "some-uuid", 119 }, 120 } 121 initial := NewModel(args) 122 model := s.exportImport(c, initial) 123 c.Assert(model.LatestToolsVersion(), gc.Equals, version.Zero) 124 } 125 126 func (s *ModelSerializationSuite) TestAnnotations(c *gc.C) { 127 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 128 annotations := map[string]string{ 129 "string": "value", 130 "another": "one", 131 } 132 initial.SetAnnotations(annotations) 133 134 bytes, err := yaml.Marshal(initial) 135 c.Assert(err, jc.ErrorIsNil) 136 137 model, err := Deserialize(bytes) 138 c.Assert(err, jc.ErrorIsNil) 139 c.Assert(model.Annotations(), jc.DeepEquals, annotations) 140 } 141 142 func (s *ModelSerializationSuite) TestSequences(c *gc.C) { 143 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 144 initial.SetSequence("machine", 4) 145 initial.SetSequence("service-foo", 3) 146 initial.SetSequence("service-bar", 1) 147 bytes, err := yaml.Marshal(initial) 148 c.Assert(err, jc.ErrorIsNil) 149 150 model, err := Deserialize(bytes) 151 c.Assert(err, jc.ErrorIsNil) 152 153 c.Assert(model.Sequences(), jc.DeepEquals, map[string]int{ 154 "machine": 4, 155 "service-foo": 3, 156 "service-bar": 1, 157 }) 158 } 159 160 func (s *ModelSerializationSuite) TestConstraints(c *gc.C) { 161 initial := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 162 args := ConstraintsArgs{ 163 Architecture: "amd64", 164 Memory: 8 * gig, 165 } 166 initial.SetConstraints(args) 167 168 bytes, err := yaml.Marshal(initial) 169 c.Assert(err, jc.ErrorIsNil) 170 171 model, err := Deserialize(bytes) 172 c.Assert(err, jc.ErrorIsNil) 173 c.Assert(model.Constraints(), jc.DeepEquals, newConstraints(args)) 174 } 175 176 func (*ModelSerializationSuite) TestModelValidation(c *gc.C) { 177 model := NewModel(ModelArgs{}) 178 err := model.Validate() 179 c.Assert(err, gc.ErrorMatches, "missing model owner not valid") 180 c.Assert(err, jc.Satisfies, errors.IsNotValid) 181 } 182 183 func (*ModelSerializationSuite) TestModelValidationChecksMachines(c *gc.C) { 184 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 185 model.AddMachine(MachineArgs{}) 186 err := model.Validate() 187 c.Assert(err, gc.ErrorMatches, "machine missing id not valid") 188 c.Assert(err, jc.Satisfies, errors.IsNotValid) 189 } 190 191 func (s *ModelSerializationSuite) addMachineToModel(model Model, id string) Machine { 192 machine := model.AddMachine(MachineArgs{Id: names.NewMachineTag(id)}) 193 machine.SetInstance(CloudInstanceArgs{InstanceId: "magic"}) 194 machine.SetTools(minimalAgentToolsArgs()) 195 machine.SetStatus(minimalStatusArgs()) 196 return machine 197 } 198 199 func (s *ModelSerializationSuite) TestModelValidationChecksMachinesGood(c *gc.C) { 200 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 201 s.addMachineToModel(model, "0") 202 err := model.Validate() 203 c.Assert(err, jc.ErrorIsNil) 204 } 205 206 func (s *ModelSerializationSuite) TestModelValidationChecksOpenPortsUnits(c *gc.C) { 207 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 208 machine := s.addMachineToModel(model, "0") 209 machine.AddOpenedPorts(OpenedPortsArgs{ 210 OpenedPorts: []PortRangeArgs{ 211 { 212 UnitName: "missing/0", 213 FromPort: 8080, 214 ToPort: 8080, 215 Protocol: "tcp", 216 }, 217 }, 218 }) 219 err := model.Validate() 220 c.Assert(err.Error(), gc.Equals, "unknown unit names in open ports: [missing/0]") 221 } 222 223 func (*ModelSerializationSuite) TestModelValidationChecksServices(c *gc.C) { 224 model := NewModel(ModelArgs{Owner: names.NewUserTag("owner")}) 225 model.AddService(ServiceArgs{}) 226 err := model.Validate() 227 c.Assert(err, gc.ErrorMatches, "service missing name not valid") 228 c.Assert(err, jc.Satisfies, errors.IsNotValid) 229 } 230 231 func (s *ModelSerializationSuite) addServiceToModel(model Model, name string, numUnits int) Service { 232 service := model.AddService(ServiceArgs{ 233 Tag: names.NewServiceTag(name), 234 Settings: map[string]interface{}{}, 235 LeadershipSettings: map[string]interface{}{}, 236 }) 237 service.SetStatus(minimalStatusArgs()) 238 for i := 0; i < numUnits; i++ { 239 // The index i is used as both the machine id and the unit id. 240 // A happy coincidence. 241 machine := s.addMachineToModel(model, fmt.Sprint(i)) 242 unit := service.AddUnit(UnitArgs{ 243 Tag: names.NewUnitTag(fmt.Sprintf("%s/%d", name, i)), 244 Machine: machine.Tag(), 245 }) 246 unit.SetTools(minimalAgentToolsArgs()) 247 unit.SetAgentStatus(minimalStatusArgs()) 248 unit.SetWorkloadStatus(minimalStatusArgs()) 249 } 250 251 return service 252 } 253 254 func (s *ModelSerializationSuite) wordpressModel() (Model, Endpoint, Endpoint) { 255 model := NewModel(ModelArgs{ 256 Owner: names.NewUserTag("owner"), 257 Config: map[string]interface{}{ 258 "uuid": "some-uuid", 259 }}) 260 s.addServiceToModel(model, "wordpress", 2) 261 s.addServiceToModel(model, "mysql", 1) 262 263 // Add a relation between wordpress and mysql. 264 rel := model.AddRelation(RelationArgs{ 265 Id: 42, 266 Key: "special key", 267 }) 268 wordpressEndpoint := rel.AddEndpoint(EndpointArgs{ 269 ServiceName: "wordpress", 270 Name: "db", 271 // Ignoring other aspects of endpoints. 272 }) 273 mysqlEndpoint := rel.AddEndpoint(EndpointArgs{ 274 ServiceName: "mysql", 275 Name: "mysql", 276 // Ignoring other aspects of endpoints. 277 }) 278 return model, wordpressEndpoint, mysqlEndpoint 279 } 280 281 func (s *ModelSerializationSuite) wordpressModelWithSettings() Model { 282 model, wordpressEndpoint, mysqlEndpoint := s.wordpressModel() 283 284 wordpressEndpoint.SetUnitSettings("wordpress/0", map[string]interface{}{ 285 "key": "value", 286 }) 287 wordpressEndpoint.SetUnitSettings("wordpress/1", map[string]interface{}{ 288 "key": "value", 289 }) 290 mysqlEndpoint.SetUnitSettings("mysql/0", map[string]interface{}{ 291 "key": "value", 292 }) 293 return model 294 } 295 296 func (s *ModelSerializationSuite) TestModelValidationChecksRelationsMissingSettings(c *gc.C) { 297 model, _, _ := s.wordpressModel() 298 err := model.Validate() 299 c.Assert(err, gc.ErrorMatches, "missing relation settings for units \\[wordpress/0 wordpress/1\\] in relation 42") 300 } 301 302 func (s *ModelSerializationSuite) TestModelValidationChecksRelationsMissingSettings2(c *gc.C) { 303 model, wordpressEndpoint, _ := s.wordpressModel() 304 305 wordpressEndpoint.SetUnitSettings("wordpress/0", map[string]interface{}{ 306 "key": "value", 307 }) 308 wordpressEndpoint.SetUnitSettings("wordpress/1", map[string]interface{}{ 309 "key": "value", 310 }) 311 err := model.Validate() 312 c.Assert(err, gc.ErrorMatches, "missing relation settings for units \\[mysql/0\\] in relation 42") 313 } 314 315 func (s *ModelSerializationSuite) TestModelValidationChecksRelations(c *gc.C) { 316 model := s.wordpressModelWithSettings() 317 err := model.Validate() 318 c.Assert(err, jc.ErrorIsNil) 319 } 320 321 func (s *ModelSerializationSuite) TestModelSerializationWithRelations(c *gc.C) { 322 initial := s.wordpressModelWithSettings() 323 bytes, err := yaml.Marshal(initial) 324 c.Assert(err, jc.ErrorIsNil) 325 model, err := Deserialize(bytes) 326 c.Assert(err, jc.ErrorIsNil) 327 c.Assert(model, jc.DeepEquals, initial) 328 }