github.com/instana/go-sensor@v1.62.2-0.20240520081010-4919868049e1/instrumentation_sql_go1.10_test.go (about)

     1  // (c) Copyright IBM Corp. 2021
     2  // (c) Copyright Instana Inc. 2020
     3  
     4  package instana_test
     5  
     6  import (
     7  	"context"
     8  	"database/sql"
     9  	"database/sql/driver"
    10  	"errors"
    11  	"testing"
    12  
    13  	instana "github.com/instana/go-sensor"
    14  	ot "github.com/opentracing/opentracing-go"
    15  	"github.com/opentracing/opentracing-go/ext"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  func TestWrapSQLConnector_Exec(t *testing.T) {
    21  
    22  	recorder := instana.NewTestRecorder()
    23  	s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(&instana.Options{
    24  		Service:     "go-sensor-test",
    25  		AgentClient: alwaysReadyClient{},
    26  	}, recorder))
    27  	defer instana.ShutdownSensor()
    28  
    29  	db := sql.OpenDB(instana.WrapSQLConnector(s, "connection string", sqlConnector{}))
    30  
    31  	pSpan := s.Tracer().StartSpan("parent-span")
    32  	ctx := context.Background()
    33  	if pSpan != nil {
    34  		ctx = instana.ContextWithSpan(ctx, pSpan)
    35  	}
    36  
    37  	res, err := db.ExecContext(ctx, "TEST QUERY")
    38  	require.NoError(t, err)
    39  
    40  	lastID, err := res.LastInsertId()
    41  	require.NoError(t, err)
    42  	assert.Equal(t, int64(42), lastID)
    43  
    44  	spans := recorder.GetQueuedSpans()
    45  	require.Len(t, spans, 1)
    46  
    47  	span := spans[0]
    48  	assert.Equal(t, 0, span.Ec)
    49  	assert.EqualValues(t, instana.ExitSpanKind, span.Kind)
    50  
    51  	require.IsType(t, instana.SDKSpanData{}, span.Data)
    52  	data := span.Data.(instana.SDKSpanData)
    53  
    54  	assert.Equal(t, instana.SDKSpanTags{
    55  		Name: "sdk.database",
    56  		Type: "exit",
    57  		Custom: map[string]interface{}{
    58  			"tags": ot.Tags{
    59  				"span.kind":    ext.SpanKindRPCClientEnum,
    60  				"db.instance":  "connection string",
    61  				"db.statement": "TEST QUERY",
    62  				"db.type":      "sql",
    63  				"peer.address": "connection string",
    64  			},
    65  		},
    66  	}, data.Tags)
    67  }
    68  
    69  func TestWrapSQLConnector_Exec_Error(t *testing.T) {
    70  
    71  	recorder := instana.NewTestRecorder()
    72  	s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(&instana.Options{
    73  		Service:     "go-sensor-test",
    74  		AgentClient: alwaysReadyClient{},
    75  	}, recorder))
    76  	defer instana.ShutdownSensor()
    77  
    78  	pSpan := s.Tracer().StartSpan("parent-span")
    79  	ctx := context.Background()
    80  	if pSpan != nil {
    81  		ctx = instana.ContextWithSpan(ctx, pSpan)
    82  	}
    83  
    84  	db := sql.OpenDB(instana.WrapSQLConnector(s, "connection string", sqlConnector{
    85  		Error: errors.New("something went wrong"),
    86  	}))
    87  
    88  	_, err := db.ExecContext(ctx, "TEST QUERY")
    89  	assert.Error(t, err)
    90  
    91  	spans := recorder.GetQueuedSpans()
    92  	require.Len(t, spans, 2)
    93  
    94  	span, logSpan := spans[0], spans[1]
    95  	assert.Equal(t, 1, span.Ec)
    96  	assert.EqualValues(t, instana.ExitSpanKind, span.Kind)
    97  
    98  	require.IsType(t, instana.SDKSpanData{}, span.Data)
    99  
   100  	assert.Equal(t, span.TraceID, logSpan.TraceID)
   101  	assert.Equal(t, span.SpanID, logSpan.ParentID)
   102  	assert.Equal(t, "log.go", logSpan.Name)
   103  
   104  	// assert that log message has been recorded within the span interval
   105  	assert.GreaterOrEqual(t, logSpan.Timestamp, span.Timestamp)
   106  	assert.LessOrEqual(t, logSpan.Duration, span.Duration)
   107  
   108  	require.IsType(t, instana.LogSpanData{}, logSpan.Data)
   109  	logData := logSpan.Data.(instana.LogSpanData)
   110  
   111  	assert.Equal(t, instana.LogSpanTags{
   112  		Level:   "ERROR",
   113  		Message: `error.object: "something went wrong"`,
   114  	}, logData.Tags)
   115  }
   116  
   117  func TestWrapSQLConnector_Query(t *testing.T) {
   118  
   119  	recorder := instana.NewTestRecorder()
   120  	s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(&instana.Options{
   121  		Service:     "go-sensor-test",
   122  		AgentClient: alwaysReadyClient{},
   123  	}, recorder))
   124  	defer instana.ShutdownSensor()
   125  
   126  	pSpan := s.Tracer().StartSpan("parent-span")
   127  	ctx := context.Background()
   128  	if pSpan != nil {
   129  		ctx = instana.ContextWithSpan(ctx, pSpan)
   130  	}
   131  
   132  	db := sql.OpenDB(instana.WrapSQLConnector(s, "connection string", sqlConnector{}))
   133  
   134  	res, err := db.QueryContext(ctx, "TEST QUERY")
   135  	require.NoError(t, err)
   136  
   137  	cols, err := res.Columns()
   138  	require.NoError(t, err)
   139  	assert.Equal(t, []string{"col1", "col2"}, cols)
   140  
   141  	spans := recorder.GetQueuedSpans()
   142  	require.Len(t, spans, 1)
   143  
   144  	span := spans[0]
   145  	assert.Equal(t, 0, span.Ec)
   146  	assert.EqualValues(t, instana.ExitSpanKind, span.Kind)
   147  
   148  	require.IsType(t, instana.SDKSpanData{}, span.Data)
   149  	data := span.Data.(instana.SDKSpanData)
   150  
   151  	assert.Equal(t, instana.SDKSpanTags{
   152  		Name: "sdk.database",
   153  		Type: "exit",
   154  		Custom: map[string]interface{}{
   155  			"tags": ot.Tags{
   156  				"span.kind":    ext.SpanKindRPCClientEnum,
   157  				"db.instance":  "connection string",
   158  				"db.statement": "TEST QUERY",
   159  				"db.type":      "sql",
   160  				"peer.address": "connection string",
   161  			},
   162  		},
   163  	}, data.Tags)
   164  }
   165  
   166  func TestWrapSQLConnector_Query_Error(t *testing.T) {
   167  
   168  	recorder := instana.NewTestRecorder()
   169  	s := instana.NewSensorWithTracer(instana.NewTracerWithEverything(&instana.Options{
   170  		Service:     "go-sensor-test",
   171  		AgentClient: alwaysReadyClient{},
   172  	}, recorder))
   173  	defer instana.ShutdownSensor()
   174  
   175  	dbErr := errors.New("something went wrong")
   176  	db := sql.OpenDB(instana.WrapSQLConnector(s, "connection string", sqlConnector{
   177  		Error: dbErr,
   178  	}))
   179  
   180  	pSpan := s.Tracer().StartSpan("parent-span")
   181  	ctx := context.Background()
   182  	if pSpan != nil {
   183  		ctx = instana.ContextWithSpan(ctx, pSpan)
   184  	}
   185  
   186  	_, err := db.QueryContext(ctx, "TEST QUERY")
   187  	assert.Error(t, err)
   188  
   189  	spans := recorder.GetQueuedSpans()
   190  	require.Len(t, spans, 2)
   191  
   192  	span, logSpan := spans[0], spans[1]
   193  	assert.Equal(t, 1, span.Ec)
   194  	assert.EqualValues(t, instana.ExitSpanKind, span.Kind)
   195  
   196  	require.IsType(t, instana.SDKSpanData{}, span.Data)
   197  
   198  	assert.Equal(t, span.TraceID, logSpan.TraceID)
   199  	assert.Equal(t, span.SpanID, logSpan.ParentID)
   200  	assert.Equal(t, "log.go", logSpan.Name)
   201  
   202  	// assert that log message has been recorded within the span interval
   203  	assert.GreaterOrEqual(t, logSpan.Timestamp, span.Timestamp)
   204  	assert.LessOrEqual(t, logSpan.Duration, span.Duration)
   205  
   206  	require.IsType(t, instana.LogSpanData{}, logSpan.Data)
   207  	logData := logSpan.Data.(instana.LogSpanData)
   208  
   209  	assert.Equal(t, instana.LogSpanTags{
   210  		Level:   "ERROR",
   211  		Message: `error.object: "something went wrong"`,
   212  	}, logData.Tags)
   213  }
   214  
   215  type sqlConnector struct{ Error error }
   216  
   217  func (c sqlConnector) Connect(context.Context) (driver.Conn, error) {
   218  	return sqlConn{Error: c.Error}, nil
   219  }                                          //nolint:gosimple
   220  func (sqlConnector) Driver() driver.Driver { return sqlDriver{} }