github.com/newrelic/go-agent@v3.26.0+incompatible/internal_synthetics_test.go (about) 1 // Copyright 2020 New Relic Corporation. All rights reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package newrelic 5 6 import ( 7 "net/http" 8 "testing" 9 10 "github.com/newrelic/go-agent/internal" 11 "github.com/newrelic/go-agent/internal/cat" 12 ) 13 14 // This collection of top-level tests affirms, for all possible combinations of 15 // Old CAT, BetterCAT, and Synthetics, that when an inbound request contains a 16 // synthetics header, the subsequent outbound request propagates that synthetics 17 // header. Synthetics uses an obfuscated JSON header, so this test requires a 18 // really particular set of values, e.g. rrrrrrr-rrrr-1234-rrrr-rrrrrrrrrrrr. 19 20 var ( 21 trustedAccounts = func() map[int]struct{} { 22 ta := make(map[int]struct{}) 23 ta[1] = struct{}{} // Trust account 1, from syntheticsConnectReplyFn. 24 ta[444] = struct{}{} // Trust account 444, from syntheticsHeader. 25 return ta 26 }() 27 28 syntheticsConnectReplyFn = func(reply *internal.ConnectReply) { 29 reply.EncodingKey = "1234567890123456789012345678901234567890" 30 reply.CrossProcessID = "1#1" 31 reply.TrustedAccounts = trustedAccounts 32 } 33 ) 34 35 func inboundSyntheticsRequestBuilder(oldCatEnabled bool, betterCatEnabled bool) *http.Request { 36 cfgFn := func(cfg *Config) { 37 cfg.CrossApplicationTracer.Enabled = oldCatEnabled 38 cfg.DistributedTracer.Enabled = betterCatEnabled 39 } 40 app := testApp(syntheticsConnectReplyFn, cfgFn, nil) 41 txn := app.StartTransaction("requester", nil, nil) 42 req, err := http.NewRequest("GET", "newrelic.com", nil) 43 if nil != err { 44 panic(err) 45 } 46 47 req.Header.Add( 48 "X-NewRelic-Synthetics", 49 "agMfAAECGxpLQkNAQUZHG0VKS0IcAwEHARtFSktCHEBBRkdERUpLQkNAQRYZFF1SU1pbWFkZX1xdUhQBAwEHGV9cXVIUWltYWV5fXF1SU1pbEB8WWFtaVVRdXB9eWVhbGgkLAwUfXllYWxpVVF1cX15ZWFtaVVQSbA==") 50 51 StartExternalSegment(txn, req) 52 53 if betterCatEnabled || !oldCatEnabled { 54 if cat.NewRelicIDName == req.Header.Get(cat.NewRelicIDName) { 55 panic("Header contains old cat header NewRelicIDName: " + req.Header.Get(cat.NewRelicIDName)) 56 } 57 if cat.NewRelicTxnName == req.Header.Get(cat.NewRelicTxnName) { 58 panic("Header contains old cat header NewRelicTxnName: " + req.Header.Get(cat.NewRelicTxnName)) 59 } 60 } 61 62 if oldCatEnabled { 63 if "" == req.Header.Get(cat.NewRelicIDName) { 64 panic("Missing old cat header NewRelicIDName: " + req.Header.Get(cat.NewRelicIDName)) 65 } 66 if "" == req.Header.Get(cat.NewRelicTxnName) { 67 panic("Missing old cat header NewRelicTxnName: " + req.Header.Get(cat.NewRelicTxnName)) 68 } 69 } 70 71 if "" == req.Header.Get(cat.NewRelicSyntheticsName) { 72 panic("missing synthetics header NewRelicSyntheticsName: " + req.Header.Get(cat.NewRelicSyntheticsName)) 73 } 74 75 return req 76 } 77 78 func TestSyntheticsOldCAT(t *testing.T) { 79 cfgFn := func(cfg *Config) { cfg.CrossApplicationTracer.Enabled = true } 80 app := testApp(syntheticsConnectReplyFn, cfgFn, t) 81 clientTxn := app.StartTransaction( 82 "helloOldCAT", 83 nil, 84 inboundSyntheticsRequestBuilder(true, false)) 85 86 req, err := http.NewRequest("GET", "newrelic.com", nil) 87 88 if nil != err { 89 panic(err) 90 } 91 92 StartExternalSegment(clientTxn, req) 93 clientTxn.End() 94 95 if "" == req.Header.Get(cat.NewRelicSyntheticsName) { 96 panic("Outbound request missing synthetics header NewRelicSyntheticsName: " + req.Header.Get(cat.NewRelicSyntheticsName)) 97 } 98 99 expectedIntrinsics := map[string]interface{}{ 100 "name": "WebTransaction/Go/helloOldCAT", 101 "client_cross_process_id": "1#1", 102 "nr.syntheticsResourceId": "rrrrrrr-rrrr-1234-rrrr-rrrrrrrrrrrr", 103 "nr.syntheticsJobId": "jjjjjjj-jjjj-1234-jjjj-jjjjjjjjjjjj", 104 "nr.syntheticsMonitorId": "mmmmmmm-mmmm-1234-mmmm-mmmmmmmmmmmm", 105 "nr.apdexPerfZone": internal.MatchAnything, 106 "nr.tripId": internal.MatchAnything, 107 "nr.pathHash": internal.MatchAnything, 108 "nr.referringPathHash": internal.MatchAnything, 109 "nr.referringTransactionGuid": internal.MatchAnything, 110 "nr.guid": internal.MatchAnything, 111 } 112 113 app.ExpectTxnEvents(t, []internal.WantEvent{{ 114 Intrinsics: expectedIntrinsics, 115 }}) 116 } 117 118 func TestSyntheticsBetterCAT(t *testing.T) { 119 cfgFn := func(cfg *Config) { 120 cfg.CrossApplicationTracer.Enabled = false 121 cfg.DistributedTracer.Enabled = true 122 } 123 app := testApp(syntheticsConnectReplyFn, cfgFn, t) 124 clientTxn := app.StartTransaction( 125 "helloBetterCAT", 126 nil, 127 inboundSyntheticsRequestBuilder(false, true)) 128 129 req, err := http.NewRequest("GET", "newrelic.com", nil) 130 131 if nil != err { 132 panic(err) 133 } 134 135 StartExternalSegment(clientTxn, req) 136 clientTxn.End() 137 138 if "" == req.Header.Get(cat.NewRelicSyntheticsName) { 139 panic("Outbound request missing synthetics header NewRelicSyntheticsName: " + req.Header.Get(cat.NewRelicSyntheticsName)) 140 } 141 142 expectedIntrinsics := map[string]interface{}{ 143 "name": "WebTransaction/Go/helloBetterCAT", 144 "nr.syntheticsResourceId": "rrrrrrr-rrrr-1234-rrrr-rrrrrrrrrrrr", 145 "nr.syntheticsJobId": "jjjjjjj-jjjj-1234-jjjj-jjjjjjjjjjjj", 146 "nr.syntheticsMonitorId": "mmmmmmm-mmmm-1234-mmmm-mmmmmmmmmmmm", 147 "nr.apdexPerfZone": internal.MatchAnything, 148 "priority": internal.MatchAnything, 149 "sampled": internal.MatchAnything, 150 "traceId": internal.MatchAnything, 151 "guid": internal.MatchAnything, 152 } 153 154 app.ExpectTxnEvents(t, []internal.WantEvent{{ 155 Intrinsics: expectedIntrinsics, 156 }}) 157 } 158 159 func TestSyntheticsStandalone(t *testing.T) { 160 cfgFn := func(cfg *Config) { 161 cfg.AppName = "syntheticsReceiver" 162 cfg.CrossApplicationTracer.Enabled = false 163 } 164 app := testApp(syntheticsConnectReplyFn, cfgFn, t) 165 clientTxn := app.StartTransaction( 166 "helloSynthetics", 167 nil, 168 inboundSyntheticsRequestBuilder(false, false)) 169 170 req, err := http.NewRequest("GET", "newrelic.com", nil) 171 172 if nil != err { 173 panic(err) 174 } 175 176 StartExternalSegment(clientTxn, req) 177 clientTxn.End() 178 179 if "" == req.Header.Get(cat.NewRelicSyntheticsName) { 180 panic("Outbound request missing synthetics header NewRelicSyntheticsName: " + req.Header.Get(cat.NewRelicSyntheticsName)) 181 } 182 183 expectedIntrinsics := map[string]interface{}{ 184 "name": "WebTransaction/Go/helloSynthetics", 185 "nr.syntheticsResourceId": "rrrrrrr-rrrr-1234-rrrr-rrrrrrrrrrrr", 186 "nr.syntheticsJobId": "jjjjjjj-jjjj-1234-jjjj-jjjjjjjjjjjj", 187 "nr.syntheticsMonitorId": "mmmmmmm-mmmm-1234-mmmm-mmmmmmmmmmmm", 188 "nr.apdexPerfZone": internal.MatchAnything, 189 "nr.guid": internal.MatchAnything, 190 } 191 192 app.ExpectTxnEvents(t, []internal.WantEvent{{ 193 Intrinsics: expectedIntrinsics, 194 }}) 195 }