1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the LGPLv3, see LICENCE file for details.
4
package migrationflag_test
7
"github.com/juju/errors"
8
"github.com/juju/testing"
9
jc "github.com/juju/testing/checkers"
10
gc "gopkg.in/check.v1"
11
"gopkg.in/juju/names.v2"
13
"github.com/juju/juju/api/base"
14
"github.com/juju/juju/core/migration"
15
"github.com/juju/juju/watcher"
16
"github.com/juju/juju/worker"
17
dt "github.com/juju/juju/worker/dependency/testing"
18
"github.com/juju/juju/worker/migrationflag"
19
"github.com/juju/juju/worker/workertest"
22
// newMockFacade returns a mock Facade that will add calls to the
23
// supplied testing.Stub, and return errors in the sequences it
24
// specifies; if any Phase call does not return an error, it will
25
// return a phase consumed from the head of the supplied list (or
26
// panic if it's empty).
27
func newMockFacade(stub *testing.Stub, phases ...migration.Phase) *mockFacade {
34
// mockFacade implements migrationflag.Facade for use in the tests.
35
type mockFacade struct {
37
phases []migration.Phase
40
// Phase is part of the migrationflag.Facade interface.
41
func (mock *mockFacade) Phase(uuid string) (migration.Phase, error) {
42
mock.stub.AddCall("Phase", uuid)
43
if err := mock.stub.NextErr(); err != nil {
46
return mock.nextPhase(), nil
49
// nextPhase consumes a phase and returns it, or panics.
50
func (mock *mockFacade) nextPhase() migration.Phase {
51
phase := mock.phases[0]
52
mock.phases = mock.phases[1:]
56
// Watch is part of the migrationflag.Facade interface.
57
func (mock *mockFacade) Watch(uuid string) (watcher.NotifyWatcher, error) {
58
mock.stub.AddCall("Watch", uuid)
59
if err := mock.stub.NextErr(); err != nil {
62
return newMockWatcher(), nil
65
// newMockWatcher returns a watcher.NotifyWatcher that always
66
// sends 3 changes and then sits quietly until killed.
67
func newMockWatcher() *mockWatcher {
69
changes := make(chan struct{}, count)
70
for i := 0; i < count; i++ {
74
Worker: workertest.NewErrorWorker(nil),
79
// mockWatcher implements watcher.NotifyWatcher for use in the tests.
80
type mockWatcher struct {
85
// Changes is part of the watcher.NotifyWatcher interface.
86
func (mock *mockWatcher) Changes() watcher.NotifyChannel {
90
// checkCalls checks that all the supplied call names were invoked
91
// in the supplied order, and that every one was passed [validUUID].
92
func checkCalls(c *gc.C, stub *testing.Stub, names ...string) {
93
stub.CheckCallNames(c, names...)
94
for _, call := range stub.Calls() {
95
c.Check(call.Args, jc.DeepEquals, []interface{}{validUUID})
99
// validUUID is the model UUID we're using in the tests.
100
var validUUID = "01234567-89ab-cdef-0123-456789abcdef"
102
// panicCheck is a Config.Check value that should not be called.
103
func panicCheck(migration.Phase) bool { panic("unexpected") }
105
// neverCheck is a Config.Check value that always returns false.
106
func neverCheck(migration.Phase) bool { return false }
108
// panicFacade is a NewFacade that should not be called.
109
func panicFacade(base.APICaller) (migrationflag.Facade, error) {
113
// panicWorker is a NewWorker that should not be called.
114
func panicWorker(migrationflag.Config) (worker.Worker, error) {
118
// isQuiesce is a Config.Check value that returns whether the phase is QUIESCE.
119
func isQuiesce(p migration.Phase) bool { return p == migration.QUIESCE }
121
// validConfig returns a minimal config stuffed with dummy objects that
122
// will explode when used.
123
func validConfig() migrationflag.Config {
124
return migrationflag.Config{
125
Facade: struct{ migrationflag.Facade }{},
131
// checkNotValid checks that the supplied migrationflag.Config fails to
132
// Validate, and cannot be used to construct a migrationflag.Worker.
133
func checkNotValid(c *gc.C, config migrationflag.Config, expect string) {
134
check := func(err error) {
135
c.Check(err, gc.ErrorMatches, expect)
136
c.Check(err, jc.Satisfies, errors.IsNotValid)
139
err := config.Validate()
142
worker, err := migrationflag.New(config)
143
c.Check(worker, gc.IsNil)
147
// validManifoldConfig returns a minimal config stuffed with dummy objects
148
// that will explode when used.
149
func validManifoldConfig() migrationflag.ManifoldConfig {
150
return migrationflag.ManifoldConfig{
151
APICallerName: "api-caller",
153
NewFacade: panicFacade,
154
NewWorker: panicWorker,
158
// checkManifoldNotValid checks that the supplied ManifoldConfig creates
159
// a manifold that cannot be started.
160
func checkManifoldNotValid(c *gc.C, config migrationflag.ManifoldConfig, expect string) {
161
manifold := migrationflag.Manifold(config)
162
worker, err := manifold.Start(dt.StubContext(nil, nil))
163
c.Check(worker, gc.IsNil)
164
c.Check(err, gc.ErrorMatches, expect)
165
c.Check(err, jc.Satisfies, errors.IsNotValid)
168
// stubCaller is a base.APICaller that only implements ModelTag.
169
type stubCaller struct {
173
// ModelTag is part of the base.APICaller interface.
174
func (*stubCaller) ModelTag() (names.ModelTag, error) {
175
return names.NewModelTag(validUUID), nil