Merge lp:~thumper/juju-core/refactor-uniter-tests into lp:~go-bot/juju-core/trunk

Proposed by Tim Penhey
Status: Merged
Approved by: Tim Penhey
Approved revision: no longer in the source branch.
Merged at revision: 2141
Proposed branch: lp:~thumper/juju-core/refactor-uniter-tests
Merge into: lp:~go-bot/juju-core/trunk
Prerequisite: lp:~thumper/juju-core/juju-run-listener
Diff against target: 510 lines (+185/-112)
5 files modified
worker/uniter/context.go (+33/-16)
worker/uniter/context_test.go (+7/-2)
worker/uniter/export_test.go (+8/-0)
worker/uniter/uniter.go (+112/-48)
worker/uniter/uniter_test.go (+25/-46)
To merge this branch: bzr merge lp:~thumper/juju-core/refactor-uniter-tests
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+198668@code.launchpad.net

Commit message

Refactor uniter tests

We needed to have a better way to match the hooks that had been executed by
the uniter in the tests. Instead of relying on log messages that the hooks
wrote out, instead we have the uniter optionally call out to an observer.

Part of this work also involved breaking up some of the larger methods in the
Context and the Uniter methods. These broken up bits are used by the code
that runs generic commands coming shortly.

A fundamental change is that now if a hook is missing, instead of silently
passing, the context now returns a missingHookError.

https://codereview.appspot.com/41210043/

Description of the change

Refactor uniter tests

We needed to have a better way to match the hooks that had been executed by
the uniter in the tests. Instead of relying on log messages that the hooks
wrote out, instead we have the uniter optionally call out to an observer.

Part of this work also involved breaking up some of the larger methods in the
Context and the Uniter methods. These broken up bits are used by the code
that runs generic commands coming shortly.

A fundamental change is that now if a hook is missing, instead of silently
passing, the context now returns a missingHookError.

https://codereview.appspot.com/41210043/

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

Reviewers: mp+198668_code.launchpad.net,

Message:
Please take a look.

Description:
Refactor uniter tests

We needed to have a better way to match the hooks that had been executed
by
the uniter in the tests. Instead of relying on log messages that the
hooks
wrote out, instead we have the uniter optionally call out to an
observer.

Part of this work also involved breaking up some of the larger methods
in the
Context and the Uniter methods. These broken up bits are used by the
code
that runs generic commands coming shortly.

A fundamental change is that now if a hook is missing, instead of
silently
passing, the context now returns a missingHookError.

https://code.launchpad.net/~thumper/juju-core/refactor-uniter-tests/+merge/198668

Requires:
https://code.launchpad.net/~thumper/juju-core/juju-run-listener/+merge/198662

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/41210043/

Affected files (+181, -109 lines):
   A [revision details]
   M worker/uniter/context.go
   M worker/uniter/context_test.go
   A worker/uniter/export_test.go
   M worker/uniter/uniter.go
   M worker/uniter/uniter_test.go

Revision history for this message
Ian Booth (wallyworld) wrote :

LGTM with some tweaks

https://codereview.appspot.com/41210043/diff/1/worker/uniter/context.go
File worker/uniter/context.go (right):

https://codereview.appspot.com/41210043/diff/1/worker/uniter/context.go#newcode191
worker/uniter/context.go:191: writeChanges := err == nil
Why not just make writeChanges a method param?
And set it accordingly in the caller if the err the caller has is nil?

https://codereview.appspot.com/41210043/diff/1/worker/uniter/uniter.go
File worker/uniter/uniter.go (right):

https://codereview.appspot.com/41210043/diff/1/worker/uniter/uniter.go#newcode35
worker/uniter/uniter.go:35: type UniterExecutionObserver interface {
Doc string please

https://codereview.appspot.com/41210043/diff/1/worker/uniter/uniter_test.go
File worker/uniter/uniter_test.go (left):

https://codereview.appspot.com/41210043/diff/1/worker/uniter/uniter_test.go#oldcode192
worker/uniter/uniter_test.go:192: func (ctx *context) matchLogHooks(c
*gc.C) (match bool, overshoot bool) {
Is this still the best method name?

https://codereview.appspot.com/41210043/

Revision history for this message
Tim Penhey (thumper) wrote :

Please take a look.

https://codereview.appspot.com/41210043/diff/1/worker/uniter/context.go
File worker/uniter/context.go (right):

https://codereview.appspot.com/41210043/diff/1/worker/uniter/context.go#newcode191
worker/uniter/context.go:191: writeChanges := err == nil
On 2013/12/13 00:23:11, wallyworld wrote:
> Why not just make writeChanges a method param?
> And set it accordingly in the caller if the err the caller has is nil?

Because doing it this way makes the caller much cleaner, and we need the
error anyway as we return that if it is not-nil.

https://codereview.appspot.com/41210043/diff/1/worker/uniter/uniter.go
File worker/uniter/uniter.go (right):

https://codereview.appspot.com/41210043/diff/1/worker/uniter/uniter.go#newcode35
worker/uniter/uniter.go:35: type UniterExecutionObserver interface {
On 2013/12/13 00:23:11, wallyworld wrote:
> Doc string please

Done.

https://codereview.appspot.com/41210043/diff/1/worker/uniter/uniter_test.go
File worker/uniter/uniter_test.go (left):

https://codereview.appspot.com/41210043/diff/1/worker/uniter/uniter_test.go#oldcode192
worker/uniter/uniter_test.go:192: func (ctx *context) matchLogHooks(c
*gc.C) (match bool, overshoot bool) {
On 2013/12/13 00:23:11, wallyworld wrote:
> Is this still the best method name?

Haha, ah, no. I'll change to something more meaningful.

https://codereview.appspot.com/41210043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'worker/uniter/context.go'
2--- worker/uniter/context.go 2013-10-04 17:38:30 +0000
3+++ worker/uniter/context.go 2013-12-13 02:48:10 +0000
4@@ -22,6 +22,19 @@
5 "launchpad.net/juju-core/worker/uniter/jujuc"
6 )
7
8+type missingHookError struct {
9+ hookName string
10+}
11+
12+func (e *missingHookError) Error() string {
13+ return e.hookName + " does not exist"
14+}
15+
16+func IsMissingHookError(err error) bool {
17+ _, ok := err.(*missingHookError)
18+ return ok
19+}
20+
21 // HookContext is the implementation of jujuc.Context.
22 type HookContext struct {
23 unit *uniter.Unit
24@@ -174,25 +187,14 @@
25 return vars
26 }
27
28-// RunHook executes a hook in an environment which allows it to to call back
29-// into ctx to execute jujuc tools.
30-func (ctx *HookContext) RunHook(hookName, charmDir, toolsDir, socketPath string) error {
31- var err error
32- env := ctx.hookVars(charmDir, toolsDir, socketPath)
33- debugctx := unitdebug.NewHooksContext(ctx.unit.Name())
34- if session, _ := debugctx.FindSession(); session != nil && session.MatchHook(hookName) {
35- logger.Infof("executing %s via debug-hooks", hookName)
36- err = session.RunHook(hookName, charmDir, env)
37- } else {
38- err = runCharmHook(hookName, charmDir, env)
39- }
40- write := err == nil
41+func (ctx *HookContext) finalizeContext(process string, err error) error {
42+ writeChanges := err == nil
43 for id, rctx := range ctx.relations {
44- if write {
45+ if writeChanges {
46 if e := rctx.WriteSettings(); e != nil {
47 e = fmt.Errorf(
48 "could not write settings from %q to relation %d: %v",
49- hookName, id, e,
50+ process, id, e,
51 )
52 logger.Errorf("%v", e)
53 if err == nil {
54@@ -205,6 +207,21 @@
55 return err
56 }
57
58+// RunHook executes a hook in an environment which allows it to to call back
59+// into ctx to execute jujuc tools.
60+func (ctx *HookContext) RunHook(hookName, charmDir, toolsDir, socketPath string) error {
61+ var err error
62+ env := ctx.hookVars(charmDir, toolsDir, socketPath)
63+ debugctx := unitdebug.NewHooksContext(ctx.unit.Name())
64+ if session, _ := debugctx.FindSession(); session != nil && session.MatchHook(hookName) {
65+ logger.Infof("executing %s via debug-hooks", hookName)
66+ err = session.RunHook(hookName, charmDir, env)
67+ } else {
68+ err = runCharmHook(hookName, charmDir, env)
69+ }
70+ return ctx.finalizeContext(hookName, err)
71+}
72+
73 func runCharmHook(hookName, charmDir string, env []string) error {
74 ps := exec.Command(filepath.Join(charmDir, "hooks", hookName))
75 ps.Env = env
76@@ -230,7 +247,7 @@
77 if os.IsNotExist(ee.Err) {
78 // Missing hook is perfectly valid, but worth mentioning.
79 logger.Infof("skipped %q hook (not implemented)", hookName)
80- return nil
81+ return &missingHookError{hookName}
82 }
83 }
84 return err
85
86=== modified file 'worker/uniter/context_test.go'
87--- worker/uniter/context_test.go 2013-11-14 12:32:14 +0000
88+++ worker/uniter/context_test.go 2013-12-13 02:48:10 +0000
89@@ -19,6 +19,7 @@
90 "launchpad.net/juju-core/state/api"
91 "launchpad.net/juju-core/state/api/params"
92 apiuniter "launchpad.net/juju-core/state/api/uniter"
93+ jc "launchpad.net/juju-core/testing/checkers"
94 "launchpad.net/juju-core/utils"
95 "launchpad.net/juju-core/worker/uniter"
96 "launchpad.net/juju-core/worker/uniter/jujuc"
97@@ -206,9 +207,10 @@
98 uuid, err := utils.NewUUID()
99 c.Assert(err, gc.IsNil)
100 for i, t := range runHookTests {
101- c.Logf("test %d: %s; perm %v", i, t.summary, t.spec.perm)
102+ c.Logf("\ntest %d: %s; perm %v", i, t.summary, t.spec.perm)
103 ctx := s.GetHookContext(c, uuid.String(), t.relid, t.remote)
104 var charmDir, outPath string
105+ var hookExists bool
106 if t.spec.perm == 0 {
107 charmDir = c.MkDir()
108 } else {
109@@ -216,12 +218,15 @@
110 spec.name = "something-happened"
111 c.Logf("makeCharm %#v", spec)
112 charmDir, outPath = makeCharm(c, spec)
113+ hookExists = true
114 }
115 toolsDir := c.MkDir()
116 t0 := time.Now()
117 err := ctx.RunHook("something-happened", charmDir, toolsDir, "/path/to/socket")
118- if t.err == "" {
119+ if t.err == "" && hookExists {
120 c.Assert(err, gc.IsNil)
121+ } else if !hookExists {
122+ c.Assert(uniter.IsMissingHookError(err), jc.IsTrue)
123 } else {
124 c.Assert(err, gc.ErrorMatches, t.err)
125 }
126
127=== added file 'worker/uniter/export_test.go'
128--- worker/uniter/export_test.go 1970-01-01 00:00:00 +0000
129+++ worker/uniter/export_test.go 2013-12-13 02:48:10 +0000
130@@ -0,0 +1,8 @@
131+// Copyright 2013 Canonical Ltd.
132+// Licensed under the AGPLv3, see LICENCE file for details.
133+
134+package uniter
135+
136+func SetUniterObserver(u *Uniter, observer UniterExecutionObserver) {
137+ u.observer = observer
138+}
139
140=== modified file 'worker/uniter/uniter.go'
141--- worker/uniter/uniter.go 2013-11-14 12:32:14 +0000
142+++ worker/uniter/uniter.go 2013-12-13 02:48:10 +0000
143@@ -32,6 +32,14 @@
144
145 var logger = loggo.GetLogger("juju.worker.uniter")
146
147+// A UniterExecutionObserver gets the appropriate methods called when a hook
148+// is executed and either succeeds or fails. Missing hooks don't get reported
149+// in this way.
150+type UniterExecutionObserver interface {
151+ HookCompleted(hookName string)
152+ HookFailed(hookName string)
153+}
154+
155 // Uniter implements the capabilities of the unit agent. It is not intended to
156 // implement the actual *behaviour* of the unit agent; that responsibility is
157 // delegated to Mode values, which are expected to react to events and direct
158@@ -59,6 +67,9 @@
159 hookLock *fslock.Lock
160
161 ranConfigChanged bool
162+ // The execution observer is only used in tests at this stage. Should this
163+ // need to be extended, perhaps a list of observers would be needed.
164+ observer UniterExecutionObserver
165 }
166
167 // NewUniter creates a new Uniter which will install, run, and upgrade
168@@ -274,23 +285,26 @@
169 // operation is not affected by the error.
170 var errHookFailed = stderrors.New("hook execution failed")
171
172-// runHook executes the supplied hook.Info in an appropriate hook context. If
173-// the hook itself fails to execute, it returns errHookFailed.
174-func (u *Uniter) runHook(hi hook.Info) (err error) {
175- // Prepare context.
176- if err = hi.Validate(); err != nil {
177- return err
178- }
179-
180- hookName := string(hi.Kind)
181- relationId := -1
182- if hi.Kind.IsRelation() {
183- relationId = hi.RelationId
184- if hookName, err = u.relationers[relationId].PrepareHook(hi); err != nil {
185- return err
186- }
187- }
188- hctxId := fmt.Sprintf("%s:%s:%d", u.unit.Name(), hookName, u.rand.Int63())
189+func (u *Uniter) getHookContext(hctxId string, relationId int, remoteUnitName string) (context *HookContext, err error) {
190+
191+ apiAddrs, err := u.st.APIAddresses()
192+ if err != nil {
193+ return nil, err
194+ }
195+ ownerTag, err := u.service.GetOwnerTag()
196+ if err != nil {
197+ return nil, err
198+ }
199+ ctxRelations := map[int]*ContextRelation{}
200+ for id, r := range u.relationers {
201+ ctxRelations[id] = r.Context()
202+ }
203+
204+ return NewHookContext(u.unit, hctxId, u.uuid, relationId, remoteUnitName,
205+ ctxRelations, apiAddrs, ownerTag)
206+}
207+
208+func (u *Uniter) acquireHookLock(message string) (err error) {
209 // We want to make sure we don't block forever when locking, but take the
210 // tomb into account.
211 checkTomb := func() error {
212@@ -302,48 +316,88 @@
213 }
214 return nil
215 }
216- lockMessage := fmt.Sprintf("%s: running hook %q", u.unit.Name(), hookName)
217- if err = u.hookLock.LockWithFunc(lockMessage, checkTomb); err != nil {
218- return err
219- }
220- defer u.hookLock.Unlock()
221-
222- ctxRelations := map[int]*ContextRelation{}
223- for id, r := range u.relationers {
224- ctxRelations[id] = r.Context()
225- }
226- apiAddrs, err := u.st.APIAddresses()
227- if err != nil {
228- return err
229- }
230-
231- ownerTag, err := u.service.GetOwnerTag()
232- if err != nil {
233- return err
234- }
235- hctx, err := NewHookContext(u.unit, hctxId, u.uuid, relationId, hi.RemoteUnit,
236- ctxRelations, apiAddrs, ownerTag)
237- if err != nil {
238- return err
239- }
240-
241+ if err = u.hookLock.LockWithFunc(message, checkTomb); err != nil {
242+ return err
243+ }
244+ return nil
245+}
246+
247+func (u *Uniter) startJujucServer(context *HookContext) (*jujuc.Server, string, error) {
248 // Prepare server.
249 getCmd := func(ctxId, cmdName string) (cmd.Command, error) {
250 // TODO: switch to long-running server with single context;
251 // use nonce in place of context id.
252- if ctxId != hctxId {
253- return nil, fmt.Errorf("expected context id %q, got %q", hctxId, ctxId)
254+ if ctxId != context.id {
255+ return nil, fmt.Errorf("expected context id %q, got %q", context.id, ctxId)
256 }
257- return jujuc.NewCommand(hctx, cmdName)
258+ return jujuc.NewCommand(context, cmdName)
259 }
260 socketPath := filepath.Join(u.baseDir, "agent.socket")
261 // Use abstract namespace so we don't get stale socket files.
262 socketPath = "@" + socketPath
263 srv, err := jujuc.NewServer(getCmd, socketPath)
264 if err != nil {
265- return err
266+ return nil, "", err
267 }
268 go srv.Run()
269+ return srv, socketPath, nil
270+}
271+
272+func (u *Uniter) notifyHookInternal(hook string, hctx *HookContext, method func(string)) {
273+ if r, ok := hctx.HookRelation(); ok {
274+ remote, _ := hctx.RemoteUnitName()
275+ if remote != "" {
276+ remote = " " + remote
277+ }
278+ hook = hook + remote + " " + r.FakeId()
279+ }
280+ method(hook)
281+}
282+
283+func (u *Uniter) notifyHookCompleted(hook string, hctx *HookContext) {
284+ if u.observer != nil {
285+ u.notifyHookInternal(hook, hctx, u.observer.HookCompleted)
286+ }
287+}
288+
289+func (u *Uniter) notifyHookFailed(hook string, hctx *HookContext) {
290+ if u.observer != nil {
291+ u.notifyHookInternal(hook, hctx, u.observer.HookFailed)
292+ }
293+}
294+
295+// runHook executes the supplied hook.Info in an appropriate hook context. If
296+// the hook itself fails to execute, it returns errHookFailed.
297+func (u *Uniter) runHook(hi hook.Info) (err error) {
298+ // Prepare context.
299+ if err = hi.Validate(); err != nil {
300+ return err
301+ }
302+
303+ hookName := string(hi.Kind)
304+ relationId := -1
305+ if hi.Kind.IsRelation() {
306+ relationId = hi.RelationId
307+ if hookName, err = u.relationers[relationId].PrepareHook(hi); err != nil {
308+ return err
309+ }
310+ }
311+ hctxId := fmt.Sprintf("%s:%s:%d", u.unit.Name(), hookName, u.rand.Int63())
312+
313+ lockMessage := fmt.Sprintf("%s: running hook %q", u.unit.Name(), hookName)
314+ if err = u.acquireHookLock(lockMessage); err != nil {
315+ return err
316+ }
317+ defer u.hookLock.Unlock()
318+
319+ hctx, err := u.getHookContext(hctxId, relationId, hi.RemoteUnit)
320+ if err != nil {
321+ return err
322+ }
323+ srv, socketPath, err := u.startJujucServer(hctx)
324+ if err != nil {
325+ return err
326+ }
327 defer srv.Close()
328
329 // Run the hook.
330@@ -351,14 +405,24 @@
331 return err
332 }
333 logger.Infof("running %q hook", hookName)
334- if err := hctx.RunHook(hookName, u.charm.Path(), u.toolsDir, socketPath); err != nil {
335+ ranHook := true
336+ err = hctx.RunHook(hookName, u.charm.Path(), u.toolsDir, socketPath)
337+ if IsMissingHookError(err) {
338+ ranHook = false
339+ } else if err != nil {
340 logger.Errorf("hook failed: %s", err)
341+ u.notifyHookFailed(hookName, hctx)
342 return errHookFailed
343 }
344 if err := u.writeState(RunHook, Done, &hi, nil); err != nil {
345 return err
346 }
347- logger.Infof("ran %q hook", hookName)
348+ if ranHook {
349+ logger.Infof("ran %q hook", hookName)
350+ u.notifyHookCompleted(hookName, hctx)
351+ } else {
352+ logger.Infof("skipped %q hook (missing)", hookName)
353+ }
354 return u.commitHook(hi)
355 }
356
357
358=== modified file 'worker/uniter/uniter_test.go'
359--- worker/uniter/uniter_test.go 2013-11-07 09:09:55 +0000
360+++ worker/uniter/uniter_test.go 2013-12-13 02:48:10 +0000
361@@ -14,9 +14,7 @@
362 "os"
363 "os/exec"
364 "path/filepath"
365- "regexp"
366 "strconv"
367- "strings"
368 stdtesting "testing"
369 "time"
370
371@@ -32,7 +30,7 @@
372 "launchpad.net/juju-core/state/api/params"
373 apiuniter "launchpad.net/juju-core/state/api/uniter"
374 coretesting "launchpad.net/juju-core/testing"
375- "launchpad.net/juju-core/testing/checkers"
376+ jc "launchpad.net/juju-core/testing/checkers"
377 "launchpad.net/juju-core/utils"
378 "launchpad.net/juju-core/utils/fslock"
379 "launchpad.net/juju-core/worker"
380@@ -153,6 +151,18 @@
381 relation *state.Relation
382 relationUnits map[string]*state.RelationUnit
383 subordinate *state.Unit
384+
385+ hooksCompleted []string
386+}
387+
388+var _ uniter.UniterExecutionObserver = (*context)(nil)
389+
390+func (ctx *context) HookCompleted(hookName string) {
391+ ctx.hooksCompleted = append(ctx.hooksCompleted, hookName)
392+}
393+
394+func (ctx *context) HookFailed(hookName string) {
395+ ctx.hooksCompleted = append(ctx.hooksCompleted, "fail-"+hookName)
396 }
397
398 func (ctx *context) run(c *gc.C, steps []stepper) {
399@@ -189,49 +199,17 @@
400 c.Assert(err, gc.IsNil)
401 }
402
403-func (ctx *context) matchLogHooks(c *gc.C) (match bool, overshoot bool) {
404- // TODO(thumper): fix this to actually use a log writer to catch interesting log messages.
405- // hookPattern matches juju-log calls as generated by writeHook.
406- hookPattern := fmt.Sprintf(`^.* INFO juju `+
407- `u/0(| [a-z0-9-]+:[0-9]+)`+ // juju-log badge; group matches relation id
408- `: %s`+ // JUJU_ENV_UUID (context badge; prevents cross-test pollution)
409- ` ([0-9a-z-/ ]+)$`, // foo-relation-joined bar/123
410- ctx.uuid,
411- )
412- // donePattern matches uniter logging that indicates a hook has run.
413- donePattern := `^.* (INFO|ERROR) juju\.worker\.uniter (ran "[a-z0-9-]+" hook|hook failed)`
414- hookRegexp := regexp.MustCompile(hookPattern)
415- doneRegexp := regexp.MustCompile(donePattern)
416-
417- // pending is empty while we scan for a new hook, and holds a value while
418- // we scan for output indicating that hook execution has finished; at which
419- // point, we add it to...
420- pending := ""
421- // ...actual, which holds a list of executed hooks, with basic information
422- // about the relation context, and which will be compared against ctx's
423- // complete list of expected hooks.
424- var actual []string
425- for _, line := range strings.Split(c.GetTestLog(), "\n") {
426- if pending == "" {
427- if parts := hookRegexp.FindStringSubmatch(line); parts != nil {
428- // "hook-name[ JUJU_REMOTE_UNIT]" + "[ JUJU_RELATION_ID]
429- pending = parts[2] + parts[1]
430- }
431- } else if doneRegexp.MatchString(line) {
432- actual = append(actual, pending)
433- pending = ""
434- }
435- }
436- c.Logf("actual: %#v", actual)
437- if len(actual) < len(ctx.hooks) {
438+func (ctx *context) matchHooks(c *gc.C) (match bool, overshoot bool) {
439+ c.Logf("ctx.hooksCompleted: %#v", ctx.hooksCompleted)
440+ if len(ctx.hooksCompleted) < len(ctx.hooks) {
441 return false, false
442 }
443 for i, e := range ctx.hooks {
444- if actual[i] != e {
445+ if ctx.hooksCompleted[i] != e {
446 return false, false
447 }
448 }
449- return true, len(actual) > len(ctx.hooks)
450+ return true, len(ctx.hooksCompleted) > len(ctx.hooks)
451 }
452
453 var startupTests = []uniterTest{
454@@ -827,7 +805,7 @@
455
456 // ignore should not (only in v1)
457 _, err = os.Stat(filepath.Join(ctx.path, "charm", "ignore"))
458- c.Assert(err, checkers.Satisfies, os.IsNotExist)
459+ c.Assert(err, jc.Satisfies, os.IsNotExist)
460
461 // data should contain what was written in the start hook
462 data, err := ioutil.ReadFile(filepath.Join(ctx.path, "charm", "data"))
463@@ -1257,6 +1235,7 @@
464 panic("API connection not established")
465 }
466 ctx.uniter = uniter.NewUniter(ctx.s.uniter, s.unitTag, ctx.dataDir)
467+ uniter.SetUniterObserver(ctx.uniter, ctx)
468 }
469
470 type waitUniterDead struct {
471@@ -1487,7 +1466,7 @@
472 }
473 ctx.hooks = append(ctx.hooks, s...)
474 c.Logf("waiting for hooks: %#v", ctx.hooks)
475- match, overshoot := ctx.matchLogHooks(c)
476+ match, overshoot := ctx.matchHooks(c)
477 if overshoot && len(s) == 0 {
478 c.Fatalf("ran more hooks than expected")
479 }
480@@ -1499,7 +1478,7 @@
481 ctx.s.BackingState.StartSync()
482 select {
483 case <-time.After(coretesting.ShortWait):
484- if match, _ = ctx.matchLogHooks(c); match {
485+ if match, _ = ctx.matchHooks(c); match {
486 return
487 }
488 case <-timeout:
489@@ -1680,7 +1659,7 @@
490 func (s relationState) step(c *gc.C, ctx *context) {
491 err := ctx.relation.Refresh()
492 if s.removed {
493- c.Assert(err, checkers.Satisfies, errors.IsNotFoundError)
494+ c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
495 return
496 }
497 c.Assert(err, gc.IsNil)
498@@ -1908,10 +1887,10 @@
499
500 var verifyHookSyncLockUnlocked = custom{func(c *gc.C, ctx *context) {
501 lock := createHookLock(c, ctx.dataDir)
502- c.Assert(lock.IsLocked(), gc.Equals, false)
503+ c.Assert(lock.IsLocked(), jc.IsFalse)
504 }}
505
506 var verifyHookSyncLockLocked = custom{func(c *gc.C, ctx *context) {
507 lock := createHookLock(c, ctx.dataDir)
508- c.Assert(lock, checkers.Satisfies, (*fslock.Lock).IsLocked)
509+ c.Assert(lock.IsLocked(), jc.IsTrue)
510 }}

Subscribers

People subscribed via source and target branches

to status/vote changes: