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

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package nrgrpc
     5  
     6  import (
     7  	"context"
     8  	"io"
     9  	"net"
    10  	"strings"
    11  	"testing"
    12  	"time"
    13  
    14  	newrelic "github.com/newrelic/go-agent"
    15  	"github.com/newrelic/go-agent/_integrations/nrgrpc/testapp"
    16  	"github.com/newrelic/go-agent/internal"
    17  	"google.golang.org/grpc"
    18  	"google.golang.org/grpc/test/bufconn"
    19  )
    20  
    21  // newTestServerAndConn creates a new *grpc.Server and *grpc.ClientConn for use
    22  // in testing. It adds instrumentation to both. If app is nil, then
    23  // instrumentation is not applied to the server. Be sure to Stop() the server
    24  // and Close() the connection when done with them.
    25  func newTestServerAndConn(t *testing.T, app newrelic.Application) (*grpc.Server, *grpc.ClientConn) {
    26  	s := grpc.NewServer(
    27  		grpc.UnaryInterceptor(UnaryServerInterceptor(app)),
    28  		grpc.StreamInterceptor(StreamServerInterceptor(app)),
    29  	)
    30  	testapp.RegisterTestApplicationServer(s, &testapp.Server{})
    31  	lis := bufconn.Listen(1024 * 1024)
    32  
    33  	go func() {
    34  		s.Serve(lis)
    35  	}()
    36  
    37  	bufDialer := func(string, time.Duration) (net.Conn, error) {
    38  		return lis.Dial()
    39  	}
    40  	conn, err := grpc.Dial("bufnet",
    41  		grpc.WithDialer(bufDialer),
    42  		grpc.WithInsecure(),
    43  		grpc.WithBlock(), // create the connection synchronously
    44  		grpc.WithUnaryInterceptor(UnaryClientInterceptor),
    45  		grpc.WithStreamInterceptor(StreamClientInterceptor),
    46  	)
    47  	if err != nil {
    48  		t.Fatal("failure to create ClientConn", err)
    49  	}
    50  
    51  	return s, conn
    52  }
    53  
    54  func TestUnaryServerInterceptor(t *testing.T) {
    55  	app := testApp()
    56  
    57  	s, conn := newTestServerAndConn(t, app)
    58  	defer s.Stop()
    59  	defer conn.Close()
    60  
    61  	client := testapp.NewTestApplicationClient(conn)
    62  	txn := app.StartTransaction("client", nil, nil)
    63  	ctx := newrelic.NewContext(context.Background(), txn)
    64  	_, err := client.DoUnaryUnary(ctx, &testapp.Message{})
    65  	if nil != err {
    66  		t.Fatal("unable to call client DoUnaryUnary", err)
    67  	}
    68  
    69  	app.ExpectMetrics(t, []internal.WantMetric{
    70  		{Name: "Apdex", Scope: "", Forced: true, Data: nil},
    71  		{Name: "Apdex/Go/TestApplication/DoUnaryUnary", Scope: "", Forced: false, Data: nil},
    72  		{Name: "Custom/DoUnaryUnary", Scope: "", Forced: false, Data: nil},
    73  		{Name: "Custom/DoUnaryUnary", Scope: "WebTransaction/Go/TestApplication/DoUnaryUnary", Forced: false, Data: nil},
    74  		{Name: "DurationByCaller/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},
    75  		{Name: "DurationByCaller/App/123/456/HTTP/allWeb", Scope: "", Forced: false, Data: nil},
    76  		{Name: "HttpDispatcher", Scope: "", Forced: true, Data: nil},
    77  		{Name: "Supportability/DistributedTrace/AcceptPayload/Success", Scope: "", Forced: true, Data: nil},
    78  		{Name: "TransportDuration/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},
    79  		{Name: "TransportDuration/App/123/456/HTTP/allWeb", Scope: "", Forced: false, Data: nil},
    80  		{Name: "WebTransaction", Scope: "", Forced: true, Data: nil},
    81  		{Name: "WebTransaction/Go/TestApplication/DoUnaryUnary", Scope: "", Forced: true, Data: nil},
    82  		{Name: "WebTransactionTotalTime", Scope: "", Forced: true, Data: nil},
    83  		{Name: "WebTransactionTotalTime/Go/TestApplication/DoUnaryUnary", Scope: "", Forced: false, Data: nil},
    84  	})
    85  	app.ExpectTxnEvents(t, []internal.WantEvent{{
    86  		Intrinsics: map[string]interface{}{
    87  			"guid":                     internal.MatchAnything,
    88  			"name":                     "WebTransaction/Go/TestApplication/DoUnaryUnary",
    89  			"nr.apdexPerfZone":         internal.MatchAnything,
    90  			"parent.account":           123,
    91  			"parent.app":               456,
    92  			"parent.transportDuration": internal.MatchAnything,
    93  			"parent.transportType":     "HTTP",
    94  			"parent.type":              "App",
    95  			"parentId":                 internal.MatchAnything,
    96  			"parentSpanId":             internal.MatchAnything,
    97  			"priority":                 internal.MatchAnything,
    98  			"sampled":                  internal.MatchAnything,
    99  			"traceId":                  internal.MatchAnything,
   100  		},
   101  		UserAttributes: map[string]interface{}{},
   102  		AgentAttributes: map[string]interface{}{
   103  			"httpResponseCode":            0,
   104  			"request.headers.contentType": "application/grpc",
   105  			"request.method":              "TestApplication/DoUnaryUnary",
   106  			"request.uri":                 "grpc://bufnet/TestApplication/DoUnaryUnary",
   107  		},
   108  	}})
   109  	app.ExpectSpanEvents(t, []internal.WantEvent{
   110  		{
   111  			Intrinsics: map[string]interface{}{
   112  				"category":      "generic",
   113  				"name":          "WebTransaction/Go/TestApplication/DoUnaryUnary",
   114  				"nr.entryPoint": true,
   115  				"parentId":      internal.MatchAnything,
   116  			},
   117  			UserAttributes:  map[string]interface{}{},
   118  			AgentAttributes: map[string]interface{}{},
   119  		},
   120  		{
   121  			Intrinsics: map[string]interface{}{
   122  				"category": "generic",
   123  				"name":     "Custom/DoUnaryUnary",
   124  				"parentId": internal.MatchAnything,
   125  			},
   126  			UserAttributes:  map[string]interface{}{},
   127  			AgentAttributes: map[string]interface{}{},
   128  		},
   129  	})
   130  }
   131  
   132  func TestUnaryServerInterceptorError(t *testing.T) {
   133  	app := testApp()
   134  
   135  	s, conn := newTestServerAndConn(t, app)
   136  	defer s.Stop()
   137  	defer conn.Close()
   138  
   139  	client := testapp.NewTestApplicationClient(conn)
   140  	_, err := client.DoUnaryUnaryError(context.Background(), &testapp.Message{})
   141  	if nil == err {
   142  		t.Fatal("DoUnaryUnaryError should have returned an error")
   143  	}
   144  
   145  	app.ExpectMetrics(t, []internal.WantMetric{
   146  		{Name: "Apdex", Scope: "", Forced: true, Data: nil},
   147  		{Name: "Apdex/Go/TestApplication/DoUnaryUnaryError", Scope: "", Forced: false, Data: nil},
   148  		{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
   149  		{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/allWeb", Scope: "", Forced: false, Data: nil},
   150  		{Name: "Errors/WebTransaction/Go/TestApplication/DoUnaryUnaryError", Scope: "", Forced: true, Data: nil},
   151  		{Name: "Errors/all", Scope: "", Forced: true, Data: nil},
   152  		{Name: "Errors/allWeb", Scope: "", Forced: true, Data: nil},
   153  		{Name: "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
   154  		{Name: "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown/allWeb", Scope: "", Forced: false, Data: nil},
   155  		{Name: "HttpDispatcher", Scope: "", Forced: true, Data: nil},
   156  		{Name: "WebTransaction", Scope: "", Forced: true, Data: nil},
   157  		{Name: "WebTransaction/Go/TestApplication/DoUnaryUnaryError", Scope: "", Forced: true, Data: nil},
   158  		{Name: "WebTransactionTotalTime", Scope: "", Forced: true, Data: nil},
   159  		{Name: "WebTransactionTotalTime/Go/TestApplication/DoUnaryUnaryError", Scope: "", Forced: false, Data: nil},
   160  	})
   161  	app.ExpectTxnEvents(t, []internal.WantEvent{{
   162  		Intrinsics: map[string]interface{}{
   163  			"guid":             internal.MatchAnything,
   164  			"name":             "WebTransaction/Go/TestApplication/DoUnaryUnaryError",
   165  			"nr.apdexPerfZone": internal.MatchAnything,
   166  			"priority":         internal.MatchAnything,
   167  			"sampled":          internal.MatchAnything,
   168  			"traceId":          internal.MatchAnything,
   169  		},
   170  		UserAttributes: map[string]interface{}{},
   171  		AgentAttributes: map[string]interface{}{
   172  			"httpResponseCode":            15,
   173  			"request.headers.contentType": "application/grpc",
   174  			"request.method":              "TestApplication/DoUnaryUnaryError",
   175  			"request.uri":                 "grpc://bufnet/TestApplication/DoUnaryUnaryError",
   176  		},
   177  	}})
   178  	app.ExpectErrorEvents(t, []internal.WantEvent{{
   179  		Intrinsics: map[string]interface{}{
   180  			"error.class":     "15",
   181  			"error.message":   "response code 15",
   182  			"guid":            internal.MatchAnything,
   183  			"priority":        internal.MatchAnything,
   184  			"sampled":         internal.MatchAnything,
   185  			"traceId":         internal.MatchAnything,
   186  			"transactionName": "WebTransaction/Go/TestApplication/DoUnaryUnaryError",
   187  		},
   188  		AgentAttributes: map[string]interface{}{
   189  			"httpResponseCode":            15,
   190  			"request.headers.User-Agent":  internal.MatchAnything,
   191  			"request.headers.contentType": "application/grpc",
   192  			"request.method":              "TestApplication/DoUnaryUnaryError",
   193  			"request.uri":                 "grpc://bufnet/TestApplication/DoUnaryUnaryError",
   194  		},
   195  		UserAttributes: map[string]interface{}{},
   196  	}})
   197  }
   198  
   199  func TestUnaryStreamServerInterceptor(t *testing.T) {
   200  	app := testApp()
   201  
   202  	s, conn := newTestServerAndConn(t, app)
   203  	defer s.Stop()
   204  	defer conn.Close()
   205  
   206  	client := testapp.NewTestApplicationClient(conn)
   207  	txn := app.StartTransaction("client", nil, nil)
   208  	ctx := newrelic.NewContext(context.Background(), txn)
   209  	stream, err := client.DoUnaryStream(ctx, &testapp.Message{})
   210  	if nil != err {
   211  		t.Fatal("client call to DoUnaryStream failed", err)
   212  	}
   213  	var recved int
   214  	for {
   215  		_, err := stream.Recv()
   216  		if err == io.EOF {
   217  			break
   218  		}
   219  		if nil != err {
   220  			t.Fatal("error receiving message", err)
   221  		}
   222  		recved++
   223  	}
   224  	if recved != 3 {
   225  		t.Fatal("received incorrect number of messages from server", recved)
   226  	}
   227  
   228  	app.ExpectMetrics(t, []internal.WantMetric{
   229  		{Name: "Apdex", Scope: "", Forced: true, Data: nil},
   230  		{Name: "Apdex/Go/TestApplication/DoUnaryStream", Scope: "", Forced: false, Data: nil},
   231  		{Name: "Custom/DoUnaryStream", Scope: "", Forced: false, Data: nil},
   232  		{Name: "Custom/DoUnaryStream", Scope: "WebTransaction/Go/TestApplication/DoUnaryStream", Forced: false, Data: nil},
   233  		{Name: "DurationByCaller/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},
   234  		{Name: "DurationByCaller/App/123/456/HTTP/allWeb", Scope: "", Forced: false, Data: nil},
   235  		{Name: "HttpDispatcher", Scope: "", Forced: true, Data: nil},
   236  		{Name: "Supportability/DistributedTrace/AcceptPayload/Success", Scope: "", Forced: true, Data: nil},
   237  		{Name: "TransportDuration/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},
   238  		{Name: "TransportDuration/App/123/456/HTTP/allWeb", Scope: "", Forced: false, Data: nil},
   239  		{Name: "WebTransaction", Scope: "", Forced: true, Data: nil},
   240  		{Name: "WebTransaction/Go/TestApplication/DoUnaryStream", Scope: "", Forced: true, Data: nil},
   241  		{Name: "WebTransactionTotalTime", Scope: "", Forced: true, Data: nil},
   242  		{Name: "WebTransactionTotalTime/Go/TestApplication/DoUnaryStream", Scope: "", Forced: false, Data: nil},
   243  	})
   244  	app.ExpectTxnEvents(t, []internal.WantEvent{{
   245  		Intrinsics: map[string]interface{}{
   246  			"guid":                     internal.MatchAnything,
   247  			"name":                     "WebTransaction/Go/TestApplication/DoUnaryStream",
   248  			"nr.apdexPerfZone":         internal.MatchAnything,
   249  			"parent.account":           123,
   250  			"parent.app":               456,
   251  			"parent.transportDuration": internal.MatchAnything,
   252  			"parent.transportType":     "HTTP",
   253  			"parent.type":              "App",
   254  			"parentId":                 internal.MatchAnything,
   255  			"parentSpanId":             internal.MatchAnything,
   256  			"priority":                 internal.MatchAnything,
   257  			"sampled":                  internal.MatchAnything,
   258  			"traceId":                  internal.MatchAnything,
   259  		},
   260  		UserAttributes: map[string]interface{}{},
   261  		AgentAttributes: map[string]interface{}{
   262  			"httpResponseCode":            0,
   263  			"request.headers.contentType": "application/grpc",
   264  			"request.method":              "TestApplication/DoUnaryStream",
   265  			"request.uri":                 "grpc://bufnet/TestApplication/DoUnaryStream",
   266  		},
   267  	}})
   268  	app.ExpectSpanEvents(t, []internal.WantEvent{
   269  		{
   270  			Intrinsics: map[string]interface{}{
   271  				"category":      "generic",
   272  				"name":          "WebTransaction/Go/TestApplication/DoUnaryStream",
   273  				"nr.entryPoint": true,
   274  				"parentId":      internal.MatchAnything,
   275  			},
   276  			UserAttributes:  map[string]interface{}{},
   277  			AgentAttributes: map[string]interface{}{},
   278  		},
   279  		{
   280  			Intrinsics: map[string]interface{}{
   281  				"category": "generic",
   282  				"name":     "Custom/DoUnaryStream",
   283  				"parentId": internal.MatchAnything,
   284  			},
   285  			UserAttributes:  map[string]interface{}{},
   286  			AgentAttributes: map[string]interface{}{},
   287  		},
   288  	})
   289  }
   290  
   291  func TestStreamUnaryServerInterceptor(t *testing.T) {
   292  	app := testApp()
   293  
   294  	s, conn := newTestServerAndConn(t, app)
   295  	defer s.Stop()
   296  	defer conn.Close()
   297  
   298  	client := testapp.NewTestApplicationClient(conn)
   299  	txn := app.StartTransaction("client", nil, nil)
   300  	ctx := newrelic.NewContext(context.Background(), txn)
   301  	stream, err := client.DoStreamUnary(ctx)
   302  	if nil != err {
   303  		t.Fatal("client call to DoStreamUnary failed", err)
   304  	}
   305  	for i := 0; i < 3; i++ {
   306  		if err := stream.Send(&testapp.Message{Text: "Hello DoStreamUnary"}); nil != err {
   307  			if err == io.EOF {
   308  				break
   309  			}
   310  			t.Fatal("failure to Send", err)
   311  		}
   312  	}
   313  	_, err = stream.CloseAndRecv()
   314  	if nil != err {
   315  		t.Fatal("failure to CloseAndRecv", err)
   316  	}
   317  
   318  	app.ExpectMetrics(t, []internal.WantMetric{
   319  		{Name: "Apdex", Scope: "", Forced: true, Data: nil},
   320  		{Name: "Apdex/Go/TestApplication/DoStreamUnary", Scope: "", Forced: false, Data: nil},
   321  		{Name: "Custom/DoStreamUnary", Scope: "", Forced: false, Data: nil},
   322  		{Name: "Custom/DoStreamUnary", Scope: "WebTransaction/Go/TestApplication/DoStreamUnary", Forced: false, Data: nil},
   323  		{Name: "DurationByCaller/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},
   324  		{Name: "DurationByCaller/App/123/456/HTTP/allWeb", Scope: "", Forced: false, Data: nil},
   325  		{Name: "HttpDispatcher", Scope: "", Forced: true, Data: nil},
   326  		{Name: "Supportability/DistributedTrace/AcceptPayload/Success", Scope: "", Forced: true, Data: nil},
   327  		{Name: "TransportDuration/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},
   328  		{Name: "TransportDuration/App/123/456/HTTP/allWeb", Scope: "", Forced: false, Data: nil},
   329  		{Name: "WebTransaction", Scope: "", Forced: true, Data: nil},
   330  		{Name: "WebTransaction/Go/TestApplication/DoStreamUnary", Scope: "", Forced: true, Data: nil},
   331  		{Name: "WebTransactionTotalTime", Scope: "", Forced: true, Data: nil},
   332  		{Name: "WebTransactionTotalTime/Go/TestApplication/DoStreamUnary", Scope: "", Forced: false, Data: nil},
   333  	})
   334  	app.ExpectTxnEvents(t, []internal.WantEvent{{
   335  		Intrinsics: map[string]interface{}{
   336  			"guid":                     internal.MatchAnything,
   337  			"name":                     "WebTransaction/Go/TestApplication/DoStreamUnary",
   338  			"nr.apdexPerfZone":         internal.MatchAnything,
   339  			"parent.account":           123,
   340  			"parent.app":               456,
   341  			"parent.transportDuration": internal.MatchAnything,
   342  			"parent.transportType":     "HTTP",
   343  			"parent.type":              "App",
   344  			"parentId":                 internal.MatchAnything,
   345  			"parentSpanId":             internal.MatchAnything,
   346  			"priority":                 internal.MatchAnything,
   347  			"sampled":                  internal.MatchAnything,
   348  			"traceId":                  internal.MatchAnything,
   349  		},
   350  		UserAttributes: map[string]interface{}{},
   351  		AgentAttributes: map[string]interface{}{
   352  			"httpResponseCode":            0,
   353  			"request.headers.contentType": "application/grpc",
   354  			"request.method":              "TestApplication/DoStreamUnary",
   355  			"request.uri":                 "grpc://bufnet/TestApplication/DoStreamUnary",
   356  		},
   357  	}})
   358  	app.ExpectSpanEvents(t, []internal.WantEvent{
   359  		{
   360  			Intrinsics: map[string]interface{}{
   361  				"category":      "generic",
   362  				"name":          "WebTransaction/Go/TestApplication/DoStreamUnary",
   363  				"nr.entryPoint": true,
   364  				"parentId":      internal.MatchAnything,
   365  			},
   366  			UserAttributes:  map[string]interface{}{},
   367  			AgentAttributes: map[string]interface{}{},
   368  		},
   369  		{
   370  			Intrinsics: map[string]interface{}{
   371  				"category": "generic",
   372  				"name":     "Custom/DoStreamUnary",
   373  				"parentId": internal.MatchAnything,
   374  			},
   375  			UserAttributes:  map[string]interface{}{},
   376  			AgentAttributes: map[string]interface{}{},
   377  		},
   378  	})
   379  }
   380  
   381  func TestStreamStreamServerInterceptor(t *testing.T) {
   382  	app := testApp()
   383  
   384  	s, conn := newTestServerAndConn(t, app)
   385  	defer s.Stop()
   386  	defer conn.Close()
   387  
   388  	client := testapp.NewTestApplicationClient(conn)
   389  	txn := app.StartTransaction("client", nil, nil)
   390  	ctx := newrelic.NewContext(context.Background(), txn)
   391  	stream, err := client.DoStreamStream(ctx)
   392  	if nil != err {
   393  		t.Fatal("client call to DoStreamStream failed", err)
   394  	}
   395  	waitc := make(chan struct{})
   396  	go func() {
   397  		defer close(waitc)
   398  		var recved int
   399  		for {
   400  			_, err := stream.Recv()
   401  			if err == io.EOF {
   402  				break
   403  			}
   404  			if err != nil {
   405  				t.Fatal("failure to Recv", err)
   406  			}
   407  			recved++
   408  		}
   409  		if recved != 3 {
   410  			t.Fatal("received incorrect number of messages from server", recved)
   411  		}
   412  	}()
   413  	for i := 0; i < 3; i++ {
   414  		if err := stream.Send(&testapp.Message{Text: "Hello DoStreamStream"}); err != nil {
   415  			t.Fatal("failure to Send", err)
   416  		}
   417  	}
   418  	stream.CloseSend()
   419  	<-waitc
   420  
   421  	app.ExpectMetrics(t, []internal.WantMetric{
   422  		{Name: "Apdex", Scope: "", Forced: true, Data: nil},
   423  		{Name: "Apdex/Go/TestApplication/DoStreamStream", Scope: "", Forced: false, Data: nil},
   424  		{Name: "Custom/DoStreamStream", Scope: "", Forced: false, Data: nil},
   425  		{Name: "Custom/DoStreamStream", Scope: "WebTransaction/Go/TestApplication/DoStreamStream", Forced: false, Data: nil},
   426  		{Name: "DurationByCaller/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},
   427  		{Name: "DurationByCaller/App/123/456/HTTP/allWeb", Scope: "", Forced: false, Data: nil},
   428  		{Name: "HttpDispatcher", Scope: "", Forced: true, Data: nil},
   429  		{Name: "Supportability/DistributedTrace/AcceptPayload/Success", Scope: "", Forced: true, Data: nil},
   430  		{Name: "TransportDuration/App/123/456/HTTP/all", Scope: "", Forced: false, Data: nil},
   431  		{Name: "TransportDuration/App/123/456/HTTP/allWeb", Scope: "", Forced: false, Data: nil},
   432  		{Name: "WebTransaction", Scope: "", Forced: true, Data: nil},
   433  		{Name: "WebTransaction/Go/TestApplication/DoStreamStream", Scope: "", Forced: true, Data: nil},
   434  		{Name: "WebTransactionTotalTime", Scope: "", Forced: true, Data: nil},
   435  		{Name: "WebTransactionTotalTime/Go/TestApplication/DoStreamStream", Scope: "", Forced: false, Data: nil},
   436  	})
   437  	app.ExpectTxnEvents(t, []internal.WantEvent{{
   438  		Intrinsics: map[string]interface{}{
   439  			"guid":                     internal.MatchAnything,
   440  			"name":                     "WebTransaction/Go/TestApplication/DoStreamStream",
   441  			"nr.apdexPerfZone":         internal.MatchAnything,
   442  			"parent.account":           123,
   443  			"parent.app":               456,
   444  			"parent.transportDuration": internal.MatchAnything,
   445  			"parent.transportType":     "HTTP",
   446  			"parent.type":              "App",
   447  			"parentId":                 internal.MatchAnything,
   448  			"parentSpanId":             internal.MatchAnything,
   449  			"priority":                 internal.MatchAnything,
   450  			"sampled":                  internal.MatchAnything,
   451  			"traceId":                  internal.MatchAnything,
   452  		},
   453  		UserAttributes: map[string]interface{}{},
   454  		AgentAttributes: map[string]interface{}{
   455  			"httpResponseCode":            0,
   456  			"request.headers.contentType": "application/grpc",
   457  			"request.method":              "TestApplication/DoStreamStream",
   458  			"request.uri":                 "grpc://bufnet/TestApplication/DoStreamStream",
   459  		},
   460  	}})
   461  	app.ExpectSpanEvents(t, []internal.WantEvent{
   462  		{
   463  			Intrinsics: map[string]interface{}{
   464  				"category":      "generic",
   465  				"name":          "WebTransaction/Go/TestApplication/DoStreamStream",
   466  				"nr.entryPoint": true,
   467  				"parentId":      internal.MatchAnything,
   468  			},
   469  			UserAttributes:  map[string]interface{}{},
   470  			AgentAttributes: map[string]interface{}{},
   471  		},
   472  		{
   473  			Intrinsics: map[string]interface{}{
   474  				"category": "generic",
   475  				"name":     "Custom/DoStreamStream",
   476  				"parentId": internal.MatchAnything,
   477  			},
   478  			UserAttributes:  map[string]interface{}{},
   479  			AgentAttributes: map[string]interface{}{},
   480  		},
   481  	})
   482  }
   483  
   484  func TestStreamServerInterceptorError(t *testing.T) {
   485  	app := testApp()
   486  
   487  	s, conn := newTestServerAndConn(t, app)
   488  	defer s.Stop()
   489  	defer conn.Close()
   490  
   491  	client := testapp.NewTestApplicationClient(conn)
   492  	stream, err := client.DoUnaryStreamError(context.Background(), &testapp.Message{})
   493  	if nil != err {
   494  		t.Fatal("client call to DoUnaryStream failed", err)
   495  	}
   496  	_, err = stream.Recv()
   497  	if nil == err {
   498  		t.Fatal("DoUnaryStreamError should have returned an error")
   499  	}
   500  
   501  	app.ExpectMetrics(t, []internal.WantMetric{
   502  		{Name: "Apdex", Scope: "", Forced: true, Data: nil},
   503  		{Name: "Apdex/Go/TestApplication/DoUnaryStreamError", Scope: "", Forced: false, Data: nil},
   504  		{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
   505  		{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/allWeb", Scope: "", Forced: false, Data: nil},
   506  		{Name: "Errors/WebTransaction/Go/TestApplication/DoUnaryStreamError", Scope: "", Forced: true, Data: nil},
   507  		{Name: "Errors/all", Scope: "", Forced: true, Data: nil},
   508  		{Name: "Errors/allWeb", Scope: "", Forced: true, Data: nil},
   509  		{Name: "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
   510  		{Name: "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown/allWeb", Scope: "", Forced: false, Data: nil},
   511  		{Name: "HttpDispatcher", Scope: "", Forced: true, Data: nil},
   512  		{Name: "WebTransaction", Scope: "", Forced: true, Data: nil},
   513  		{Name: "WebTransaction/Go/TestApplication/DoUnaryStreamError", Scope: "", Forced: true, Data: nil},
   514  		{Name: "WebTransactionTotalTime", Scope: "", Forced: true, Data: nil},
   515  		{Name: "WebTransactionTotalTime/Go/TestApplication/DoUnaryStreamError", Scope: "", Forced: false, Data: nil},
   516  	})
   517  	app.ExpectTxnEvents(t, []internal.WantEvent{{
   518  		Intrinsics: map[string]interface{}{
   519  			"guid":             internal.MatchAnything,
   520  			"name":             "WebTransaction/Go/TestApplication/DoUnaryStreamError",
   521  			"nr.apdexPerfZone": internal.MatchAnything,
   522  			"priority":         internal.MatchAnything,
   523  			"sampled":          internal.MatchAnything,
   524  			"traceId":          internal.MatchAnything,
   525  		},
   526  		UserAttributes: map[string]interface{}{},
   527  		AgentAttributes: map[string]interface{}{
   528  			"httpResponseCode":            15,
   529  			"request.headers.contentType": "application/grpc",
   530  			"request.method":              "TestApplication/DoUnaryStreamError",
   531  			"request.uri":                 "grpc://bufnet/TestApplication/DoUnaryStreamError",
   532  		},
   533  	}})
   534  	app.ExpectErrorEvents(t, []internal.WantEvent{{
   535  		Intrinsics: map[string]interface{}{
   536  			"error.class":     "15",
   537  			"error.message":   "response code 15",
   538  			"guid":            internal.MatchAnything,
   539  			"priority":        internal.MatchAnything,
   540  			"sampled":         internal.MatchAnything,
   541  			"traceId":         internal.MatchAnything,
   542  			"transactionName": "WebTransaction/Go/TestApplication/DoUnaryStreamError",
   543  		},
   544  		AgentAttributes: map[string]interface{}{
   545  			"httpResponseCode":            15,
   546  			"request.headers.User-Agent":  internal.MatchAnything,
   547  			"request.headers.contentType": "application/grpc",
   548  			"request.method":              "TestApplication/DoUnaryStreamError",
   549  			"request.uri":                 "grpc://bufnet/TestApplication/DoUnaryStreamError",
   550  		},
   551  		UserAttributes: map[string]interface{}{},
   552  	}})
   553  }
   554  
   555  func TestUnaryServerInterceptorNilApp(t *testing.T) {
   556  	s, conn := newTestServerAndConn(t, nil)
   557  	defer s.Stop()
   558  	defer conn.Close()
   559  
   560  	client := testapp.NewTestApplicationClient(conn)
   561  	msg, err := client.DoUnaryUnary(context.Background(), &testapp.Message{})
   562  	if nil != err {
   563  		t.Fatal("unable to call client DoUnaryUnary", err)
   564  	}
   565  	if !strings.Contains(msg.Text, "content-type") {
   566  		t.Error("incorrect message received")
   567  	}
   568  }
   569  
   570  func TestStreamServerInterceptorNilApp(t *testing.T) {
   571  	s, conn := newTestServerAndConn(t, nil)
   572  	defer s.Stop()
   573  	defer conn.Close()
   574  
   575  	client := testapp.NewTestApplicationClient(conn)
   576  	stream, err := client.DoStreamUnary(context.Background())
   577  	if nil != err {
   578  		t.Fatal("client call to DoStreamUnary failed", err)
   579  	}
   580  	for i := 0; i < 3; i++ {
   581  		if err := stream.Send(&testapp.Message{Text: "Hello DoStreamUnary"}); nil != err {
   582  			if err == io.EOF {
   583  				break
   584  			}
   585  			t.Fatal("failure to Send", err)
   586  		}
   587  	}
   588  	msg, err := stream.CloseAndRecv()
   589  	if nil != err {
   590  		t.Fatal("failure to CloseAndRecv", err)
   591  	}
   592  	if !strings.Contains(msg.Text, "content-type") {
   593  		t.Error("incorrect message received")
   594  	}
   595  }
   596  
   597  func TestInterceptorsNilAppReturnNonNil(t *testing.T) {
   598  	uInt := UnaryServerInterceptor(nil)
   599  	if uInt == nil {
   600  		t.Error("UnaryServerInterceptor returned nil")
   601  	}
   602  
   603  	sInt := StreamServerInterceptor(nil)
   604  	if sInt == nil {
   605  		t.Error("StreamServerInterceptor returned nil")
   606  	}
   607  }