github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/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/onflow/flow-go/module/component"
    13  	"github.com/onflow/flow-go/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  }