func (s *RelationerSuite) SetUpTest(c *gc.C) { s.JujuConnSuite.SetUpTest(c) var err error s.svc = s.AddTestingService(c, "u", s.AddTestingCharm(c, "riak")) c.Assert(err, gc.IsNil) rels, err := s.svc.Relations() c.Assert(err, gc.IsNil) c.Assert(rels, gc.HasLen, 1) s.rel = rels[0] _, unit := s.AddRelationUnit(c, "u/0") s.dirPath = c.MkDir() s.dir, err = relation.ReadStateDir(s.dirPath, s.rel.Id()) c.Assert(err, gc.IsNil) s.hooks = make(chan hook.Info) password, err := utils.RandomPassword() c.Assert(err, gc.IsNil) err = unit.SetPassword(password) c.Assert(err, gc.IsNil) s.st = s.OpenAPIAs(c, unit.Tag(), password) s.uniter = s.st.Uniter() c.Assert(s.uniter, gc.NotNil) apiUnit, err := s.uniter.Unit(unit.Tag()) c.Assert(err, gc.IsNil) apiRel, err := s.uniter.Relation(s.rel.Tag()) c.Assert(err, gc.IsNil) s.apiRelUnit, err = apiRel.Unit(apiUnit) c.Assert(err, gc.IsNil) }
func (s *StateDirSuite) TestWrite(c *gc.C) { for i, t := range writeTests { c.Logf("test %d", i) basedir := c.MkDir() setUpDir(c, basedir, "123", map[string]string{ "foo-1": "change-version: 0\n", "foo-2": "change-version: 0\n", }) dir, err := relation.ReadStateDir(basedir, 123) c.Assert(err, gc.IsNil) for i, hi := range t.hooks { c.Logf(" hook %d", i) if i == len(t.hooks)-1 && t.err != "" { err = dir.State().Validate(hi) expect := fmt.Sprintf(`inappropriate %q for %q: %s`, hi.Kind, hi.RemoteUnit, t.err) c.Assert(err, gc.ErrorMatches, expect) } else { err = dir.State().Validate(hi) c.Assert(err, gc.IsNil) err = dir.Write(hi) c.Assert(err, gc.IsNil) // Check that writing the same change again is OK. err = dir.Write(hi) c.Assert(err, gc.IsNil) } } members := t.members if members == nil && !t.deleted { members = defaultMembers } assertState(c, dir, basedir, 123, members, t.pending, t.deleted) } }
func (s *StateDirSuite) TestRemove(c *gc.C) { basedir := c.MkDir() dir, err := relation.ReadStateDir(basedir, 1) c.Assert(err, gc.IsNil) err = dir.Ensure() c.Assert(err, gc.IsNil) err = dir.Remove() c.Assert(err, gc.IsNil) err = dir.Remove() c.Assert(err, gc.IsNil) setUpDir(c, basedir, "99", map[string]string{ "foo-1": "change-version: 0\n", }) dir, err = relation.ReadStateDir(basedir, 99) c.Assert(err, gc.IsNil) err = dir.Remove() c.Assert(err, gc.ErrorMatches, ".*: directory not empty") }
func (s *StateDirSuite) TestBadRelations(c *gc.C) { for i, t := range badRelationsTests { c.Logf("test %d", i) basedir := c.MkDir() reldir := setUpDir(c, basedir, "123", t.contents) for _, subdir := range t.subdirs { setUpDir(c, reldir, subdir, nil) } _, err := relation.ReadStateDir(basedir, 123) expect := `cannot load relation state from ".*": ` + t.err c.Assert(err, gc.ErrorMatches, expect) } }
func assertState(c *gc.C, dir *relation.StateDir, relsdir string, relationId int, members msi, pending string, deleted bool) { expect := &relation.State{ RelationId: relationId, Members: map[string]int64(members), ChangedPending: pending, } c.Assert(dir.State(), gc.DeepEquals, expect) if deleted { _, err := os.Stat(filepath.Join(relsdir, strconv.Itoa(relationId))) c.Assert(err, jc.Satisfies, os.IsNotExist) } else { fresh, err := relation.ReadStateDir(relsdir, relationId) c.Assert(err, gc.IsNil) c.Assert(fresh.State(), gc.DeepEquals, expect) } }
func (s *StateDirSuite) TestReadStateDirValid(c *gc.C) { basedir := c.MkDir() reldir := setUpDir(c, basedir, "123", map[string]string{ "foo-bar-1": "change-version: 99\n", "foo-bar-1.preparing": "change-version: 100\n", "baz-qux-7": "change-version: 101\nchanged-pending: true\n", "nonsensical": "blah", "27": "blah", }) setUpDir(c, reldir, "ignored", nil) dir, err := relation.ReadStateDir(basedir, 123) c.Assert(err, gc.IsNil) state := dir.State() c.Assert(state.RelationId, gc.Equals, 123) c.Assert(msi(state.Members), gc.DeepEquals, msi{"foo-bar/1": 99, "baz-qux/7": 101}) c.Assert(state.ChangedPending, gc.Equals, "baz-qux/7") }
func (s *StateDirSuite) TestReadStateDirEmpty(c *gc.C) { basedir := c.MkDir() reldir := filepath.Join(basedir, "123") dir, err := relation.ReadStateDir(basedir, 123) c.Assert(err, gc.IsNil) state := dir.State() c.Assert(state.RelationId, gc.Equals, 123) c.Assert(msi(state.Members), gc.DeepEquals, msi{}) c.Assert(state.ChangedPending, gc.Equals, "") _, err = os.Stat(reldir) c.Assert(err, jc.Satisfies, os.IsNotExist) err = dir.Ensure() c.Assert(err, gc.IsNil) fi, err := os.Stat(reldir) c.Assert(err, gc.IsNil) c.Assert(fi, jc.Satisfies, os.FileInfo.IsDir) }
func (s *RelationerImplicitSuite) TestImplicitRelationer(c *gc.C) { // Create a relationer for an implicit endpoint (mysql:juju-info). mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) u, err := mysql.AddUnit() c.Assert(err, gc.IsNil) machine, err := s.State.AddMachine("quantal", state.JobHostUnits) c.Assert(err, gc.IsNil) err = u.AssignToMachine(machine) c.Assert(err, gc.IsNil) err = machine.SetAddresses(instance.NewAddress("blah", instance.NetworkCloudLocal)) c.Assert(err, gc.IsNil) logging := s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging")) eps, err := s.State.InferEndpoints([]string{"logging", "mysql"}) c.Assert(err, gc.IsNil) rel, err := s.State.AddRelation(eps...) c.Assert(err, gc.IsNil) relsDir := c.MkDir() dir, err := relation.ReadStateDir(relsDir, rel.Id()) c.Assert(err, gc.IsNil) hooks := make(chan hook.Info) password, err := utils.RandomPassword() c.Assert(err, gc.IsNil) err = u.SetPassword(password) c.Assert(err, gc.IsNil) st := s.OpenAPIAs(c, u.Tag(), password) uniterState := st.Uniter() c.Assert(uniterState, gc.NotNil) apiUnit, err := uniterState.Unit(u.Tag()) c.Assert(err, gc.IsNil) apiRel, err := uniterState.Relation(rel.Tag()) c.Assert(err, gc.IsNil) apiRelUnit, err := apiRel.Unit(apiUnit) c.Assert(err, gc.IsNil) r := uniter.NewRelationer(apiRelUnit, dir, hooks) c.Assert(r, jc.Satisfies, (*uniter.Relationer).IsImplicit) // Join the relation. err = r.Join() c.Assert(err, gc.IsNil) sub, err := logging.Unit("logging/0") c.Assert(err, gc.IsNil) // Join the other side; check no hooks are sent. r.StartHooks() defer func() { c.Assert(r.StopHooks(), gc.IsNil) }() subru, err := rel.Unit(sub) c.Assert(err, gc.IsNil) err = subru.EnterScope(map[string]interface{}{"some": "data"}) c.Assert(err, gc.IsNil) s.State.StartSync() select { case <-time.After(coretesting.ShortWait): case <-hooks: c.Fatalf("unexpected hook generated") } // Set it to Dying; check that the dir is removed immediately. err = r.SetDying() c.Assert(err, gc.IsNil) path := strconv.Itoa(rel.Id()) ft.Removed{path}.Check(c, relsDir) // Check that it left scope, by leaving scope on the other side and destroying // the relation. err = subru.LeaveScope() c.Assert(err, gc.IsNil) err = rel.Destroy() c.Assert(err, gc.IsNil) err = rel.Refresh() c.Assert(err, jc.Satisfies, errors.IsNotFound) // Verify that no other hooks were sent at any stage. select { case <-hooks: c.Fatalf("unexpected hook generated") default: } }