github.com/lulzWill/go-agent@v2.1.2+incompatible/internal_slow_queries_test.go (about)

     1  package newrelic
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/lulzWill/go-agent/internal"
     9  	"github.com/lulzWill/go-agent/internal/crossagent"
    10  )
    11  
    12  func TestSlowQueryBasic(t *testing.T) {
    13  	cfgfn := func(cfg *Config) {
    14  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
    15  	}
    16  	app := testApp(nil, cfgfn, t)
    17  	txn := app.StartTransaction("hello", nil, helloRequest)
    18  	s1 := DatastoreSegment{
    19  		StartTime:          StartSegmentNow(txn),
    20  		Product:            DatastoreMySQL,
    21  		Collection:         "users",
    22  		Operation:          "INSERT",
    23  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
    24  	}
    25  	s1.End()
    26  	txn.End()
    27  
    28  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
    29  		Count:        1,
    30  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
    31  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
    32  		TxnName:      "WebTransaction/Go/hello",
    33  		TxnURL:       "/hello",
    34  		DatabaseName: "",
    35  		Host:         "",
    36  		PortPathOrID: "",
    37  	}})
    38  }
    39  
    40  func TestSlowQueryLocallyDisabled(t *testing.T) {
    41  	cfgfn := func(cfg *Config) {
    42  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
    43  		cfg.DatastoreTracer.SlowQuery.Enabled = false
    44  	}
    45  	app := testApp(nil, cfgfn, t)
    46  	txn := app.StartTransaction("hello", nil, helloRequest)
    47  	s1 := DatastoreSegment{
    48  		StartTime:          StartSegmentNow(txn),
    49  		Product:            DatastoreMySQL,
    50  		Collection:         "users",
    51  		Operation:          "INSERT",
    52  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
    53  	}
    54  	s1.End()
    55  	txn.End()
    56  
    57  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{})
    58  }
    59  
    60  func TestSlowQueryRemotelyDisabled(t *testing.T) {
    61  	cfgfn := func(cfg *Config) {
    62  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
    63  	}
    64  	replyfn := func(reply *internal.ConnectReply) {
    65  		reply.CollectTraces = false
    66  	}
    67  	app := testApp(replyfn, cfgfn, t)
    68  	txn := app.StartTransaction("hello", nil, helloRequest)
    69  	s1 := DatastoreSegment{
    70  		StartTime:          StartSegmentNow(txn),
    71  		Product:            DatastoreMySQL,
    72  		Collection:         "users",
    73  		Operation:          "INSERT",
    74  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
    75  	}
    76  	s1.End()
    77  	txn.End()
    78  
    79  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{})
    80  }
    81  
    82  func TestSlowQueryBelowThreshold(t *testing.T) {
    83  	cfgfn := func(cfg *Config) {
    84  		cfg.DatastoreTracer.SlowQuery.Threshold = 1 * time.Hour
    85  	}
    86  	app := testApp(nil, cfgfn, t)
    87  	txn := app.StartTransaction("hello", nil, helloRequest)
    88  	s1 := DatastoreSegment{
    89  		StartTime:          StartSegmentNow(txn),
    90  		Product:            DatastoreMySQL,
    91  		Collection:         "users",
    92  		Operation:          "INSERT",
    93  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
    94  	}
    95  	s1.End()
    96  	txn.End()
    97  
    98  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{})
    99  }
   100  
   101  func TestSlowQueryDatabaseProvided(t *testing.T) {
   102  	cfgfn := func(cfg *Config) {
   103  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   104  	}
   105  	app := testApp(nil, cfgfn, t)
   106  	txn := app.StartTransaction("hello", nil, helloRequest)
   107  	s1 := DatastoreSegment{
   108  		StartTime:          StartSegmentNow(txn),
   109  		Product:            DatastoreMySQL,
   110  		Collection:         "users",
   111  		Operation:          "INSERT",
   112  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   113  		DatabaseName:       "my_database",
   114  	}
   115  	s1.End()
   116  	txn.End()
   117  
   118  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   119  		Count:        1,
   120  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   121  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   122  		TxnName:      "WebTransaction/Go/hello",
   123  		TxnURL:       "/hello",
   124  		DatabaseName: "my_database",
   125  		Host:         "",
   126  		PortPathOrID: "",
   127  	}})
   128  }
   129  
   130  func TestSlowQueryHostProvided(t *testing.T) {
   131  	cfgfn := func(cfg *Config) {
   132  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   133  	}
   134  	app := testApp(nil, cfgfn, t)
   135  	txn := app.StartTransaction("hello", nil, helloRequest)
   136  	s1 := DatastoreSegment{
   137  		StartTime:          StartSegmentNow(txn),
   138  		Product:            DatastoreMySQL,
   139  		Collection:         "users",
   140  		Operation:          "INSERT",
   141  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   142  		Host:               "db-server-1",
   143  	}
   144  	s1.End()
   145  	txn.End()
   146  
   147  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   148  		Count:        1,
   149  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   150  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   151  		TxnName:      "WebTransaction/Go/hello",
   152  		TxnURL:       "/hello",
   153  		DatabaseName: "",
   154  		Host:         "db-server-1",
   155  		PortPathOrID: "unknown",
   156  	}})
   157  	scope := "WebTransaction/Go/hello"
   158  	app.ExpectMetrics(t, append([]internal.WantMetric{
   159  		{Name: "Datastore/all", Scope: "", Forced: true, Data: nil},
   160  		{Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil},
   161  		{Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil},
   162  		{Name: "Datastore/MySQL/allWeb", Scope: "", Forced: true, Data: nil},
   163  		{Name: "Datastore/operation/MySQL/INSERT", Scope: "", Forced: false, Data: nil},
   164  		{Name: "Datastore/statement/MySQL/users/INSERT", Scope: "", Forced: false, Data: nil},
   165  		{Name: "Datastore/statement/MySQL/users/INSERT", Scope: scope, Forced: false, Data: nil},
   166  		{Name: "Datastore/instance/MySQL/db-server-1/unknown", Scope: "", Forced: false, Data: nil},
   167  	}, webMetrics...))
   168  }
   169  
   170  func TestSlowQueryPortProvided(t *testing.T) {
   171  	cfgfn := func(cfg *Config) {
   172  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   173  	}
   174  	app := testApp(nil, cfgfn, t)
   175  	txn := app.StartTransaction("hello", nil, helloRequest)
   176  	s1 := DatastoreSegment{
   177  		StartTime:          StartSegmentNow(txn),
   178  		Product:            DatastoreMySQL,
   179  		Collection:         "users",
   180  		Operation:          "INSERT",
   181  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   182  		PortPathOrID:       "98021",
   183  	}
   184  	s1.End()
   185  	txn.End()
   186  
   187  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   188  		Count:        1,
   189  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   190  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   191  		TxnName:      "WebTransaction/Go/hello",
   192  		TxnURL:       "/hello",
   193  		DatabaseName: "",
   194  		Host:         "unknown",
   195  		PortPathOrID: "98021",
   196  	}})
   197  	scope := "WebTransaction/Go/hello"
   198  	app.ExpectMetrics(t, append([]internal.WantMetric{
   199  		{Name: "Datastore/all", Scope: "", Forced: true, Data: nil},
   200  		{Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil},
   201  		{Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil},
   202  		{Name: "Datastore/MySQL/allWeb", Scope: "", Forced: true, Data: nil},
   203  		{Name: "Datastore/operation/MySQL/INSERT", Scope: "", Forced: false, Data: nil},
   204  		{Name: "Datastore/statement/MySQL/users/INSERT", Scope: "", Forced: false, Data: nil},
   205  		{Name: "Datastore/statement/MySQL/users/INSERT", Scope: scope, Forced: false, Data: nil},
   206  		{Name: "Datastore/instance/MySQL/unknown/98021", Scope: "", Forced: false, Data: nil},
   207  	}, webMetrics...))
   208  }
   209  
   210  func TestSlowQueryHostPortProvided(t *testing.T) {
   211  	cfgfn := func(cfg *Config) {
   212  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   213  	}
   214  	app := testApp(nil, cfgfn, t)
   215  	txn := app.StartTransaction("hello", nil, helloRequest)
   216  	s1 := DatastoreSegment{
   217  		StartTime:          StartSegmentNow(txn),
   218  		Product:            DatastoreMySQL,
   219  		Collection:         "users",
   220  		Operation:          "INSERT",
   221  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   222  		Host:               "db-server-1",
   223  		PortPathOrID:       "98021",
   224  	}
   225  	s1.End()
   226  	txn.End()
   227  
   228  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   229  		Count:        1,
   230  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   231  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   232  		TxnName:      "WebTransaction/Go/hello",
   233  		TxnURL:       "/hello",
   234  		DatabaseName: "",
   235  		Host:         "db-server-1",
   236  		PortPathOrID: "98021",
   237  	}})
   238  	scope := "WebTransaction/Go/hello"
   239  	app.ExpectMetrics(t, append([]internal.WantMetric{
   240  		{Name: "Datastore/all", Scope: "", Forced: true, Data: nil},
   241  		{Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil},
   242  		{Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil},
   243  		{Name: "Datastore/MySQL/allWeb", Scope: "", Forced: true, Data: nil},
   244  		{Name: "Datastore/operation/MySQL/INSERT", Scope: "", Forced: false, Data: nil},
   245  		{Name: "Datastore/statement/MySQL/users/INSERT", Scope: "", Forced: false, Data: nil},
   246  		{Name: "Datastore/statement/MySQL/users/INSERT", Scope: scope, Forced: false, Data: nil},
   247  		{Name: "Datastore/instance/MySQL/db-server-1/98021", Scope: "", Forced: false, Data: nil},
   248  	}, webMetrics...))
   249  }
   250  
   251  func TestSlowQueryAggregation(t *testing.T) {
   252  	cfgfn := func(cfg *Config) {
   253  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   254  	}
   255  	app := testApp(nil, cfgfn, t)
   256  	txn := app.StartTransaction("hello", nil, helloRequest)
   257  	ds := DatastoreSegment{
   258  		StartTime:          StartSegmentNow(txn),
   259  		Product:            DatastoreMySQL,
   260  		Collection:         "users",
   261  		Operation:          "INSERT",
   262  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   263  	}
   264  	ds.End()
   265  	ds = DatastoreSegment{
   266  		StartTime:          StartSegmentNow(txn),
   267  		Product:            DatastoreMySQL,
   268  		Collection:         "users",
   269  		Operation:          "INSERT",
   270  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   271  	}
   272  	ds.End()
   273  	ds = DatastoreSegment{
   274  		StartTime:          StartSegmentNow(txn),
   275  		Product:            DatastorePostgres,
   276  		Collection:         "products",
   277  		Operation:          "INSERT",
   278  		ParameterizedQuery: "INSERT INTO products (name, price) VALUES ($1, $2)",
   279  	}
   280  	ds.End()
   281  	txn.End()
   282  
   283  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   284  		Count:        2,
   285  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   286  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   287  		TxnName:      "WebTransaction/Go/hello",
   288  		TxnURL:       "/hello",
   289  		DatabaseName: "",
   290  		Host:         "",
   291  		PortPathOrID: "",
   292  	}, {
   293  		Count:        1,
   294  		MetricName:   "Datastore/statement/Postgres/products/INSERT",
   295  		Query:        "INSERT INTO products (name, price) VALUES ($1, $2)",
   296  		TxnName:      "WebTransaction/Go/hello",
   297  		TxnURL:       "/hello",
   298  		DatabaseName: "",
   299  		Host:         "",
   300  		PortPathOrID: "",
   301  	},
   302  	})
   303  }
   304  
   305  func TestSlowQueryMissingQuery(t *testing.T) {
   306  	cfgfn := func(cfg *Config) {
   307  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   308  	}
   309  	app := testApp(nil, cfgfn, t)
   310  	txn := app.StartTransaction("hello", nil, helloRequest)
   311  	s1 := DatastoreSegment{
   312  		StartTime:  StartSegmentNow(txn),
   313  		Product:    DatastoreMySQL,
   314  		Collection: "users",
   315  		Operation:  "INSERT",
   316  	}
   317  	s1.End()
   318  	txn.End()
   319  
   320  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   321  		Count:        1,
   322  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   323  		Query:        "'INSERT' on 'users' using 'MySQL'",
   324  		TxnName:      "WebTransaction/Go/hello",
   325  		TxnURL:       "/hello",
   326  		DatabaseName: "",
   327  		Host:         "",
   328  		PortPathOrID: "",
   329  	}})
   330  }
   331  
   332  func TestSlowQueryMissingEverything(t *testing.T) {
   333  	cfgfn := func(cfg *Config) {
   334  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   335  	}
   336  	app := testApp(nil, cfgfn, t)
   337  	txn := app.StartTransaction("hello", nil, helloRequest)
   338  	s1 := DatastoreSegment{
   339  		StartTime: StartSegmentNow(txn),
   340  	}
   341  	s1.End()
   342  	txn.End()
   343  
   344  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   345  		Count:        1,
   346  		MetricName:   "Datastore/operation/Unknown/other",
   347  		Query:        "'other' on 'unknown' using 'Unknown'",
   348  		TxnName:      "WebTransaction/Go/hello",
   349  		TxnURL:       "/hello",
   350  		DatabaseName: "",
   351  		Host:         "",
   352  		PortPathOrID: "",
   353  	}})
   354  	scope := "WebTransaction/Go/hello"
   355  	app.ExpectMetrics(t, append([]internal.WantMetric{
   356  		{Name: "Datastore/all", Scope: "", Forced: true, Data: nil},
   357  		{Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil},
   358  		{Name: "Datastore/Unknown/all", Scope: "", Forced: true, Data: nil},
   359  		{Name: "Datastore/Unknown/allWeb", Scope: "", Forced: true, Data: nil},
   360  		{Name: "Datastore/operation/Unknown/other", Scope: "", Forced: false, Data: nil},
   361  		{Name: "Datastore/operation/Unknown/other", Scope: scope, Forced: false, Data: nil},
   362  	}, webMetrics...))
   363  }
   364  
   365  func TestSlowQueryWithQueryParameters(t *testing.T) {
   366  	cfgfn := func(cfg *Config) {
   367  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   368  	}
   369  	app := testApp(nil, cfgfn, t)
   370  	txn := app.StartTransaction("hello", nil, helloRequest)
   371  	params := map[string]interface{}{
   372  		"str": "zap",
   373  		"int": 123,
   374  	}
   375  	s1 := DatastoreSegment{
   376  		StartTime:          StartSegmentNow(txn),
   377  		Product:            DatastoreMySQL,
   378  		Collection:         "users",
   379  		Operation:          "INSERT",
   380  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   381  		QueryParameters:    params,
   382  	}
   383  	s1.End()
   384  	txn.End()
   385  
   386  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   387  		Count:        1,
   388  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   389  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   390  		TxnName:      "WebTransaction/Go/hello",
   391  		TxnURL:       "/hello",
   392  		DatabaseName: "",
   393  		Host:         "",
   394  		PortPathOrID: "",
   395  		Params:       params,
   396  	}})
   397  }
   398  
   399  func TestSlowQueryHighSecurity(t *testing.T) {
   400  	cfgfn := func(cfg *Config) {
   401  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   402  		cfg.HighSecurity = true
   403  	}
   404  	app := testApp(nil, cfgfn, t)
   405  	txn := app.StartTransaction("hello", nil, helloRequest)
   406  	params := map[string]interface{}{
   407  		"str": "zap",
   408  		"int": 123,
   409  	}
   410  	s1 := DatastoreSegment{
   411  		StartTime:          StartSegmentNow(txn),
   412  		Product:            DatastoreMySQL,
   413  		Collection:         "users",
   414  		Operation:          "INSERT",
   415  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   416  		QueryParameters:    params,
   417  	}
   418  	s1.End()
   419  	txn.End()
   420  
   421  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   422  		Count:        1,
   423  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   424  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   425  		TxnName:      "WebTransaction/Go/hello",
   426  		TxnURL:       "/hello",
   427  		DatabaseName: "",
   428  		Host:         "",
   429  		PortPathOrID: "",
   430  		Params:       nil,
   431  	}})
   432  }
   433  
   434  func TestSlowQuerySecurityPolicyFalse(t *testing.T) {
   435  	// When the record_sql security policy is set to false, sql parameters
   436  	// and the sql format string should be replaced.
   437  	cfgfn := func(cfg *Config) {
   438  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   439  	}
   440  	replyfn := func(reply *internal.ConnectReply) {
   441  		reply.SecurityPolicies.RecordSQL.SetEnabled(false)
   442  	}
   443  	app := testApp(replyfn, cfgfn, t)
   444  	txn := app.StartTransaction("hello", nil, helloRequest)
   445  	params := map[string]interface{}{
   446  		"str": "zap",
   447  		"int": 123,
   448  	}
   449  	s1 := DatastoreSegment{
   450  		StartTime:          StartSegmentNow(txn),
   451  		Product:            DatastoreMySQL,
   452  		Collection:         "users",
   453  		Operation:          "INSERT",
   454  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   455  		QueryParameters:    params,
   456  	}
   457  	s1.End()
   458  	txn.End()
   459  
   460  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   461  		Count:        1,
   462  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   463  		Query:        "'INSERT' on 'users' using 'MySQL'",
   464  		TxnName:      "WebTransaction/Go/hello",
   465  		TxnURL:       "/hello",
   466  		DatabaseName: "",
   467  		Host:         "",
   468  		PortPathOrID: "",
   469  		Params:       nil,
   470  	}})
   471  }
   472  
   473  func TestSlowQuerySecurityPolicyTrue(t *testing.T) {
   474  	// When the record_sql security policy is set to true, sql parameters
   475  	// should be omitted.
   476  	cfgfn := func(cfg *Config) {
   477  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   478  	}
   479  	replyfn := func(reply *internal.ConnectReply) {
   480  		reply.SecurityPolicies.RecordSQL.SetEnabled(true)
   481  	}
   482  	app := testApp(replyfn, cfgfn, t)
   483  	txn := app.StartTransaction("hello", nil, helloRequest)
   484  	params := map[string]interface{}{
   485  		"str": "zap",
   486  		"int": 123,
   487  	}
   488  	s1 := DatastoreSegment{
   489  		StartTime:          StartSegmentNow(txn),
   490  		Product:            DatastoreMySQL,
   491  		Collection:         "users",
   492  		Operation:          "INSERT",
   493  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   494  		QueryParameters:    params,
   495  	}
   496  	s1.End()
   497  	txn.End()
   498  
   499  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   500  		Count:        1,
   501  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   502  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   503  		TxnName:      "WebTransaction/Go/hello",
   504  		TxnURL:       "/hello",
   505  		DatabaseName: "",
   506  		Host:         "",
   507  		PortPathOrID: "",
   508  		Params:       nil,
   509  	}})
   510  }
   511  
   512  func TestSlowQueryInvalidParameters(t *testing.T) {
   513  	cfgfn := func(cfg *Config) {
   514  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   515  	}
   516  	app := testApp(nil, cfgfn, t)
   517  	txn := app.StartTransaction("hello", nil, helloRequest)
   518  	params := map[string]interface{}{
   519  		"str":                               "zap",
   520  		"int":                               123,
   521  		"invalid_value":                     struct{}{},
   522  		strings.Repeat("key-too-long", 100): 1,
   523  		"long-key":                          strings.Repeat("A", 300),
   524  	}
   525  	s1 := DatastoreSegment{
   526  		StartTime:          StartSegmentNow(txn),
   527  		Product:            DatastoreMySQL,
   528  		Collection:         "users",
   529  		Operation:          "INSERT",
   530  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   531  		QueryParameters:    params,
   532  	}
   533  	s1.End()
   534  	txn.End()
   535  
   536  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   537  		Count:        1,
   538  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   539  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   540  		TxnName:      "WebTransaction/Go/hello",
   541  		TxnURL:       "/hello",
   542  		DatabaseName: "",
   543  		Host:         "",
   544  		PortPathOrID: "",
   545  		Params: map[string]interface{}{
   546  			"str":      "zap",
   547  			"int":      123,
   548  			"long-key": strings.Repeat("A", 255),
   549  		},
   550  	}})
   551  }
   552  
   553  func TestSlowQueryParametersDisabled(t *testing.T) {
   554  	cfgfn := func(cfg *Config) {
   555  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   556  		cfg.DatastoreTracer.QueryParameters.Enabled = false
   557  	}
   558  	app := testApp(nil, cfgfn, t)
   559  	txn := app.StartTransaction("hello", nil, helloRequest)
   560  	params := map[string]interface{}{
   561  		"str": "zap",
   562  		"int": 123,
   563  	}
   564  	s1 := DatastoreSegment{
   565  		StartTime:          StartSegmentNow(txn),
   566  		Product:            DatastoreMySQL,
   567  		Collection:         "users",
   568  		Operation:          "INSERT",
   569  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   570  		QueryParameters:    params,
   571  	}
   572  	s1.End()
   573  	txn.End()
   574  
   575  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   576  		Count:        1,
   577  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   578  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   579  		TxnName:      "WebTransaction/Go/hello",
   580  		TxnURL:       "/hello",
   581  		DatabaseName: "",
   582  		Host:         "",
   583  		PortPathOrID: "",
   584  		Params:       nil,
   585  	}})
   586  }
   587  
   588  func TestSlowQueryInstanceDisabled(t *testing.T) {
   589  	cfgfn := func(cfg *Config) {
   590  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   591  		cfg.DatastoreTracer.InstanceReporting.Enabled = false
   592  	}
   593  	app := testApp(nil, cfgfn, t)
   594  	txn := app.StartTransaction("hello", nil, helloRequest)
   595  	s1 := DatastoreSegment{
   596  		StartTime:          StartSegmentNow(txn),
   597  		Product:            DatastoreMySQL,
   598  		Collection:         "users",
   599  		Operation:          "INSERT",
   600  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   601  		Host:               "db-server-1",
   602  	}
   603  	s1.End()
   604  	txn.End()
   605  
   606  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   607  		Count:        1,
   608  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   609  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   610  		TxnName:      "WebTransaction/Go/hello",
   611  		TxnURL:       "/hello",
   612  		DatabaseName: "",
   613  		Host:         "",
   614  		PortPathOrID: "",
   615  	}})
   616  	scope := "WebTransaction/Go/hello"
   617  	app.ExpectMetrics(t, append([]internal.WantMetric{
   618  		{Name: "Datastore/all", Scope: "", Forced: true, Data: nil},
   619  		{Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil},
   620  		{Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil},
   621  		{Name: "Datastore/MySQL/allWeb", Scope: "", Forced: true, Data: nil},
   622  		{Name: "Datastore/operation/MySQL/INSERT", Scope: "", Forced: false, Data: nil},
   623  		{Name: "Datastore/statement/MySQL/users/INSERT", Scope: "", Forced: false, Data: nil},
   624  		{Name: "Datastore/statement/MySQL/users/INSERT", Scope: scope, Forced: false, Data: nil},
   625  	}, webMetrics...))
   626  }
   627  
   628  func TestSlowQueryInstanceDisabledLocalhost(t *testing.T) {
   629  	cfgfn := func(cfg *Config) {
   630  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   631  		cfg.DatastoreTracer.InstanceReporting.Enabled = false
   632  	}
   633  	app := testApp(nil, cfgfn, t)
   634  	txn := app.StartTransaction("hello", nil, helloRequest)
   635  	s1 := DatastoreSegment{
   636  		StartTime:          StartSegmentNow(txn),
   637  		Product:            DatastoreMySQL,
   638  		Collection:         "users",
   639  		Operation:          "INSERT",
   640  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   641  		Host:               "localhost",
   642  		PortPathOrID:       "3306",
   643  	}
   644  	s1.End()
   645  	txn.End()
   646  
   647  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   648  		Count:        1,
   649  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   650  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   651  		TxnName:      "WebTransaction/Go/hello",
   652  		TxnURL:       "/hello",
   653  		DatabaseName: "",
   654  		Host:         "",
   655  		PortPathOrID: "",
   656  	}})
   657  	scope := "WebTransaction/Go/hello"
   658  	app.ExpectMetrics(t, append([]internal.WantMetric{
   659  		{Name: "Datastore/all", Scope: "", Forced: true, Data: nil},
   660  		{Name: "Datastore/allWeb", Scope: "", Forced: true, Data: nil},
   661  		{Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil},
   662  		{Name: "Datastore/MySQL/allWeb", Scope: "", Forced: true, Data: nil},
   663  		{Name: "Datastore/operation/MySQL/INSERT", Scope: "", Forced: false, Data: nil},
   664  		{Name: "Datastore/statement/MySQL/users/INSERT", Scope: "", Forced: false, Data: nil},
   665  		{Name: "Datastore/statement/MySQL/users/INSERT", Scope: scope, Forced: false, Data: nil},
   666  	}, webMetrics...))
   667  }
   668  
   669  func TestSlowQueryDatabaseNameDisabled(t *testing.T) {
   670  	cfgfn := func(cfg *Config) {
   671  		cfg.DatastoreTracer.SlowQuery.Threshold = 0
   672  		cfg.DatastoreTracer.DatabaseNameReporting.Enabled = false
   673  	}
   674  	app := testApp(nil, cfgfn, t)
   675  	txn := app.StartTransaction("hello", nil, helloRequest)
   676  	s1 := DatastoreSegment{
   677  		StartTime:          StartSegmentNow(txn),
   678  		Product:            DatastoreMySQL,
   679  		Collection:         "users",
   680  		Operation:          "INSERT",
   681  		ParameterizedQuery: "INSERT INTO users (name, age) VALUES ($1, $2)",
   682  		DatabaseName:       "db-server-1",
   683  	}
   684  	s1.End()
   685  	txn.End()
   686  
   687  	app.ExpectSlowQueries(t, []internal.WantSlowQuery{{
   688  		Count:        1,
   689  		MetricName:   "Datastore/statement/MySQL/users/INSERT",
   690  		Query:        "INSERT INTO users (name, age) VALUES ($1, $2)",
   691  		TxnName:      "WebTransaction/Go/hello",
   692  		TxnURL:       "/hello",
   693  		DatabaseName: "",
   694  		Host:         "",
   695  		PortPathOrID: "",
   696  	}})
   697  }
   698  
   699  func TestDatastoreAPICrossAgent(t *testing.T) {
   700  	var testcases []struct {
   701  		TestName string `json:"test_name"`
   702  		Input    struct {
   703  			Parameters struct {
   704  				Product      string `json:"product"`
   705  				Collection   string `json:"collection"`
   706  				Operation    string `json:"operation"`
   707  				Host         string `json:"host"`
   708  				PortPathOrID string `json:"port_path_or_id"`
   709  				DatabaseName string `json:"database_name"`
   710  			} `json:"parameters"`
   711  			IsWeb          bool   `json:"is_web"`
   712  			SystemHostname string `json:"system_hostname"`
   713  			Configuration  struct {
   714  				InstanceEnabled bool `json:"datastore_tracer.instance_reporting.enabled"`
   715  				DatabaseEnabled bool `json:"datastore_tracer.database_name_reporting.enabled"`
   716  			}
   717  		}
   718  		Expectation struct {
   719  			MetricsScoped   []string `json:"metrics_scoped"`
   720  			MetricsUnscoped []string `json:"metrics_unscoped"`
   721  			Trace           struct {
   722  				MetricName   string `json:"metric_name"`
   723  				Host         string `json:"host"`
   724  				PortPathOrID string `json:"port_path_or_id"`
   725  				DatabaseName string `json:"database_name"`
   726  			} `json:"transaction_segment_and_slow_query_trace"`
   727  		}
   728  	}
   729  
   730  	err := crossagent.ReadJSON("datastores/datastore_api.json", &testcases)
   731  	if err != nil {
   732  		t.Fatal(err)
   733  	}
   734  
   735  	for _, tc := range testcases {
   736  		query := "my query"
   737  		cfgfn := func(cfg *Config) {
   738  			cfg.DatastoreTracer.SlowQuery.Threshold = 0
   739  			cfg.DatastoreTracer.InstanceReporting.Enabled =
   740  				tc.Input.Configuration.InstanceEnabled
   741  			cfg.DatastoreTracer.DatabaseNameReporting.Enabled =
   742  				tc.Input.Configuration.DatabaseEnabled
   743  		}
   744  		app := testApp(nil, cfgfn, t)
   745  		var txn Transaction
   746  		var txnURL string
   747  		if tc.Input.IsWeb {
   748  			txnURL = helloPath
   749  			txn = app.StartTransaction("hello", nil, helloRequest)
   750  		} else {
   751  			txn = app.StartTransaction("hello", nil, nil)
   752  		}
   753  		ds := DatastoreSegment{
   754  			StartTime:          StartSegmentNow(txn),
   755  			Product:            DatastoreProduct(tc.Input.Parameters.Product),
   756  			Operation:          tc.Input.Parameters.Operation,
   757  			Collection:         tc.Input.Parameters.Collection,
   758  			PortPathOrID:       tc.Input.Parameters.PortPathOrID,
   759  			Host:               tc.Input.Parameters.Host,
   760  			DatabaseName:       tc.Input.Parameters.DatabaseName,
   761  			ParameterizedQuery: query,
   762  		}
   763  		ds.End()
   764  		txn.End()
   765  
   766  		var metrics []internal.WantMetric
   767  		var scope string
   768  		if tc.Input.IsWeb {
   769  			scope = "WebTransaction/Go/hello"
   770  			metrics = append([]internal.WantMetric{}, webMetrics...)
   771  		} else {
   772  			scope = "OtherTransaction/Go/hello"
   773  			metrics = append([]internal.WantMetric{}, backgroundMetrics...)
   774  		}
   775  
   776  		for _, m := range tc.Expectation.MetricsScoped {
   777  			metrics = append(metrics, internal.WantMetric{
   778  				Name: m, Scope: scope, Forced: nil, Data: nil,
   779  			})
   780  		}
   781  		for _, m := range tc.Expectation.MetricsUnscoped {
   782  			metrics = append(metrics, internal.WantMetric{
   783  				Name: m, Scope: "", Forced: nil, Data: nil,
   784  			})
   785  		}
   786  
   787  		expectTraceHost := tc.Expectation.Trace.Host
   788  		if tc.Input.SystemHostname != "" {
   789  			for i := range metrics {
   790  				metrics[i].Name = strings.Replace(metrics[i].Name,
   791  					tc.Input.SystemHostname,
   792  					internal.ThisHost, -1)
   793  			}
   794  			expectTraceHost = strings.Replace(expectTraceHost,
   795  				tc.Input.SystemHostname,
   796  				internal.ThisHost, -1)
   797  		}
   798  
   799  		tt := internal.ExtendValidator(t, tc.TestName)
   800  		app.ExpectMetrics(tt, metrics)
   801  		app.ExpectSlowQueries(tt, []internal.WantSlowQuery{{
   802  			Count:        1,
   803  			MetricName:   tc.Expectation.Trace.MetricName,
   804  			TxnName:      scope,
   805  			DatabaseName: tc.Expectation.Trace.DatabaseName,
   806  			Host:         expectTraceHost,
   807  			PortPathOrID: tc.Expectation.Trace.PortPathOrID,
   808  			TxnURL:       txnURL,
   809  			Query:        query,
   810  		}})
   811  	}
   812  }