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

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package newrelic
     5  
     6  import (
     7  	"encoding/json"
     8  	"net/http"
     9  	"os"
    10  	"reflect"
    11  	"regexp"
    12  	"strconv"
    13  	"strings"
    14  	"testing"
    15  
    16  	"github.com/newrelic/go-agent/internal"
    17  	"github.com/newrelic/go-agent/internal/utilization"
    18  )
    19  
    20  var (
    21  	fixRegex = regexp.MustCompile(`e\+\d+`)
    22  )
    23  
    24  // In Go 1.8 Marshalling of numbers was changed:
    25  // Before: "StackTraceThreshold":5e+08
    26  // After:  "StackTraceThreshold":500000000
    27  func standardizeNumbers(input string) string {
    28  	return fixRegex.ReplaceAllStringFunc(input, func(s string) string {
    29  		n, err := strconv.Atoi(s[2:])
    30  		if nil != err {
    31  			return s
    32  		}
    33  		return strings.Repeat("0", n)
    34  	})
    35  }
    36  
    37  func TestCopyConfigReferenceFieldsPresent(t *testing.T) {
    38  	cfg := NewConfig("my appname", "0123456789012345678901234567890123456789")
    39  	cfg.Labels["zip"] = "zap"
    40  	cfg.ErrorCollector.IgnoreStatusCodes = append(cfg.ErrorCollector.IgnoreStatusCodes, 405)
    41  	cfg.Attributes.Include = append(cfg.Attributes.Include, "1")
    42  	cfg.Attributes.Exclude = append(cfg.Attributes.Exclude, "2")
    43  	cfg.TransactionEvents.Attributes.Include = append(cfg.TransactionEvents.Attributes.Include, "3")
    44  	cfg.TransactionEvents.Attributes.Exclude = append(cfg.TransactionEvents.Attributes.Exclude, "4")
    45  	cfg.ErrorCollector.Attributes.Include = append(cfg.ErrorCollector.Attributes.Include, "5")
    46  	cfg.ErrorCollector.Attributes.Exclude = append(cfg.ErrorCollector.Attributes.Exclude, "6")
    47  	cfg.TransactionTracer.Attributes.Include = append(cfg.TransactionTracer.Attributes.Include, "7")
    48  	cfg.TransactionTracer.Attributes.Exclude = append(cfg.TransactionTracer.Attributes.Exclude, "8")
    49  	cfg.BrowserMonitoring.Attributes.Include = append(cfg.BrowserMonitoring.Attributes.Include, "9")
    50  	cfg.BrowserMonitoring.Attributes.Exclude = append(cfg.BrowserMonitoring.Attributes.Exclude, "10")
    51  	cfg.SpanEvents.Attributes.Include = append(cfg.SpanEvents.Attributes.Include, "11")
    52  	cfg.SpanEvents.Attributes.Exclude = append(cfg.SpanEvents.Attributes.Exclude, "12")
    53  	cfg.TransactionTracer.Segments.Attributes.Include = append(cfg.TransactionTracer.Segments.Attributes.Include, "13")
    54  	cfg.TransactionTracer.Segments.Attributes.Exclude = append(cfg.TransactionTracer.Segments.Attributes.Exclude, "14")
    55  	cfg.Transport = &http.Transport{}
    56  	cfg.Logger = NewLogger(os.Stdout)
    57  
    58  	cp := copyConfigReferenceFields(cfg)
    59  
    60  	cfg.Labels["zop"] = "zup"
    61  	cfg.ErrorCollector.IgnoreStatusCodes[0] = 201
    62  	cfg.Attributes.Include[0] = "zap"
    63  	cfg.Attributes.Exclude[0] = "zap"
    64  	cfg.TransactionEvents.Attributes.Include[0] = "zap"
    65  	cfg.TransactionEvents.Attributes.Exclude[0] = "zap"
    66  	cfg.ErrorCollector.Attributes.Include[0] = "zap"
    67  	cfg.ErrorCollector.Attributes.Exclude[0] = "zap"
    68  	cfg.TransactionTracer.Attributes.Include[0] = "zap"
    69  	cfg.TransactionTracer.Attributes.Exclude[0] = "zap"
    70  	cfg.BrowserMonitoring.Attributes.Include[0] = "zap"
    71  	cfg.BrowserMonitoring.Attributes.Exclude[0] = "zap"
    72  	cfg.SpanEvents.Attributes.Include[0] = "zap"
    73  	cfg.SpanEvents.Attributes.Exclude[0] = "zap"
    74  	cfg.TransactionTracer.Segments.Attributes.Include[0] = "zap"
    75  	cfg.TransactionTracer.Segments.Attributes.Exclude[0] = "zap"
    76  
    77  	expect := internal.CompactJSONString(`[
    78  	{
    79  		"pid":123,
    80  		"language":"go",
    81  		"agent_version":"0.2.2",
    82  		"host":"my-hostname",
    83  		"settings":{
    84  			"AppName":"my appname",
    85  			"Attributes":{"Enabled":true,"Exclude":["2"],"Include":["1"]},
    86  			"BrowserMonitoring":{
    87  				"Attributes":{"Enabled":false,"Exclude":["10"],"Include":["9"]},
    88  				"Enabled":true
    89  			},
    90  			"CrossApplicationTracer":{"Enabled":true},
    91  			"CustomInsightsEvents":{"Enabled":true},
    92  			"DatastoreTracer":{
    93  				"DatabaseNameReporting":{"Enabled":true},
    94  				"InstanceReporting":{"Enabled":true},
    95  				"QueryParameters":{"Enabled":true},
    96  				"SlowQuery":{
    97  					"Enabled":true,
    98  					"Threshold":10000000
    99  				}
   100  			},
   101  			"DistributedTracer":{"Enabled":false},
   102  			"Enabled":true,
   103  			"ErrorCollector":{
   104  				"Attributes":{"Enabled":true,"Exclude":["6"],"Include":["5"]},
   105  				"CaptureEvents":true,
   106  				"Enabled":true,
   107  				"IgnoreStatusCodes":[0,5,404,405]
   108  			},
   109  			"HighSecurity":false,
   110  			"HostDisplayName":"",
   111  			"Labels":{"zip":"zap"},
   112  			"Logger":"*logger.logFile",
   113  			"RuntimeSampler":{"Enabled":true},
   114  			"SecurityPoliciesToken":"",
   115  			"ServerlessMode":{
   116  				"AccountID":"",
   117  				"ApdexThreshold":500000000,
   118  				"Enabled":false,
   119  				"PrimaryAppID":"",
   120  				"TrustedAccountKey":""
   121  			},
   122  			"SpanEvents":{
   123  				"Attributes":{
   124  					"Enabled":true,"Exclude":["12"],"Include":["11"]
   125  				},
   126  				"Enabled":true
   127  			},
   128  			"TransactionEvents":{
   129  				"Attributes":{"Enabled":true,"Exclude":["4"],"Include":["3"]},
   130  				"Enabled":true,
   131  				"MaxSamplesStored": 10000
   132  			},
   133  			"TransactionTracer":{
   134  				"Attributes":{"Enabled":true,"Exclude":["8"],"Include":["7"]},
   135  				"Enabled":true,
   136  				"SegmentThreshold":2000000,
   137  				"Segments":{"Attributes":{"Enabled":true,"Exclude":["14"],"Include":["13"]}},
   138  				"StackTraceThreshold":500000000,
   139  				"Threshold":{
   140  					"Duration":500000000,
   141  					"IsApdexFailing":true
   142  				}
   143  			},
   144  			"Transport":"*http.Transport",
   145  			"Utilization":{
   146  				"BillingHostname":"",
   147  				"DetectAWS":true,
   148  				"DetectAzure":true,
   149  				"DetectDocker":true,
   150  				"DetectGCP":true,
   151  				"DetectKubernetes":true,
   152  				"DetectPCF":true,
   153  				"LogicalProcessors":0,
   154  				"TotalRAMMIB":0
   155  			},
   156  			"browser_monitoring.loader":"rum"
   157  		},
   158  		"app_name":["my appname"],
   159  		"high_security":false,
   160  		"labels":[{"label_type":"zip","label_value":"zap"}],
   161  		"environment":[
   162  			["runtime.Compiler","comp"],
   163  			["runtime.GOARCH","arch"],
   164  			["runtime.GOOS","goos"],
   165  			["runtime.Version","vers"],
   166  			["runtime.NumCPU",8]
   167  		],
   168  		"identifier":"my appname",
   169  		"utilization":{
   170  			"metadata_version":5,
   171  			"logical_processors":16,
   172  			"total_ram_mib":1024,
   173  			"hostname":"my-hostname"
   174  		},
   175  		"security_policies":{
   176  			"record_sql":{"enabled":false},
   177  			"attributes_include":{"enabled":false},
   178  			"allow_raw_exception_messages":{"enabled":false},
   179  			"custom_events":{"enabled":false},
   180  			"custom_parameters":{"enabled":false}
   181  		},
   182  		"metadata":{
   183  			"NEW_RELIC_METADATA_ZAP":"zip"
   184  		},
   185  		"event_harvest_config": {
   186  			"report_period_ms": 60000,
   187  			"harvest_limits": {
   188  				"analytic_event_data": 10000,
   189  				"custom_event_data": 10000,
   190  				"error_event_data": 100
   191  			}
   192  		}
   193  	}]`)
   194  
   195  	securityPoliciesInput := []byte(`{
   196  		"record_sql":                    { "enabled": false, "required": false },
   197  	        "attributes_include":            { "enabled": false, "required": false },
   198  	        "allow_raw_exception_messages":  { "enabled": false, "required": false },
   199  	        "custom_events":                 { "enabled": false, "required": false },
   200  	        "custom_parameters":             { "enabled": false, "required": false },
   201  	        "custom_instrumentation_editor": { "enabled": false, "required": false },
   202  	        "message_parameters":            { "enabled": false, "required": false },
   203  	        "job_arguments":                 { "enabled": false, "required": false }
   204  	}`)
   205  	var sp internal.SecurityPolicies
   206  	err := json.Unmarshal(securityPoliciesInput, &sp)
   207  	if nil != err {
   208  		t.Fatal(err)
   209  	}
   210  
   211  	metadata := map[string]string{
   212  		"NEW_RELIC_METADATA_ZAP": "zip",
   213  	}
   214  	js, err := configConnectJSONInternal(cp, 123, &utilization.SampleData, internal.SampleEnvironment, "0.2.2", sp.PointerIfPopulated(), metadata)
   215  	if nil != err {
   216  		t.Fatal(err)
   217  	}
   218  	out := standardizeNumbers(string(js))
   219  	if out != expect {
   220  		t.Error(out)
   221  	}
   222  }
   223  
   224  func TestCopyConfigReferenceFieldsAbsent(t *testing.T) {
   225  	cfg := NewConfig("my appname", "0123456789012345678901234567890123456789")
   226  	cfg.Labels = nil
   227  	cfg.ErrorCollector.IgnoreStatusCodes = nil
   228  
   229  	cp := copyConfigReferenceFields(cfg)
   230  
   231  	expect := internal.CompactJSONString(`[
   232  	{
   233  		"pid":123,
   234  		"language":"go",
   235  		"agent_version":"0.2.2",
   236  		"host":"my-hostname",
   237  		"settings":{
   238  			"AppName":"my appname",
   239  			"Attributes":{"Enabled":true,"Exclude":null,"Include":null},
   240  			"BrowserMonitoring":{
   241  				"Attributes":{
   242  					"Enabled":false,
   243  					"Exclude":null,
   244  					"Include":null
   245  				},
   246  				"Enabled":true
   247  			},
   248  			"CrossApplicationTracer":{"Enabled":true},
   249  			"CustomInsightsEvents":{"Enabled":true},
   250  			"DatastoreTracer":{
   251  				"DatabaseNameReporting":{"Enabled":true},
   252  				"InstanceReporting":{"Enabled":true},
   253  				"QueryParameters":{"Enabled":true},
   254  				"SlowQuery":{
   255  					"Enabled":true,
   256  					"Threshold":10000000
   257  				}
   258  			},
   259  			"DistributedTracer":{"Enabled":false},
   260  			"Enabled":true,
   261  			"ErrorCollector":{
   262  				"Attributes":{"Enabled":true,"Exclude":null,"Include":null},
   263  				"CaptureEvents":true,
   264  				"Enabled":true,
   265  				"IgnoreStatusCodes":null
   266  			},
   267  			"HighSecurity":false,
   268  			"HostDisplayName":"",
   269  			"Labels":null,
   270  			"Logger":null,
   271  			"RuntimeSampler":{"Enabled":true},
   272  			"SecurityPoliciesToken":"",
   273  			"ServerlessMode":{
   274  				"AccountID":"",
   275  				"ApdexThreshold":500000000,
   276  				"Enabled":false,
   277  				"PrimaryAppID":"",
   278  				"TrustedAccountKey":""
   279  			},
   280  			"SpanEvents":{
   281  				"Attributes":{"Enabled":true,"Exclude":null,"Include":null},
   282  				"Enabled":true
   283  			},
   284  			"TransactionEvents":{
   285  				"Attributes":{"Enabled":true,"Exclude":null,"Include":null},
   286  				"Enabled":true,
   287  				"MaxSamplesStored": 10000
   288  			},
   289  			"TransactionTracer":{
   290  				"Attributes":{"Enabled":true,"Exclude":null,"Include":null},
   291  				"Enabled":true,
   292  				"SegmentThreshold":2000000,
   293  				"Segments":{"Attributes":{"Enabled":true,"Exclude":null,"Include":null}},
   294  				"StackTraceThreshold":500000000,
   295  				"Threshold":{
   296  					"Duration":500000000,
   297  					"IsApdexFailing":true
   298  				}
   299  			},
   300  			"Transport":null,
   301  			"Utilization":{
   302  				"BillingHostname":"",
   303  				"DetectAWS":true,
   304  				"DetectAzure":true,
   305  				"DetectDocker":true,
   306  				"DetectGCP":true,
   307  				"DetectKubernetes":true,
   308  				"DetectPCF":true,
   309  				"LogicalProcessors":0,
   310  				"TotalRAMMIB":0
   311  			},
   312  			"browser_monitoring.loader":"rum"
   313  		},
   314  		"app_name":["my appname"],
   315  		"high_security":false,
   316  		"environment":[
   317  			["runtime.Compiler","comp"],
   318  			["runtime.GOARCH","arch"],
   319  			["runtime.GOOS","goos"],
   320  			["runtime.Version","vers"],
   321  			["runtime.NumCPU",8]
   322  		],
   323  		"identifier":"my appname",
   324  		"utilization":{
   325  			"metadata_version":5,
   326  			"logical_processors":16,
   327  			"total_ram_mib":1024,
   328  			"hostname":"my-hostname"
   329  		},
   330  		"metadata":{},
   331  		"event_harvest_config": {
   332  			"report_period_ms": 60000,
   333  			"harvest_limits": {
   334  				"analytic_event_data": 10000,
   335  				"custom_event_data": 10000,
   336  				"error_event_data": 100
   337  			}
   338  		}
   339  	}]`)
   340  
   341  	metadata := map[string]string{}
   342  	js, err := configConnectJSONInternal(cp, 123, &utilization.SampleData, internal.SampleEnvironment, "0.2.2", nil, metadata)
   343  	if nil != err {
   344  		t.Fatal(err)
   345  	}
   346  	out := standardizeNumbers(string(js))
   347  	if out != expect {
   348  		t.Error(string(js))
   349  	}
   350  }
   351  
   352  func TestValidate(t *testing.T) {
   353  	c := Config{
   354  		License: "0123456789012345678901234567890123456789",
   355  		AppName: "my app",
   356  		Enabled: true,
   357  	}
   358  	if err := c.Validate(); nil != err {
   359  		t.Error(err)
   360  	}
   361  	c = Config{
   362  		License: "",
   363  		AppName: "my app",
   364  		Enabled: true,
   365  	}
   366  	if err := c.Validate(); err != errLicenseLen {
   367  		t.Error(err)
   368  	}
   369  	c = Config{
   370  		License: "",
   371  		AppName: "my app",
   372  		Enabled: false,
   373  	}
   374  	if err := c.Validate(); nil != err {
   375  		t.Error(err)
   376  	}
   377  	c = Config{
   378  		License: "wronglength",
   379  		AppName: "my app",
   380  		Enabled: true,
   381  	}
   382  	if err := c.Validate(); err != errLicenseLen {
   383  		t.Error(err)
   384  	}
   385  	c = Config{
   386  		License: "0123456789012345678901234567890123456789",
   387  		AppName: "too;many;app;names",
   388  		Enabled: true,
   389  	}
   390  	if err := c.Validate(); err != errAppNameLimit {
   391  		t.Error(err)
   392  	}
   393  	c = Config{
   394  		License: "0123456789012345678901234567890123456789",
   395  		AppName: "",
   396  		Enabled: true,
   397  	}
   398  	if err := c.Validate(); err != errAppNameMissing {
   399  		t.Error(err)
   400  	}
   401  	c = Config{
   402  		License: "0123456789012345678901234567890123456789",
   403  		AppName: "",
   404  		Enabled: false,
   405  	}
   406  	if err := c.Validate(); err != nil {
   407  		t.Error(err)
   408  	}
   409  	c = Config{
   410  		License:      "0123456789012345678901234567890123456789",
   411  		AppName:      "my app",
   412  		Enabled:      true,
   413  		HighSecurity: true,
   414  	}
   415  	if err := c.Validate(); err != nil {
   416  		t.Error(err)
   417  	}
   418  }
   419  
   420  func TestValidateWithPoliciesToken(t *testing.T) {
   421  	c := Config{
   422  		License:               "0123456789012345678901234567890123456789",
   423  		AppName:               "my app",
   424  		Enabled:               true,
   425  		HighSecurity:          true,
   426  		SecurityPoliciesToken: "0123456789",
   427  	}
   428  	if err := c.Validate(); err != errHighSecurityWithSecurityPolicies {
   429  		t.Error(err)
   430  	}
   431  	c = Config{
   432  		License:               "0123456789012345678901234567890123456789",
   433  		AppName:               "my app",
   434  		Enabled:               true,
   435  		SecurityPoliciesToken: "0123456789",
   436  	}
   437  	if err := c.Validate(); err != nil {
   438  		t.Error(err)
   439  	}
   440  }
   441  
   442  func TestGatherMetadata(t *testing.T) {
   443  	metadata := gatherMetadata(func() []string { return nil })
   444  	if !reflect.DeepEqual(metadata, map[string]string{}) {
   445  		t.Error(metadata)
   446  	}
   447  	metadata = gatherMetadata(func() []string {
   448  		return []string{
   449  			"NEW_RELIC_METADATA_ZIP=zap",
   450  			"NEW_RELIC_METADATA_PIZZA=cheese",
   451  			"NEW_RELIC_METADATA_=hello",
   452  			"NEW_RELIC_METADATA_LOTS_OF_EQUALS=one=two",
   453  			"NEW_RELIC_METADATA_",
   454  			"NEW_RELIC_METADATA_NO_EQUALS",
   455  			"NEW_RELIC_METADATA_EMPTY=",
   456  			"NEW_RELIC_",
   457  			"hello=world",
   458  		}
   459  	})
   460  	if !reflect.DeepEqual(metadata, map[string]string{
   461  		"NEW_RELIC_METADATA_ZIP":            "zap",
   462  		"NEW_RELIC_METADATA_PIZZA":          "cheese",
   463  		"NEW_RELIC_METADATA_":               "hello",
   464  		"NEW_RELIC_METADATA_LOTS_OF_EQUALS": "one=two",
   465  		"NEW_RELIC_METADATA_EMPTY":          "",
   466  	}) {
   467  		t.Error(metadata)
   468  	}
   469  }
   470  
   471  func TestValidateServerless(t *testing.T) {
   472  	// AppName and License can be empty in serverless mode.
   473  	c := NewConfig("", "")
   474  	c.ServerlessMode.Enabled = true
   475  	if err := c.Validate(); nil != err {
   476  		t.Error(err)
   477  	}
   478  }