Best Go-testdeep code snippet using trace.Match
internal_distributed_trace_test.go
Source:internal_distributed_trace_test.go
...121 "parent.type": "App",122 "parent.account": "123",123 "parent.app": "456",124 "parent.transportType": "HTTP",125 "parent.transportDuration": internal.MatchAnything,126 "parentId": "52fdfc072182654f",127 "traceId": "52fdfc072182654f163f5f0f9a621d72",128 "parentSpanId": "9566c74d10d1e2c6",129 "guid": internal.MatchAnything,130 "sampled": true,131 "priority": 1.437714, // priority must be >1 when sampled is true132 },133 }})134}135func TestAcceptMultiple(t *testing.T) {136 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)137 hdrs := getDTHeaders(app.Application)138 txn := app.StartTransaction("hello")139 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)140 app.expectNoLoggedErrors(t)141 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)142 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{143 "reason": errAlreadyAccepted.Error(),144 })145 txn.End()146 app.expectNoLoggedErrors(t)147 app.ExpectMetrics(t, append([]internal.WantMetric{148 {Name: "Supportability/DistributedTrace/AcceptPayload/Ignored/Multiple", Scope: "", Forced: true, Data: singleCount},149 }, distributedTracingSuccessMetrics...))150 app.ExpectTxnEvents(t, []internal.WantEvent{{151 Intrinsics: map[string]interface{}{152 "name": "OtherTransaction/Go/hello",153 "parent.type": "App",154 "parent.account": "123",155 "parent.app": "456",156 "parent.transportType": "HTTP",157 "parent.transportDuration": internal.MatchAnything,158 "parentId": "52fdfc072182654f",159 "traceId": "52fdfc072182654f163f5f0f9a621d72",160 "parentSpanId": "9566c74d10d1e2c6",161 "guid": internal.MatchAnything,162 "sampled": internal.MatchAnything,163 "priority": internal.MatchAnything,164 },165 }})166}167func TestInsertDistributedTraceHeadersNotConnected(t *testing.T) {168 // Test that DT headers do not get created if the connect reply does not169 // contain the necessary fields.170 app := testApp(nil, enableBetterCAT, t)171 txn := app.StartTransaction("hello")172 hdrs := http.Header{}173 txn.InsertDistributedTraceHeaders(hdrs)174 if len(hdrs) != 0 {175 t.Error(hdrs)176 }177 app.expectNoLoggedErrors(t)178}179func TestAcceptDistributedTraceHeadersNil(t *testing.T) {180 // Test that AcceptDistributedTraceHeaders does not have issues181 // accepting nil headers.182 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)183 txn := app.StartTransaction("hello")184 txn.AcceptDistributedTraceHeaders(TransportHTTP, nil)185 app.expectNoLoggedErrors(t)186 txn.End()187 app.expectNoLoggedErrors(t)188 app.ExpectMetrics(t, append([]internal.WantMetric{189 {Name: "Supportability/DistributedTrace/AcceptPayload/Ignored/Null", Scope: "", Forced: true, Data: nil},190 }, backgroundMetricsUnknownCaller...))191 app.ExpectTxnEvents(t, []internal.WantEvent{{192 Intrinsics: map[string]interface{}{193 "name": "OtherTransaction/Go/hello",194 "guid": internal.MatchAnything,195 "traceId": internal.MatchAnything,196 "priority": internal.MatchAnything,197 "sampled": internal.MatchAnything,198 },199 }})200}201func TestAcceptDistributedTraceHeadersBetterCatDisabled(t *testing.T) {202 // Test that AcceptDistributedTraceHeaders only accepts DT headers if DT203 // is enabled.204 app := testApp(nil, disableCAT, t)205 hdrs := makeHeaders(t)206 txn := app.StartTransaction("hello")207 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)208 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{209 "reason": errInboundPayloadDTDisabled.Error(),210 })211 txn.End()212 app.expectNoLoggedErrors(t)213 app.ExpectMetrics(t, backgroundMetrics)214 app.ExpectTxnEvents(t, []internal.WantEvent{{215 Intrinsics: map[string]interface{}{216 "name": "OtherTransaction/Go/hello",217 },218 }})219}220func TestPayloadTransactionsDisabled(t *testing.T) {221 cfgFn := func(cfg *Config) {222 cfg.DistributedTracer.Enabled = true223 cfg.SpanEvents.Enabled = true224 cfg.TransactionEvents.Enabled = false225 }226 app := testApp(nil, cfgFn, t)227 txn := app.StartTransaction("hello")228 hdrs := http.Header{}229 txn.InsertDistributedTraceHeaders(hdrs)230 if len(hdrs) != 0 {231 t.Fatal(hdrs)232 }233 txn.End()234 app.expectNoLoggedErrors(t)235}236func TestPayloadConnectionEmptyString(t *testing.T) {237 app := testApp(nil, enableBetterCAT, t)238 txn := app.StartTransaction("hello")239 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(""))240 app.expectNoLoggedErrors(t)241 txn.End()242 app.expectNoLoggedErrors(t)243 app.ExpectMetrics(t, backgroundMetricsUnknownCaller)244 app.ExpectTxnEvents(t, []internal.WantEvent{{245 Intrinsics: map[string]interface{}{246 "name": "OtherTransaction/Go/hello",247 "guid": internal.MatchAnything,248 "traceId": internal.MatchAnything,249 "priority": internal.MatchAnything,250 "sampled": internal.MatchAnything,251 },252 }})253}254func TestCreatePayloadFinished(t *testing.T) {255 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)256 txn := app.StartTransaction("hello")257 txn.End()258 hdrs := http.Header{}259 txn.InsertDistributedTraceHeaders(hdrs)260 if len(hdrs) != 0 {261 t.Fatal(hdrs)262 }263}264func TestAcceptPayloadFinished(t *testing.T) {265 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)266 hdrs := getDTHeaders(app.Application)267 txn := app.StartTransaction("hello")268 txn.End()269 app.expectNoLoggedErrors(t)270 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)271 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{272 "reason": errAlreadyEnded.Error(),273 })274 app.ExpectMetrics(t, backgroundMetricsUnknownCaller)275 app.ExpectTxnEvents(t, []internal.WantEvent{{276 Intrinsics: map[string]interface{}{277 "name": "OtherTransaction/Go/hello",278 "guid": internal.MatchAnything,279 "traceId": internal.MatchAnything,280 "priority": internal.MatchAnything,281 "sampled": internal.MatchAnything,282 },283 }})284}285func TestPayloadAcceptAfterCreate(t *testing.T) {286 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)287 hdrs1 := getDTHeaders(app.Application)288 txn := app.StartTransaction("hello")289 hdrs2 := http.Header{}290 txn.InsertDistributedTraceHeaders(hdrs2)291 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs1)292 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{293 "reason": errOutboundPayloadCreated.Error(),294 })295 txn.End()296 app.expectNoLoggedErrors(t)297 app.ExpectMetrics(t, append([]internal.WantMetric{298 {Name: "Supportability/DistributedTrace/CreatePayload/Success", Scope: "", Forced: true, Data: singleCount},299 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: singleCount},300 {Name: "Supportability/DistributedTrace/AcceptPayload/Ignored/CreateBeforeAccept", Scope: "", Forced: true, Data: singleCount},301 }, backgroundMetricsUnknownCaller...))302 app.ExpectTxnEvents(t, []internal.WantEvent{{303 Intrinsics: map[string]interface{}{304 "name": "OtherTransaction/Go/hello",305 "guid": internal.MatchAnything,306 "traceId": internal.MatchAnything,307 "priority": internal.MatchAnything,308 "sampled": internal.MatchAnything,309 },310 }})311}312func TestPayloadFromApplicationEmptyTransportType(t *testing.T) {313 // A user has two options when it comes to TransportType. They can either use one of the314 // defined vars, like TransportHTTP, or create their own empty variable. The name field inside of315 // the TransportType struct is not exported outside of the package so users cannot modify its value.316 // When they make the attempt, Go reports:317 //318 // implicit assignment of unexported field 'name' in newrelic.TransportType literal.319 //320 // This test makes sure an empty TransportType resolves to "Unknown"321 var emptyTransport TransportType322 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)323 txn := app.StartTransaction("hello")324 p := `{325 "v":[0,1],326 "d":{327 "ty":"App",328 "ap":"456",329 "ac":"123",330 "id":"id",331 "tr":"traceID",332 "ti":1488325987402333 }334 }`335 txn.AcceptDistributedTraceHeaders(emptyTransport, headersFromString(p))336 app.expectNoLoggedErrors(t)337 txn.End()338 app.expectNoLoggedErrors(t)339 app.ExpectMetrics(t, []internal.WantMetric{340 {Name: "OtherTransaction/Go/hello", Scope: "", Forced: true, Data: nil},341 {Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},342 {Name: "OtherTransactionTotalTime/Go/hello", Scope: "", Forced: false, Data: nil},343 {Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},344 {Name: "DurationByCaller/App/123/456/Unknown/all", Scope: "", Forced: false, Data: nil},345 {Name: "DurationByCaller/App/123/456/Unknown/allOther", Scope: "", Forced: false, Data: nil},346 {Name: "TransportDuration/App/123/456/Unknown/all", Scope: "", Forced: false, Data: nil},347 {Name: "TransportDuration/App/123/456/Unknown/allOther", Scope: "", Forced: false, Data: nil},348 {Name: "Supportability/DistributedTrace/AcceptPayload/Success", Scope: "", Forced: true, Data: singleCount},349 })350 app.ExpectTxnEvents(t, []internal.WantEvent{{351 Intrinsics: map[string]interface{}{352 "name": "OtherTransaction/Go/hello",353 "parent.type": "App",354 "parent.account": "123",355 "parent.app": "456",356 "parent.transportType": "Unknown",357 "parent.transportDuration": internal.MatchAnything,358 "sampled": internal.MatchAnything,359 "priority": internal.MatchAnything,360 "traceId": "traceID",361 "parentSpanId": "id",362 "guid": internal.MatchAnything,363 },364 }})365}366func TestPayloadFutureVersion(t *testing.T) {367 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)368 txn := app.StartTransaction("hello")369 p := `{370 "v":[100,0],371 "d":{372 "ty":"App",373 "ap":"456",374 "ac":"123",375 "ti":1488325987402376 }377 }`378 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))379 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{380 "reason": "unsupported major version number 100",381 })382 txn.End()383 app.expectNoLoggedErrors(t)384 app.ExpectMetrics(t, append([]internal.WantMetric{385 {Name: "Supportability/DistributedTrace/AcceptPayload/Ignored/MajorVersion", Scope: "", Forced: true, Data: singleCount},386 }, backgroundUnknownCallerWithTransport...))387 app.ExpectTxnEvents(t, []internal.WantEvent{{388 Intrinsics: map[string]interface{}{389 "name": "OtherTransaction/Go/hello",390 "sampled": internal.MatchAnything,391 "priority": internal.MatchAnything,392 "traceId": internal.MatchAnything,393 "guid": internal.MatchAnything,394 },395 }})396}397func TestPayloadParsingError(t *testing.T) {398 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)399 txn := app.StartTransaction("hello")400 p := `{401 "v":[0,1],402 "d":[]403 }`404 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))405 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{406 "reason": "unable to unmarshal payload data: json: cannot unmarshal array into Go value of type newrelic.payload",407 })408 txn.End()409 app.expectNoLoggedErrors(t)410 app.ExpectMetrics(t, append([]internal.WantMetric{411 {Name: "Supportability/DistributedTrace/AcceptPayload/ParseException", Scope: "", Forced: true, Data: singleCount},412 }, backgroundUnknownCallerWithTransport...))413 app.ExpectTxnEvents(t, []internal.WantEvent{{414 Intrinsics: map[string]interface{}{415 "name": "OtherTransaction/Go/hello",416 "sampled": internal.MatchAnything,417 "priority": internal.MatchAnything,418 "traceId": internal.MatchAnything,419 "guid": internal.MatchAnything,420 },421 }})422}423func TestPayloadFromFuture(t *testing.T) {424 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)425 hdrs := http.Header{}426 traceParent := "00-52fdfc072182654f163f5f0f9a621d72-9566c74d10037c4d-01"427 traceState := "123@nr=0-0-123-456-9566c74d10037c4d-52fdfc072182654f-1-0.390345-TIME"428 futureTime := time.Now().Add(1 * time.Hour)429 timeStr := fmt.Sprintf("%d", timeToUnixMilliseconds(futureTime))430 traceState = strings.Replace(traceState, "TIME", timeStr, 1)431 hdrs.Set(DistributedTraceW3CTraceParentHeader, traceParent)432 hdrs.Set(DistributedTraceW3CTraceStateHeader, traceState)433 txn := app.StartTransaction("hello")434 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)435 app.expectNoLoggedErrors(t)436 txn.End()437 app.expectNoLoggedErrors(t)438 app.ExpectMetrics(t, distributedTracingSuccessMetrics)439 app.ExpectTxnEvents(t, []internal.WantEvent{{440 Intrinsics: map[string]interface{}{441 "name": "OtherTransaction/Go/hello",442 "parent.type": "App",443 "parent.account": "123",444 "parent.app": "456",445 "parent.transportType": "HTTP",446 "parent.transportDuration": 0,447 "parentId": "52fdfc072182654f",448 "traceId": "52fdfc072182654f163f5f0f9a621d72",449 "parentSpanId": "9566c74d10037c4d",450 "guid": internal.MatchAnything,451 "sampled": internal.MatchAnything,452 "priority": internal.MatchAnything,453 },454 }})455}456func TestPayloadUntrustedAccount(t *testing.T) {457 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)458 p := `{459 "v":[0,1],460 "d":{461 "ty":"App",462 "ap":"456",463 "ac":"321",464 "id":"id",465 "tr":"traceID",466 "ti":1488325987402467 }468 }`469 txn := app.StartTransaction("hello")470 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))471 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{472 "reason": errTrustedAccountKey.Error(),473 })474 txn.End()475 app.expectNoLoggedErrors(t)476 app.ExpectMetrics(t, append([]internal.WantMetric{477 {Name: "Supportability/DistributedTrace/AcceptPayload/Ignored/UntrustedAccount", Scope: "", Forced: true, Data: singleCount},478 {Name: "Supportability/DistributedTrace/AcceptPayload/Success", Scope: "", Forced: true, Data: singleCount},479 }, backgroundUnknownCallerWithTransport...))480 app.ExpectTxnEvents(t, []internal.WantEvent{{481 Intrinsics: map[string]interface{}{482 "name": "OtherTransaction/Go/hello",483 "guid": internal.MatchAnything,484 "traceId": internal.MatchAnything,485 "priority": internal.MatchAnything,486 "sampled": internal.MatchAnything,487 },488 }})489}490func TestPayloadMissingVersion(t *testing.T) {491 // ensures that a complete distributed trace payload without a version fails492 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)493 txn := app.StartTransaction("hello")494 p := `{495 "d":{496 "ty":"App",497 "ap":"456",498 "ac":"123",499 "id":"id",500 "tr":"traceID",501 "ti":1488325987402502 }503 }`504 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))505 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{506 "reason": "payload is missing Version/v",507 })508 txn.End()509 app.expectNoLoggedErrors(t)510}511func TestTrustedAccountKeyPayloadHasKeyAndMatches(t *testing.T) {512 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)513 // fixture has a "tk" of 123, which matches the trusted_account_key514 // from distributedTracingReplyFields.515 p := `{516 "v":[0,1],517 "d":{518 "ty":"App",519 "ap":"456",520 "ac":"321",521 "id":"id",522 "tr":"traceID",523 "ti":1488325987402,524 "tk":"123"525 }526 }`527 txn := app.StartTransaction("hello")528 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))529 app.expectNoLoggedErrors(t)530 txn.End()531 app.expectNoLoggedErrors(t)532}533func TestTrustedAccountKeyPayloadHasKeyAndDoesNotMatch(t *testing.T) {534 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)535 // fixture has a "tk" of 1234, which does not match the536 // trusted_account_key from distributedTracingReplyFields.537 p := `{538 "v":[0,1],539 "d":{540 "ty":"App",541 "ap":"456",542 "ac":"321",543 "id":"id",544 "tr":"traceID",545 "ti":1488325987402,546 "tk":"1234"547 }548 }`549 txn := app.StartTransaction("hello")550 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))551 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{552 "reason": errTrustedAccountKey.Error(),553 })554 txn.End()555 app.expectNoLoggedErrors(t)556}557func TestTrustedAccountKeyPayloadMissingKeyAndAccountIdMatches(t *testing.T) {558 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)559 // fixture has no trust key but its account id of 123 matches560 // trusted_account_key from distributedTracingReplyFields.561 p := `{562 "v":[0,1],563 "d":{564 "ty":"App",565 "ap":"456",566 "ac":"123",567 "id":"id",568 "tr":"traceID",569 "ti":1488325987402570 }571 }`572 txn := app.StartTransaction("hello")573 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))574 app.expectNoLoggedErrors(t)575 txn.End()576 app.expectNoLoggedErrors(t)577}578func TestTrustedAccountKeyPayloadMissingKeyAndAccountIdDoesNotMatch(t *testing.T) {579 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)580 // fixture has no trust key and its account id of 1234 does not match the581 // trusted_account_key from distributedTracingReplyFields.582 p := `{583 "v":[0,1],584 "d":{585 "ty":"App",586 "ap":"456",587 "ac":"1234",588 "id":"id",589 "tr":"traceID",590 "ti":1488325987402591 }592 }`593 txn := app.StartTransaction("hello")594 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))595 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{596 "reason": errTrustedAccountKey.Error(),597 })598 txn.End()599 app.expectNoLoggedErrors(t)600}601var (602 backgroundUnknownCaller = []internal.WantMetric{603 {Name: "OtherTransaction/Go/hello", Scope: "", Forced: true, Data: nil},604 {Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},605 {Name: "OtherTransactionTotalTime/Go/hello", Scope: "", Forced: false, Data: nil},606 {Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},607 {Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},608 {Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/allOther", Scope: "", Forced: false, Data: nil},609 }610 backgroundUnknownCallerWithTransport = []internal.WantMetric{611 {Name: "OtherTransaction/Go/hello", Scope: "", Forced: true, Data: nil},612 {Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},613 {Name: "OtherTransactionTotalTime/Go/hello", Scope: "", Forced: false, Data: nil},614 {Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},615 {Name: "DurationByCaller/Unknown/Unknown/Unknown/HTTP/all", Scope: "", Forced: false, Data: nil},616 {Name: "DurationByCaller/Unknown/Unknown/Unknown/HTTP/allOther", Scope: "", Forced: false, Data: nil},617 }618)619func TestNilPayload(t *testing.T) {620 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)621 txn := app.StartTransaction("hello")622 txn.AcceptDistributedTraceHeaders(TransportHTTP, nil)623 app.expectNoLoggedErrors(t)624 txn.End()625 app.expectNoLoggedErrors(t)626 app.ExpectMetrics(t, append([]internal.WantMetric{627 {Name: "Supportability/DistributedTrace/AcceptPayload/Ignored/Null", Scope: "", Forced: true, Data: singleCount},628 }, backgroundUnknownCaller...))629}630func TestNoticeErrorPayload(t *testing.T) {631 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)632 txn := app.StartTransaction("hello")633 txn.NoticeError(errors.New("oh no"))634 txn.End()635 app.expectNoLoggedErrors(t)636 app.ExpectMetrics(t, append([]internal.WantMetric{637 {Name: "Errors/all", Scope: "", Forced: true, Data: nil},638 {Name: "Errors/allOther", Scope: "", Forced: true, Data: nil},639 {Name: "Errors/OtherTransaction/Go/hello", Scope: "", Forced: true, Data: nil},640 {Name: "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},641 {Name: "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown/allOther", Scope: "", Forced: false, Data: nil},642 }, backgroundUnknownCaller...))643}644func TestMissingIDsForSupportabilityMetric(t *testing.T) {645 p := `{646 "v":[0,1],647 "d":{648 "ty":"App",649 "ap":"456",650 "ac":"123",651 "tr":"traceID",652 "ti":1488325987402653 }654 }`655 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)656 txn := app.StartTransaction("hello")657 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))658 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{659 "reason": "payload is missing both guid/id and TransactionId/tx",660 })661 txn.End()662 app.expectNoLoggedErrors(t)663 app.ExpectMetrics(t, append([]internal.WantMetric{664 {Name: "Supportability/DistributedTrace/AcceptPayload/ParseException", Scope: "", Forced: true, Data: nil},665 }, backgroundUnknownCallerWithTransport...))666}667func TestMissingVersionForSupportabilityMetric(t *testing.T) {668 p := `{669 "d":{670 "ty":"App",671 "ap":"456",672 "ac":"123",673 "id":"id",674 "tr":"traceID",675 "ti":1488325987402676 }677 }`678 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)679 txn := app.StartTransaction("hello")680 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))681 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{682 "reason": "payload is missing Version/v",683 })684 txn.End()685 app.expectNoLoggedErrors(t)686 app.ExpectMetrics(t, append([]internal.WantMetric{687 {Name: "Supportability/DistributedTrace/AcceptPayload/ParseException", Scope: "", Forced: true, Data: nil},688 }, backgroundUnknownCallerWithTransport...))689}690func TestMissingFieldForSupportabilityMetric(t *testing.T) {691 p := `{692 "v":[0,1],693 "d":{694 "ty":"App",695 "ap":"456",696 "id":"id",697 "tr":"traceID",698 "ti":1488325987402699 }700 }`701 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)702 txn := app.StartTransaction("hello")703 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))704 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{705 "reason": "payload is missing Account/ac",706 })707 txn.End()708 app.expectNoLoggedErrors(t)709 app.ExpectMetrics(t, append([]internal.WantMetric{710 {Name: "Supportability/DistributedTrace/AcceptPayload/ParseException", Scope: "", Forced: true, Data: nil},711 }, backgroundUnknownCallerWithTransport...))712}713func TestParseExceptionSupportabilityMetric(t *testing.T) {714 p := `{715 "v":[0,1],716 "d":{717 "ty":"App",718 "ap":"456",719 "id":"id",720 "tr":"traceID",721 "ti":1488325987402722 }723 `724 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)725 txn := app.StartTransaction("hello")726 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))727 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{728 "reason": "unable to unmarshal payload: unexpected end of JSON input",729 })730 txn.End()731 app.expectNoLoggedErrors(t)732 app.ExpectMetrics(t, append([]internal.WantMetric{733 {Name: "Supportability/DistributedTrace/AcceptPayload/ParseException", Scope: "", Forced: true, Data: nil},734 }, backgroundUnknownCallerWithTransport...))735}736func TestErrorsByCaller(t *testing.T) {737 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)738 txn := app.StartTransaction("hello")739 hdrs := getDTHeaders(app.Application)740 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)741 app.expectNoLoggedErrors(t)742 txn.NoticeError(errors.New("oh no"))743 txn.End()744 app.expectNoLoggedErrors(t)745 app.ExpectMetrics(t, []internal.WantMetric{746 {Name: "OtherTransaction/Go/hello", Scope: "", Forced: true, Data: nil},747 {Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},748 {Name: "OtherTransactionTotalTime/Go/hello", Scope: "", Forced: false, Data: nil},749 {Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},750 {Name: "TransportDuration/App/123/456/HTTP/allOther", Scope: "", Forced: false, Data: nil},751 {Name: "Supportability/TraceContext/Accept/Success", Scope: "", Forced: true, Data: nil},752 {Name: "DurationByCaller/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},753 {Name: "DurationByCaller/App/123/456/HTTP/allOther", Scope: "", Forced: false, Data: nil},754 {Name: "TransportDuration/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},755 {Name: "ErrorsByCaller/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},756 {Name: "ErrorsByCaller/App/123/456/HTTP/allOther", Scope: "", Forced: false, Data: nil},757 {Name: "Errors/all", Scope: "", Forced: true, Data: nil},758 {Name: "Errors/allOther", Scope: "", Forced: true, Data: nil},759 {Name: "Errors/OtherTransaction/Go/hello", Scope: "", Forced: true, Data: nil},760 })761}762func TestCreateDistributedTraceCatDisabled(t *testing.T) {763 // when distributed tracing is disabled, CreateDistributedTracePayload764 // should return a value that indicates an empty payload. Examples of765 // this depend on language but may be nil/null/None or an empty payload766 // object.767 app := testApp(distributedTracingReplyFields, disableCAT, t)768 txn := app.StartTransaction("hello")769 hdrs := http.Header{}770 txn.InsertDistributedTraceHeaders(hdrs)771 // empty/shim payload objects return empty strings772 if len(hdrs) != 0 {773 t.Log("Non empty result of InsertDistributedTraceHeaders() method:", hdrs)774 t.Fail()775 }776 txn.End()777 app.expectNoLoggedErrors(t)778 app.ExpectMetrics(t, []internal.WantMetric{779 {Name: "OtherTransaction/Go/hello", Scope: "", Forced: true, Data: nil},780 {Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},781 {Name: "OtherTransactionTotalTime/Go/hello", Scope: "", Forced: false, Data: nil},782 {Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},783 })784}785func TestCreateDistributedTraceBetterCatDisabled(t *testing.T) {786 // when distributed tracing is disabled, CreateDistributedTracePayload787 // should return a value that indicates an empty payload. Examples of788 // this depend on language but may be nil/null/None or an empty payload789 // object.790 app := testApp(distributedTracingReplyFields, enableOldCATDisableBetterCat, t)791 txn := app.StartTransaction("hello")792 hdrs := http.Header{}793 txn.InsertDistributedTraceHeaders(hdrs)794 if len(hdrs) != 0 {795 t.Log("Non empty result of InsertDistributedTraceHeaders() method:", hdrs)796 t.Fail()797 }798 txn.End()799 app.expectNoLoggedErrors(t)800 app.ExpectMetrics(t, []internal.WantMetric{801 {Name: "OtherTransaction/Go/hello", Scope: "", Forced: true, Data: nil},802 {Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},803 {Name: "OtherTransactionTotalTime/Go/hello", Scope: "", Forced: false, Data: nil},804 {Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},805 })806}807func TestCreateDistributedTraceBetterCatEnabled(t *testing.T) {808 // When distributed tracing is enabled and the application is connected,809 // CreateDistributedTracePayload should return a valid payload object810 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)811 txn := app.StartTransaction("hello")812 hdrs := http.Header{}813 txn.InsertDistributedTraceHeaders(hdrs)814 if len(hdrs) == 0 {815 t.Log("Empty result of InsertDistributedTraceHeaders() method:", hdrs)816 t.Fail()817 }818 txn.End()819 app.expectNoLoggedErrors(t)820 app.ExpectMetrics(t, append([]internal.WantMetric{821 {Name: "Supportability/DistributedTrace/CreatePayload/Success", Scope: "", Forced: true, Data: nil},822 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},823 }, backgroundUnknownCaller...))824}825func isZeroValue(x interface{}) bool {826 // https://stackoverflow.com/questions/13901819/quick-way-to-detect-empty-values-via-reflection-in-go827 return nil == x || x == reflect.Zero(reflect.TypeOf(x)).Interface()828}829func payloadFieldsFromHeaders(t *testing.T, hdrs http.Header) (out struct {830 Version []int `json:"v"`831 Data map[string]interface{} `json:"d"`832}) {833 encoded := hdrs.Get(DistributedTraceNewRelicHeader)834 decoded, err := base64.StdEncoding.DecodeString(encoded)835 if err != nil {836 t.Fatal("unable to bas64 decode tracing header", err)837 }838 if err := json.Unmarshal(decoded, &out); nil != err {839 t.Fatal("unable to unmarshal payload NRText", err)840 }841 return842}843func testPayloadFieldsPresent(t *testing.T, hdrs http.Header, keys ...string) {844 out := payloadFieldsFromHeaders(t, hdrs)845 for _, key := range keys {846 val, ok := out.Data[key]847 if !ok {848 t.Fatal("required key missing", key)849 }850 if isZeroValue(val) {851 t.Fatal("value has default value", key, val)852 }853 }854}855func TestCreateDistributedTraceRequiredFields(t *testing.T) {856 // creates a distributed trace payload and then checks857 // to ensure the required fields are in place858 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)859 txn := app.StartTransaction("hello")860 hdrs := http.Header{}861 txn.InsertDistributedTraceHeaders(hdrs)862 testPayloadFieldsPresent(t, hdrs, "ty", "ac", "ap", "tr", "ti")863 txn.End()864 app.expectNoLoggedErrors(t)865 app.ExpectMetrics(t, append([]internal.WantMetric{866 {Name: "Supportability/DistributedTrace/CreatePayload/Success", Scope: "", Forced: true, Data: nil},867 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},868 }, backgroundUnknownCaller...))869}870func TestCreateDistributedTraceTrustKeyAbsent(t *testing.T) {871 // creates a distributed trace payload and then checks872 // to ensure the required fields are in place873 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)874 txn := app.StartTransaction("hello")875 hdrs := http.Header{}876 txn.InsertDistributedTraceHeaders(hdrs)877 data := payloadFieldsFromHeaders(t, hdrs)878 if nil != data.Data["tk"] {879 t.Fatal("unexpected trust key (tk)", hdrs)880 }881 txn.End()882 app.expectNoLoggedErrors(t)883 app.ExpectMetrics(t, append([]internal.WantMetric{884 {Name: "Supportability/DistributedTrace/CreatePayload/Success", Scope: "", Forced: true, Data: nil},885 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},886 }, backgroundUnknownCaller...))887}888func TestCreateDistributedTraceTrustKeyNeeded(t *testing.T) {889 // creates a distributed trace payload and then checks890 // to ensure the required fields are in place891 app := testApp(distributedTracingReplyFieldsNeedTrustKey, enableBetterCAT, t)892 txn := app.StartTransaction("hello")893 hdrs := http.Header{}894 txn.InsertDistributedTraceHeaders(hdrs)895 testPayloadFieldsPresent(t, hdrs, "tk")896 txn.End()897 app.expectNoLoggedErrors(t)898 app.ExpectMetrics(t, append([]internal.WantMetric{899 {Name: "Supportability/DistributedTrace/CreatePayload/Success", Scope: "", Forced: true, Data: nil},900 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},901 }, backgroundUnknownCaller...))902}903func TestCreateDistributedTraceAfterAcceptSampledTrue(t *testing.T) {904 // simulates 1. reading distributed trace payload from non-header external storage905 // (for queues, other customer integrations); 2. Accpeting that Payload; 3. Creating906 // a new payload907 // tests that the required fields, plus priority and sampled are set908 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)909 // fixture has a "tk" of 123, which matches the trusted_account_key910 // from distributedTracingReplyFields.911 p := `{912 "v":[0,1],913 "d":{914 "ty":"App",915 "ap":"456",916 "ac":"321",917 "id":"id",918 "tr":"traceID",919 "ti":1488325987402,920 "tk":"123",921 "sa":true922 }923}`924 txn := app.StartTransaction("hello")925 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))926 app.expectNoLoggedErrors(t)927 hdrs := http.Header{}928 txn.InsertDistributedTraceHeaders(hdrs)929 testPayloadFieldsPresent(t, hdrs,930 "ty", "ac", "ap", "tr", "ti", "pr", "sa")931 txn.End()932 app.expectNoLoggedErrors(t)933}934func TestCreateDistributedTraceAfterAcceptSampledNotSet(t *testing.T) {935 // simulates 1. reading distributed trace payload from non-header external storage936 // (for queues, other customer integrations); 2. Accpeting that Payload; 3. Creating937 // a new payload938 // tests that the required fields, plus priority and sampled are set. When "sa"939 // is not set, the payload should pickup on sampled value of the transaction940 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)941 // fixture has a "tk" of 123, which matches the trusted_account_key942 // from distributedTracingReplyFields.943 p := `{944 "v":[0,1],945 "d":{946 "ty":"App",947 "ap":"456",948 "ac":"321",949 "id":"id",950 "tr":"traceID",951 "ti":1488325987402,952 "tk":"123",953 "pr":0.54343954 }955}`956 txn := app.StartTransaction("hello")957 txn.AcceptDistributedTraceHeaders(TransportHTTP, headersFromString(p))958 app.expectNoLoggedErrors(t)959 hdrs := http.Header{}960 txn.InsertDistributedTraceHeaders(hdrs)961 testPayloadFieldsPresent(t, hdrs,962 "ty", "ac", "ap", "id", "tr", "ti", "pr", "sa")963 txn.End()964 app.expectNoLoggedErrors(t)965}966type fieldExpectations struct {967 Exact map[string]interface{} `json:"exact,omitempty"`968 Expected []string `json:"expected,omitempty"`969 Unexpected []string `json:"unexpected,omitempty"`970}971type distributedTraceTestcase struct {972 TestName string `json:"test_name"`973 Comment string `json:"comment,omitempty"`974 TrustedAccountKey string `json:"trusted_account_key"`975 AccountID string `json:"account_id"`976 WebTransaction bool `json:"web_transaction"`977 RaisesException bool `json:"raises_exception"`978 ForceSampledTrue bool `json:"force_sampled_true"`979 SpanEventsEnabled bool `json:"span_events_enabled"`980 MajorVersion int `json:"major_version"`981 MinorVersion int `json:"minor_version"`982 TransportType string `json:"transport_type"`983 InboundPayloads []json.RawMessage `json:"inbound_payloads"`984 OutboundPayloads []fieldExpectations `json:"outbound_payloads,omitempty"`985 Intrinsics struct {986 TargetEvents []string `json:"target_events"`987 Common *fieldExpectations `json:"common,omitempty"`988 Transaction *fieldExpectations `json:"Transaction,omitempty"`989 Span *fieldExpectations `json:"Span,omitempty"`990 TransactionError *fieldExpectations `json:"TransactionError,omitempty"`991 UnexpectedEvents []string `json:"unexpected_events,omitempty"`992 } `json:"intrinsics"`993 ExpectedMetrics [][2]interface{} `json:"expected_metrics"`994}995func (fe *fieldExpectations) add(intrinsics map[string]interface{}) {996 if nil != fe {997 for k, v := range fe.Exact {998 intrinsics[k] = v999 }1000 for _, v := range fe.Expected {1001 intrinsics[v] = internal.MatchAnything1002 }1003 }1004}1005func (fe *fieldExpectations) unexpected() []string {1006 if nil != fe {1007 return fe.Unexpected1008 }1009 return nil1010}1011// getTransport ensures that our transport names match cross agent test values.1012func getTransport(transport string) TransportType {1013 switch TransportType(transport) {1014 case TransportHTTP, TransportHTTPS, TransportKafka, TransportJMS, TransportIronMQ, TransportAMQP,1015 TransportQueue, TransportOther:1016 return TransportType(transport)1017 default:1018 return TransportUnknown1019 }1020}1021func runDistributedTraceCrossAgentTestcase(tst *testing.T, tc distributedTraceTestcase, extraAsserts func(expectApp, internal.Validator)) {1022 t := extendValidator(tst, "test="+tc.TestName)1023 configCallback := enableBetterCAT1024 if false == tc.SpanEventsEnabled {1025 configCallback = disableSpanEvents1026 }1027 app := testApp(func(reply *internal.ConnectReply) {1028 reply.AccountID = tc.AccountID1029 reply.AppID = "456"1030 reply.PrimaryAppID = "456"1031 reply.TrustedAccountKey = tc.TrustedAccountKey1032 // if cross agent tests ever include logic for sampling1033 // we'll need to revisit this testing sampler1034 reply.SetSampleEverything()1035 }, configCallback, tst)1036 txn := app.StartTransaction("hello")1037 if tc.WebTransaction {1038 txn.SetWebRequestHTTP(nil)1039 }1040 // If the tests wants us to have an error, give 'em an error1041 if tc.RaisesException {1042 txn.NoticeError(errors.New("my error message"))1043 }1044 // If there are no inbound payloads, invoke Accept on an empty inbound payload.1045 if nil == tc.InboundPayloads {1046 txn.AcceptDistributedTraceHeaders(getTransport(tc.TransportType), nil)1047 }1048 for _, value := range tc.InboundPayloads {1049 // Note that the error return value is not tested here because1050 // some of the tests are intentionally errors.1051 txn.AcceptDistributedTraceHeaders(getTransport(tc.TransportType), headersFromString(string(value)))1052 }1053 //call create each time an outbound payload appears in the testcase1054 for _, expect := range tc.OutboundPayloads {1055 hdrs := http.Header{}1056 txn.InsertDistributedTraceHeaders(hdrs)1057 actual := hdrs.Get(DistributedTraceNewRelicHeader)1058 assertTestCaseOutboundPayload(expect, t, actual)1059 }1060 txn.End()1061 // create WantMetrics and assert1062 var wantMetrics []internal.WantMetric1063 for _, metric := range tc.ExpectedMetrics {1064 wantMetrics = append(wantMetrics,1065 internal.WantMetric{Name: metric[0].(string), Scope: "", Forced: nil, Data: nil})1066 }1067 app.ExpectMetricsPresent(t, wantMetrics)1068 // Add extra fields that are not listed in the JSON file so that we can1069 // always do exact intrinsic set match.1070 extraTxnFields := &fieldExpectations{Expected: []string{"name"}}1071 if tc.WebTransaction {1072 extraTxnFields.Expected = append(extraTxnFields.Expected, "nr.apdexPerfZone")1073 }1074 extraSpanFields := &fieldExpectations{1075 Expected: []string{"name", "transaction.name", "category", "nr.entryPoint"},1076 }1077 // There is a single test with an error (named "exception"), so these1078 // error expectations can be hard coded. TODO: Move some of these.1079 // fields into the cross agent tests.1080 extraErrorFields := &fieldExpectations{1081 Expected: []string{"parent.type", "parent.account", "parent.app",1082 "parent.transportType", "error.message", "transactionName",1083 "parent.transportDuration", "error.class", "spanId"},1084 }1085 for _, value := range tc.Intrinsics.TargetEvents {1086 switch value {1087 case "Transaction":1088 assertTestCaseIntrinsics(t,1089 app.ExpectTxnEvents,1090 tc.Intrinsics.Common,1091 tc.Intrinsics.Transaction,1092 extraTxnFields)1093 case "Span":1094 assertTestCaseIntrinsics(t,1095 app.ExpectSpanEvents,1096 tc.Intrinsics.Common,1097 tc.Intrinsics.Span,1098 extraSpanFields)1099 case "TransactionError":1100 assertTestCaseIntrinsics(t,1101 app.ExpectErrorEvents,1102 tc.Intrinsics.Common,1103 tc.Intrinsics.TransactionError,1104 extraErrorFields)1105 }1106 }1107 extraAsserts(app, t)1108}1109func assertTestCaseOutboundPayload(expect fieldExpectations, t internal.Validator, encoded string) {1110 decoded, err := base64.StdEncoding.DecodeString(encoded)1111 if nil != err {1112 t.Error("unable to decode payload header", err)1113 return1114 }1115 type outboundTestcase struct {1116 Version [2]uint `json:"v"`1117 Data map[string]interface{} `json:"d"`1118 }1119 var actualPayload outboundTestcase1120 err = json.Unmarshal([]byte(decoded), &actualPayload)1121 if nil != err {1122 t.Error(err)1123 }1124 // Affirm that the exact values are in the payload.1125 for k, v := range expect.Exact {1126 if k != "v" {1127 field := strings.Split(k, ".")[1]1128 if v != actualPayload.Data[field] {1129 t.Error(fmt.Sprintf("exact outbound payload field mismatch key=%s wanted=%v got=%v",1130 k, v, actualPayload.Data[field]))1131 }1132 }1133 }1134 // Affirm that the expected values are in the actual payload.1135 for _, e := range expect.Expected {1136 field := strings.Split(e, ".")[1]1137 if nil == actualPayload.Data[field] {1138 t.Error(fmt.Sprintf("expected outbound payload field missing key=%s", e))1139 }1140 }1141 // Affirm that the unexpected values are not in the actual payload.1142 for _, u := range expect.Unexpected {1143 field := strings.Split(u, ".")[1]1144 if nil != actualPayload.Data[field] {1145 t.Error(fmt.Sprintf("unexpected outbound payload field present key=%s", u))1146 }1147 }1148}1149func assertTestCaseIntrinsics(t internal.Validator,1150 expect func(internal.Validator, []internal.WantEvent),1151 fields ...*fieldExpectations) {1152 intrinsics := map[string]interface{}{}1153 for _, f := range fields {1154 f.add(intrinsics)1155 }1156 expect(t, []internal.WantEvent{{Intrinsics: intrinsics}})1157}1158func TestDistributedTraceCrossAgent(t *testing.T) {1159 var tcs []distributedTraceTestcase1160 data, err := crossagent.ReadFile(`distributed_tracing/distributed_tracing.json`)1161 if nil != err {1162 t.Fatal(err)1163 }1164 if err := json.Unmarshal(data, &tcs); nil != err {1165 t.Fatal(err)1166 }1167 // Test that we are correctly parsing all of the testcase fields by1168 // comparing an opaque object from original JSON to an object from JSON1169 // created by our testcases.1170 backToJSON, err := json.Marshal(tcs)1171 if nil != err {1172 t.Fatal(err)1173 }1174 var fromFile []map[string]interface{}1175 var fromMarshalled []map[string]interface{}1176 if err := json.Unmarshal(data, &fromFile); nil != err {1177 t.Fatal(err)1178 }1179 if err := json.Unmarshal(backToJSON, &fromMarshalled); nil != err {1180 t.Fatal(err)1181 }1182 if !reflect.DeepEqual(fromFile, fromMarshalled) {1183 t.Error(internal.CompactJSONString(string(data)), "\n",1184 internal.CompactJSONString(string(backToJSON)))1185 }1186 // Iterate over all cross-agent tests1187 for _, tc := range tcs {1188 extraAsserts := func(app expectApp, t internal.Validator) {}1189 if "spans_disabled_in_child" == tc.TestName {1190 // if span events are disabled but distributed tracing is enabled, then1191 // we expect there are zero span events1192 extraAsserts = func(app expectApp, t internal.Validator) {1193 app.ExpectSpanEvents(t, nil)1194 }1195 }1196 runDistributedTraceCrossAgentTestcase(t, tc, extraAsserts)1197 }1198}1199func TestDistributedTraceDisabledSpanEventsEnabled(t *testing.T) {1200 app := testApp(distributedTracingReplyFields, disableDistributedTracerEnableSpanEvents, t)1201 hdrs := makeHeaders(t)1202 txn := app.StartTransaction("hello")1203 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)1204 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{1205 "reason": errInboundPayloadDTDisabled.Error(),1206 })1207 txn.End()1208 app.expectNoLoggedErrors(t)1209 // ensure no span events created1210 app.ExpectSpanEvents(t, nil)1211}1212func TestCreatePayloadAppNotConnected(t *testing.T) {1213 // Test that an app which isn't connected does not create distributed1214 // trace payloads.1215 app := testApp(nil, enableBetterCAT, t)1216 txn := app.StartTransaction("hello")1217 hdrs := http.Header{}1218 txn.InsertDistributedTraceHeaders(hdrs)1219 if len(hdrs) != 0 {1220 t.Error(hdrs)1221 }1222}1223func TestCreatePayloadReplyMissingTrustKey(t *testing.T) {1224 // Test that an app whose reply is missing the trust key does not create1225 // distributed trace payloads.1226 app := testApp(func(reply *internal.ConnectReply) {1227 distributedTracingReplyFields(reply)1228 reply.TrustedAccountKey = ""1229 }, enableBetterCAT, t)1230 txn := app.StartTransaction("hello")1231 hdrs := http.Header{}1232 txn.InsertDistributedTraceHeaders(hdrs)1233 if len(hdrs) != 0 {1234 t.Error(hdrs)1235 }1236}1237func TestAcceptPayloadAppNotConnected(t *testing.T) {1238 // Test that an app which isn't connected does not accept distributed1239 // trace payloads.1240 app := testApp(nil, enableBetterCAT, t)1241 txn := testApp(distributedTracingReplyFields, enableBetterCAT, t).1242 StartTransaction("name")1243 hdrs := http.Header{}1244 txn.InsertDistributedTraceHeaders(hdrs)1245 if len(hdrs) == 0 {1246 t.Fatal(hdrs)1247 }1248 txn2 := app.StartTransaction("hello")1249 txn2.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)1250 app.expectNoLoggedErrors(t)1251 txn2.End()1252 app.ExpectMetrics(t, backgroundUnknownCaller)1253}1254func TestAcceptPayloadReplyMissingTrustKey(t *testing.T) {1255 // Test that an app whose reply is missing a trust key does not accept1256 // distributed trace payloads.1257 app := testApp(func(reply *internal.ConnectReply) {1258 distributedTracingReplyFields(reply)1259 reply.TrustedAccountKey = ""1260 }, enableBetterCAT, t)1261 txn := testApp(distributedTracingReplyFields, enableBetterCAT, t).1262 StartTransaction("name")1263 hdrs := http.Header{}1264 txn.InsertDistributedTraceHeaders(hdrs)1265 if len(hdrs) == 0 {1266 t.Fatal(hdrs)1267 }1268 txn2 := app.StartTransaction("hello")1269 txn2.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)1270 app.expectNoLoggedErrors(t)1271 txn2.End()1272 app.ExpectMetrics(t, backgroundUnknownCaller)1273}1274func verifyHeaders(t *testing.T, actual http.Header, expected http.Header) {1275 if !reflect.DeepEqual(actual, expected) {1276 t.Error("Headers do not match - expected/actual: ", expected, actual)1277 }1278}1279func TestW3CTraceHeaders(t *testing.T) {1280 app := testApp(distributedTracingReplyFields, enableW3COnly, t)1281 txn := app.StartTransaction("hello")1282 hdrs := http.Header{}1283 txn.InsertDistributedTraceHeaders(hdrs)1284 expected := http.Header{1285 DistributedTraceW3CTraceParentHeader: []string{"00-52fdfc072182654f163f5f0f9a621d72-9566c74d10d1e2c6-01"},1286 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456-9566c74d10d1e2c6-52fdfc072182654f-1-1.437714-1577830891900"},1287 }1288 verifyHeaders(t, hdrs, expected)1289 txn.End()1290 app.expectNoLoggedErrors(t)1291 app.ExpectMetrics(t, append([]internal.WantMetric{1292 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},1293 }, backgroundUnknownCaller...))1294}1295var acceptAndSendDT = []internal.WantMetric{1296 {Name: "OtherTransaction/Go/hello", Scope: "", Forced: true, Data: nil},1297 {Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},1298 {Name: "OtherTransactionTotalTime/Go/hello", Scope: "", Forced: false, Data: nil},1299 {Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},1300 {Name: "Supportability/TraceContext/Accept/Success", Scope: "", Forced: true, Data: nil},1301 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},1302 {Name: "DurationByCaller/App/1349956/41346604/HTTP/all", Scope: "", Forced: false, Data: nil},1303 {Name: "DurationByCaller/App/1349956/41346604/HTTP/allOther", Scope: "", Forced: false, Data: nil},1304 {Name: "TransportDuration/App/1349956/41346604/HTTP/all", Scope: "", Forced: false, Data: nil},1305 {Name: "TransportDuration/App/1349956/41346604/HTTP/allOther", Scope: "", Forced: false, Data: nil},1306}1307func TestW3CTraceHeadersNoMatchingNREntry(t *testing.T) {1308 app := testApp(distributedTracingReplyFields, enableW3COnly, t)1309 txn := app.StartTransaction("hello")1310 hdrs := http.Header{}1311 hdrs.Set(DistributedTraceW3CTraceParentHeader,1312 "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01")1313 hdrs.Set(DistributedTraceW3CTraceStateHeader,1314 "99999@nr=0-0-1349956-41346604-27ddd2d8890283b4-b28be285632bbc0a-1-0.246890-1569367663277")1315 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)1316 outgoingHdrs := http.Header{}1317 txn.InsertDistributedTraceHeaders(outgoingHdrs)1318 expected := http.Header{1319 DistributedTraceW3CTraceParentHeader: []string{"00-4bf92f3577b34da6a3ce929d0e0e4736-9566c74d10d1e2c6-01"},1320 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456-9566c74d10d1e2c6-52fdfc072182654f-1-1.437714-1577830891900,99999@nr=0-0-1349956-41346604-27ddd2d8890283b4-b28be285632bbc0a-1-0.246890-1569367663277"},1321 }1322 verifyHeaders(t, outgoingHdrs, expected)1323 txn.End()1324 app.expectNoLoggedErrors(t)1325 app.ExpectMetrics(t, append([]internal.WantMetric{1326 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},1327 {Name: "Supportability/TraceContext/TraceState/NoNrEntry", Scope: "", Forced: true, Data: nil},1328 {Name: "Supportability/TraceContext/Accept/Success", Scope: "", Forced: true, Data: nil},1329 }, backgroundUnknownCallerWithTransport...))1330 app.ExpectSpanEvents(t, []internal.WantEvent{1331 {1332 Intrinsics: map[string]interface{}{1333 "name": "OtherTransaction/Go/hello",1334 "transaction.name": "OtherTransaction/Go/hello",1335 "sampled": true,1336 "priority": internal.MatchAnything,1337 "category": "generic",1338 "parentId": "00f067aa0ba902b7",1339 "nr.entryPoint": true,1340 "guid": "9566c74d10d1e2c6",1341 "transactionId": "52fdfc072182654f",1342 "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",1343 "tracingVendors": "99999@nr",1344 },1345 UserAttributes: map[string]interface{}{},1346 AgentAttributes: map[string]interface{}{1347 "parent.transportType": "HTTP",1348 },1349 },1350 })1351}1352func TestW3CTraceHeadersRoundTrip(t *testing.T) {1353 app := testApp(distributedTracingReplyFields, enableW3COnly, t)1354 txn := app.StartTransaction("hello")1355 hdrs := http.Header{}1356 hdrs.Set(DistributedTraceW3CTraceParentHeader,1357 "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01")1358 hdrs.Set(DistributedTraceW3CTraceStateHeader,1359 "123@nr=0-0-1349956-41346604-27ddd2d8890283b4-b28be285632bbc0a-1-0.246890-1569367663277")1360 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)1361 outgoingHdrs := http.Header{}1362 txn.InsertDistributedTraceHeaders(outgoingHdrs)1363 expected := http.Header{1364 DistributedTraceW3CTraceParentHeader: []string{"00-4bf92f3577b34da6a3ce929d0e0e4736-9566c74d10d1e2c6-01"},1365 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456-9566c74d10d1e2c6-52fdfc072182654f-1-0.24689-1577830891900"},1366 }1367 verifyHeaders(t, outgoingHdrs, expected)1368 txn.End()1369 app.expectNoLoggedErrors(t)1370 app.ExpectMetrics(t, acceptAndSendDT)1371}1372func TestW3CTraceHeadersDuplicateTraceState(t *testing.T) {1373 app := testApp(distributedTracingReplyFields, enableW3COnly, t)1374 txn := app.StartTransaction("hello")1375 hdrs := http.Header{}1376 hdrs.Set(DistributedTraceW3CTraceParentHeader,1377 "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01")1378 hdrs.Set(DistributedTraceW3CTraceStateHeader,1379 "123@nr=0-0-1349956-41346604-27ddd2d8890283b4-b28be285632bbc0a-1-0.246890-1569367663277,congo=congosSecondPosition,rojo=rojosFirstPosition,123@nr=0-0-1349956-41346604-aaaaaaaaaaaaaaaa-b28be285632bbc0a-1-0.246890-1569367663277")1380 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)1381 outgoingHdrs := http.Header{}1382 txn.InsertDistributedTraceHeaders(outgoingHdrs)1383 expected := http.Header{1384 DistributedTraceW3CTraceParentHeader: []string{"00-4bf92f3577b34da6a3ce929d0e0e4736-9566c74d10d1e2c6-01"},1385 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456-9566c74d10d1e2c6-52fdfc072182654f-1-0.24689-1577830891900,congo=congosSecondPosition,rojo=rojosFirstPosition"},1386 }1387 verifyHeaders(t, outgoingHdrs, expected)1388 txn.End()1389 app.expectNoLoggedErrors(t)1390 app.ExpectMetrics(t, acceptAndSendDT)1391}1392func TestW3CTraceHeadersSpansDisabledSampledTrue(t *testing.T) {1393 app := testApp(distributedTracingReplyFieldsSpansDisabled, enableW3COnly, t)1394 txn := app.StartTransaction("hello")1395 hdrs := http.Header{}1396 txn.InsertDistributedTraceHeaders(hdrs)1397 expected := http.Header{1398 DistributedTraceW3CTraceParentHeader: []string{"00-52fdfc072182654f163f5f0f9a621d72-9566c74d10d1e2c6-01"},1399 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456--52fdfc072182654f-1-1.437714-1577830891900"},1400 }1401 verifyHeaders(t, hdrs, expected)1402 txn.End()1403 app.expectNoLoggedErrors(t)1404 app.ExpectMetrics(t, append([]internal.WantMetric{1405 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},1406 }, backgroundUnknownCaller...))1407}1408func TestW3CTraceHeadersSpansDisabledSampledFalse(t *testing.T) {1409 replyfn := func(reply *internal.ConnectReply) {1410 distributedTracingReplyFieldsSpansDisabled(reply)1411 reply.SetSampleNothing()1412 }1413 app := testApp(replyfn, enableW3COnly, t)1414 txn := app.StartTransaction("hello")1415 hdrs := http.Header{}1416 txn.InsertDistributedTraceHeaders(hdrs)1417 expected := http.Header{1418 DistributedTraceW3CTraceParentHeader: []string{"00-52fdfc072182654f163f5f0f9a621d72-9566c74d10d1e2c6-00"},1419 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456--52fdfc072182654f-0-0.437714-1577830891900"},1420 }1421 verifyHeaders(t, hdrs, expected)1422 txn.End()1423 app.expectNoLoggedErrors(t)1424 app.ExpectMetrics(t, append([]internal.WantMetric{1425 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},1426 }, backgroundUnknownCaller...))1427}1428func TestW3CTraceHeadersSpansDisabledWithTraceState(t *testing.T) {1429 app := testApp(distributedTracingReplyFieldsSpansDisabled, enableW3COnly, t)1430 txn := app.StartTransaction("hello")1431 originalTraceParent := "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"1432 originalTraceState := "rojo=00f067aa0ba902b7"1433 incomingHdrs := http.Header{}1434 incomingHdrs.Set(DistributedTraceW3CTraceParentHeader, originalTraceParent)1435 incomingHdrs.Set(DistributedTraceW3CTraceStateHeader, originalTraceState)1436 txn.AcceptDistributedTraceHeaders(TransportHTTP, incomingHdrs)1437 hdrs := http.Header{}1438 txn.InsertDistributedTraceHeaders(hdrs)1439 expected := http.Header{1440 DistributedTraceW3CTraceParentHeader: []string{"00-4bf92f3577b34da6a3ce929d0e0e4736-9566c74d10d1e2c6-01"},1441 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456--52fdfc072182654f-1-1.437714-1577830891900," + originalTraceState},1442 }1443 verifyHeaders(t, hdrs, expected)1444 txn.End()1445 app.expectNoLoggedErrors(t)1446 app.ExpectMetrics(t, append([]internal.WantMetric{1447 {Name: "Supportability/TraceContext/Accept/Success", Scope: "", Forced: true, Data: nil},1448 {Name: "Supportability/TraceContext/TraceState/NoNrEntry", Scope: "", Forced: true, Data: nil},1449 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},1450 }, backgroundUnknownCallerWithTransport...))1451}1452func TestW3CTraceHeadersTxnEventsDisabled(t *testing.T) {1453 cfgfn := func(cfg *Config) {1454 enableW3COnly(cfg)1455 cfg.TransactionEvents.Enabled = false1456 }1457 app := testApp(distributedTracingReplyFields, cfgfn, t)1458 txn := app.StartTransaction("hello")1459 hdrs := http.Header{}1460 txn.InsertDistributedTraceHeaders(hdrs)1461 expected := http.Header{1462 DistributedTraceW3CTraceParentHeader: []string{"00-52fdfc072182654f163f5f0f9a621d72-9566c74d10d1e2c6-01"},1463 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456-9566c74d10d1e2c6--1-1.437714-1577830891900"},1464 }1465 verifyHeaders(t, hdrs, expected)1466 txn.End()1467 app.expectNoLoggedErrors(t)1468 app.ExpectMetrics(t, append([]internal.WantMetric{1469 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},1470 }, backgroundUnknownCaller...))1471}1472func TestW3CTraceHeadersTxnAndSpanEventsDisabledSampledTrue(t *testing.T) {1473 cfgfn := func(cfg *Config) {1474 enableW3COnly(cfg)1475 cfg.TransactionEvents.Enabled = false1476 }1477 app := testApp(distributedTracingReplyFieldsSpansDisabled, cfgfn, t)1478 txn := app.StartTransaction("hello")1479 hdrs := http.Header{}1480 txn.InsertDistributedTraceHeaders(hdrs)1481 expected := http.Header{1482 DistributedTraceW3CTraceParentHeader: []string{"00-52fdfc072182654f163f5f0f9a621d72-9566c74d10d1e2c6-01"},1483 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456---1-1.437714-1577830891900"},1484 }1485 verifyHeaders(t, hdrs, expected)1486 txn.End()1487 app.expectNoLoggedErrors(t)1488 app.ExpectMetrics(t, append([]internal.WantMetric{1489 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},1490 }, backgroundUnknownCaller...))1491}1492func TestW3CTraceHeadersTxnAndSpanEventsDisabledSampledFalse(t *testing.T) {1493 cfgfn := func(cfg *Config) {1494 enableW3COnly(cfg)1495 cfg.TransactionEvents.Enabled = false1496 }1497 app := testApp(distributedTracingReplyFieldsSpansDisabled, cfgfn, t)1498 txn := app.StartTransaction("hello")1499 hdrs := http.Header{}1500 txn.InsertDistributedTraceHeaders(hdrs)1501 expected := http.Header{1502 DistributedTraceW3CTraceParentHeader: []string{"00-52fdfc072182654f163f5f0f9a621d72-9566c74d10d1e2c6-01"},1503 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456---1-1.437714-1577830891900"},1504 }1505 verifyHeaders(t, hdrs, expected)1506 txn.End()1507 app.expectNoLoggedErrors(t)1508 app.ExpectMetrics(t, append([]internal.WantMetric{1509 {Name: "Supportability/TraceContext/Create/Success", Scope: "", Forced: true, Data: nil},1510 }, backgroundUnknownCaller...))1511}1512func TestW3CTraceHeadersNoTraceState(t *testing.T) {1513 app := testApp(distributedTracingReplyFields, enableW3COnly, t)1514 txn := app.StartTransaction("hello")1515 originalTraceParent := "00-12345678901234567890123456789012-1234567890123456-01"1516 incomingHdrs := http.Header{}1517 incomingHdrs.Set(DistributedTraceW3CTraceParentHeader, originalTraceParent)1518 txn.AcceptDistributedTraceHeaders(TransportHTTP, incomingHdrs)1519 hdrs := http.Header{}1520 txn.InsertDistributedTraceHeaders(hdrs)1521 expected := http.Header{1522 DistributedTraceW3CTraceParentHeader: []string{"00-12345678901234567890123456789012-9566c74d10d1e2c6-01"},1523 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456-9566c74d10d1e2c6-52fdfc072182654f-1-1.437714-1577830891900"},1524 }1525 verifyHeaders(t, hdrs, expected)1526 txn.End()1527 app.expectNoLoggedErrors(t)1528}1529// Based on test_traceparent_trace_id_all_zero in1530// https://github.com/w3c/trace-context/blob/3d02cfc15778ef850df9bc4e9d2740a4a2627fd5/test/test.py1531func TestW3CTraceHeadersInvalidTraceID(t *testing.T) {1532 app := testApp(distributedTracingReplyFields, enableW3COnly, t)1533 txn := app.StartTransaction("hello")1534 originalTraceParent := "00-00000000000000000000000000000000-1234567890123456-01"1535 incomingHdrs := http.Header{}1536 incomingHdrs.Set(DistributedTraceW3CTraceParentHeader, originalTraceParent)1537 txn.AcceptDistributedTraceHeaders(TransportHTTP, incomingHdrs)1538 hdrs := http.Header{}1539 txn.InsertDistributedTraceHeaders(hdrs)1540 expected := http.Header{1541 DistributedTraceW3CTraceParentHeader: []string{"00-52fdfc072182654f163f5f0f9a621d72-9566c74d10d1e2c6-01"},1542 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456-9566c74d10d1e2c6-52fdfc072182654f-1-1.437714-1577830891900"},1543 }1544 verifyHeaders(t, hdrs, expected)1545 txn.End()1546 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{1547 "reason": "invalid TraceParent trace ID",1548 })1549}1550// Based on test_traceparent_parent_id_all_zero in1551// https://github.com/w3c/trace-context/blob/3d02cfc15778ef850df9bc4e9d2740a4a2627fd5/test/test.py1552func TestW3CTraceHeadersInvalidParentID(t *testing.T) {1553 app := testApp(distributedTracingReplyFields, enableW3COnly, t)1554 txn := app.StartTransaction("hello")1555 originalTraceParent := "00-12345678901234567890123456789012-0000000000000000-01"1556 incomingHdrs := http.Header{}1557 incomingHdrs.Set(DistributedTraceW3CTraceParentHeader, originalTraceParent)1558 txn.AcceptDistributedTraceHeaders(TransportHTTP, incomingHdrs)1559 hdrs := http.Header{}1560 txn.InsertDistributedTraceHeaders(hdrs)1561 expected := http.Header{1562 DistributedTraceW3CTraceParentHeader: []string{"00-52fdfc072182654f163f5f0f9a621d72-9566c74d10d1e2c6-01"},1563 DistributedTraceW3CTraceStateHeader: []string{"123@nr=0-0-123-456-9566c74d10d1e2c6-52fdfc072182654f-1-1.437714-1577830891900"},1564 }1565 verifyHeaders(t, hdrs, expected)1566 txn.End()1567 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{1568 "reason": "invalid TraceParent parent ID",1569 })1570}1571// Based on test_traceparent_version_0x00, test_traceparent_version_0xcc, test_traceparent_version_0xff in1572// https://github.com/w3c/trace-context/blob/3d02cfc15778ef850df9bc4e9d2740a4a2627fd5/test/test.py1573func TestW3CTraceHeadersFutureVersion(t *testing.T) {1574 cases := map[string]string{1575 "00-12345678901234567890123456789012-1234567890123456-01-what-the-future-will-be-like": "invalid TraceParent flags for this version",1576 "cc-12345678901234567890123456789012-1234567890123456-01": "",1577 "cc-12345678901234567890123456789012-1234567890123456-01-what-the-future-will-be-like": "",1578 "cc-12345678901234567890123456789012-1234567890123456-01.what-the-future-will-be-like": "invalid number of TraceParent entries",1579 "ff-12345678901234567890123456789012-1234567890123456-01": "invalid TraceParent flags for this version",1580 }1581 for testCase, failureMessage := range cases {1582 app := testApp(distributedTracingReplyFields, enableW3COnly, t)1583 txn := app.StartTransaction("hello")1584 originalTraceParent := testCase1585 incomingHdrs := http.Header{}1586 incomingHdrs.Set(DistributedTraceW3CTraceParentHeader, originalTraceParent)1587 txn.AcceptDistributedTraceHeaders(TransportHTTP, incomingHdrs)1588 outgoingHdrs := http.Header{}1589 txn.InsertDistributedTraceHeaders(outgoingHdrs)1590 if len(outgoingHdrs) != 2 {1591 t.Log("Not all headers present:", outgoingHdrs)1592 t.Fail()1593 }1594 expected := "00-12345678901234567890123456789012-9566c74d10d1e2c6-01"1595 if failureMessage != "" {1596 if outgoingHdrs.Get(DistributedTraceW3CTraceParentHeader) == expected {1597 t.Errorf("Invalid TraceParent header resulting from %s", testCase)1598 }1599 } else {1600 if outgoingHdrs.Get(DistributedTraceW3CTraceParentHeader) != expected {1601 t.Errorf("Invalid TraceParent header resulting from %s", testCase)1602 }1603 }1604 txn.End()1605 if failureMessage != "" {1606 app.expectSingleLoggedError(t, "unable to accept trace payload", map[string]interface{}{1607 "reason": failureMessage,1608 })1609 } else {1610 app.expectNoLoggedErrors(t)1611 }1612 }1613}1614func TestW3CTraceParentWithoutTraceContext(t *testing.T) {1615 traceparent := "00-050c91b77efca9b0ef38b30c182355ce-560ccffb087d1906-01"1616 app := testApp(distributedTracingReplyFields, enableW3COnly, t)1617 txn := app.StartTransaction("hello")1618 hdrs := http.Header{}1619 hdrs.Set(DistributedTraceW3CTraceParentHeader, traceparent)1620 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)1621 txn.End()1622 app.ExpectTxnEvents(t, []internal.WantEvent{{1623 Intrinsics: map[string]interface{}{1624 "name": "OtherTransaction/Go/hello",1625 "traceId": "050c91b77efca9b0ef38b30c182355ce",1626 "parentSpanId": "560ccffb087d1906",1627 "guid": internal.MatchAnything,1628 "sampled": internal.MatchAnything,1629 "priority": internal.MatchAnything,1630 "parent.transportType": "HTTP",1631 },1632 }})1633}1634func TestDistributedTraceInteroperabilityErrorFallbacks(t *testing.T) {1635 // Test what happens in varying cases when both w3c and newrelic headers1636 // are found1637 // parent.type = "App"1638 // parentSpanId = "5f474d64b9cc9b2a"1639 // traceId = "3221bf09aa0bcf0d3221bf09aa0bcf0d"1640 newrelicHdr := `{1641 "v": [0,1],1642 "d": {1643 "ty": "App",1644 "ac": "123",1645 "ap": "51424",1646 "id": "5f474d64b9cc9b2a",1647 "tr": "3221bf09aa0bcf0d3221bf09aa0bcf0d",1648 "pr": 0.1234,1649 "sa": true,1650 "ti": 1482959525577,1651 "tx": "27856f70d3d314b7"1652 }1653 }`1654 // parentSpanId = "560ccffb087d1906"1655 // traceId = "050c91b77efca9b0ef38b30c182355ce"1656 traceparentHdr := "00-050c91b77efca9b0ef38b30c182355ce-560ccffb087d1906-01"1657 // parent.type = "Browser"1658 tracestateHdr := "123@nr=0-1-123-456-1234567890123456-6543210987654321-0-0.24689-0"1659 testcases := []struct {1660 name string1661 traceparent string1662 tracestate string1663 newrelic string1664 expIntrinsics map[string]interface{}1665 }{1666 {1667 name: "w3c present, newrelic absent, failure to parse traceparent",1668 traceparent: "garbage",1669 tracestate: tracestateHdr,1670 newrelic: "",1671 expIntrinsics: map[string]interface{}{1672 "guid": internal.MatchAnything,1673 "priority": internal.MatchAnything,1674 "sampled": internal.MatchAnything,1675 "name": internal.MatchAnything,1676 "traceId": "52fdfc072182654f163f5f0f9a621d72", // randomly generated1677 },1678 },1679 {1680 name: "w3c present, newrelic absent, failure to parse tracestate",1681 traceparent: traceparentHdr,1682 tracestate: "123@nr=garbage",1683 newrelic: "",1684 expIntrinsics: map[string]interface{}{1685 "guid": internal.MatchAnything,1686 "priority": internal.MatchAnything,1687 "sampled": internal.MatchAnything,1688 "name": internal.MatchAnything,1689 "parent.transportType": internal.MatchAnything,1690 "parentSpanId": "560ccffb087d1906", // from traceparent header1691 "traceId": "050c91b77efca9b0ef38b30c182355ce", // from traceparent header1692 },1693 },1694 {1695 name: "w3c present, newrelic present, failure to parse traceparent",1696 traceparent: "garbage",1697 tracestate: tracestateHdr,1698 newrelic: newrelicHdr,1699 expIntrinsics: map[string]interface{}{1700 "guid": internal.MatchAnything,1701 "priority": internal.MatchAnything,1702 "sampled": internal.MatchAnything,1703 "name": internal.MatchAnything,1704 "traceId": "52fdfc072182654f163f5f0f9a621d72", // randomly generated1705 },1706 },1707 {1708 name: "w3c present, newrelic present, failure to parse tracestate",1709 traceparent: traceparentHdr,1710 tracestate: "123@nr=garbage",1711 newrelic: newrelicHdr,1712 expIntrinsics: map[string]interface{}{1713 "guid": internal.MatchAnything,1714 "priority": internal.MatchAnything,1715 "sampled": internal.MatchAnything,1716 "name": internal.MatchAnything,1717 "parent.transportType": internal.MatchAnything,1718 "parentSpanId": "560ccffb087d1906", // from traceparent header1719 "traceId": "050c91b77efca9b0ef38b30c182355ce", // from traceparent header1720 },1721 },1722 {1723 name: "w3c present, newrelic present",1724 traceparent: traceparentHdr,1725 tracestate: tracestateHdr,1726 newrelic: newrelicHdr,1727 expIntrinsics: map[string]interface{}{1728 "parent.app": internal.MatchAnything,1729 "parent.transportDuration": internal.MatchAnything,1730 "guid": internal.MatchAnything,1731 "priority": internal.MatchAnything,1732 "sampled": internal.MatchAnything,1733 "parent.account": internal.MatchAnything,1734 "parentId": internal.MatchAnything,1735 "name": internal.MatchAnything,1736 "parent.transportType": internal.MatchAnything,1737 "parent.type": "Browser", // from tracestate header1738 "parentSpanId": "560ccffb087d1906", // from traceparent header1739 "traceId": "050c91b77efca9b0ef38b30c182355ce", // from traceparent header1740 },1741 },1742 {1743 name: "w3c absent, newrelic present",1744 traceparent: "",1745 tracestate: "",1746 newrelic: newrelicHdr,1747 expIntrinsics: map[string]interface{}{1748 "parent.app": internal.MatchAnything,1749 "parent.transportDuration": internal.MatchAnything,1750 "guid": internal.MatchAnything,1751 "priority": internal.MatchAnything,1752 "sampled": internal.MatchAnything,1753 "parent.account": internal.MatchAnything,1754 "parentId": internal.MatchAnything,1755 "name": internal.MatchAnything,1756 "parent.transportType": internal.MatchAnything,1757 "parent.type": "App", // from newrelic header1758 "parentSpanId": "5f474d64b9cc9b2a", // from newrelic header1759 "traceId": "3221bf09aa0bcf0d3221bf09aa0bcf0d", // from newrelic header1760 },1761 },1762 {1763 name: "w3c absent, newrelic absent",1764 traceparent: "",1765 tracestate: "",1766 newrelic: "",1767 expIntrinsics: map[string]interface{}{1768 "guid": internal.MatchAnything,1769 "priority": internal.MatchAnything,1770 "sampled": internal.MatchAnything,1771 "name": internal.MatchAnything,1772 "traceId": "52fdfc072182654f163f5f0f9a621d72", // randomly generated1773 },1774 },1775 }1776 addHdr := func(hdrs http.Header, key, val string) {1777 if val != "" {1778 hdrs.Add(key, val)1779 }1780 }1781 for _, tc := range testcases {1782 t.Run(tc.name, func(t *testing.T) {1783 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)1784 txn := app.StartTransaction("hello")1785 hdrs := http.Header{}1786 addHdr(hdrs, DistributedTraceW3CTraceParentHeader, tc.traceparent)1787 addHdr(hdrs, DistributedTraceW3CTraceStateHeader, tc.tracestate)1788 addHdr(hdrs, DistributedTraceNewRelicHeader, tc.newrelic)1789 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)1790 txn.End()1791 app.ExpectTxnEvents(t, []internal.WantEvent{{1792 Intrinsics: tc.expIntrinsics,1793 }})1794 })1795 }1796}1797func TestW3CTraceStateMultipleHeaders(t *testing.T) {1798 traceparent := "00-050c91b77efca9b0ef38b30c182355ce-560ccffb087d1906-01"1799 nrstatekey := "123@nr=0-0-123-456-1234567890123456-6543210987654321-1-0.24689-0"1800 testcases := []struct {1801 firstheader string1802 secondheader string1803 }{1804 {firstheader: "a=1,b=2", secondheader: nrstatekey},1805 {firstheader: "a=1", secondheader: "b=2," + nrstatekey},1806 {firstheader: "a=1", secondheader: nrstatekey + ",b=2"},1807 }1808 for _, tc := range testcases {1809 t.Run(tc.firstheader+"_"+tc.secondheader, func(t *testing.T) {1810 app := testApp(distributedTracingReplyFields, enableBetterCAT, t)1811 txn := app.StartTransaction("hello")1812 hdrs := http.Header{}1813 hdrs.Add(DistributedTraceW3CTraceParentHeader, traceparent)1814 hdrs.Add(DistributedTraceW3CTraceStateHeader, tc.firstheader)1815 hdrs.Add(DistributedTraceW3CTraceStateHeader, tc.secondheader)1816 txn.AcceptDistributedTraceHeaders(TransportHTTP, hdrs)1817 txn.End()1818 app.expectNoLoggedErrors(t)1819 app.ExpectSpanEvents(t, []internal.WantEvent{{1820 Intrinsics: map[string]interface{}{1821 "category": "generic",1822 "guid": "9566c74d10d1e2c6",1823 "name": "OtherTransaction/Go/hello",1824 "transaction.name": "OtherTransaction/Go/hello",1825 "nr.entryPoint": true,1826 "parentId": "560ccffb087d1906",1827 "priority": internal.MatchAnything,1828 "sampled": true,1829 "traceId": "050c91b77efca9b0ef38b30c182355ce",1830 "tracingVendors": "a,b", // ensures both headers read1831 "transactionId": "52fdfc072182654f",1832 "trustedParentId": "1234567890123456",1833 },1834 }})1835 })1836 }1837}1838func TestW3CTraceIDLengths(t *testing.T) {1839 // Test that if the agent received an inbound traceId that is less than 321840 // characters, the traceId included in an outbound payload must be1841 // left-padded with zeros. If it is too long, we chop off from the left....
index.go
Source:index.go
1package gopan2import (3 "compress/gzip"4 "github.com/ian-kent/go-log/log"5 "io/ioutil"6 "os"7 "regexp"8 "strings"9)10func CountIndex(indexes map[string]map[string]*Source) (int, int, int, int) {11 var n1, n2, n3, n4 int12 n1 = len(indexes)13 for fname, _ := range indexes {14 for _, idx := range indexes[fname] {15 n2 += len(idx.Authors)16 for _, auth := range idx.Authors {17 n3 += len(auth.Packages)18 for _, pkg := range auth.Packages {19 n4 += len(pkg.Provides)20 }21 }22 }23 }24 return n1, n2, n3, n425}26func AppendToIndex(index string, source *Source, author *Author, pkg *Package) {27 out, err := os.OpenFile(index, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660)28 if err != nil {29 log.Error("Error opening index: %s", err.Error())30 return31 }32 out.Write([]byte(source.Name + " [" + source.URL + "]\n"))33 out.Write([]byte(" " + author.Name + " [" + author.URL + "]\n"))34 out.Write([]byte(" " + pkg.Name + " => " + pkg.URL + "\n"))35 for p, pk := range pkg.Provides {36 out.Write([]byte(" " + p + " (" + pk.Version + "): " + pk.File + "\n"))37 }38 out.Close()39}40func RemoveModule(index string, source *Source, author *Author, pkg *Package) {41 out, err := os.OpenFile(index, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0660)42 if err != nil {43 log.Error("Error opening index: %s", err.Error())44 return45 }46 out.Write([]byte(source.Name + " [" + source.URL + "]\n"))47 out.Write([]byte(" " + author.Name + " [" + author.URL + "]\n"))48 out.Write([]byte(" -" + pkg.Name + " => " + pkg.URL + "\n"))49 out.Close()50}51func SaveIndex(index string, indexes map[string]*Source) {52 // TODO append, but needs to know which stuff is new53 //out, err := os.OpenFile(".gopancache/index", os.O_RDWR|os.O_APPEND, 0660)54 out, err := os.Create(index)55 if err != nil {56 log.Error("Error creating index: %s", err.Error())57 }58 for _, source := range indexes {59 out.Write([]byte(source.Name + " [" + source.URL + "]\n"))60 log.Trace(source.Name)61 for _, author := range source.Authors {62 out.Write([]byte(" " + author.Name + " [" + author.URL + "]\n"))63 log.Trace(" %s", author.Name)64 for _, pkg := range author.Packages {65 out.Write([]byte(" " + pkg.Name + " => " + pkg.URL + "\n"))66 log.Trace(" %s => %s", pkg.Name, pkg.URL)67 for p, pk := range pkg.Provides {68 out.Write([]byte(" " + p + " (" + pk.Version + "): " + pk.File + "\n"))69 log.Trace(" %s (%s): %s", p, pk.Version, pk.File)70 }71 }72 }73 }74 out.Close()75}76func LoadIndex(index string) map[string]*Source {77 indexes := make(map[string]*Source)78 log.Info("Loading cached index file %s", index)79 if _, err := os.Stat(index); err != nil {80 log.Error("Cached index file not found")81 return indexes82 }83 var bytes []byte84 if strings.HasSuffix(index, ".gz") {85 fi, err := os.Open(index)86 if err != nil {87 log.Error("Error reading index: %s", err.Error())88 return indexes89 }90 defer fi.Close()91 gz, err := gzip.NewReader(fi)92 if err != nil {93 log.Error("Error creating gzip reader: %s", err.Error())94 return indexes95 }96 bytes, err = ioutil.ReadAll(gz)97 if err != nil {98 log.Error("Error reading from gzip: %s", err.Error())99 return indexes100 }101 } else {102 var err error103 bytes, err = ioutil.ReadFile(index)104 if err != nil {105 log.Error("Error reading index: %s", err.Error())106 return indexes107 }108 }109 lines := strings.Split(string(bytes), "\n")110 var csource *Source111 var cauth *Author112 var cpkg *Package113 resrcauth := regexp.MustCompile("^\\s*(.*)\\s\\[(.*)\\]\\s*$")114 repackage := regexp.MustCompile("^\\s*(.*)\\s=>\\s(.*)\\s*$")115 reprovides := regexp.MustCompile("^\\s*(.*)\\s\\((.*)\\):\\s(.*)\\s*$")116 for _, l := range lines {117 log.Trace("Line: %s", l)118 if strings.HasPrefix(l, " ") {119 // provides120 log.Trace("=> Provides")121 match := reprovides.FindStringSubmatch(l)122 if len(match) > 0 {123 if strings.HasPrefix(match[1], "-") {124 log.Trace(" - Is a removal")125 match[1] = strings.TrimPrefix(match[1], "-")126 if _, ok := cpkg.Provides[match[1]]; ok {127 delete(cpkg.Provides, match[1])128 }129 if len(cpkg.Provides) == 0 {130 delete(cauth.Packages, cpkg.Name)131 cpkg = nil132 }133 if len(cauth.Packages) == 0 {134 delete(csource.Authors, cauth.Name)135 cauth = nil136 }137 if len(csource.Authors) == 0 {138 delete(indexes, csource.Name)139 csource = nil140 }141 } else {142 cpkg.Provides[match[1]] = &PerlPackage{143 Name: match[1],144 Version: match[2],145 Package: cpkg,146 File: match[3],147 }148 }149 }150 } else if strings.HasPrefix(l, " ") {151 // its a package152 log.Trace("=> Package")153 match := repackage.FindStringSubmatch(l)154 if len(match) > 0 {155 if strings.HasPrefix(match[1], "-") {156 log.Trace(" - Is a removal")157 match[1] = strings.TrimPrefix(match[1], "-")158 if _, ok := cauth.Packages[match[1]]; ok {159 delete(cauth.Packages, match[1])160 }161 if len(cauth.Packages) == 0 {162 delete(csource.Authors, cauth.Name)163 cauth = nil164 }165 if len(csource.Authors) == 0 {166 delete(indexes, csource.Name)167 csource = nil168 }169 } else {170 if _, ok := cauth.Packages[match[1]]; ok {171 // we've seen this package before172 log.Trace("Seen this package before: %s", match[1])173 cpkg = cauth.Packages[match[1]]174 continue175 }176 cpkg = &Package{177 Name: match[1],178 URL: match[2],179 Author: cauth,180 Provides: make(map[string]*PerlPackage),181 }182 cauth.Packages[match[1]] = cpkg183 }184 }185 } else if strings.HasPrefix(l, " ") {186 // its an author187 log.Trace("=> Author")188 match := resrcauth.FindStringSubmatch(l)189 if len(match) > 0 {190 if strings.HasPrefix(match[1], "-") {191 log.Trace(" - Is a removal")192 match[1] = strings.TrimPrefix(match[1], "-")193 if _, ok := csource.Authors[match[1]]; ok {194 delete(csource.Authors, match[1])195 }196 if len(csource.Authors) == 0 {197 delete(indexes, csource.Name)198 csource = nil199 }200 } else {201 if _, ok := csource.Authors[match[1]]; ok {202 // we've seen this author before203 log.Trace("Seen this author before: %s", match[1])204 cauth = csource.Authors[match[1]]205 continue206 }207 cauth = &Author{208 Name: match[1],209 URL: match[2],210 Source: csource,211 Packages: make(map[string]*Package, 0),212 }213 csource.Authors[match[1]] = cauth214 }215 }216 } else {217 // its a source218 log.Trace("=> Source")219 match := resrcauth.FindStringSubmatch(l)220 if len(match) > 0 {221 if strings.HasPrefix(match[1], "-") {222 log.Trace(" - Is a removal")223 match[1] = strings.TrimPrefix(match[1], "-")224 if _, ok := indexes[match[1]]; ok {225 delete(indexes, match[1])226 }227 } else {228 seen := false229 for _, idx := range indexes {230 if idx.Name == match[1] {231 // we've seen this source before232 log.Trace("Seen this source before: %s", idx.Name)233 csource = idx234 seen = true235 break236 }237 }238 if seen {239 continue240 }241 csource = &Source{242 Name: match[1],243 URL: match[2],244 Authors: make(map[string]*Author, 0),245 }246 indexes[csource.Name] = csource247 }248 }249 }250 }251 for _, source := range indexes {252 log.Trace(source.Name)253 for _, author := range source.Authors {254 log.Trace(" %s", author.Name)255 for _, pkg := range author.Packages {256 log.Trace(" %s => %s", pkg.Name, pkg.URL)257 }258 }259 }260 return indexes261}...
pbcodec_test.go
Source:pbcodec_test.go
...11// causes a cycle because `codec` uses `pb/codec` which would use `codec/testing` which12// uses `codec`.13//14// Easiest solution was to find a "third-party" package to host those tests, here we are.15func TestFilteringActionMatcher(t *testing.T) {16 newAccount := []pbcodec.ActionMatcher{17 func(actTrace *pbcodec.ActionTrace) bool {18 fmt.Printf("%#v\n", actTrace)19 return actTrace.Receiver == "zswhq" && actTrace.Action.Account == "zswhq" && actTrace.Action.Name == "newaccount"20 },21 }22 tests := []struct {23 name string24 block *pbcodec.Block25 requireSystemActions []pbcodec.ActionMatcher26 expectedMatch []uint3227 expectedNotMatch []uint3228 }{29 {30 "none matching",31 ct.Block(t, "00000001aa", ct.FilteredBlock{}, ct.TrxTrace(t,32 ct.ActionTrace(t, "match:match:zero"),33 ct.ActionTrace(t, "match:match:first"),34 )),35 nil,36 nil,37 []uint32{0, 1},38 },39 {40 "some matching",41 ct.Block(t, "00000001aa", ct.FilteredBlock{}, ct.TrxTrace(t,42 ct.ActionTrace(t, "match:match:zero", ct.ActionMatched),43 ct.ActionTrace(t, "nonmatch:nonmatch:middle"),44 ct.ActionTrace(t, "match:match:first", ct.ActionMatched),45 )),46 nil,47 []uint32{0, 2},48 []uint32{1},49 },50 {51 "all matching",52 ct.Block(t, "00000001aa", ct.FilteredBlock{}, ct.TrxTrace(t,53 ct.ActionTrace(t, "match:match:zero", ct.ActionMatched),54 ct.ActionTrace(t, "match:match:first", ct.ActionMatched),55 )),56 nil,57 []uint32{0, 1},58 nil,59 },60 {61 "block is unfiltered, everything is included",62 ct.Block(t, "00000001aa", ct.TrxTrace(t,63 ct.ActionTrace(t, "match:match:zero"),64 ct.ActionTrace(t, "match:match:first", ct.ActionMatched),65 )),66 nil,67 []uint32{0, 1},68 nil,69 },70 {71 "is required system actions but was not system included, still match",72 ct.Block(t, "00000001aa", ct.FilteredBlock{}, ct.TrxTrace(t,73 ct.ActionTrace(t, "zswhq:zswhq:newaccount", ct.ActionMatched),74 ct.ActionTrace(t, "zswhq:zswhq:newaccount", ct.ActionMatched),75 )),76 newAccount,77 []uint32{0, 1},78 nil,79 },80 {81 "is required system actions and was system included, still match",82 ct.Block(t, "00000001aa", ct.FilteredBlock{}, ct.TrxTrace(t,83 ct.ActionTrace(t, "zswhq:zswhq:newaccount", ct.ActionSystemMatched),84 ct.ActionTrace(t, "zswhq:zswhq:newaccount", ct.ActionSystemMatched),85 )),86 newAccount,87 []uint32{0, 1},88 nil,89 },90 {91 "was system included but is not a required actions when empty, does not match",92 ct.Block(t, "00000001aa", ct.FilteredBlock{}, ct.TrxTrace(t,93 ct.ActionTrace(t, "zswhq:zswhq:newaccount", ct.ActionSystemMatched),94 ct.ActionTrace(t, "zswhq:zswhq:newaccount", ct.ActionSystemMatched),95 )),96 nil,97 nil,98 []uint32{0, 1},99 },100 {101 "was system included but is not a required actions not matching, does not match",102 ct.Block(t, "00000001aa", ct.FilteredBlock{}, ct.TrxTrace(t,103 ct.ActionTrace(t, "zswhq:zswhq:setabi", ct.ActionSystemMatched),104 ct.ActionTrace(t, "zswhq:zswhq:setabi", ct.ActionSystemMatched),105 )),106 newAccount,107 nil,108 []uint32{0, 1},109 },110 }111 for _, test := range tests {112 t.Run(test.name, func(t *testing.T) {113 matcher := test.block.FilteringActionMatcher(test.block.TransactionTraces()[0], test.requireSystemActions...)114 for _, expectedMatch := range test.expectedMatch {115 assert.True(t, matcher.Matched(expectedMatch), "Expecting action index %d to be included in matcher, but it was not", expectedMatch)116 }117 for _, expectedNotMatch := range test.expectedNotMatch {118 assert.False(t, matcher.Matched(expectedNotMatch), "Expecting action index %d to be excluded from matcher, but it was not", expectedNotMatch)119 }120 })121 }122}...
Match
Using AI Code Generation
1import (2func main() {3 re := regexp.MustCompile("p([a-z]+)ch")4 fmt.Println(re.MatchString("peach"))5}6import (7func main() {8 match, _ := regexp.MatchString("p([a-z]+)ch", "peach")9 fmt.Println(match)10}11import (12func main() {13 re := regexp.MustCompile("p([a-z]+)ch")14 fmt.Println(re.FindString("peach punch"))15}16import (17func main() {18 re := regexp.MustCompile("p([a-z]+)ch")19 fmt.Println(re.FindStringIndex("peach punch"))20}21import (22func main() {23 re := regexp.MustCompile("p([a-z]+)ch")24 fmt.Println(re.FindStringSubmatch("peach punch"))25}
Match
Using AI Code Generation
1import (2func main() {3 re, err := regexp.Compile("[0-9]+")4 if err != nil {5 fmt.Println(err)6 }7 match := re.Match([]byte("123"))8 fmt.Println(match)9 match = re.Match([]byte("abc"))10 fmt.Println(match)11}
Match
Using AI Code Generation
1import (2func main() {3 re := regexp.MustCompile("a([a-z]+)e")4 fmt.Println(re.MatchString("apple"))5 fmt.Println(re.MatchString("peach"))6}7func (re *Regexp) MatchReader(r io.RuneScanner) bool8import (9func main() {10 re := regexp.MustCompile("a([a-z]+)e")11 fmt.Println(re.MatchReader(strings.NewReader("apple")))12 fmt.Println(re.MatchReader(strings.NewReader("peach")))13}14func (re *Regexp) MatchString(s string) bool15import (16func main() {17 re := regexp.MustCompile("a([a-z]+)e")18 fmt.Println(re.MatchString("apple"))19 fmt.Println(re.MatchString("peach"))20}21func (re *Regexp) NumSubexp() int22import (23func main() {
Match
Using AI Code Generation
1import "fmt"2import "regexp"3func main() {4 var matches = pattern.FindAllString(text, -1)5 fmt.Println(matches)6}7import "fmt"8import "regexp"9func main() {10 var matches = pattern.FindAllString(text, 2)11 fmt.Println(matches)12}13import "fmt"14import "regexp"15func main() {16 var matches = pattern.FindAllString(text, 1)17 fmt.Println(matches)18}19import "fmt"20import "regexp"21func main() {22 var matches = pattern.FindAllString(text, 0)23 fmt.Println(matches)24}25import "fmt"26import "regexp"27func main() {28 var matches = pattern.FindAllStringIndex(text, -1)29 fmt.Println(matches)30}
Match
Using AI Code Generation
1import (2func main() {3 t := trace.Trace{3, 4, "hello"}4 fmt.Println(t.Match(3, 4, "hello"))5 fmt.Println(t.Match(3, 4, "world"))6}
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!