github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/annotations/client_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package annotations_test 5 6 import ( 7 "fmt" 8 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 "gopkg.in/juju/names.v2" 12 13 "github.com/juju/juju/apiserver/annotations" 14 "github.com/juju/juju/apiserver/params" 15 apiservertesting "github.com/juju/juju/apiserver/testing" 16 jujutesting "github.com/juju/juju/juju/testing" 17 "github.com/juju/juju/state" 18 "github.com/juju/juju/testing/factory" 19 ) 20 21 type annotationSuite struct { 22 // TODO(anastasiamac) mock to remove JujuConnSuite 23 jujutesting.JujuConnSuite 24 25 annotationsAPI *annotations.API 26 authorizer apiservertesting.FakeAuthorizer 27 } 28 29 var _ = gc.Suite(&annotationSuite{}) 30 31 func (s *annotationSuite) SetUpTest(c *gc.C) { 32 s.JujuConnSuite.SetUpTest(c) 33 s.authorizer = apiservertesting.FakeAuthorizer{ 34 Tag: s.AdminUserTag(c), 35 } 36 var err error 37 s.annotationsAPI, err = annotations.NewAPI(s.State, nil, s.authorizer) 38 c.Assert(err, jc.ErrorIsNil) 39 } 40 41 func (s *annotationSuite) TestEnvironmentAnnotations(c *gc.C) { 42 env, err := s.State.Model() 43 c.Assert(err, jc.ErrorIsNil) 44 s.testSetGetEntitiesAnnotations(c, env.Tag()) 45 } 46 47 func (s *annotationSuite) TestMachineAnnotations(c *gc.C) { 48 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 49 Jobs: []state.MachineJob{state.JobHostUnits}, 50 }) 51 s.testSetGetEntitiesAnnotations(c, machine.Tag()) 52 53 // on machine removal 54 err := machine.EnsureDead() 55 c.Assert(err, jc.ErrorIsNil) 56 err = machine.Remove() 57 c.Assert(err, jc.ErrorIsNil) 58 s.assertAnnotationsRemoval(c, machine.Tag()) 59 } 60 61 func (s *annotationSuite) TestCharmAnnotations(c *gc.C) { 62 charm := s.Factory.MakeCharm(c, &factory.CharmParams{Name: "wordpress"}) 63 s.testSetGetEntitiesAnnotations(c, charm.Tag()) 64 } 65 66 func (s *annotationSuite) TestServiceAnnotations(c *gc.C) { 67 charm := s.Factory.MakeCharm(c, &factory.CharmParams{Name: "wordpress"}) 68 wordpress := s.Factory.MakeApplication(c, &factory.ApplicationParams{ 69 Charm: charm, 70 }) 71 s.testSetGetEntitiesAnnotations(c, wordpress.Tag()) 72 73 // on service removal 74 err := wordpress.Destroy() 75 c.Assert(err, jc.ErrorIsNil) 76 s.assertAnnotationsRemoval(c, wordpress.Tag()) 77 } 78 79 func (s *annotationSuite) assertAnnotationsRemoval(c *gc.C, tag names.Tag) { 80 entity := tag.String() 81 entities := params.Entities{[]params.Entity{{entity}}} 82 ann := s.annotationsAPI.Get(entities) 83 c.Assert(ann.Results, gc.HasLen, 1) 84 85 aResult := ann.Results[0] 86 c.Assert(aResult.EntityTag, gc.DeepEquals, entity) 87 c.Assert(aResult.Annotations, gc.HasLen, 0) 88 } 89 90 func (s *annotationSuite) TestInvalidEntityAnnotations(c *gc.C) { 91 entity := "charm-invalid" 92 entities := params.Entities{[]params.Entity{{entity}}} 93 annotations := map[string]string{"mykey": "myvalue"} 94 95 setResult := s.annotationsAPI.Set( 96 params.AnnotationsSet{Annotations: constructSetParameters([]string{entity}, annotations)}) 97 c.Assert(setResult.OneError().Error(), gc.Matches, ".*permission denied.*") 98 99 got := s.annotationsAPI.Get(entities) 100 c.Assert(got.Results, gc.HasLen, 1) 101 102 aResult := got.Results[0] 103 c.Assert(aResult.EntityTag, gc.DeepEquals, entity) 104 c.Assert(aResult.Error.Error.Error(), gc.Matches, ".*permission denied.*") 105 } 106 107 func (s *annotationSuite) TestUnitAnnotations(c *gc.C) { 108 machine := s.Factory.MakeMachine(c, &factory.MachineParams{ 109 Jobs: []state.MachineJob{state.JobHostUnits}, 110 }) 111 charm := s.Factory.MakeCharm(c, &factory.CharmParams{Name: "wordpress"}) 112 wordpress := s.Factory.MakeApplication(c, &factory.ApplicationParams{ 113 Charm: charm, 114 }) 115 unit := s.Factory.MakeUnit(c, &factory.UnitParams{ 116 Application: wordpress, 117 Machine: machine, 118 }) 119 s.testSetGetEntitiesAnnotations(c, unit.Tag()) 120 121 // on unit removal 122 err := unit.EnsureDead() 123 c.Assert(err, jc.ErrorIsNil) 124 err = unit.Remove() 125 c.Assert(err, jc.ErrorIsNil) 126 s.assertAnnotationsRemoval(c, wordpress.Tag()) 127 } 128 129 func (s *annotationSuite) makeRelation(c *gc.C) (*state.Application, *state.Relation) { 130 s1 := s.Factory.MakeApplication(c, &factory.ApplicationParams{ 131 Name: "service1", 132 Charm: s.Factory.MakeCharm(c, &factory.CharmParams{ 133 Name: "wordpress", 134 }), 135 }) 136 e1, err := s1.Endpoint("db") 137 c.Assert(err, jc.ErrorIsNil) 138 139 s2 := s.Factory.MakeApplication(c, &factory.ApplicationParams{ 140 Name: "service2", 141 Charm: s.Factory.MakeCharm(c, &factory.CharmParams{ 142 Name: "mysql", 143 }), 144 }) 145 e2, err := s2.Endpoint("server") 146 c.Assert(err, jc.ErrorIsNil) 147 148 relation := s.Factory.MakeRelation(c, &factory.RelationParams{ 149 Endpoints: []state.Endpoint{e1, e2}, 150 }) 151 c.Assert(relation, gc.NotNil) 152 return s1, relation 153 } 154 155 // Cannot annotate relations... 156 func (s *annotationSuite) TestRelationAnnotations(c *gc.C) { 157 _, relation := s.makeRelation(c) 158 159 tag := relation.Tag().String() 160 entity := params.Entity{tag} 161 entities := params.Entities{[]params.Entity{entity}} 162 annotations := map[string]string{"mykey": "myvalue"} 163 164 setResult := s.annotationsAPI.Set( 165 params.AnnotationsSet{Annotations: constructSetParameters([]string{tag}, annotations)}) 166 c.Assert(setResult.OneError().Error(), gc.Matches, ".*does not support annotations.*") 167 168 got := s.annotationsAPI.Get(entities) 169 c.Assert(got.Results, gc.HasLen, 1) 170 171 aResult := got.Results[0] 172 c.Assert(aResult.EntityTag, gc.DeepEquals, tag) 173 c.Assert(aResult.Error.Error.Error(), gc.Matches, ".*does not support annotations.*") 174 } 175 176 func constructSetParameters( 177 entities []string, 178 annotations map[string]string) []params.EntityAnnotations { 179 result := []params.EntityAnnotations{} 180 for _, entity := range entities { 181 one := params.EntityAnnotations{ 182 EntityTag: entity, 183 Annotations: annotations, 184 } 185 result = append(result, one) 186 } 187 return result 188 } 189 190 func (s *annotationSuite) TestMultipleEntitiesAnnotations(c *gc.C) { 191 s1, relation := s.makeRelation(c) 192 193 rTag := relation.Tag() 194 rEntity := rTag.String() 195 sTag := s1.Tag() 196 sEntity := sTag.String() 197 198 entities := []string{ 199 sEntity, //service: expect success in set/get 200 rEntity, //relation:expect failure in set/get - cannot annotate relations 201 } 202 annotations := map[string]string{"mykey": "myvalue"} 203 204 setResult := s.annotationsAPI.Set( 205 params.AnnotationsSet{Annotations: constructSetParameters(entities, annotations)}) 206 c.Assert(setResult.Results, gc.HasLen, 1) 207 208 oneError := setResult.Results[0].Error.Error() 209 // Only attempt at annotate relation should have erred 210 c.Assert(oneError, gc.Matches, fmt.Sprintf(".*%q.*", rTag)) 211 c.Assert(oneError, gc.Matches, ".*does not support annotations.*") 212 213 got := s.annotationsAPI.Get(params.Entities{[]params.Entity{ 214 {rEntity}, 215 {sEntity}}}) 216 c.Assert(got.Results, gc.HasLen, 2) 217 218 var rGet, sGet bool 219 for _, aResult := range got.Results { 220 if aResult.EntityTag == rTag.String() { 221 rGet = true 222 c.Assert(aResult.Error.Error.Error(), gc.Matches, ".*does not support annotations.*") 223 } else { 224 sGet = true 225 c.Assert(aResult.EntityTag, gc.DeepEquals, sEntity) 226 c.Assert(aResult.Annotations, gc.DeepEquals, annotations) 227 } 228 } 229 // Both entities should have processed 230 c.Assert(sGet, jc.IsTrue) 231 c.Assert(rGet, jc.IsTrue) 232 } 233 234 func (s *annotationSuite) testSetGetEntitiesAnnotations(c *gc.C, tag names.Tag) { 235 entity := tag.String() 236 entities := []string{entity} 237 for i, t := range clientAnnotationsTests { 238 c.Logf("test %d. %s. entity %s", i, t.about, tag.Id()) 239 s.setupEntity(c, entities, t.initial) 240 s.assertSetEntityAnnotations(c, entities, t.input, t.err) 241 if t.err != "" { 242 continue 243 } 244 aResult := s.assertGetEntityAnnotations(c, params.Entities{[]params.Entity{{entity}}}, entity, t.expected) 245 s.cleanupEntityAnnotations(c, entities, aResult) 246 } 247 } 248 249 func (s *annotationSuite) setupEntity( 250 c *gc.C, 251 entities []string, 252 initialAnnotations map[string]string) { 253 if initialAnnotations != nil { 254 initialResult := s.annotationsAPI.Set( 255 params.AnnotationsSet{ 256 Annotations: constructSetParameters(entities, initialAnnotations)}) 257 c.Assert(initialResult.Combine(), jc.ErrorIsNil) 258 } 259 } 260 261 func (s *annotationSuite) assertSetEntityAnnotations(c *gc.C, 262 entities []string, 263 annotations map[string]string, 264 expectedError string) { 265 setResult := s.annotationsAPI.Set( 266 params.AnnotationsSet{Annotations: constructSetParameters(entities, annotations)}) 267 if expectedError != "" { 268 c.Assert(setResult.OneError().Error(), gc.Matches, expectedError) 269 } else { 270 c.Assert(setResult.Combine(), jc.ErrorIsNil) 271 } 272 } 273 274 func (s *annotationSuite) assertGetEntityAnnotations(c *gc.C, 275 entities params.Entities, 276 entity string, 277 expected map[string]string) params.AnnotationsGetResult { 278 got := s.annotationsAPI.Get(entities) 279 c.Assert(got.Results, gc.HasLen, 1) 280 281 aResult := got.Results[0] 282 c.Assert(aResult.EntityTag, gc.DeepEquals, entity) 283 c.Assert(aResult.Annotations, gc.DeepEquals, expected) 284 return aResult 285 } 286 287 func (s *annotationSuite) cleanupEntityAnnotations(c *gc.C, 288 entities []string, 289 aResult params.AnnotationsGetResult) { 290 cleanup := make(map[string]string) 291 for key := range aResult.Annotations { 292 cleanup[key] = "" 293 } 294 cleanupResult := s.annotationsAPI.Set( 295 params.AnnotationsSet{Annotations: constructSetParameters(entities, cleanup)}) 296 c.Assert(cleanupResult.Combine(), jc.ErrorIsNil) 297 } 298 299 var clientAnnotationsTests = []struct { 300 about string 301 initial map[string]string 302 input map[string]string 303 expected map[string]string 304 err string 305 }{ 306 { 307 about: "test setting an annotation", 308 input: map[string]string{"mykey": "myvalue"}, 309 expected: map[string]string{"mykey": "myvalue"}, 310 }, 311 { 312 about: "test setting multiple annotations", 313 input: map[string]string{"key1": "value1", "key2": "value2"}, 314 expected: map[string]string{"key1": "value1", "key2": "value2"}, 315 }, 316 { 317 about: "test overriding annotations", 318 initial: map[string]string{"mykey": "myvalue"}, 319 input: map[string]string{"mykey": "another-value"}, 320 expected: map[string]string{"mykey": "another-value"}, 321 }, 322 { 323 about: "test setting an invalid annotation", 324 input: map[string]string{"invalid.key": "myvalue"}, 325 err: `.*: invalid key "invalid.key"`, 326 }, 327 }