github.com/newrelic/go-agent@v3.26.0+incompatible/_integrations/nrgin/v1/nrgin_test.go (about)

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package nrgin
     5  
     6  import (
     7  	"errors"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"testing"
    11  
    12  	"github.com/gin-gonic/gin"
    13  	newrelic "github.com/newrelic/go-agent"
    14  	"github.com/newrelic/go-agent/internal"
    15  	"github.com/newrelic/go-agent/internal/integrationsupport"
    16  )
    17  
    18  var (
    19  	pkg = "github.com/newrelic/go-agent/_integrations/nrgin/v1"
    20  )
    21  
    22  func hello(c *gin.Context) {
    23  	c.Writer.WriteString("hello response")
    24  }
    25  
    26  func TestBasicRoute(t *testing.T) {
    27  	app := integrationsupport.NewBasicTestApp()
    28  	router := gin.Default()
    29  	router.Use(Middleware(app))
    30  	router.GET("/hello", hello)
    31  
    32  	response := httptest.NewRecorder()
    33  	req, err := http.NewRequest("GET", "/hello", nil)
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	router.ServeHTTP(response, req)
    38  	if respBody := response.Body.String(); respBody != "hello response" {
    39  		t.Error("wrong response body", respBody)
    40  	}
    41  	app.ExpectTxnMetrics(t, internal.WantTxn{
    42  		Name:  pkg + ".hello",
    43  		IsWeb: true,
    44  	})
    45  }
    46  
    47  func TestRouterGroup(t *testing.T) {
    48  	app := integrationsupport.NewBasicTestApp()
    49  	router := gin.Default()
    50  	router.Use(Middleware(app))
    51  	group := router.Group("/group")
    52  	group.GET("/hello", hello)
    53  
    54  	response := httptest.NewRecorder()
    55  	req, err := http.NewRequest("GET", "/group/hello", nil)
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  	router.ServeHTTP(response, req)
    60  	if respBody := response.Body.String(); respBody != "hello response" {
    61  		t.Error("wrong response body", respBody)
    62  	}
    63  	app.ExpectTxnMetrics(t, internal.WantTxn{
    64  		Name:  pkg + ".hello",
    65  		IsWeb: true,
    66  	})
    67  }
    68  
    69  func TestAnonymousHandler(t *testing.T) {
    70  	app := integrationsupport.NewBasicTestApp()
    71  	router := gin.Default()
    72  	router.Use(Middleware(app))
    73  	router.GET("/anon", func(c *gin.Context) {
    74  		c.Writer.WriteString("anonymous function handler")
    75  	})
    76  
    77  	response := httptest.NewRecorder()
    78  	req, err := http.NewRequest("GET", "/anon", nil)
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  	router.ServeHTTP(response, req)
    83  	if respBody := response.Body.String(); respBody != "anonymous function handler" {
    84  		t.Error("wrong response body", respBody)
    85  	}
    86  	app.ExpectTxnMetrics(t, internal.WantTxn{
    87  		Name:  pkg + ".TestAnonymousHandler.func1",
    88  		IsWeb: true,
    89  	})
    90  }
    91  
    92  func multipleWriteHeader(c *gin.Context) {
    93  	// Unlike http.ResponseWriter, gin.ResponseWriter does not immediately
    94  	// write the first WriteHeader.  Instead, it gets buffered until the
    95  	// first Write call.
    96  	c.Writer.WriteHeader(200)
    97  	c.Writer.WriteHeader(500)
    98  	c.Writer.WriteString("multipleWriteHeader")
    99  }
   100  
   101  func TestMultipleWriteHeader(t *testing.T) {
   102  	app := integrationsupport.NewBasicTestApp()
   103  	router := gin.Default()
   104  	router.Use(Middleware(app))
   105  	router.GET("/header", multipleWriteHeader)
   106  
   107  	response := httptest.NewRecorder()
   108  	req, err := http.NewRequest("GET", "/header", nil)
   109  	if err != nil {
   110  		t.Fatal(err)
   111  	}
   112  	router.ServeHTTP(response, req)
   113  	if respBody := response.Body.String(); respBody != "multipleWriteHeader" {
   114  		t.Error("wrong response body", respBody)
   115  	}
   116  	if response.Code != 500 {
   117  		t.Error("wrong response code", response.Code)
   118  	}
   119  	// Error metrics test the 500 response code capture.
   120  	app.ExpectTxnMetrics(t, internal.WantTxn{
   121  		Name:      pkg + ".multipleWriteHeader",
   122  		IsWeb:     true,
   123  		NumErrors: 1,
   124  	})
   125  }
   126  
   127  func accessTransactionGinContext(c *gin.Context) {
   128  	if txn := Transaction(c); nil != txn {
   129  		txn.NoticeError(errors.New("problem"))
   130  	}
   131  	c.Writer.WriteString("accessTransactionGinContext")
   132  }
   133  
   134  func TestContextTransaction(t *testing.T) {
   135  	app := integrationsupport.NewBasicTestApp()
   136  	router := gin.Default()
   137  	router.Use(Middleware(app))
   138  	router.GET("/txn", accessTransactionGinContext)
   139  
   140  	response := httptest.NewRecorder()
   141  	req, err := http.NewRequest("GET", "/txn", nil)
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	router.ServeHTTP(response, req)
   146  	if respBody := response.Body.String(); respBody != "accessTransactionGinContext" {
   147  		t.Error("wrong response body", respBody)
   148  	}
   149  	if response.Code != 200 {
   150  		t.Error("wrong response code", response.Code)
   151  	}
   152  	app.ExpectTxnMetrics(t, internal.WantTxn{
   153  		Name:      pkg + ".accessTransactionGinContext",
   154  		IsWeb:     true,
   155  		NumErrors: 1,
   156  	})
   157  }
   158  
   159  func TestNilApp(t *testing.T) {
   160  	var app newrelic.Application
   161  	router := gin.Default()
   162  	router.Use(Middleware(app))
   163  	router.GET("/hello", hello)
   164  
   165  	response := httptest.NewRecorder()
   166  	req, err := http.NewRequest("GET", "/hello", nil)
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  	router.ServeHTTP(response, req)
   171  	if respBody := response.Body.String(); respBody != "hello response" {
   172  		t.Error("wrong response body", respBody)
   173  	}
   174  }
   175  
   176  func errorStatus(c *gin.Context) {
   177  	c.String(500, "an error happened")
   178  }
   179  
   180  func TestStatusCodes(t *testing.T) {
   181  	// Test that we are correctly able to collect status code.
   182  	// This behavior changed with this pull request: https://github.com/gin-gonic/gin/pull/1606
   183  	// In Gin v1.4.0 and below, we always recorded a 200 status, whereas with
   184  	// newer Gin versions we now correctly capture the status.
   185  	app := integrationsupport.NewBasicTestApp()
   186  	router := gin.Default()
   187  	router.Use(Middleware(app))
   188  	router.GET("/err", errorStatus)
   189  
   190  	response := httptest.NewRecorder()
   191  	req, err := http.NewRequest("GET", "/err", nil)
   192  	if err != nil {
   193  		t.Fatal(err)
   194  	}
   195  	router.ServeHTTP(response, req)
   196  	if respBody := response.Body.String(); respBody != "an error happened" {
   197  		t.Error("wrong response body", respBody)
   198  	}
   199  	if response.Code != 500 {
   200  		t.Error("wrong response code", response.Code)
   201  	}
   202  	app.ExpectTxnEvents(t, []internal.WantEvent{{
   203  		Intrinsics: map[string]interface{}{
   204  			"name":             "WebTransaction/Go/" + pkg + ".errorStatus",
   205  			"nr.apdexPerfZone": internal.MatchAnything,
   206  		},
   207  		UserAttributes: map[string]interface{}{},
   208  		AgentAttributes: map[string]interface{}{
   209  			"httpResponseCode":             500,
   210  			"request.method":               "GET",
   211  			"request.uri":                  "/err",
   212  			"response.headers.contentType": "text/plain; charset=utf-8",
   213  		},
   214  	}})
   215  }
   216  
   217  func noBody(c *gin.Context) {
   218  	c.Status(500)
   219  }
   220  
   221  func TestNoResponseBody(t *testing.T) {
   222  	// Test that when no response body is sent (i.e. c.Writer.Write is never
   223  	// called) that we still capture status code.
   224  	app := integrationsupport.NewBasicTestApp()
   225  	router := gin.Default()
   226  	router.Use(Middleware(app))
   227  	router.GET("/nobody", noBody)
   228  
   229  	response := httptest.NewRecorder()
   230  	req, err := http.NewRequest("GET", "/nobody", nil)
   231  	if err != nil {
   232  		t.Fatal(err)
   233  	}
   234  	router.ServeHTTP(response, req)
   235  	if respBody := response.Body.String(); respBody != "" {
   236  		t.Error("wrong response body", respBody)
   237  	}
   238  	if response.Code != 500 {
   239  		t.Error("wrong response code", response.Code)
   240  	}
   241  	app.ExpectTxnEvents(t, []internal.WantEvent{{
   242  		Intrinsics: map[string]interface{}{
   243  			"name":             "WebTransaction/Go/" + pkg + ".noBody",
   244  			"nr.apdexPerfZone": internal.MatchAnything,
   245  		},
   246  		UserAttributes: map[string]interface{}{},
   247  		AgentAttributes: map[string]interface{}{
   248  			"httpResponseCode": 500,
   249  			"request.method":   "GET",
   250  			"request.uri":      "/nobody",
   251  		},
   252  	}})
   253  }