github.com/newrelic/go-agent@v3.26.0+incompatible/internal/slow_queries_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  	"math/rand"
     8  	"strconv"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  )
    13  
    14  func TestEmptySlowQueriesData(t *testing.T) {
    15  	slows := newSlowQueries(maxHarvestSlowSQLs)
    16  	js, err := slows.Data("agentRunID", time.Now())
    17  	if nil != js || nil != err {
    18  		t.Error(string(js), err)
    19  	}
    20  }
    21  
    22  func TestSlowQueriesBasic(t *testing.T) {
    23  	acfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
    24  	attr := NewAttributes(acfg)
    25  	attr.Agent.Add(attributeRequestURI, "/zip/zap", nil)
    26  	txnEvent := TxnEvent{
    27  		FinalName: "WebTransaction/Go/hello",
    28  		Duration:  3 * time.Second,
    29  		Attrs:     attr,
    30  		BetterCAT: BetterCAT{
    31  			Enabled: false,
    32  		},
    33  	}
    34  
    35  	txnSlows := newSlowQueries(maxTxnSlowQueries)
    36  	qParams, err := vetQueryParameters(map[string]interface{}{
    37  		strings.Repeat("X", attributeKeyLengthLimit+1): "invalid-key",
    38  		"invalid-value": struct{}{},
    39  		"valid":         123,
    40  	})
    41  	if nil == err {
    42  		t.Error("expected error")
    43  	}
    44  	txnSlows.observeInstance(slowQueryInstance{
    45  		Duration:           2 * time.Second,
    46  		DatastoreMetric:    "Datastore/statement/MySQL/users/INSERT",
    47  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
    48  		Host:               "db-server-1",
    49  		PortPathOrID:       "3306",
    50  		DatabaseName:       "production",
    51  		StackTrace:         nil,
    52  		QueryParameters:    qParams,
    53  	})
    54  	harvestSlows := newSlowQueries(maxHarvestSlowSQLs)
    55  	harvestSlows.Merge(txnSlows, txnEvent)
    56  	js, err := harvestSlows.Data("agentRunID", time.Now())
    57  	expect := CompactJSONString(`[[
    58  	[
    59  		"WebTransaction/Go/hello",
    60  		"/zip/zap",
    61  		3722056893,
    62  		"INSERT INTO users (name, age) VALUES ($1, $2)",
    63  		"Datastore/statement/MySQL/users/INSERT",
    64  		1,
    65  		2000,
    66  		2000,
    67  		2000,
    68  		{
    69  			"host":"db-server-1",
    70  			"port_path_or_id":"3306",
    71  			"database_name":"production",
    72  			"query_parameters":{
    73  				"valid":123
    74  			}
    75  		}
    76  	]
    77  ]]`)
    78  	if nil != err {
    79  		t.Error(err)
    80  	}
    81  	if string(js) != expect {
    82  		t.Error(string(js), expect)
    83  	}
    84  }
    85  
    86  func TestSlowQueriesExcludeURI(t *testing.T) {
    87  	c := sampleAttributeConfigInput
    88  	c.Attributes.Exclude = []string{"request.uri"}
    89  	acfg := CreateAttributeConfig(c, true)
    90  	attr := NewAttributes(acfg)
    91  	attr.Agent.Add(attributeRequestURI, "/zip/zap", nil)
    92  	txnEvent := TxnEvent{
    93  		FinalName: "WebTransaction/Go/hello",
    94  		Duration:  3 * time.Second,
    95  		Attrs:     attr,
    96  		BetterCAT: BetterCAT{
    97  			Enabled: false,
    98  		},
    99  	}
   100  	txnSlows := newSlowQueries(maxTxnSlowQueries)
   101  	qParams, err := vetQueryParameters(map[string]interface{}{
   102  		strings.Repeat("X", attributeKeyLengthLimit+1): "invalid-key",
   103  		"invalid-value": struct{}{},
   104  		"valid":         123,
   105  	})
   106  	if nil == err {
   107  		t.Error("expected error")
   108  	}
   109  	txnSlows.observeInstance(slowQueryInstance{
   110  		Duration:           2 * time.Second,
   111  		DatastoreMetric:    "Datastore/statement/MySQL/users/INSERT",
   112  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   113  		Host:               "db-server-1",
   114  		PortPathOrID:       "3306",
   115  		DatabaseName:       "production",
   116  		StackTrace:         nil,
   117  		QueryParameters:    qParams,
   118  	})
   119  	harvestSlows := newSlowQueries(maxHarvestSlowSQLs)
   120  	harvestSlows.Merge(txnSlows, txnEvent)
   121  	js, err := harvestSlows.Data("agentRunID", time.Now())
   122  	expect := CompactJSONString(`[[
   123  	[
   124  		"WebTransaction/Go/hello",
   125  		"",
   126  		3722056893,
   127  		"INSERT INTO users (name, age) VALUES ($1, $2)",
   128  		"Datastore/statement/MySQL/users/INSERT",
   129  		1,
   130  		2000,
   131  		2000,
   132  		2000,
   133  		{
   134  			"host":"db-server-1",
   135  			"port_path_or_id":"3306",
   136  			"database_name":"production",
   137  			"query_parameters":{
   138  				"valid":123
   139  			}
   140  		}
   141  	]
   142  ]]`)
   143  	if nil != err {
   144  		t.Error(err)
   145  	}
   146  	if string(js) != expect {
   147  		t.Error(string(js), expect)
   148  	}
   149  }
   150  
   151  func TestSlowQueriesAggregation(t *testing.T) {
   152  	max := 50
   153  	slows := make([]slowQueryInstance, 3*max)
   154  	for i := 0; i < max; i++ {
   155  		num := i + 1
   156  		str := strconv.Itoa(num)
   157  		duration := time.Duration(num) * time.Second
   158  		slow := slowQueryInstance{
   159  			DatastoreMetric:    "Datastore/" + str,
   160  			ParameterizedQuery: str,
   161  		}
   162  		slow.Duration = duration
   163  		slow.TxnEvent = TxnEvent{
   164  			FinalName: "Txn/0" + str,
   165  		}
   166  		slows[i*3+0] = slow
   167  		slow.Duration = duration + (100 * time.Second)
   168  		slow.TxnEvent = TxnEvent{
   169  			FinalName: "Txn/1" + str,
   170  		}
   171  		slows[i*3+1] = slow
   172  		slow.Duration = duration + (200 * time.Second)
   173  		slow.TxnEvent = TxnEvent{
   174  			FinalName: "Txn/2" + str,
   175  		}
   176  		slows[i*3+2] = slow
   177  	}
   178  	sq := newSlowQueries(10)
   179  	seed := int64(99) // arbitrary fixed seed
   180  	r := rand.New(rand.NewSource(seed))
   181  	perm := r.Perm(max * 3)
   182  	for _, idx := range perm {
   183  		sq.observeInstance(slows[idx])
   184  	}
   185  	js, err := sq.Data("agentRunID", time.Now())
   186  	expect := CompactJSONString(`[[
   187  	["Txn/241","",2296612630,"41","Datastore/41",1,241000,241000,241000,{}],
   188  	["Txn/242","",2279835011,"42","Datastore/42",2,384000,142000,242000,{}],
   189  	["Txn/243","",2263057392,"43","Datastore/43",2,386000,143000,243000,{}],
   190  	["Txn/244","",2380500725,"44","Datastore/44",3,432000,44000,244000,{}],
   191  	["Txn/247","",2330167868,"47","Datastore/47",2,394000,147000,247000,{}],
   192  	["Txn/245","",2363723106,"45","Datastore/45",2,290000,45000,245000,{}],
   193  	["Txn/250","",2212577440,"50","Datastore/50",1,250000,250000,250000,{}],
   194  	["Txn/246","",2346945487,"46","Datastore/46",2,392000,146000,246000,{}],
   195  	["Txn/249","",2430833582,"49","Datastore/49",3,447000,49000,249000,{}],
   196  	["Txn/248","",2447611201,"48","Datastore/48",3,444000,48000,248000,{}]
   197  ]]`)
   198  	if nil != err {
   199  		t.Error(err)
   200  	}
   201  	if string(js) != expect {
   202  		t.Error(string(js), expect)
   203  	}
   204  }
   205  
   206  func TestSlowQueriesBetterCAT(t *testing.T) {
   207  	acfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   208  	attr := NewAttributes(acfg)
   209  	attr.Agent.Add(attributeRequestURI, "/zip/zap", nil)
   210  	txnEvent := TxnEvent{
   211  		FinalName: "WebTransaction/Go/hello",
   212  		Duration:  3 * time.Second,
   213  		Attrs:     attr,
   214  		BetterCAT: BetterCAT{
   215  			Enabled:  true,
   216  			ID:       "txn-id",
   217  			Priority: 0.5,
   218  		},
   219  	}
   220  
   221  	txnEvent.BetterCAT.Inbound = &Payload{
   222  		payloadCaller: payloadCaller{
   223  			TransportType: "HTTP",
   224  			Type:          "Browser",
   225  			App:           "caller-app",
   226  			Account:       "caller-account",
   227  		},
   228  		ID:                "caller-id",
   229  		TransactionID:     "caller-parent-id",
   230  		TracedID:          "trace-id",
   231  		TransportDuration: 2 * time.Second,
   232  	}
   233  
   234  	txnSlows := newSlowQueries(maxTxnSlowQueries)
   235  	qParams, err := vetQueryParameters(map[string]interface{}{
   236  		strings.Repeat("X", attributeKeyLengthLimit+1): "invalid-key",
   237  		"invalid-value": struct{}{},
   238  		"valid":         123,
   239  	})
   240  	if nil == err {
   241  		t.Error("expected error")
   242  	}
   243  	txnSlows.observeInstance(slowQueryInstance{
   244  		Duration:           2 * time.Second,
   245  		DatastoreMetric:    "Datastore/statement/MySQL/users/INSERT",
   246  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   247  		Host:               "db-server-1",
   248  		PortPathOrID:       "3306",
   249  		DatabaseName:       "production",
   250  		StackTrace:         nil,
   251  		QueryParameters:    qParams,
   252  	})
   253  	harvestSlows := newSlowQueries(maxHarvestSlowSQLs)
   254  	harvestSlows.Merge(txnSlows, txnEvent)
   255  	js, err := harvestSlows.Data("agentRunID", time.Now())
   256  	expect := CompactJSONString(`[[
   257  	[
   258  		"WebTransaction/Go/hello",
   259  		"/zip/zap",
   260  		3722056893,
   261  		"INSERT INTO users (name, age) VALUES ($1, $2)",
   262  		"Datastore/statement/MySQL/users/INSERT",
   263  		1,
   264  		2000,
   265  		2000,
   266  		2000,
   267  		{
   268  			"host":"db-server-1",
   269  			"port_path_or_id":"3306",
   270  			"database_name":"production",
   271  			"query_parameters":{"valid":123},
   272  			"parent.type": "Browser",
   273  			"parent.app": "caller-app",
   274  			"parent.account": "caller-account",
   275  			"parent.transportType": "HTTP",
   276  			"parent.transportDuration": 2,
   277  			"guid":"txn-id",
   278  			"traceId":"trace-id",
   279  			"priority":0.500000,
   280  			"sampled":false
   281  		}
   282  	]
   283  ]]`)
   284  	if nil != err {
   285  		t.Error(err)
   286  	}
   287  	if string(js) != expect {
   288  		t.Error(string(js), expect)
   289  	}
   290  }