github.com/newrelic/go-agent@v3.26.0+incompatible/internal/connect_reply_test.go (about)

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package internal
     5  
     6  import (
     7  	"encoding/json"
     8  	"testing"
     9  	"time"
    10  )
    11  
    12  func TestCreateFullTxnNameBasic(t *testing.T) {
    13  	emptyReply := ConnectReplyDefaults()
    14  
    15  	tcs := []struct {
    16  		input      string
    17  		background bool
    18  		expect     string
    19  	}{
    20  		{"", true, "WebTransaction/Go/"},
    21  		{"/", true, "WebTransaction/Go/"},
    22  		{"hello", true, "WebTransaction/Go/hello"},
    23  		{"/hello", true, "WebTransaction/Go/hello"},
    24  
    25  		{"", false, "OtherTransaction/Go/"},
    26  		{"/", false, "OtherTransaction/Go/"},
    27  		{"hello", false, "OtherTransaction/Go/hello"},
    28  		{"/hello", false, "OtherTransaction/Go/hello"},
    29  	}
    30  
    31  	for _, tc := range tcs {
    32  		if out := CreateFullTxnName(tc.input, emptyReply, tc.background); out != tc.expect {
    33  			t.Error(tc.input, tc.background, out, tc.expect)
    34  		}
    35  	}
    36  }
    37  
    38  func TestCreateFullTxnNameURLRulesIgnore(t *testing.T) {
    39  	js := `[{
    40  		"match_expression":".*zip.*$",
    41  		"ignore":true
    42  	}]`
    43  	reply := ConnectReplyDefaults()
    44  	err := json.Unmarshal([]byte(js), &reply.URLRules)
    45  	if nil != err {
    46  		t.Fatal(err)
    47  	}
    48  	if out := CreateFullTxnName("/zap/zip/zep", reply, true); out != "" {
    49  		t.Error(out)
    50  	}
    51  }
    52  
    53  func TestCreateFullTxnNameTxnRulesIgnore(t *testing.T) {
    54  	js := `[{
    55  		"match_expression":"^WebTransaction/Go/zap/zip/zep$",
    56  		"ignore":true
    57  	}]`
    58  	reply := ConnectReplyDefaults()
    59  	err := json.Unmarshal([]byte(js), &reply.TxnNameRules)
    60  	if nil != err {
    61  		t.Fatal(err)
    62  	}
    63  	if out := CreateFullTxnName("/zap/zip/zep", reply, true); out != "" {
    64  		t.Error(out)
    65  	}
    66  }
    67  
    68  func TestCreateFullTxnNameAllRulesWithCache(t *testing.T) {
    69  	js := `{
    70  		"url_rules":[
    71  			{"match_expression":"zip","each_segment":true,"replacement":"zoop"}
    72  		],
    73  		"transaction_name_rules":[
    74  			{"match_expression":"WebTransaction/Go/zap/zoop/zep",
    75  			 "replacement":"WebTransaction/Go/zap/zoop/zep/zup/zyp"}
    76  		],
    77  		"transaction_segment_terms":[
    78  			{"prefix": "WebTransaction/Go/",
    79  			 "terms": ["zyp", "zoop", "zap"]}
    80  		]
    81  	}`
    82  	reply := ConnectReplyDefaults()
    83  	reply.rulesCache = newRulesCache(3)
    84  	err := json.Unmarshal([]byte(js), &reply)
    85  	if nil != err {
    86  		t.Fatal(err)
    87  	}
    88  	want := "WebTransaction/Go/zap/zoop/*/zyp"
    89  	if out := CreateFullTxnName("/zap/zip/zep", reply, true); out != want {
    90  		t.Error("wanted:", want, "got:", out)
    91  	}
    92  	// Check that the cache was populated as expected.
    93  	if out := reply.rulesCache.find("/zap/zip/zep", true); out != want {
    94  		t.Error("wanted:", want, "got:", out)
    95  	}
    96  	// Check that the next CreateFullTxnName returns the same output.
    97  	if out := CreateFullTxnName("/zap/zip/zep", reply, true); out != want {
    98  		t.Error("wanted:", want, "got:", out)
    99  	}
   100  }
   101  
   102  func TestCalculateApdexThreshold(t *testing.T) {
   103  	reply := ConnectReplyDefaults()
   104  	threshold := CalculateApdexThreshold(reply, "WebTransaction/Go/hello")
   105  	if threshold != 500*time.Millisecond {
   106  		t.Error("default apdex threshold", threshold)
   107  	}
   108  
   109  	reply = ConnectReplyDefaults()
   110  	reply.ApdexThresholdSeconds = 1.3
   111  	reply.KeyTxnApdex = map[string]float64{
   112  		"WebTransaction/Go/zip": 2.2,
   113  		"WebTransaction/Go/zap": 2.3,
   114  	}
   115  	threshold = CalculateApdexThreshold(reply, "WebTransaction/Go/hello")
   116  	if threshold != 1300*time.Millisecond {
   117  		t.Error(threshold)
   118  	}
   119  	threshold = CalculateApdexThreshold(reply, "WebTransaction/Go/zip")
   120  	if threshold != 2200*time.Millisecond {
   121  		t.Error(threshold)
   122  	}
   123  }
   124  
   125  func TestIsTrusted(t *testing.T) {
   126  	for _, test := range []struct {
   127  		id       int
   128  		trusted  string
   129  		expected bool
   130  	}{
   131  		{1, `[]`, false},
   132  		{1, `[2, 3]`, false},
   133  		{1, `[1]`, true},
   134  		{1, `[1, 2, 3]`, true},
   135  	} {
   136  		trustedAccounts := make(trustedAccountSet)
   137  		if err := json.Unmarshal([]byte(test.trusted), &trustedAccounts); err != nil {
   138  			t.Fatal(err)
   139  		}
   140  
   141  		if actual := trustedAccounts.IsTrusted(test.id); test.expected != actual {
   142  			t.Errorf("failed asserting whether %d is trusted by %v: expected %v; got %v", test.id, test.trusted, test.expected, actual)
   143  		}
   144  	}
   145  }
   146  
   147  func BenchmarkDefaultRules(b *testing.B) {
   148  	js := `{"url_rules":[
   149  		{
   150  			"match_expression":".*\\.(ace|arj|ini|txt|udl|plist|css|gif|ico|jpe?g|js|png|swf|woff|caf|aiff|m4v|mpe?g|mp3|mp4|mov)$",
   151  			"replacement":"/*.\\1",
   152  			"ignore":false,
   153  			"eval_order":1000,
   154  			"terminate_chain":true,
   155  			"replace_all":false,
   156  			"each_segment":false
   157  		},
   158  		{
   159  			"match_expression":"^[0-9][0-9a-f_,.-]*$",
   160  			"replacement":"*",
   161  			"ignore":false,
   162  			"eval_order":1001,
   163  			"terminate_chain":false,
   164  			"replace_all":false,
   165  			"each_segment":true
   166  		},
   167  		{
   168  			"match_expression":"^(.*)/[0-9][0-9a-f_,-]*\\.([0-9a-z][0-9a-z]*)$",
   169  			"replacement":"\\1/.*\\2",
   170  			"ignore":false,
   171  			"eval_order":1002,
   172  			"terminate_chain":false,
   173  			"replace_all":false,
   174  			"each_segment":false
   175  		}
   176  	]}`
   177  	reply := ConnectReplyDefaults()
   178  	reply.rulesCache = newRulesCache(1)
   179  	err := json.Unmarshal([]byte(js), &reply)
   180  	if nil != err {
   181  		b.Fatal(err)
   182  	}
   183  
   184  	b.ResetTimer()
   185  	b.ReportAllocs()
   186  
   187  	for i := 0; i < b.N; i++ {
   188  		if out := CreateFullTxnName("/myEndpoint", reply, true); out != "WebTransaction/Go/myEndpoint" {
   189  			b.Error(out)
   190  		}
   191  	}
   192  }
   193  
   194  func TestNegativeHarvestLimits(t *testing.T) {
   195  	// Test that negative harvest event limits will cause a connect error.
   196  	// Harvest event limits are never expected to be negative:  This is just
   197  	// extra defensiveness.
   198  	_, err := ConstructConnectReply([]byte(`{"return_value":{
   199  			"event_harvest_config": {
   200  				"harvest_limits": {
   201  					"error_event_data": -1
   202  				}
   203  			}
   204  		}}`), PreconnectReply{})
   205  	if err == nil {
   206  		t.Fatal("expected error missing")
   207  	}
   208  }
   209  
   210  type dfltMaxTxnEvents struct{}
   211  
   212  func (dfltMaxTxnEvents) MaxTxnEvents() int {
   213  	return MaxTxnEvents
   214  }
   215  
   216  func TestDefaultEventHarvestConfigJSON(t *testing.T) {
   217  	js, err := json.Marshal(DefaultEventHarvestConfig(dfltMaxTxnEvents{}))
   218  	if err != nil {
   219  		t.Error(err)
   220  	}
   221  	if string(js) != `{"report_period_ms":60000,"harvest_limits":{"analytic_event_data":10000,"custom_event_data":10000,"error_event_data":100}}` {
   222  		t.Error(string(js))
   223  	}
   224  }