github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/migrationflag/util_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package migrationflag_test 5 6 import ( 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" 12 "gopkg.in/juju/worker.v1" 13 dt "gopkg.in/juju/worker.v1/dependency/testing" 14 "gopkg.in/juju/worker.v1/workertest" 15 16 "github.com/juju/juju/api/base" 17 "github.com/juju/juju/core/migration" 18 "github.com/juju/juju/core/watcher" 19 "github.com/juju/juju/worker/migrationflag" 20 ) 21 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 { 28 return &mockFacade{ 29 stub: stub, 30 phases: phases, 31 } 32 } 33 34 // mockFacade implements migrationflag.Facade for use in the tests. 35 type mockFacade struct { 36 stub *testing.Stub 37 phases []migration.Phase 38 } 39 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 { 44 return 0, err 45 } 46 return mock.nextPhase(), nil 47 } 48 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:] 53 return phase 54 } 55 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 { 60 return nil, err 61 } 62 return newMockWatcher(), nil 63 } 64 65 // newMockWatcher returns a watcher.NotifyWatcher that always 66 // sends 3 changes and then sits quietly until killed. 67 func newMockWatcher() *mockWatcher { 68 const count = 3 69 changes := make(chan struct{}, count) 70 for i := 0; i < count; i++ { 71 changes <- struct{}{} 72 } 73 return &mockWatcher{ 74 Worker: workertest.NewErrorWorker(nil), 75 changes: changes, 76 } 77 } 78 79 // mockWatcher implements watcher.NotifyWatcher for use in the tests. 80 type mockWatcher struct { 81 worker.Worker 82 changes chan struct{} 83 } 84 85 // Changes is part of the watcher.NotifyWatcher interface. 86 func (mock *mockWatcher) Changes() watcher.NotifyChannel { 87 return mock.changes 88 } 89 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}) 96 } 97 } 98 99 // validUUID is the model UUID we're using in the tests. 100 var validUUID = "01234567-89ab-cdef-0123-456789abcdef" 101 102 // panicCheck is a Config.Check value that should not be called. 103 func panicCheck(migration.Phase) bool { panic("unexpected") } 104 105 // neverCheck is a Config.Check value that always returns false. 106 func neverCheck(migration.Phase) bool { return false } 107 108 // panicFacade is a NewFacade that should not be called. 109 func panicFacade(base.APICaller) (migrationflag.Facade, error) { 110 panic("panicFacade") 111 } 112 113 // panicWorker is a NewWorker that should not be called. 114 func panicWorker(migrationflag.Config) (worker.Worker, error) { 115 panic("panicWorker") 116 } 117 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 } 120 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 }{}, 126 Model: validUUID, 127 Check: panicCheck, 128 } 129 } 130 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) 137 } 138 139 err := config.Validate() 140 check(err) 141 142 worker, err := migrationflag.New(config) 143 c.Check(worker, gc.IsNil) 144 check(err) 145 } 146 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", 152 Check: panicCheck, 153 NewFacade: panicFacade, 154 NewWorker: panicWorker, 155 } 156 } 157 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) 166 } 167 168 // stubCaller is a base.APICaller that only implements ModelTag. 169 type stubCaller struct { 170 base.APICaller 171 } 172 173 // ModelTag is part of the base.APICaller interface. 174 func (*stubCaller) ModelTag() (names.ModelTag, bool) { 175 return names.NewModelTag(validUUID), true 176 }