github.com/lulzWill/go-agent@v2.1.2+incompatible/internal/txn_cross_process_test.go (about) 1 package internal 2 3 import ( 4 "fmt" 5 "net/http" 6 "reflect" 7 "testing" 8 "time" 9 10 "github.com/lulzWill/go-agent/internal/cat" 11 ) 12 13 var ( 14 replyAccountOne = &ConnectReply{ 15 CrossProcessID: "1#1", 16 EncodingKey: "foo", 17 TrustedAccounts: map[int]struct{}{1: struct{}{}}, 18 } 19 20 replyAccountTwo = &ConnectReply{ 21 CrossProcessID: "2#2", 22 EncodingKey: "foo", 23 TrustedAccounts: map[int]struct{}{2: struct{}{}}, 24 } 25 26 requestEmpty = newRequest().Request 27 requestCATOne = newRequest().withCAT(newTxnCrossProcessFromConnectReply(replyAccountOne), "txn", "app").Request 28 requestSyntheticsOne = newRequest().withSynthetics(1, "foo").Request 29 requestCATSyntheticsOne = newRequest().withCAT(newTxnCrossProcessFromConnectReply(replyAccountOne), "txn", "app").withSynthetics(1, "foo").Request 30 ) 31 32 func mustObfuscate(input, encodingKey string) string { 33 output, err := obfuscate([]byte(input), []byte(encodingKey)) 34 if err != nil { 35 panic(err) 36 } 37 38 return string(output) 39 } 40 41 func newTxnCrossProcessFromConnectReply(reply *ConnectReply) *TxnCrossProcess { 42 txp := &TxnCrossProcess{GUID: "abcdefgh"} 43 txp.InitFromHTTPRequest(true, reply, nil) 44 45 return txp 46 } 47 48 type request struct { 49 *http.Request 50 } 51 52 func newRequest() *request { 53 req, err := http.NewRequest("GET", "http://foo.bar", nil) 54 if err != nil { 55 panic(err) 56 } 57 58 return &request{Request: req} 59 } 60 61 func (req *request) withCAT(txp *TxnCrossProcess, txnName, appName string) *request { 62 metadata, err := txp.CreateCrossProcessMetadata(txnName, appName) 63 if err != nil { 64 panic(err) 65 } 66 67 for k, values := range MetadataToHTTPHeader(metadata) { 68 for _, v := range values { 69 req.Header.Add(k, v) 70 } 71 } 72 73 return req 74 } 75 76 func (req *request) withSynthetics(account int, encodingKey string) *request { 77 header := fmt.Sprintf(`[1,%d,"resource","job","monitor"]`, account) 78 obfuscated, err := obfuscate([]byte(header), []byte(encodingKey)) 79 if err != nil { 80 panic(err) 81 } 82 83 req.Header.Add(cat.NewRelicSyntheticsName, string(obfuscated)) 84 return req 85 } 86 87 func TestTxnCrossProcessInit(t *testing.T) { 88 for _, tc := range []struct { 89 name string 90 enabled bool 91 reply *ConnectReply 92 req *http.Request 93 expected *TxnCrossProcess 94 expectedError bool 95 }{ 96 { 97 name: "disabled", 98 enabled: false, 99 reply: replyAccountOne, 100 req: nil, 101 expected: &TxnCrossProcess{ 102 CrossProcessID: []byte("1#1"), 103 EncodingKey: []byte("foo"), 104 Enabled: false, 105 TrustedAccounts: map[int]struct{}{1: struct{}{}}, 106 }, 107 expectedError: false, 108 }, 109 { 110 name: "normal connect reply without a request", 111 enabled: true, 112 reply: replyAccountOne, 113 req: nil, 114 expected: &TxnCrossProcess{ 115 CrossProcessID: []byte("1#1"), 116 EncodingKey: []byte("foo"), 117 Enabled: true, 118 TrustedAccounts: map[int]struct{}{1: struct{}{}}, 119 }, 120 expectedError: false, 121 }, 122 { 123 name: "normal connect reply with a request without headers", 124 enabled: true, 125 reply: replyAccountOne, 126 req: requestEmpty, 127 expected: &TxnCrossProcess{ 128 CrossProcessID: []byte("1#1"), 129 EncodingKey: []byte("foo"), 130 Enabled: true, 131 TrustedAccounts: map[int]struct{}{1: struct{}{}}, 132 }, 133 expectedError: false, 134 }, 135 { 136 name: "normal connect reply with a request with untrusted headers", 137 enabled: true, 138 reply: replyAccountTwo, 139 req: requestCATOne, 140 expected: &TxnCrossProcess{ 141 CrossProcessID: []byte("2#2"), 142 EncodingKey: []byte("foo"), 143 Enabled: true, 144 TrustedAccounts: map[int]struct{}{2: struct{}{}}, 145 }, 146 expectedError: true, 147 }, 148 { 149 name: "normal connect reply with a request with trusted headers", 150 enabled: true, 151 reply: replyAccountOne, 152 req: requestCATOne, 153 expected: &TxnCrossProcess{ 154 CrossProcessID: []byte("1#1"), 155 EncodingKey: []byte("foo"), 156 Enabled: true, 157 TrustedAccounts: map[int]struct{}{1: struct{}{}}, 158 }, 159 expectedError: false, 160 }, 161 } { 162 actual := &TxnCrossProcess{} 163 164 id := "" 165 txnData := "" 166 synthetics := "" 167 if tc.req != nil { 168 id = tc.req.Header.Get(cat.NewRelicIDName) 169 txnData = tc.req.Header.Get(cat.NewRelicTxnName) 170 synthetics = tc.req.Header.Get(cat.NewRelicSyntheticsName) 171 } 172 173 err := actual.Init(tc.enabled, tc.reply, CrossProcessMetadata{id, txnData, synthetics}) 174 if tc.expectedError == false && err != nil { 175 t.Errorf("%s: unexpected error returned from Init: %v", tc.name, err) 176 } else if tc.expectedError && err == nil { 177 t.Errorf("%s: no error returned from Init when one was expected", tc.name) 178 } 179 180 if !reflect.DeepEqual(actual.EncodingKey, tc.expected.EncodingKey) { 181 t.Errorf("%s: EncodingKey mismatch: expected=%v; got=%v", tc.name, tc.expected.EncodingKey, actual.EncodingKey) 182 } 183 184 if !reflect.DeepEqual(actual.CrossProcessID, tc.expected.CrossProcessID) { 185 t.Errorf("%s: CrossProcessID mismatch: expected=%v; got=%v", tc.name, tc.expected.CrossProcessID, actual.CrossProcessID) 186 } 187 188 if !reflect.DeepEqual(actual.TrustedAccounts, tc.expected.TrustedAccounts) { 189 t.Errorf("%s: TrustedAccounts mismatch: expected=%v; got=%v", tc.name, tc.expected.TrustedAccounts, actual.TrustedAccounts) 190 } 191 192 if actual.Enabled != tc.expected.Enabled { 193 t.Errorf("%s: Enabled mismatch: expected=%v; got=%v", tc.name, tc.expected.Enabled, actual.Enabled) 194 } 195 } 196 } 197 198 func TestTxnCrossProcessCreateCrossProcessMetadata(t *testing.T) { 199 for _, tc := range []struct { 200 name string 201 enabled bool 202 reply *ConnectReply 203 req *http.Request 204 txnName string 205 appName string 206 expectedError bool 207 expectedMetadata CrossProcessMetadata 208 }{ 209 { 210 name: "disabled, no header", 211 enabled: false, 212 reply: replyAccountOne, 213 req: nil, 214 txnName: "txn", 215 appName: "app", 216 expectedError: false, 217 expectedMetadata: CrossProcessMetadata{}, 218 }, 219 { 220 name: "disabled, header", 221 enabled: false, 222 reply: replyAccountOne, 223 req: requestCATOne, 224 txnName: "txn", 225 appName: "app", 226 expectedError: false, 227 expectedMetadata: CrossProcessMetadata{}, 228 }, 229 { 230 name: "disabled, synthetics", 231 enabled: false, 232 reply: replyAccountOne, 233 req: requestSyntheticsOne, 234 txnName: "txn", 235 appName: "app", 236 expectedError: false, 237 expectedMetadata: CrossProcessMetadata{ 238 Synthetics: mustObfuscate(`[1,1,"resource","job","monitor"]`, "foo"), 239 }, 240 }, 241 { 242 name: "disabled, header, synthetics", 243 enabled: false, 244 reply: replyAccountOne, 245 req: requestCATSyntheticsOne, 246 txnName: "txn", 247 appName: "app", 248 expectedError: false, 249 expectedMetadata: CrossProcessMetadata{ 250 Synthetics: mustObfuscate(`[1,1,"resource","job","monitor"]`, "foo"), 251 }, 252 }, 253 { 254 name: "enabled, no header, no synthetics", 255 enabled: true, 256 reply: replyAccountOne, 257 req: requestEmpty, 258 txnName: "txn", 259 appName: "app", 260 expectedError: false, 261 expectedMetadata: CrossProcessMetadata{ 262 ID: mustObfuscate(`1#1`, "foo"), 263 TxnData: mustObfuscate(`["00000000",false,"00000000","b95be233"]`, "foo"), 264 }, 265 }, 266 { 267 name: "enabled, no header, synthetics", 268 enabled: true, 269 reply: replyAccountOne, 270 req: requestSyntheticsOne, 271 txnName: "txn", 272 appName: "app", 273 expectedError: false, 274 expectedMetadata: CrossProcessMetadata{ 275 ID: mustObfuscate(`1#1`, "foo"), 276 TxnData: mustObfuscate(`["00000000",false,"00000000","b95be233"]`, "foo"), 277 Synthetics: mustObfuscate(`[1,1,"resource","job","monitor"]`, "foo"), 278 }, 279 }, 280 { 281 name: "enabled, header, no synthetics", 282 enabled: true, 283 reply: replyAccountOne, 284 req: requestCATOne, 285 txnName: "txn", 286 appName: "app", 287 expectedError: false, 288 expectedMetadata: CrossProcessMetadata{ 289 ID: mustObfuscate(`1#1`, "foo"), 290 TxnData: mustObfuscate(`["00000000",false,"abcdefgh","cbec2654"]`, "foo"), 291 }, 292 }, 293 { 294 name: "enabled, header, synthetics", 295 enabled: true, 296 reply: replyAccountOne, 297 req: requestCATSyntheticsOne, 298 txnName: "txn", 299 appName: "app", 300 expectedError: false, 301 expectedMetadata: CrossProcessMetadata{ 302 ID: mustObfuscate(`1#1`, "foo"), 303 TxnData: mustObfuscate(`["00000000",false,"abcdefgh","cbec2654"]`, "foo"), 304 Synthetics: mustObfuscate(`[1,1,"resource","job","monitor"]`, "foo"), 305 }, 306 }, 307 } { 308 txp := &TxnCrossProcess{GUID: "00000000"} 309 txp.InitFromHTTPRequest(tc.enabled, tc.reply, tc.req) 310 metadata, err := txp.CreateCrossProcessMetadata(tc.txnName, tc.appName) 311 312 if tc.expectedError == false && err != nil { 313 t.Errorf("%s: unexpected error returned from CreateCrossProcessMetadata: %v", tc.name, err) 314 } else if tc.expectedError && err == nil { 315 t.Errorf("%s: no error returned from CreateCrossProcessMetadata when one was expected", tc.name) 316 } 317 318 if !reflect.DeepEqual(tc.expectedMetadata, metadata) { 319 t.Errorf("%s: metadata mismatch: expected=%v; got=%v", tc.name, tc.expectedMetadata, metadata) 320 } 321 322 // Ensure that a path hash was generated if TxnData was created. 323 if metadata.TxnData != "" && txp.PathHash == "" { 324 t.Errorf("%s: no path hash generated", tc.name) 325 } 326 } 327 } 328 329 func TestTxnCrossProcessCreateCrossProcessMetadataError(t *testing.T) { 330 // Ensure errors bubble back up from deeper within our obfuscation code. 331 // It's likely impossible to get outboundTxnData() to fail, but we can get 332 // outboundID() to fail by having an empty encoding key. 333 txp := &TxnCrossProcess{Enabled: true} 334 metadata, err := txp.CreateCrossProcessMetadata("txn", "app") 335 if metadata.ID != "" || metadata.TxnData != "" || metadata.Synthetics != "" { 336 t.Errorf("one or more metadata fields were set unexpectedly; got %v", metadata) 337 } 338 if err == nil { 339 t.Errorf("did not get expected error with an empty encoding key") 340 } 341 342 // Test the above with Synthetics support to ensure that the Synthetics 343 // payload is still set. 344 txp = &TxnCrossProcess{ 345 Enabled: true, 346 Type: txnCrossProcessSynthetics, 347 SyntheticsHeader: "foo", 348 // This won't be actually examined, but can't be nil for the IsSynthetics() 349 // check to pass. 350 Synthetics: &cat.SyntheticsHeader{}, 351 } 352 metadata, err = txp.CreateCrossProcessMetadata("txn", "app") 353 if metadata.ID != "" || metadata.TxnData != "" { 354 t.Errorf("one or more metadata fields were set unexpectedly; got %v", metadata) 355 } 356 if metadata.Synthetics != "foo" { 357 t.Errorf("unexpected synthetics metadata: expected %s; got %s", "foo", metadata.Synthetics) 358 } 359 if err == nil { 360 t.Errorf("did not get expected error with an empty encoding key") 361 } 362 } 363 364 func TestTxnCrossProcessFinalise(t *testing.T) { 365 // No CAT. 366 txp := &TxnCrossProcess{} 367 txp.InitFromHTTPRequest(true, replyAccountOne, nil) 368 if err := txp.Finalise("txn", "app"); err != nil { 369 t.Errorf("unexpected error: %v", err) 370 } 371 if txp.PathHash != "" { 372 t.Errorf("unexpected path hash: %s", txp.PathHash) 373 } 374 375 // CAT, but no path hash. 376 txp = &TxnCrossProcess{} 377 txp.InitFromHTTPRequest(true, replyAccountOne, requestCATOne) 378 if txp.PathHash != "" { 379 t.Errorf("unexpected path hash: %s", txp.PathHash) 380 } 381 if err := txp.Finalise("txn", "app"); err != nil { 382 t.Errorf("unexpected error: %v", err) 383 } 384 if txp.PathHash == "" { 385 t.Error("unexpected lack of path hash") 386 } 387 388 // CAT, with a path hash. 389 txp = &TxnCrossProcess{} 390 txp.InitFromHTTPRequest(true, replyAccountOne, requestCATOne) 391 txp.CreateCrossProcessMetadata("txn", "app") 392 if txp.PathHash == "" { 393 t.Error("unexpected lack of path hash") 394 } 395 if err := txp.Finalise("txn", "app"); err != nil { 396 t.Errorf("unexpected error: %v", err) 397 } 398 if txp.PathHash == "" { 399 t.Error("unexpected lack of path hash") 400 } 401 } 402 403 func TestTxnCrossProcessIsInbound(t *testing.T) { 404 for _, tc := range []struct { 405 txpType uint8 406 expected bool 407 }{ 408 {0, false}, 409 {txnCrossProcessSynthetics, false}, 410 {txnCrossProcessInbound, true}, 411 {txnCrossProcessOutbound, false}, 412 {txnCrossProcessSynthetics | txnCrossProcessInbound, true}, 413 {txnCrossProcessSynthetics | txnCrossProcessOutbound, false}, 414 {txnCrossProcessInbound | txnCrossProcessOutbound, true}, 415 {txnCrossProcessSynthetics | txnCrossProcessInbound | txnCrossProcessOutbound, true}, 416 } { 417 txp := &TxnCrossProcess{Type: tc.txpType} 418 actual := txp.IsInbound() 419 if actual != tc.expected { 420 t.Errorf("unexpected IsInbound result for input %d: expected=%v; got=%v", tc.txpType, tc.expected, actual) 421 } 422 } 423 } 424 425 func TestTxnCrossProcessIsOutbound(t *testing.T) { 426 for _, tc := range []struct { 427 txpType uint8 428 expected bool 429 }{ 430 {0, false}, 431 {txnCrossProcessSynthetics, false}, 432 {txnCrossProcessInbound, false}, 433 {txnCrossProcessOutbound, true}, 434 {txnCrossProcessSynthetics | txnCrossProcessInbound, false}, 435 {txnCrossProcessSynthetics | txnCrossProcessOutbound, true}, 436 {txnCrossProcessInbound | txnCrossProcessOutbound, true}, 437 {txnCrossProcessSynthetics | txnCrossProcessInbound | txnCrossProcessOutbound, true}, 438 } { 439 txp := &TxnCrossProcess{Type: tc.txpType} 440 actual := txp.IsOutbound() 441 if actual != tc.expected { 442 t.Errorf("unexpected IsOutbound result for input %d: expected=%v; got=%v", tc.txpType, tc.expected, actual) 443 } 444 } 445 } 446 447 func TestTxnCrossProcessIsSynthetics(t *testing.T) { 448 for _, tc := range []struct { 449 txpType uint8 450 synthetics *cat.SyntheticsHeader 451 expected bool 452 }{ 453 {0, nil, false}, 454 {txnCrossProcessSynthetics, nil, false}, 455 {txnCrossProcessInbound, nil, false}, 456 {txnCrossProcessOutbound, nil, false}, 457 {txnCrossProcessSynthetics | txnCrossProcessInbound, nil, false}, 458 {txnCrossProcessSynthetics | txnCrossProcessOutbound, nil, false}, 459 {txnCrossProcessInbound | txnCrossProcessOutbound, nil, false}, 460 {txnCrossProcessSynthetics | txnCrossProcessInbound | txnCrossProcessOutbound, nil, false}, 461 {0, &cat.SyntheticsHeader{}, false}, 462 {txnCrossProcessSynthetics, &cat.SyntheticsHeader{}, true}, 463 {txnCrossProcessInbound, &cat.SyntheticsHeader{}, false}, 464 {txnCrossProcessOutbound, &cat.SyntheticsHeader{}, false}, 465 {txnCrossProcessSynthetics | txnCrossProcessInbound, &cat.SyntheticsHeader{}, true}, 466 {txnCrossProcessSynthetics | txnCrossProcessOutbound, &cat.SyntheticsHeader{}, true}, 467 {txnCrossProcessInbound | txnCrossProcessOutbound, &cat.SyntheticsHeader{}, false}, 468 {txnCrossProcessSynthetics | txnCrossProcessInbound | txnCrossProcessOutbound, &cat.SyntheticsHeader{}, true}, 469 } { 470 txp := &TxnCrossProcess{Type: tc.txpType, Synthetics: tc.synthetics} 471 actual := txp.IsSynthetics() 472 if actual != tc.expected { 473 t.Errorf("unexpected IsSynthetics result for input %d and %p: expected=%v; got=%v", tc.txpType, tc.synthetics, tc.expected, actual) 474 } 475 } 476 } 477 478 func TestTxnCrossProcessUsed(t *testing.T) { 479 for _, tc := range []struct { 480 txpType uint8 481 expected bool 482 }{ 483 {0, false}, 484 {txnCrossProcessSynthetics, true}, 485 {txnCrossProcessInbound, true}, 486 {txnCrossProcessOutbound, true}, 487 {txnCrossProcessSynthetics | txnCrossProcessInbound, true}, 488 {txnCrossProcessSynthetics | txnCrossProcessOutbound, true}, 489 {txnCrossProcessInbound | txnCrossProcessOutbound, true}, 490 {txnCrossProcessSynthetics | txnCrossProcessInbound | txnCrossProcessOutbound, true}, 491 } { 492 txp := &TxnCrossProcess{Type: tc.txpType} 493 actual := txp.Used() 494 if actual != tc.expected { 495 t.Errorf("unexpected Used result for input %d: expected=%v; got=%v", tc.txpType, tc.expected, actual) 496 } 497 } 498 } 499 500 func TestTxnCrossProcessSetInbound(t *testing.T) { 501 txp := &TxnCrossProcess{Type: 0} 502 503 txp.SetInbound(false) 504 if txp.IsInbound() != false { 505 t.Error("Inbound is not false after being set to false from false") 506 } 507 508 txp.SetInbound(true) 509 if txp.IsInbound() != true { 510 t.Error("Inbound is not true after being set to true from false") 511 } 512 513 txp.SetInbound(true) 514 if txp.IsInbound() != true { 515 t.Error("Inbound is not true after being set to true from true") 516 } 517 518 txp.SetInbound(false) 519 if txp.IsInbound() != false { 520 t.Error("Inbound is not false after being set to false from true") 521 } 522 } 523 524 func TestTxnCrossProcessSetOutbound(t *testing.T) { 525 txp := &TxnCrossProcess{Type: 0} 526 527 txp.SetOutbound(false) 528 if txp.IsOutbound() != false { 529 t.Error("Outbound is not false after being set to false from false") 530 } 531 532 txp.SetOutbound(true) 533 if txp.IsOutbound() != true { 534 t.Error("Outbound is not true after being set to true from false") 535 } 536 537 txp.SetOutbound(true) 538 if txp.IsOutbound() != true { 539 t.Error("Outbound is not true after being set to true from true") 540 } 541 542 txp.SetOutbound(false) 543 if txp.IsOutbound() != false { 544 t.Error("Outbound is not false after being set to false from true") 545 } 546 } 547 548 func TestTxnCrossProcessSetSynthetics(t *testing.T) { 549 // We'll always set SyntheticsHeader, since we're not really testing the full 550 // behaviour of IsSynthetics() here. 551 txp := &TxnCrossProcess{ 552 Type: 0, 553 Synthetics: &cat.SyntheticsHeader{}, 554 } 555 556 txp.SetSynthetics(false) 557 if txp.IsSynthetics() != false { 558 t.Error("Synthetics is not false after being set to false from false") 559 } 560 561 txp.SetSynthetics(true) 562 if txp.IsSynthetics() != true { 563 t.Error("Synthetics is not true after being set to true from false") 564 } 565 566 txp.SetSynthetics(true) 567 if txp.IsSynthetics() != true { 568 t.Error("Synthetics is not true after being set to true from true") 569 } 570 571 txp.SetSynthetics(false) 572 if txp.IsSynthetics() != false { 573 t.Error("Synthetics is not false after being set to false from true") 574 } 575 } 576 577 func TestTxnCrossProcessParseAppData(t *testing.T) { 578 for _, tc := range []struct { 579 name string 580 encodingKey string 581 input string 582 expectedAppData *cat.AppDataHeader 583 expectedError bool 584 }{ 585 { 586 name: "empty string", 587 encodingKey: "foo", 588 input: "", 589 expectedAppData: nil, 590 expectedError: false, 591 }, 592 { 593 name: "invalidly encoded string", 594 encodingKey: "foo", 595 input: "xxx", 596 expectedAppData: nil, 597 expectedError: true, 598 }, 599 { 600 name: "invalid JSON", 601 encodingKey: "foo", 602 input: mustObfuscate("xxx", "foo"), 603 expectedAppData: nil, 604 expectedError: true, 605 }, 606 { 607 name: "invalid encoding key", 608 encodingKey: "foo", 609 input: mustObfuscate(`["xp","txn",1,2,3,"guid",false]`, "bar"), 610 expectedAppData: nil, 611 expectedError: true, 612 }, 613 { 614 name: "success", 615 encodingKey: "foo", 616 input: mustObfuscate(`["xp","txn",1,2,3,"guid",false]`, "foo"), 617 expectedAppData: &cat.AppDataHeader{ 618 CrossProcessID: "xp", 619 TransactionName: "txn", 620 QueueTimeInSeconds: 1, 621 ResponseTimeInSeconds: 2, 622 ContentLength: 3, 623 TransactionGUID: "guid", 624 }, 625 expectedError: false, 626 }, 627 } { 628 txp := &TxnCrossProcess{ 629 Enabled: true, 630 EncodingKey: []byte(tc.encodingKey), 631 } 632 633 actualAppData, actualErr := txp.ParseAppData(tc.input) 634 635 if tc.expectedError && actualErr == nil { 636 t.Errorf("%s: expected an error, but didn't get one", tc.name) 637 } else if tc.expectedError == false && actualErr != nil { 638 t.Errorf("%s: expected no error, but got %v", tc.name, actualErr) 639 } 640 641 if !reflect.DeepEqual(actualAppData, tc.expectedAppData) { 642 t.Errorf("%s: app data mismatched: expected=%v; got=%v", tc.name, tc.expectedAppData, actualAppData) 643 } 644 } 645 } 646 647 func TestTxnCrossProcessCreateAppData(t *testing.T) { 648 for _, tc := range []struct { 649 name string 650 enabled bool 651 crossProcessID string 652 encodingKey string 653 txnName string 654 queueTime time.Duration 655 responseTime time.Duration 656 contentLength int64 657 guid string 658 expectedAppData string 659 expectedError bool 660 }{ 661 { 662 name: "cat disabled", 663 enabled: false, 664 crossProcessID: "1#1", 665 encodingKey: "foo", 666 txnName: "txn", 667 queueTime: 1 * time.Second, 668 responseTime: 2 * time.Second, 669 contentLength: 4096, 670 guid: "", 671 expectedAppData: "", 672 expectedError: false, 673 }, 674 { 675 name: "invalid encoding key", 676 enabled: true, 677 crossProcessID: "1#1", 678 encodingKey: "", 679 txnName: "txn", 680 queueTime: 1 * time.Second, 681 responseTime: 2 * time.Second, 682 contentLength: 4096, 683 guid: "", 684 expectedAppData: "", 685 expectedError: true, 686 }, 687 { 688 name: "success", 689 enabled: true, 690 crossProcessID: "1#1", 691 encodingKey: "foo", 692 txnName: "txn", 693 queueTime: 1 * time.Second, 694 responseTime: 2 * time.Second, 695 contentLength: 4096, 696 guid: "guid", 697 expectedAppData: mustObfuscate(`["1#1","txn",1,2,4096,"guid",false]`, "foo"), 698 expectedError: false, 699 }, 700 } { 701 txp := &TxnCrossProcess{ 702 Enabled: tc.enabled, 703 EncodingKey: []byte(tc.encodingKey), 704 CrossProcessID: []byte(tc.crossProcessID), 705 GUID: tc.guid, 706 } 707 708 actualAppData, actualErr := txp.CreateAppData(tc.txnName, tc.queueTime, tc.responseTime, tc.contentLength) 709 710 if tc.expectedError && actualErr == nil { 711 t.Errorf("%s: expected an error, but didn't get one", tc.name) 712 } else if tc.expectedError == false && actualErr != nil { 713 t.Errorf("%s: expected no error, but got %v", tc.name, actualErr) 714 } 715 716 if !reflect.DeepEqual(actualAppData, tc.expectedAppData) { 717 t.Errorf("%s: app data mismatched: expected=%v; got=%v", tc.name, tc.expectedAppData, actualAppData) 718 } 719 } 720 } 721 722 func TestTxnCrossProcessHandleInboundRequestHeaders(t *testing.T) { 723 for _, tc := range []struct { 724 name string 725 enabled bool 726 reply *ConnectReply 727 metadata CrossProcessMetadata 728 expectedError bool 729 }{ 730 { 731 name: "disabled, invalid encoding key, invalid synthetics", 732 enabled: false, 733 reply: &ConnectReply{ 734 EncodingKey: "", 735 }, 736 metadata: CrossProcessMetadata{ 737 Synthetics: "foo", 738 }, 739 expectedError: true, 740 }, 741 { 742 name: "disabled, valid encoding key, invalid synthetics", 743 enabled: false, 744 reply: replyAccountOne, 745 metadata: CrossProcessMetadata{ 746 Synthetics: "foo", 747 }, 748 expectedError: true, 749 }, 750 { 751 name: "disabled, valid encoding key, valid synthetics", 752 enabled: false, 753 reply: replyAccountOne, 754 metadata: CrossProcessMetadata{ 755 Synthetics: mustObfuscate(`[1,1,"resource","job","monitor"]`, "foo"), 756 }, 757 expectedError: false, 758 }, 759 { 760 name: "enabled, invalid encoding key, valid input", 761 enabled: true, 762 reply: &ConnectReply{ 763 EncodingKey: "", 764 }, 765 metadata: CrossProcessMetadata{ 766 ID: mustObfuscate(`1#1`, "foo"), 767 TxnData: mustObfuscate(`["00000000",false,"00000000","b95be233"]`, "foo"), 768 }, 769 expectedError: true, 770 }, 771 { 772 name: "enabled, valid encoding key, invalid id", 773 enabled: true, 774 reply: replyAccountOne, 775 metadata: CrossProcessMetadata{ 776 ID: mustObfuscate(`1`, "foo"), 777 TxnData: mustObfuscate(`["00000000",false,"00000000","b95be233"]`, "foo"), 778 }, 779 expectedError: true, 780 }, 781 { 782 name: "enabled, valid encoding key, invalid txndata", 783 enabled: true, 784 reply: replyAccountOne, 785 metadata: CrossProcessMetadata{ 786 ID: mustObfuscate(`1#1`, "foo"), 787 TxnData: mustObfuscate(`["00000000",alse,"00000000","b95be233"]`, "foo"), 788 }, 789 expectedError: true, 790 }, 791 { 792 name: "enabled, valid encoding key, valid input", 793 enabled: true, 794 reply: replyAccountOne, 795 metadata: CrossProcessMetadata{ 796 ID: mustObfuscate(`1#1`, "foo"), 797 TxnData: mustObfuscate(`["00000000",false,"00000000","b95be233"]`, "foo"), 798 }, 799 expectedError: false, 800 }, 801 } { 802 txp := &TxnCrossProcess{Enabled: tc.enabled} 803 txp.Init(tc.enabled, tc.reply, CrossProcessMetadata{}) 804 805 err := txp.handleInboundRequestHeaders(tc.metadata) 806 if tc.expectedError && err == nil { 807 t.Errorf("%s: expected error, but didn't get one", tc.name) 808 } else if tc.expectedError == false && err != nil { 809 t.Errorf("%s: expected no error, but got %v", tc.name, err) 810 } 811 } 812 }