-
Notifications
You must be signed in to change notification settings - Fork 153
/
controller.go
58 lines (49 loc) · 1.7 KB
/
controller.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Package controltest provides a controller for use in tests.
package controltest
import (
"context"
"runtime"
"runtime/debug"
"github.com/influxdata/flux"
"github.com/influxdata/flux/control"
)
// Controller embeds a control.Controller.
// It overrides the Query method, to return queries that require Done to be called.
// It accomplishes this by associating a finalizer with the Query that panics,
// and then clears the finalizer when Done is called.
//
// This approach is not foolproof: it is possible that garbage collection may not run during a test,
// and therefore the finalizer will not be invoked.
type Controller struct {
*control.Controller
}
// New returns a new Controller encapsulating c.
func New(c *control.Controller) *Controller {
return &Controller{Controller: c}
}
// Query returns the result of calling Query on the underlying control.Controller,
// wrapped to ensure that callers call Done on the resulting Query.
func (c *Controller) Query(ctx context.Context, compiler flux.Compiler) (flux.Query, error) {
q, err := c.Controller.Query(ctx, compiler)
if err != nil {
return nil, err
}
return newRequireDoneQuery(q), nil
}
// requireDoneQuery is a flux.Query with an associated finalizer that panics if Done is never called.
type requireDoneQuery struct {
flux.Query
}
func newRequireDoneQuery(q flux.Query) *requireDoneQuery {
rdq := &requireDoneQuery{Query: q}
stack := debug.Stack()
runtime.SetFinalizer(rdq, func(*requireDoneQuery) {
panic("Query.Done never called for query created at:\n" + string(stack))
})
return rdq
}
// Done clears the finalizer and calls Done on the underlying Query.
func (rdq *requireDoneQuery) Done() {
runtime.SetFinalizer(rdq, nil)
rdq.Query.Done()
}