4
. "launchpad.net/gocheck"
5
"launchpad.net/juju-core/charm"
6
"launchpad.net/juju-core/state"
9
type RelationSuite struct {
13
var _ = Suite(&RelationSuite{})
15
func (s *RelationSuite) TestAddRelationErrors(c *C) {
16
wordpress, err := s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpress"))
18
wordpressEP, err := wordpress.Endpoint("db")
20
mysql, err := s.State.AddService("mysql", s.AddTestingCharm(c, "mysql"))
22
mysqlEP, err := mysql.Endpoint("server")
24
riak, err := s.State.AddService("riak", s.AddTestingCharm(c, "riak"))
26
riakEP, err := riak.Endpoint("ring")
29
// Check we can't add a relation with services that don't exist.
31
yoursqlEP.ServiceName = "yoursql"
32
_, err = s.State.AddRelation(yoursqlEP, wordpressEP)
33
c.Assert(err, ErrorMatches, `cannot add relation "wordpress:db yoursql:server": service "yoursql" does not exist`)
34
assertNoRelations(c, wordpress)
35
assertNoRelations(c, mysql)
37
// Check that interfaces have to match.
39
msep3.Interface = "roflcopter"
40
_, err = s.State.AddRelation(msep3, wordpressEP)
41
c.Assert(err, ErrorMatches, `cannot add relation "wordpress:db mysql:server": endpoints do not relate`)
42
assertNoRelations(c, wordpress)
43
assertNoRelations(c, mysql)
45
// Check a variety of surprising endpoint combinations.
46
_, err = s.State.AddRelation(wordpressEP)
47
c.Assert(err, ErrorMatches, `cannot add relation "wordpress:db": relation must have two endpoints`)
48
assertNoRelations(c, wordpress)
50
_, err = s.State.AddRelation(riakEP, wordpressEP)
51
c.Assert(err, ErrorMatches, `cannot add relation "wordpress:db riak:ring": endpoints do not relate`)
52
assertOneRelation(c, riak, 0, riakEP)
53
assertNoRelations(c, wordpress)
55
_, err = s.State.AddRelation(riakEP, riakEP)
56
c.Assert(err, ErrorMatches, `cannot add relation "riak:ring riak:ring": endpoints do not relate`)
57
assertOneRelation(c, riak, 0, riakEP)
59
_, err = s.State.AddRelation()
60
c.Assert(err, ErrorMatches, `cannot add relation "": relation must have two endpoints`)
61
_, err = s.State.AddRelation(mysqlEP, wordpressEP, riakEP)
62
c.Assert(err, ErrorMatches, `cannot add relation "wordpress:db mysql:server riak:ring": relation must have two endpoints`)
63
assertOneRelation(c, riak, 0, riakEP)
64
assertNoRelations(c, wordpress)
65
assertNoRelations(c, mysql)
67
// Check that a relation can't be added to a Dying service.
68
_, err = wordpress.AddUnit()
70
err = wordpress.Destroy()
72
_, err = s.State.AddRelation(mysqlEP, wordpressEP)
73
c.Assert(err, ErrorMatches, `cannot add relation "wordpress:db mysql:server": service "wordpress" is not alive`)
74
assertNoRelations(c, wordpress)
75
assertNoRelations(c, mysql)
78
func (s *RelationSuite) TestRetrieveSuccess(c *C) {
79
wordpress, err := s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpress"))
81
wordpressEP, err := wordpress.Endpoint("db")
83
mysql, err := s.State.AddService("mysql", s.AddTestingCharm(c, "mysql"))
85
mysqlEP, err := mysql.Endpoint("server")
87
expect, err := s.State.AddRelation(wordpressEP, mysqlEP)
89
rel, err := s.State.EndpointsRelation(wordpressEP, mysqlEP)
92
c.Assert(rel.Id(), Equals, expect.Id())
93
c.Assert(rel.String(), Equals, expect.String())
96
rel, err = s.State.EndpointsRelation(mysqlEP, wordpressEP)
98
rel, err = s.State.Relation(expect.Id())
102
func (s *RelationSuite) TestRetrieveNotFound(c *C) {
103
subway := state.Endpoint{
104
ServiceName: "subway",
105
Relation: charm.Relation{
107
Interface: "mongodb",
108
Role: charm.RoleRequirer,
109
Scope: charm.ScopeGlobal,
112
mongo := state.Endpoint{
113
ServiceName: "mongo",
114
Relation: charm.Relation{
116
Interface: "mongodb",
117
Role: charm.RoleProvider,
118
Scope: charm.ScopeGlobal,
121
_, err := s.State.EndpointsRelation(subway, mongo)
122
c.Assert(err, ErrorMatches, `relation "subway:db mongo:server" not found`)
123
c.Assert(state.IsNotFound(err), Equals, true)
125
_, err = s.State.Relation(999)
126
c.Assert(err, ErrorMatches, `relation 999 not found`)
127
c.Assert(state.IsNotFound(err), Equals, true)
130
func (s *RelationSuite) TestAddRelation(c *C) {
132
wordpress, err := s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpress"))
134
wordpressEP, err := wordpress.Endpoint("db")
136
mysql, err := s.State.AddService("mysql", s.AddTestingCharm(c, "mysql"))
138
mysqlEP, err := mysql.Endpoint("server")
140
_, err = s.State.AddRelation(wordpressEP, mysqlEP)
142
assertOneRelation(c, mysql, 0, mysqlEP, wordpressEP)
143
assertOneRelation(c, wordpress, 0, wordpressEP, mysqlEP)
145
// Check we cannot re-add the same relation, regardless of endpoint ordering.
146
_, err = s.State.AddRelation(mysqlEP, wordpressEP)
147
c.Assert(err, ErrorMatches, `cannot add relation "wordpress:db mysql:server": relation already exists`)
148
_, err = s.State.AddRelation(wordpressEP, mysqlEP)
149
c.Assert(err, ErrorMatches, `cannot add relation "wordpress:db mysql:server": relation already exists`)
150
assertOneRelation(c, mysql, 0, mysqlEP, wordpressEP)
151
assertOneRelation(c, wordpress, 0, wordpressEP, mysqlEP)
154
func (s *RelationSuite) TestAddRelationSeriesNeedNotMatch(c *C) {
155
wordpress, err := s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpress"))
157
wordpressEP, err := wordpress.Endpoint("db")
159
mysql, err := s.State.AddService("mysql", s.AddSeriesCharm(c, "mysql", "otherseries"))
161
mysqlEP, err := mysql.Endpoint("server")
163
_, err = s.State.AddRelation(wordpressEP, mysqlEP)
165
assertOneRelation(c, mysql, 0, mysqlEP, wordpressEP)
166
assertOneRelation(c, wordpress, 0, wordpressEP, mysqlEP)
169
func (s *RelationSuite) TestAddContainerRelation(c *C) {
171
wordpress, err := s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpress"))
173
wordpressEP, err := wordpress.Endpoint("juju-info")
175
logging, err := s.State.AddService("logging", s.AddTestingCharm(c, "logging"))
177
loggingEP, err := logging.Endpoint("info")
179
_, err = s.State.AddRelation(wordpressEP, loggingEP)
182
// Check that the endpoints both have container scope.
183
wordpressEP.Scope = charm.ScopeContainer
184
assertOneRelation(c, logging, 0, loggingEP, wordpressEP)
185
assertOneRelation(c, wordpress, 0, wordpressEP, loggingEP)
187
// Check we cannot re-add the same relation, regardless of endpoint ordering.
188
_, err = s.State.AddRelation(loggingEP, wordpressEP)
189
c.Assert(err, ErrorMatches, `cannot add relation "logging:info wordpress:juju-info": relation already exists`)
190
_, err = s.State.AddRelation(wordpressEP, loggingEP)
191
c.Assert(err, ErrorMatches, `cannot add relation "logging:info wordpress:juju-info": relation already exists`)
192
assertOneRelation(c, logging, 0, loggingEP, wordpressEP)
193
assertOneRelation(c, wordpress, 0, wordpressEP, loggingEP)
196
func (s *RelationSuite) TestAddContainerRelationSeriesMustMatch(c *C) {
197
wordpress, err := s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpress"))
199
wordpressEP, err := wordpress.Endpoint("juju-info")
201
logging, err := s.State.AddService("logging", s.AddSeriesCharm(c, "logging", "otherseries"))
203
loggingEP, err := logging.Endpoint("info")
205
_, err = s.State.AddRelation(wordpressEP, loggingEP)
206
c.Assert(err, ErrorMatches, `cannot add relation "logging:info wordpress:juju-info": principal and subordinate services' series must match`)
209
func (s *RelationSuite) TestDestroyRelation(c *C) {
210
wordpress, err := s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpress"))
212
mysql, err := s.State.AddService("mysql", s.AddTestingCharm(c, "mysql"))
214
eps, err := s.State.InferEndpoints([]string{"wordpress", "mysql"})
216
rel, err := s.State.AddRelation(eps...)
219
// Test that the relation can be destroyed.
223
c.Assert(state.IsNotFound(err), Equals, true)
224
assertNoRelations(c, wordpress)
225
assertNoRelations(c, mysql)
227
// Check that a second destroy is a no-op.
231
// Create a new relation and check that refreshing the old does not find
233
_, err = s.State.AddRelation(eps...)
236
c.Assert(state.IsNotFound(err), Equals, true)
239
func (s *RelationSuite) TestDestroyPeerRelation(c *C) {
240
// Check that a peer relation cannot be destroyed directly.
241
riakch := s.AddTestingCharm(c, "riak")
242
riak, err := s.State.AddService("riak", riakch)
244
riakEP, err := riak.Endpoint("ring")
246
rel := assertOneRelation(c, riak, 0, riakEP)
248
c.Assert(err, ErrorMatches, `cannot destroy relation "riak:ring": is a peer relation`)
249
assertOneRelation(c, riak, 0, riakEP)
251
// Check that it is destroyed when the service is destroyed.
254
assertNoRelations(c, riak)
256
c.Assert(state.IsNotFound(err), Equals, true)
258
// Create a new service (and hence a new relation in the background); check
259
// that refreshing the old one does not accidentally get the new one.
260
newriak, err := s.State.AddService("riak", riakch)
262
assertOneRelation(c, newriak, 1, riakEP)
264
c.Assert(state.IsNotFound(err), Equals, true)
267
func assertNoRelations(c *C, srv *state.Service) {
268
rels, err := srv.Relations()
270
c.Assert(rels, HasLen, 0)
273
func assertOneRelation(c *C, srv *state.Service, relId int, endpoints ...state.Endpoint) *state.Relation {
274
rels, err := srv.Relations()
276
c.Assert(rels, HasLen, 1)
278
c.Assert(rel.Id(), Equals, relId)
280
expectEp := endpoints[0]
281
ep, err := rel.Endpoint(name)
283
c.Assert(ep, DeepEquals, expectEp)
284
if len(endpoints) == 2 {
285
expectEp = endpoints[1]
287
eps, err := rel.RelatedEndpoints(name)
289
c.Assert(eps, DeepEquals, []state.Endpoint{expectEp})