github.com/mongodb/grip@v0.0.0-20240213223901-f906268d82b9/recovery/recovery_test.go (about)

     1  package recovery
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/mongodb/grip"
    10  	"github.com/mongodb/grip/logging"
    11  	"github.com/mongodb/grip/message"
    12  	"github.com/mongodb/grip/send"
    13  	"github.com/stretchr/testify/suite"
    14  )
    15  
    16  type RecoverySuite struct {
    17  	sender       *send.InternalSender
    18  	globalSender send.Sender
    19  	suite.Suite
    20  }
    21  
    22  func TestRecoverySuite(t *testing.T) {
    23  	suite.Run(t, new(RecoverySuite))
    24  }
    25  
    26  func (s *RecoverySuite) SetupSuite() {
    27  	s.Require().NoError(os.Setenv(killOverrideVarName, "true"))
    28  }
    29  
    30  func (s *RecoverySuite) TearDownSuite() {
    31  	s.Require().NoError(os.Setenv(killOverrideVarName, ""))
    32  }
    33  
    34  func (s *RecoverySuite) SetupTest() {
    35  	s.sender = send.MakeInternalLogger()
    36  	s.globalSender = grip.GetSender()
    37  	s.Require().NoError(grip.SetSender(s.sender))
    38  }
    39  
    40  func (s *RecoverySuite) logger() grip.Journaler { return logging.MakeGrip(s.sender) }
    41  
    42  func (s *RecoverySuite) TearDownTest() {
    43  	s.Require().NoError(grip.SetSender(s.globalSender))
    44  }
    45  
    46  func (s *RecoverySuite) TestWithoutPanicNoErrorsLoged() {
    47  	s.False(s.sender.HasMessage())
    48  	LogStackTraceAndContinue()
    49  	s.False(s.sender.HasMessage())
    50  	LogStackTraceAndExit()
    51  	s.False(s.sender.HasMessage())
    52  	s.NoError(HandlePanicWithError(nil, nil))
    53  	s.False(s.sender.HasMessage())
    54  }
    55  
    56  func (s *RecoverySuite) TestPanicCausesLogsWithContinueRecoverer() {
    57  	s.False(s.sender.HasMessage())
    58  	s.NotPanics(func() {
    59  		defer LogStackTraceAndContinue()
    60  		panic("sorry")
    61  	})
    62  	s.True(s.sender.HasMessage())
    63  	msg, ok := s.sender.GetMessageSafe()
    64  	s.True(ok)
    65  	s.Contains(msg.Rendered, "hit panic; recovering")
    66  	s.Contains(msg.Rendered, "sorry")
    67  }
    68  
    69  func (s *RecoverySuite) TestPanicsCausesLogsWithExitHandler() {
    70  	s.False(s.sender.HasMessage())
    71  	s.NotPanics(func() {
    72  		defer LogStackTraceAndExit("exit op")
    73  		panic("sorry buddy")
    74  	})
    75  	s.True(s.sender.HasMessage())
    76  	msg, ok := s.sender.GetMessageSafe()
    77  	s.True(ok)
    78  	s.True(strings.Contains(msg.Rendered, "hit panic; exiting"))
    79  	s.True(strings.Contains(msg.Rendered, "sorry buddy"))
    80  	s.True(strings.Contains(msg.Rendered, "exit op"))
    81  }
    82  
    83  func (s *RecoverySuite) TestPanicCausesLogsWithErrorHandler() {
    84  	s.False(s.sender.HasMessage())
    85  	s.NotPanics(func() {
    86  		err := func() (err error) {
    87  			defer func() { err = HandlePanicWithError(recover(), nil) }()
    88  			panic("get a grip")
    89  		}()
    90  
    91  		s.Error(err)
    92  		s.True(strings.Contains(err.Error(), "get a grip"))
    93  	})
    94  	s.True(s.sender.HasMessage())
    95  	msg, ok := s.sender.GetMessageSafe()
    96  	s.True(ok)
    97  	s.True(strings.Contains(msg.Rendered, "hit panic; adding error"))
    98  	s.True(strings.Contains(msg.Rendered, "get a grip"))
    99  }
   100  
   101  func (s *RecoverySuite) TestErrorHandlerPropogatesErrorAndPanicMessage() {
   102  	s.NotPanics(func() {
   103  		err := func() (err error) {
   104  			defer func() { err = HandlePanicWithError(recover(), errors.New("bar"), "this op name") }()
   105  			panic("got grip")
   106  		}()
   107  
   108  		s.Error(err)
   109  		s.True(strings.Contains(err.Error(), "got grip"))
   110  		s.True(strings.Contains(err.Error(), "bar"))
   111  		s.False(strings.Contains(err.Error(), "op name"))
   112  	})
   113  
   114  	s.True(s.sender.HasMessage())
   115  	msg, ok := s.sender.GetMessageSafe()
   116  	s.True(ok)
   117  	s.Contains(msg.Rendered, "this op name")
   118  	s.Contains(msg.Rendered, "got grip")
   119  	s.Contains(msg.Rendered, "bar")
   120  }
   121  
   122  func (s *RecoverySuite) TestPanicHandlerWithErrorPropogatesErrorWithoutPanic() {
   123  	err := HandlePanicWithError(nil, errors.New("foo"))
   124  	s.Error(err)
   125  	s.True(strings.Contains(err.Error(), "foo"))
   126  }
   127  
   128  func (s *RecoverySuite) TestPanicHandlerPropogatesOperationName() {
   129  	s.False(s.sender.HasMessage())
   130  	s.NotPanics(func() {
   131  		defer LogStackTraceAndContinue("test handler op")
   132  		panic("sorry")
   133  	})
   134  	s.True(s.sender.HasMessage())
   135  	msg, ok := s.sender.GetMessageSafe()
   136  	s.True(ok)
   137  	s.True(strings.Contains(msg.Rendered, "test handler op"))
   138  }
   139  
   140  func (s *RecoverySuite) TestPanicHandlerPropogatesOperationNameWithArgs() {
   141  	s.False(s.sender.HasMessage())
   142  	s.NotPanics(func() {
   143  		defer LogStackTraceAndContinue("test handler op", "for real")
   144  		panic("sorry")
   145  	})
   146  	s.True(s.sender.HasMessage())
   147  	msg, ok := s.sender.GetMessageSafe()
   148  	s.True(ok)
   149  	s.True(strings.Contains(msg.Rendered, "test handler op for real"))
   150  }
   151  
   152  func (s *RecoverySuite) TestPanicHandlerAnnotationPropogagaesMessage() {
   153  	s.False(s.sender.HasMessage())
   154  	s.NotPanics(func() {
   155  		defer AnnotateMessageWithStackTraceAndContinue(message.Fields{"foo": "test handler op1 for real"})
   156  		panic("sorry")
   157  	})
   158  	s.True(s.sender.HasMessage())
   159  	msg, ok := s.sender.GetMessageSafe()
   160  	s.True(ok)
   161  	s.True(strings.Contains(msg.Rendered, "test handler op1 for real"))
   162  
   163  }
   164  
   165  func (s *RecoverySuite) TestPanicsCausesAnnotateLogsWithExitHandler() {
   166  	s.False(s.sender.HasMessage())
   167  	s.NotPanics(func() {
   168  		defer AnnotateMessageWithStackTraceAndExit(message.Fields{"foo": "exit op1"})
   169  		panic("sorry buddy")
   170  	})
   171  	s.True(s.sender.HasMessage())
   172  	msg, ok := s.sender.GetMessageSafe()
   173  	s.True(ok)
   174  	s.True(strings.Contains(msg.Rendered, "hit panic; exiting"))
   175  	s.True(strings.Contains(msg.Rendered, "sorry buddy"))
   176  	s.True(strings.Contains(msg.Rendered, "exit op1"))
   177  }
   178  
   179  func (s *RecoverySuite) TestPanicAnnotatesLogsWithErrorHandler() {
   180  	s.False(s.sender.HasMessage())
   181  	s.NotPanics(func() {
   182  		err := func() (err error) {
   183  			defer func() { err = AnnotateMessageWithPanicError(recover(), nil, message.Fields{"foo": "bar"}) }()
   184  			panic("get a grip")
   185  		}()
   186  
   187  		s.Error(err)
   188  		s.True(strings.Contains(err.Error(), "get a grip"))
   189  	})
   190  	s.True(s.sender.HasMessage())
   191  	msg, ok := s.sender.GetMessageSafe()
   192  	s.True(ok)
   193  	s.True(strings.Contains(msg.Rendered, "hit panic; adding error"))
   194  	s.True(strings.Contains(msg.Rendered, "get a grip"))
   195  	s.True(strings.Contains(msg.Rendered, "foo='bar'"))
   196  }
   197  
   198  func (s *RecoverySuite) TestPanicHandlerSendJournalerPropogagaesMessage() {
   199  	s.False(s.sender.HasMessage())
   200  	s.NotPanics(func() {
   201  		defer SendStackTraceAndContinue(s.logger(), message.Fields{"foo": "test handler op2 for real"})
   202  		panic("sorry")
   203  	})
   204  	s.True(s.sender.HasMessage())
   205  	msg, ok := s.sender.GetMessageSafe()
   206  	s.True(ok)
   207  	s.True(strings.Contains(msg.Rendered, "test handler op2 for real"))
   208  
   209  }
   210  
   211  func (s *RecoverySuite) TestPanicsCausesSendJournalerLogsWithExitHandler() {
   212  	s.False(s.sender.HasMessage())
   213  	s.NotPanics(func() {
   214  		defer SendStackTraceMessageAndExit(s.logger(), message.Fields{"foo": "exit op2"})
   215  		panic("sorry buddy")
   216  	})
   217  	s.True(s.sender.HasMessage())
   218  	msg, ok := s.sender.GetMessageSafe()
   219  	s.True(ok)
   220  	s.True(strings.Contains(msg.Rendered, "hit panic; exiting"))
   221  	s.True(strings.Contains(msg.Rendered, "sorry buddy"))
   222  	s.True(strings.Contains(msg.Rendered, "exit op2"))
   223  }
   224  
   225  func (s *RecoverySuite) TestPanicSendJournalerLogsWithErrorHandler() {
   226  	s.False(s.sender.HasMessage())
   227  	s.NotPanics(func() {
   228  		err := func() (err error) {
   229  			defer func() { err = SendMessageWithPanicError(recover(), nil, s.logger(), message.Fields{"foo": "bar1"}) }()
   230  			panic("get a grip")
   231  		}()
   232  
   233  		s.Error(err)
   234  		s.True(strings.Contains(err.Error(), "get a grip"))
   235  	})
   236  	s.True(s.sender.HasMessage())
   237  	msg, ok := s.sender.GetMessageSafe()
   238  	s.True(ok)
   239  	s.True(strings.Contains(msg.Rendered, "hit panic; adding error"))
   240  	s.True(strings.Contains(msg.Rendered, "get a grip"))
   241  	s.True(strings.Contains(msg.Rendered, "foo='bar1'"))
   242  }