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 }