github.com/koko1123/flow-go-1@v0.29.6/cmd/node_test.go (about) 1 package cmd 2 3 import ( 4 "errors" 5 "os" 6 "syscall" 7 "testing" 8 9 "github.com/rs/zerolog" 10 "github.com/stretchr/testify/assert" 11 12 "github.com/koko1123/flow-go-1/module/component" 13 "github.com/koko1123/flow-go-1/module/irrecoverable" 14 ) 15 16 func TestRunShutsDownCleanly(t *testing.T) { 17 testLogger := testLog{} 18 logger := zerolog.New(os.Stdout) 19 nodeConfig := &NodeConfig{BaseConfig: BaseConfig{NodeRole: "nodetest"}} 20 postShutdown := func() error { 21 testLogger.Log("running cleanup") 22 return nil 23 } 24 fatalHandler := func(err error) { 25 testLogger.Logf("received fatal error: %s", err) 26 } 27 28 t.Run("Run shuts down gracefully", func(t *testing.T) { 29 testLogger.Reset() 30 manager := component.NewComponentManagerBuilder(). 31 AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 32 testLogger.Log("worker starting up") 33 ready() 34 testLogger.Log("worker startup complete") 35 36 <-ctx.Done() 37 testLogger.Log("worker shutting down") 38 testLogger.Log("worker shutdown complete") 39 }). 40 Build() 41 node := NewNode(manager, nodeConfig, logger, postShutdown, fatalHandler) 42 43 finished := make(chan struct{}) 44 go func() { 45 node.Run() 46 close(finished) 47 }() 48 49 <-node.Ready() 50 51 err := syscall.Kill(syscall.Getpid(), syscall.SIGINT) 52 assert.NoError(t, err) 53 54 <-finished 55 56 assert.Equal(t, []string{ 57 "worker starting up", 58 "worker startup complete", 59 "worker shutting down", 60 "worker shutdown complete", 61 "running cleanup", 62 }, testLogger.logs) 63 }) 64 65 t.Run("Run encounters error during postShutdown", func(t *testing.T) { 66 testLogger.Reset() 67 manager := component.NewComponentManagerBuilder(). 68 AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 69 testLogger.Log("worker starting up") 70 ready() 71 testLogger.Log("worker startup complete") 72 73 <-ctx.Done() 74 testLogger.Log("worker shutting down") 75 testLogger.Log("worker shutdown complete") 76 }). 77 Build() 78 node := NewNode(manager, nodeConfig, logger, func() error { 79 testLogger.Log("error during post shutdown") 80 return errors.New("error during post shutdown") 81 }, fatalHandler) 82 83 finished := make(chan struct{}) 84 go func() { 85 node.Run() 86 close(finished) 87 }() 88 89 <-node.Ready() 90 91 err := syscall.Kill(syscall.Getpid(), syscall.SIGINT) 92 assert.NoError(t, err) 93 94 <-finished 95 96 assert.Equal(t, []string{ 97 "worker starting up", 98 "worker startup complete", 99 "worker shutting down", 100 "worker shutdown complete", 101 "error during post shutdown", 102 }, testLogger.logs) 103 }) 104 105 t.Run("Run encounters irrecoverable error during startup", func(t *testing.T) { 106 testLogger.Reset() 107 manager := component.NewComponentManagerBuilder(). 108 AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 109 testLogger.Log("worker starting up") 110 111 // throw an irrecoverable error 112 ctx.Throw(errors.New("worker startup error")) 113 114 ready() 115 testLogger.Log("worker startup complete") 116 117 <-ctx.Done() 118 testLogger.Log("worker shutting down") 119 testLogger.Log("worker shutdown complete") 120 }). 121 Build() 122 node := NewNode(manager, nodeConfig, logger, postShutdown, fatalHandler) 123 124 finished := make(chan struct{}) 125 go func() { 126 node.Run() 127 close(finished) 128 }() 129 130 <-finished 131 132 assert.Equal(t, []string{ 133 "worker starting up", 134 "received fatal error: worker startup error", 135 }, testLogger.logs) 136 }) 137 138 t.Run("Run encounters irrecoverable error during runtime", func(t *testing.T) { 139 testLogger.Reset() 140 manager := component.NewComponentManagerBuilder(). 141 AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 142 testLogger.Log("worker starting up") 143 ready() 144 testLogger.Log("worker startup complete") 145 146 // throw an irrecoverable error 147 ctx.Throw(errors.New("worker runtime error")) 148 149 <-ctx.Done() 150 testLogger.Log("worker shutting down") 151 testLogger.Log("worker shutdown complete") 152 }). 153 Build() 154 node := NewNode(manager, nodeConfig, logger, postShutdown, func(err error) { 155 testLogger.Log("received fatal error: " + err.Error()) 156 }) 157 158 finished := make(chan struct{}) 159 go func() { 160 node.Run() 161 close(finished) 162 }() 163 164 <-finished 165 166 assert.Equal(t, []string{ 167 "worker starting up", 168 "worker startup complete", 169 "received fatal error: worker runtime error", 170 }, testLogger.logs) 171 }) 172 173 t.Run("Run encounters irrecoverable error during shutdown", func(t *testing.T) { 174 testLogger.Reset() 175 manager := component.NewComponentManagerBuilder(). 176 AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 177 testLogger.Log("worker starting up") 178 ready() 179 testLogger.Log("worker startup complete") 180 181 <-ctx.Done() 182 testLogger.Log("worker shutting down") 183 184 // throw an irrecoverable error 185 ctx.Throw(errors.New("worker shutdown error")) 186 187 testLogger.Log("worker shutdown complete") 188 }). 189 Build() 190 node := NewNode(manager, nodeConfig, logger, postShutdown, fatalHandler) 191 192 finished := make(chan struct{}) 193 go func() { 194 node.Run() 195 close(finished) 196 }() 197 198 <-node.Ready() 199 200 err := syscall.Kill(syscall.Getpid(), syscall.SIGINT) 201 assert.NoError(t, err) 202 203 <-finished 204 205 assert.Equal(t, []string{ 206 "worker starting up", 207 "worker startup complete", 208 "worker shutting down", 209 "received fatal error: worker shutdown error", 210 }, testLogger.logs) 211 }) 212 }