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

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  // +build go1.10
     5  
     6  package newrelic
     7  
     8  import (
     9  	"context"
    10  	"database/sql/driver"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/newrelic/go-agent/internal"
    15  )
    16  
    17  var (
    18  	driverTestMetrics = []internal.WantMetric{
    19  		{Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},
    20  		{Name: "OtherTransaction/Go/hello", Scope: "", Forced: true, Data: nil},
    21  		{Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},
    22  		{Name: "OtherTransactionTotalTime/Go/hello", Scope: "", Forced: false, Data: nil},
    23  		{Name: "Datastore/all", Scope: "", Forced: true, Data: nil},
    24  		{Name: "Datastore/allOther", Scope: "", Forced: true, Data: nil},
    25  		{Name: "Datastore/MySQL/all", Scope: "", Forced: true, Data: nil},
    26  		{Name: "Datastore/MySQL/allOther", Scope: "", Forced: true, Data: nil},
    27  		{Name: "Datastore/operation/MySQL/myoperation", Scope: "", Forced: false, Data: nil},
    28  		{Name: "Datastore/statement/MySQL/mycollection/myoperation", Scope: "", Forced: false, Data: nil},
    29  		{Name: "Datastore/statement/MySQL/mycollection/myoperation", Scope: "OtherTransaction/Go/hello", Forced: false, Data: nil},
    30  		{Name: "Datastore/instance/MySQL/myhost/myport", Scope: "", Forced: false, Data: nil},
    31  	}
    32  )
    33  
    34  type testDriver struct{}
    35  type testConnector struct{}
    36  type testConn struct{}
    37  type testStmt struct{}
    38  
    39  func (d testDriver) OpenConnector(name string) (driver.Connector, error) { return testConnector{}, nil }
    40  func (d testDriver) Open(name string) (driver.Conn, error)               { return testConn{}, nil }
    41  
    42  func (c testConnector) Connect(context.Context) (driver.Conn, error) { return testConn{}, nil }
    43  func (c testConnector) Driver() driver.Driver                        { return testDriver{} }
    44  
    45  func (c testConn) Prepare(query string) (driver.Stmt, error) { return testStmt{}, nil }
    46  func (c testConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
    47  	return testStmt{}, nil
    48  }
    49  func (c testConn) Close() error              { return nil }
    50  func (c testConn) Begin() (driver.Tx, error) { return nil, nil }
    51  func (c testConn) ExecContext(context.Context, string, []driver.NamedValue) (driver.Result, error) {
    52  	return nil, nil
    53  }
    54  func (c testConn) QueryContext(context.Context, string, []driver.NamedValue) (driver.Rows, error) {
    55  	return nil, nil
    56  }
    57  
    58  func (s testStmt) Close() error {
    59  	return nil
    60  }
    61  func (s testStmt) NumInput() int {
    62  	return 0
    63  }
    64  func (s testStmt) Exec(args []driver.Value) (driver.Result, error) {
    65  	return nil, nil
    66  }
    67  func (s testStmt) Query(args []driver.Value) (driver.Rows, error) {
    68  	return nil, nil
    69  }
    70  func (s testStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
    71  	return nil, nil
    72  }
    73  func (s testStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
    74  	return nil, nil
    75  }
    76  
    77  var (
    78  	testBuilder = SQLDriverSegmentBuilder{
    79  		BaseSegment: DatastoreSegment{
    80  			Product: DatastoreMySQL,
    81  		},
    82  		ParseDSN: func(segment *DatastoreSegment, dsn string) {
    83  			fields := strings.Split(dsn, ",")
    84  			segment.Host = fields[0]
    85  			segment.PortPathOrID = fields[1]
    86  			segment.DatabaseName = fields[2]
    87  		},
    88  		ParseQuery: func(segment *DatastoreSegment, query string) {
    89  			fields := strings.Split(query, ",")
    90  			segment.Operation = fields[0]
    91  			segment.Collection = fields[1]
    92  		},
    93  	}
    94  )
    95  
    96  func TestDriverStmtExecContext(t *testing.T) {
    97  	// Test that driver.Stmt.ExecContext calls get instrumented.
    98  	app := testApp(nil, nil, t)
    99  	dr := InstrumentSQLDriver(testDriver{}, testBuilder)
   100  	txn := app.StartTransaction("hello", nil, nil)
   101  	conn, _ := dr.Open("myhost,myport,mydatabase")
   102  	stmt, _ := conn.Prepare("myoperation,mycollection")
   103  	ctx := NewContext(context.Background(), txn)
   104  	stmt.(driver.StmtExecContext).ExecContext(ctx, nil)
   105  	txn.End()
   106  	app.ExpectMetrics(t, driverTestMetrics)
   107  }
   108  
   109  func TestDriverStmtQueryContext(t *testing.T) {
   110  	// Test that driver.Stmt.PrepareContext calls get instrumented.
   111  	app := testApp(nil, nil, t)
   112  	dr := InstrumentSQLDriver(testDriver{}, testBuilder)
   113  	txn := app.StartTransaction("hello", nil, nil)
   114  	conn, _ := dr.Open("myhost,myport,mydatabase")
   115  	stmt, _ := conn.(driver.ConnPrepareContext).PrepareContext(context.Background(), "myoperation,mycollection")
   116  	ctx := NewContext(context.Background(), txn)
   117  	stmt.(driver.StmtQueryContext).QueryContext(ctx, nil)
   118  	txn.End()
   119  	app.ExpectMetrics(t, driverTestMetrics)
   120  }
   121  
   122  func TestDriverConnExecContext(t *testing.T) {
   123  	// Test that driver.Conn.ExecContext calls get instrumented.
   124  	app := testApp(nil, nil, t)
   125  	dr := InstrumentSQLDriver(testDriver{}, testBuilder)
   126  	txn := app.StartTransaction("hello", nil, nil)
   127  	conn, _ := dr.Open("myhost,myport,mydatabase")
   128  	ctx := NewContext(context.Background(), txn)
   129  	conn.(driver.ExecerContext).ExecContext(ctx, "myoperation,mycollection", nil)
   130  	txn.End()
   131  	app.ExpectMetrics(t, driverTestMetrics)
   132  }
   133  
   134  func TestDriverConnQueryContext(t *testing.T) {
   135  	// Test that driver.Conn.QueryContext calls get instrumented.
   136  	app := testApp(nil, nil, t)
   137  	dr := InstrumentSQLDriver(testDriver{}, testBuilder)
   138  	txn := app.StartTransaction("hello", nil, nil)
   139  	conn, _ := dr.Open("myhost,myport,mydatabase")
   140  	ctx := NewContext(context.Background(), txn)
   141  	conn.(driver.QueryerContext).QueryContext(ctx, "myoperation,mycollection", nil)
   142  	txn.End()
   143  	app.ExpectMetrics(t, driverTestMetrics)
   144  }
   145  
   146  func TestDriverContext(t *testing.T) {
   147  	// Test that driver.OpenConnector returns an instrumented connector.
   148  	app := testApp(nil, nil, t)
   149  	dr := InstrumentSQLDriver(testDriver{}, testBuilder)
   150  	txn := app.StartTransaction("hello", nil, nil)
   151  	connector, _ := dr.(driver.DriverContext).OpenConnector("myhost,myport,mydatabase")
   152  	conn, _ := connector.Connect(context.Background())
   153  	ctx := NewContext(context.Background(), txn)
   154  	conn.(driver.ExecerContext).ExecContext(ctx, "myoperation,mycollection", nil)
   155  	txn.End()
   156  	app.ExpectMetrics(t, driverTestMetrics)
   157  }
   158  
   159  func TestInstrumentSQLConnector(t *testing.T) {
   160  	// Test that connections returned by an instrumented driver.Connector
   161  	// are instrumented.
   162  	app := testApp(nil, nil, t)
   163  	bld := testBuilder
   164  	bld.BaseSegment.Host = "myhost"
   165  	bld.BaseSegment.PortPathOrID = "myport"
   166  	bld.BaseSegment.DatabaseName = "mydatabase"
   167  	connector := InstrumentSQLConnector(testConnector{}, bld)
   168  	txn := app.StartTransaction("hello", nil, nil)
   169  	conn, _ := connector.Connect(context.Background())
   170  	ctx := NewContext(context.Background(), txn)
   171  	conn.(driver.ExecerContext).ExecContext(ctx, "myoperation,mycollection", nil)
   172  	txn.End()
   173  	app.ExpectMetrics(t, driverTestMetrics)
   174  }
   175  
   176  func TestConnectorToDriver(t *testing.T) {
   177  	// Test that driver.Connector.Driver returns an instrumented Driver.
   178  	app := testApp(nil, nil, t)
   179  	connector := InstrumentSQLConnector(testConnector{}, testBuilder)
   180  	txn := app.StartTransaction("hello", nil, nil)
   181  	dr := connector.Driver()
   182  	conn, _ := dr.Open("myhost,myport,mydatabase")
   183  	ctx := NewContext(context.Background(), txn)
   184  	conn.(driver.ExecerContext).ExecContext(ctx, "myoperation,mycollection", nil)
   185  	txn.End()
   186  	app.ExpectMetrics(t, driverTestMetrics)
   187  }