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 }