github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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  }