github.com/newrelic/go-agent@v3.26.0+incompatible/internal_errors_test.go (about) 1 // Copyright 2020 New Relic Corporation. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package newrelic 5 6 import ( 7 "encoding/json" 8 "runtime" 9 "strconv" 10 "testing" 11 12 "github.com/newrelic/go-agent/internal" 13 ) 14 15 type myError struct{} 16 17 func (e myError) Error() string { return "my msg" } 18 19 func TestNoticeErrorBackground(t *testing.T) { 20 app := testApp(nil, nil, t) 21 txn := app.StartTransaction("hello", nil, nil) 22 err := txn.NoticeError(myError{}) 23 if nil != err { 24 t.Error(err) 25 } 26 txn.End() 27 app.ExpectErrors(t, []internal.WantError{{ 28 TxnName: "OtherTransaction/Go/hello", 29 Msg: "my msg", 30 Klass: "newrelic.myError", 31 }}) 32 app.ExpectErrorEvents(t, []internal.WantEvent{{ 33 Intrinsics: map[string]interface{}{ 34 "error.class": "newrelic.myError", 35 "error.message": "my msg", 36 "transactionName": "OtherTransaction/Go/hello", 37 }, 38 }}) 39 app.ExpectMetrics(t, backgroundErrorMetrics) 40 } 41 42 func TestNoticeErrorWeb(t *testing.T) { 43 app := testApp(nil, nil, t) 44 txn := app.StartTransaction("hello", nil, helloRequest) 45 err := txn.NoticeError(myError{}) 46 if nil != err { 47 t.Error(err) 48 } 49 txn.End() 50 app.ExpectErrors(t, []internal.WantError{{ 51 TxnName: "WebTransaction/Go/hello", 52 Msg: "my msg", 53 Klass: "newrelic.myError", 54 }}) 55 app.ExpectErrorEvents(t, []internal.WantEvent{{ 56 Intrinsics: map[string]interface{}{ 57 "error.class": "newrelic.myError", 58 "error.message": "my msg", 59 "transactionName": "WebTransaction/Go/hello", 60 }, 61 AgentAttributes: helloRequestAttributes, 62 }}) 63 app.ExpectMetrics(t, webErrorMetrics) 64 } 65 66 func TestNoticeErrorTxnEnded(t *testing.T) { 67 app := testApp(nil, nil, t) 68 txn := app.StartTransaction("hello", nil, nil) 69 txn.End() 70 err := txn.NoticeError(myError{}) 71 if err != errAlreadyEnded { 72 t.Error(err) 73 } 74 txn.End() 75 app.ExpectErrors(t, []internal.WantError{}) 76 app.ExpectErrorEvents(t, []internal.WantEvent{}) 77 app.ExpectMetrics(t, backgroundMetrics) 78 } 79 80 func TestNoticeErrorHighSecurity(t *testing.T) { 81 cfgFn := func(cfg *Config) { cfg.HighSecurity = true } 82 app := testApp(nil, cfgFn, t) 83 txn := app.StartTransaction("hello", nil, nil) 84 err := txn.NoticeError(myError{}) 85 if nil != err { 86 t.Error(err) 87 } 88 txn.End() 89 app.ExpectErrors(t, []internal.WantError{{ 90 TxnName: "OtherTransaction/Go/hello", 91 Msg: highSecurityErrorMsg, 92 Klass: "newrelic.myError", 93 }}) 94 app.ExpectErrorEvents(t, []internal.WantEvent{{ 95 Intrinsics: map[string]interface{}{ 96 "error.class": "newrelic.myError", 97 "error.message": highSecurityErrorMsg, 98 "transactionName": "OtherTransaction/Go/hello", 99 }, 100 }}) 101 app.ExpectMetrics(t, backgroundErrorMetrics) 102 } 103 104 func TestNoticeErrorMessageSecurityPolicy(t *testing.T) { 105 replyfn := func(reply *internal.ConnectReply) { reply.SecurityPolicies.AllowRawExceptionMessages.SetEnabled(false) } 106 app := testApp(replyfn, nil, t) 107 txn := app.StartTransaction("hello", nil, nil) 108 err := txn.NoticeError(myError{}) 109 if nil != err { 110 t.Error(err) 111 } 112 txn.End() 113 app.ExpectErrors(t, []internal.WantError{{ 114 TxnName: "OtherTransaction/Go/hello", 115 Msg: securityPolicyErrorMsg, 116 Klass: "newrelic.myError", 117 }}) 118 app.ExpectErrorEvents(t, []internal.WantEvent{{ 119 Intrinsics: map[string]interface{}{ 120 "error.class": "newrelic.myError", 121 "error.message": securityPolicyErrorMsg, 122 "transactionName": "OtherTransaction/Go/hello", 123 }, 124 }}) 125 app.ExpectMetrics(t, backgroundErrorMetrics) 126 } 127 128 func TestNoticeErrorLocallyDisabled(t *testing.T) { 129 cfgFn := func(cfg *Config) { cfg.ErrorCollector.Enabled = false } 130 app := testApp(nil, cfgFn, t) 131 txn := app.StartTransaction("hello", nil, nil) 132 err := txn.NoticeError(myError{}) 133 if errorsDisabled != err { 134 t.Error(err) 135 } 136 txn.End() 137 app.ExpectErrors(t, []internal.WantError{}) 138 app.ExpectErrorEvents(t, []internal.WantEvent{}) 139 app.ExpectMetrics(t, backgroundMetrics) 140 } 141 142 func TestErrorsDisabledByServerSideConfig(t *testing.T) { 143 // Test that errors can be disabled by server-side-config. 144 cfgFn := func(cfg *Config) {} 145 replyfn := func(reply *internal.ConnectReply) { 146 json.Unmarshal([]byte(`{"agent_config":{"error_collector.enabled":false}}`), reply) 147 } 148 app := testApp(replyfn, cfgFn, t) 149 txn := app.StartTransaction("hello", nil, nil) 150 err := txn.NoticeError(myError{}) 151 if errorsDisabled != err { 152 t.Error(err) 153 } 154 txn.End() 155 app.ExpectErrors(t, []internal.WantError{}) 156 app.ExpectErrorEvents(t, []internal.WantEvent{}) 157 app.ExpectMetrics(t, backgroundMetrics) 158 } 159 160 func TestErrorsEnabledByServerSideConfig(t *testing.T) { 161 // Test that errors can be enabled by server-side-config. 162 cfgFn := func(cfg *Config) { 163 cfg.ErrorCollector.Enabled = false 164 } 165 replyfn := func(reply *internal.ConnectReply) { 166 json.Unmarshal([]byte(`{"agent_config":{"error_collector.enabled":true}}`), reply) 167 } 168 app := testApp(replyfn, cfgFn, t) 169 txn := app.StartTransaction("hello", nil, nil) 170 err := txn.NoticeError(myError{}) 171 if nil != err { 172 t.Error(err) 173 } 174 txn.End() 175 app.ExpectErrors(t, []internal.WantError{{ 176 TxnName: "OtherTransaction/Go/hello", 177 Msg: "my msg", 178 Klass: "newrelic.myError", 179 }}) 180 app.ExpectErrorEvents(t, []internal.WantEvent{{ 181 Intrinsics: map[string]interface{}{ 182 "error.class": "newrelic.myError", 183 "error.message": "my msg", 184 "transactionName": "OtherTransaction/Go/hello", 185 }, 186 UserAttributes: map[string]interface{}{}, 187 AgentAttributes: map[string]interface{}{}, 188 }}) 189 app.ExpectMetrics(t, backgroundErrorMetrics) 190 } 191 192 func TestNoticeErrorTracedErrorsRemotelyDisabled(t *testing.T) { 193 // This tests that the connect reply field "collect_errors" controls the 194 // collection of traced-errors, not error-events. 195 replyfn := func(reply *internal.ConnectReply) { reply.CollectErrors = false } 196 app := testApp(replyfn, nil, t) 197 txn := app.StartTransaction("hello", nil, nil) 198 err := txn.NoticeError(myError{}) 199 if err != nil { 200 t.Error(err) 201 } 202 txn.End() 203 app.ExpectErrors(t, []internal.WantError{}) 204 app.ExpectErrorEvents(t, []internal.WantEvent{{ 205 Intrinsics: map[string]interface{}{ 206 "error.class": "newrelic.myError", 207 "error.message": "my msg", 208 "transactionName": "OtherTransaction/Go/hello", 209 }, 210 UserAttributes: map[string]interface{}{}, 211 AgentAttributes: map[string]interface{}{}, 212 }}) 213 app.ExpectMetrics(t, backgroundErrorMetrics) 214 } 215 216 func TestNoticeErrorNil(t *testing.T) { 217 app := testApp(nil, nil, t) 218 txn := app.StartTransaction("hello", nil, nil) 219 err := txn.NoticeError(nil) 220 if errNilError != err { 221 t.Error(err) 222 } 223 txn.End() 224 app.ExpectErrors(t, []internal.WantError{}) 225 app.ExpectErrorEvents(t, []internal.WantEvent{}) 226 app.ExpectMetrics(t, backgroundMetrics) 227 } 228 229 func TestNoticeErrorEventsLocallyDisabled(t *testing.T) { 230 cfgFn := func(cfg *Config) { cfg.ErrorCollector.CaptureEvents = false } 231 app := testApp(nil, cfgFn, t) 232 txn := app.StartTransaction("hello", nil, nil) 233 err := txn.NoticeError(myError{}) 234 if nil != err { 235 t.Error(err) 236 } 237 txn.End() 238 app.ExpectErrors(t, []internal.WantError{{ 239 TxnName: "OtherTransaction/Go/hello", 240 Msg: "my msg", 241 Klass: "newrelic.myError", 242 }}) 243 app.ExpectErrorEvents(t, []internal.WantEvent{}) 244 app.ExpectMetrics(t, backgroundErrorMetrics) 245 } 246 247 func TestNoticeErrorEventsRemotelyDisabled(t *testing.T) { 248 replyfn := func(reply *internal.ConnectReply) { reply.CollectErrorEvents = false } 249 app := testApp(replyfn, nil, t) 250 txn := app.StartTransaction("hello", nil, nil) 251 err := txn.NoticeError(myError{}) 252 if nil != err { 253 t.Error(err) 254 } 255 txn.End() 256 app.ExpectErrors(t, []internal.WantError{{ 257 TxnName: "OtherTransaction/Go/hello", 258 Msg: "my msg", 259 Klass: "newrelic.myError", 260 }}) 261 app.ExpectErrorEvents(t, []internal.WantEvent{}) 262 app.ExpectMetrics(t, backgroundErrorMetrics) 263 } 264 265 type errorWithClass struct{ class string } 266 267 func (e errorWithClass) Error() string { return "my msg" } 268 func (e errorWithClass) ErrorClass() string { return e.class } 269 270 func TestErrorWithClasser(t *testing.T) { 271 app := testApp(nil, nil, t) 272 txn := app.StartTransaction("hello", nil, nil) 273 err := txn.NoticeError(errorWithClass{class: "zap"}) 274 if nil != err { 275 t.Error(err) 276 } 277 txn.End() 278 app.ExpectErrors(t, []internal.WantError{{ 279 TxnName: "OtherTransaction/Go/hello", 280 Msg: "my msg", 281 Klass: "zap", 282 }}) 283 app.ExpectErrorEvents(t, []internal.WantEvent{{ 284 Intrinsics: map[string]interface{}{ 285 "error.class": "zap", 286 "error.message": "my msg", 287 "transactionName": "OtherTransaction/Go/hello", 288 }, 289 }}) 290 app.ExpectMetrics(t, backgroundErrorMetrics) 291 } 292 293 func TestErrorWithClasserReturnsEmpty(t *testing.T) { 294 app := testApp(nil, nil, t) 295 txn := app.StartTransaction("hello", nil, nil) 296 err := txn.NoticeError(errorWithClass{class: ""}) 297 if nil != err { 298 t.Error(err) 299 } 300 txn.End() 301 app.ExpectErrors(t, []internal.WantError{{ 302 TxnName: "OtherTransaction/Go/hello", 303 Msg: "my msg", 304 Klass: "newrelic.errorWithClass", 305 }}) 306 app.ExpectErrorEvents(t, []internal.WantEvent{{ 307 Intrinsics: map[string]interface{}{ 308 "error.class": "newrelic.errorWithClass", 309 "error.message": "my msg", 310 "transactionName": "OtherTransaction/Go/hello", 311 }, 312 }}) 313 app.ExpectMetrics(t, backgroundErrorMetrics) 314 } 315 316 type withStackTrace struct{ trace []uintptr } 317 318 func makeErrorWithStackTrace() error { 319 callers := make([]uintptr, 20) 320 written := runtime.Callers(1, callers) 321 return withStackTrace{ 322 trace: callers[0:written], 323 } 324 } 325 326 func (e withStackTrace) Error() string { return "my msg" } 327 func (e withStackTrace) StackTrace() []uintptr { return e.trace } 328 329 func TestErrorWithStackTrace(t *testing.T) { 330 app := testApp(nil, nil, t) 331 txn := app.StartTransaction("hello", nil, nil) 332 e := makeErrorWithStackTrace() 333 err := txn.NoticeError(e) 334 if nil != err { 335 t.Error(err) 336 } 337 txn.End() 338 app.ExpectErrors(t, []internal.WantError{{ 339 TxnName: "OtherTransaction/Go/hello", 340 Msg: "my msg", 341 Klass: "newrelic.withStackTrace", 342 }}) 343 app.ExpectErrorEvents(t, []internal.WantEvent{{ 344 Intrinsics: map[string]interface{}{ 345 "error.class": "newrelic.withStackTrace", 346 "error.message": "my msg", 347 "transactionName": "OtherTransaction/Go/hello", 348 }, 349 }}) 350 app.ExpectMetrics(t, backgroundErrorMetrics) 351 } 352 353 func TestErrorWithStackTraceReturnsNil(t *testing.T) { 354 app := testApp(nil, nil, t) 355 txn := app.StartTransaction("hello", nil, nil) 356 e := withStackTrace{trace: nil} 357 err := txn.NoticeError(e) 358 if nil != err { 359 t.Error(err) 360 } 361 txn.End() 362 app.ExpectErrors(t, []internal.WantError{{ 363 TxnName: "OtherTransaction/Go/hello", 364 Msg: "my msg", 365 Klass: "newrelic.withStackTrace", 366 }}) 367 app.ExpectErrorEvents(t, []internal.WantEvent{{ 368 Intrinsics: map[string]interface{}{ 369 "error.class": "newrelic.withStackTrace", 370 "error.message": "my msg", 371 "transactionName": "OtherTransaction/Go/hello", 372 }, 373 }}) 374 app.ExpectMetrics(t, backgroundErrorMetrics) 375 } 376 377 func TestNewrelicErrorNoAttributes(t *testing.T) { 378 app := testApp(nil, nil, t) 379 txn := app.StartTransaction("hello", nil, nil) 380 err := txn.NoticeError(Error{ 381 Message: "my msg", 382 Class: "my class", 383 }) 384 if nil != err { 385 t.Error(err) 386 } 387 txn.End() 388 app.ExpectErrors(t, []internal.WantError{{ 389 TxnName: "OtherTransaction/Go/hello", 390 Msg: "my msg", 391 Klass: "my class", 392 }}) 393 app.ExpectErrorEvents(t, []internal.WantEvent{{ 394 Intrinsics: map[string]interface{}{ 395 "error.class": "my class", 396 "error.message": "my msg", 397 "transactionName": "OtherTransaction/Go/hello", 398 }, 399 }}) 400 app.ExpectMetrics(t, backgroundErrorMetrics) 401 } 402 403 func TestNewrelicErrorValidAttributes(t *testing.T) { 404 extraAttributes := map[string]interface{}{ 405 "zip": "zap", 406 } 407 app := testApp(nil, nil, t) 408 txn := app.StartTransaction("hello", nil, nil) 409 err := txn.NoticeError(Error{ 410 Message: "my msg", 411 Class: "my class", 412 Attributes: extraAttributes, 413 }) 414 if nil != err { 415 t.Error(err) 416 } 417 txn.End() 418 app.ExpectErrors(t, []internal.WantError{{ 419 TxnName: "OtherTransaction/Go/hello", 420 Msg: "my msg", 421 Klass: "my class", 422 UserAttributes: extraAttributes, 423 }}) 424 app.ExpectErrorEvents(t, []internal.WantEvent{{ 425 Intrinsics: map[string]interface{}{ 426 "error.class": "my class", 427 "error.message": "my msg", 428 "transactionName": "OtherTransaction/Go/hello", 429 }, 430 UserAttributes: extraAttributes, 431 }}) 432 app.ExpectMetrics(t, backgroundErrorMetrics) 433 } 434 435 func TestNewrelicErrorAttributesHighSecurity(t *testing.T) { 436 extraAttributes := map[string]interface{}{ 437 "zip": "zap", 438 } 439 cfgFn := func(cfg *Config) { cfg.HighSecurity = true } 440 app := testApp(nil, cfgFn, t) 441 txn := app.StartTransaction("hello", nil, nil) 442 err := txn.NoticeError(Error{ 443 Message: "my msg", 444 Class: "my class", 445 Attributes: extraAttributes, 446 }) 447 if nil != err { 448 t.Error(err) 449 } 450 txn.End() 451 app.ExpectErrors(t, []internal.WantError{{ 452 TxnName: "OtherTransaction/Go/hello", 453 Msg: "message removed by high security setting", 454 Klass: "my class", 455 UserAttributes: map[string]interface{}{}, 456 }}) 457 app.ExpectErrorEvents(t, []internal.WantEvent{{ 458 Intrinsics: map[string]interface{}{ 459 "error.class": "my class", 460 "error.message": "message removed by high security setting", 461 "transactionName": "OtherTransaction/Go/hello", 462 }, 463 UserAttributes: map[string]interface{}{}, 464 }}) 465 app.ExpectMetrics(t, backgroundErrorMetrics) 466 } 467 468 func TestNewrelicErrorAttributesSecurityPolicy(t *testing.T) { 469 extraAttributes := map[string]interface{}{ 470 "zip": "zap", 471 } 472 replyfn := func(reply *internal.ConnectReply) { reply.SecurityPolicies.CustomParameters.SetEnabled(false) } 473 app := testApp(replyfn, nil, t) 474 txn := app.StartTransaction("hello", nil, nil) 475 err := txn.NoticeError(Error{ 476 Message: "my msg", 477 Class: "my class", 478 Attributes: extraAttributes, 479 }) 480 if nil != err { 481 t.Error(err) 482 } 483 txn.End() 484 app.ExpectErrors(t, []internal.WantError{{ 485 TxnName: "OtherTransaction/Go/hello", 486 Msg: "my msg", 487 Klass: "my class", 488 UserAttributes: map[string]interface{}{}, 489 }}) 490 app.ExpectErrorEvents(t, []internal.WantEvent{{ 491 Intrinsics: map[string]interface{}{ 492 "error.class": "my class", 493 "error.message": "my msg", 494 "transactionName": "OtherTransaction/Go/hello", 495 }, 496 UserAttributes: map[string]interface{}{}, 497 }}) 498 app.ExpectMetrics(t, backgroundErrorMetrics) 499 } 500 501 func TestNewrelicErrorAttributeOverridesNormalAttribute(t *testing.T) { 502 extraAttributes := map[string]interface{}{ 503 "zip": "zap", 504 } 505 app := testApp(nil, nil, t) 506 txn := app.StartTransaction("hello", nil, nil) 507 if err := txn.AddAttribute("zip", 123); nil != err { 508 t.Error(err) 509 } 510 err := txn.NoticeError(Error{ 511 Message: "my msg", 512 Class: "my class", 513 Attributes: extraAttributes, 514 }) 515 if nil != err { 516 t.Error(err) 517 } 518 txn.End() 519 app.ExpectErrors(t, []internal.WantError{{ 520 TxnName: "OtherTransaction/Go/hello", 521 Msg: "my msg", 522 Klass: "my class", 523 UserAttributes: extraAttributes, 524 }}) 525 app.ExpectErrorEvents(t, []internal.WantEvent{{ 526 Intrinsics: map[string]interface{}{ 527 "error.class": "my class", 528 "error.message": "my msg", 529 "transactionName": "OtherTransaction/Go/hello", 530 }, 531 UserAttributes: extraAttributes, 532 }}) 533 app.ExpectMetrics(t, backgroundErrorMetrics) 534 } 535 536 func TestNewrelicErrorInvalidAttributes(t *testing.T) { 537 extraAttributes := map[string]interface{}{ 538 "zip": "zap", 539 "INVALID": struct{}{}, 540 } 541 app := testApp(nil, nil, t) 542 txn := app.StartTransaction("hello", nil, nil) 543 err := txn.NoticeError(Error{ 544 Message: "my msg", 545 Class: "my class", 546 Attributes: extraAttributes, 547 }) 548 if _, ok := err.(internal.ErrInvalidAttributeType); !ok { 549 t.Error(err) 550 } 551 txn.End() 552 app.ExpectErrors(t, []internal.WantError{}) 553 app.ExpectErrorEvents(t, []internal.WantEvent{}) 554 app.ExpectMetrics(t, backgroundMetrics) 555 } 556 557 func TestExtraErrorAttributeRemovedThroughConfiguration(t *testing.T) { 558 cfgfn := func(cfg *Config) { 559 cfg.ErrorCollector.Attributes.Exclude = []string{"IGNORE_ME"} 560 } 561 app := testApp(nil, cfgfn, t) 562 txn := app.StartTransaction("hello", nil, nil) 563 err := txn.NoticeError(Error{ 564 Message: "my msg", 565 Class: "my class", 566 Attributes: map[string]interface{}{ 567 "zip": "zap", 568 "IGNORE_ME": 123, 569 }, 570 }) 571 if nil != err { 572 t.Error(err) 573 } 574 txn.End() 575 app.ExpectErrors(t, []internal.WantError{{ 576 TxnName: "OtherTransaction/Go/hello", 577 Msg: "my msg", 578 Klass: "my class", 579 UserAttributes: map[string]interface{}{"zip": "zap"}, 580 }}) 581 app.ExpectErrorEvents(t, []internal.WantEvent{{ 582 Intrinsics: map[string]interface{}{ 583 "error.class": "my class", 584 "error.message": "my msg", 585 "transactionName": "OtherTransaction/Go/hello", 586 }, 587 UserAttributes: map[string]interface{}{"zip": "zap"}, 588 }}) 589 app.ExpectMetrics(t, backgroundErrorMetrics) 590 591 } 592 593 func TestTooManyExtraErrorAttributes(t *testing.T) { 594 attrs := make(map[string]interface{}) 595 for i := 0; i <= internal.AttributeErrorLimit; i++ { 596 attrs[strconv.Itoa(i)] = i 597 } 598 app := testApp(nil, nil, t) 599 txn := app.StartTransaction("hello", nil, nil) 600 err := txn.NoticeError(Error{ 601 Message: "my msg", 602 Class: "my class", 603 Attributes: attrs, 604 }) 605 if errTooManyErrorAttributes != err { 606 t.Error(err) 607 } 608 txn.End() 609 app.ExpectErrors(t, []internal.WantError{}) 610 app.ExpectErrorEvents(t, []internal.WantEvent{}) 611 app.ExpectMetrics(t, backgroundMetrics) 612 } 613 614 type basicError struct{} 615 616 func (e basicError) Error() string { return "something went wrong" } 617 618 type withClass struct{ class string } 619 620 func (e withClass) Error() string { return "something went wrong" } 621 func (e withClass) ErrorClass() string { return e.class } 622 623 type withClassAndCause struct { 624 cause error 625 class string 626 } 627 628 func (e withClassAndCause) Error() string { return e.cause.Error() } 629 func (e withClassAndCause) Unwrap() error { return e.cause } 630 func (e withClassAndCause) ErrorClass() string { return e.class } 631 632 type withCause struct{ cause error } 633 634 func (e withCause) Error() string { return e.cause.Error() } 635 func (e withCause) Unwrap() error { return e.cause } 636 637 func errWithClass(class string) error { return withClass{class: class} } 638 func wrapWithClass(e error, class string) error { return withClassAndCause{cause: e, class: class} } 639 func wrapError(e error) error { return withCause{cause: e} } 640 641 func TestErrorClass(t *testing.T) { 642 // First choice is any ErrorClass() of the immediate error. 643 // Second choice is any ErrorClass() of the error's cause. 644 // Final choice is the reflect type of the error's cause. 645 testcases := []struct { 646 Error error 647 Expect string 648 }{ 649 {Error: basicError{}, Expect: "newrelic.basicError"}, 650 {Error: errWithClass("zap"), Expect: "zap"}, 651 {Error: errWithClass(""), Expect: "newrelic.withClass"}, 652 {Error: wrapWithClass(errWithClass("zap"), "zip"), Expect: "zip"}, 653 {Error: wrapWithClass(errWithClass("zap"), ""), Expect: "zap"}, 654 {Error: wrapWithClass(errWithClass(""), ""), Expect: "newrelic.withClass"}, 655 {Error: wrapError(basicError{}), Expect: "newrelic.basicError"}, 656 {Error: wrapError(errWithClass("zap")), Expect: "zap"}, 657 } 658 659 for idx, tc := range testcases { 660 data, err := errDataFromError(tc.Error) 661 if err != nil { 662 t.Errorf("testcase %d: got error: %v", idx, err) 663 continue 664 } 665 if data.Klass != tc.Expect { 666 t.Errorf("testcase %d: expected %s got %s", idx, tc.Expect, data.Klass) 667 } 668 } 669 }