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

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package nrnats
     5  
     6  import (
     7  	"os"
     8  	"sync"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/nats-io/nats-server/test"
    13  	"github.com/nats-io/nats.go"
    14  	newrelic "github.com/newrelic/go-agent"
    15  	"github.com/newrelic/go-agent/internal"
    16  	"github.com/newrelic/go-agent/internal/integrationsupport"
    17  )
    18  
    19  func TestMain(m *testing.M) {
    20  	s := test.RunDefaultServer()
    21  	defer s.Shutdown()
    22  	os.Exit(m.Run())
    23  }
    24  
    25  func testApp() integrationsupport.ExpectApp {
    26  	return integrationsupport.NewTestApp(integrationsupport.SampleEverythingReplyFn, cfgFn)
    27  }
    28  
    29  var cfgFn = func(cfg *newrelic.Config) {
    30  	cfg.Enabled = false
    31  	cfg.DistributedTracer.Enabled = true
    32  	cfg.TransactionTracer.SegmentThreshold = 0
    33  	cfg.TransactionTracer.Threshold.IsApdexFailing = false
    34  	cfg.TransactionTracer.Threshold.Duration = 0
    35  	cfg.Attributes.Include = append(cfg.Attributes.Include,
    36  		newrelic.AttributeMessageRoutingKey,
    37  		newrelic.AttributeMessageQueueName,
    38  		newrelic.AttributeMessageExchangeType,
    39  		newrelic.AttributeMessageReplyTo,
    40  		newrelic.AttributeMessageCorrelationID,
    41  	)
    42  }
    43  
    44  func TestStartPublishSegmentNilTxn(t *testing.T) {
    45  	// Make sure that a nil transaction does not cause panics
    46  	nc, err := nats.Connect(nats.DefaultURL)
    47  	if nil != err {
    48  		t.Fatal(err)
    49  	}
    50  	defer nc.Close()
    51  
    52  	StartPublishSegment(nil, nc, "mysubject").End()
    53  }
    54  
    55  func TestStartPublishSegmentNilConn(t *testing.T) {
    56  	// Make sure that a nil nats.Conn does not cause panics and does not record
    57  	// metrics
    58  	app := testApp()
    59  	txn := app.StartTransaction("testing", nil, nil)
    60  	StartPublishSegment(txn, nil, "mysubject").End()
    61  	txn.End()
    62  
    63  	app.ExpectMetrics(t, []internal.WantMetric{
    64  		{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
    65  		{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/allOther", Scope: "", Forced: false, Data: nil},
    66  		{Name: "OtherTransaction/Go/testing", Scope: "", Forced: true, Data: nil},
    67  		{Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},
    68  		{Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},
    69  		{Name: "OtherTransactionTotalTime/Go/testing", Scope: "", Forced: false, Data: nil},
    70  	})
    71  }
    72  
    73  func TestStartPublishSegmentBasic(t *testing.T) {
    74  	app := testApp()
    75  	txn := app.StartTransaction("testing", nil, nil)
    76  	nc, err := nats.Connect(nats.DefaultURL)
    77  	if nil != err {
    78  		t.Fatal(err)
    79  	}
    80  	defer nc.Close()
    81  
    82  	StartPublishSegment(txn, nc, "mysubject").End()
    83  	txn.End()
    84  
    85  	app.ExpectMetrics(t, []internal.WantMetric{
    86  		{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
    87  		{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/allOther", Scope: "", Forced: false, Data: nil},
    88  		{Name: "MessageBroker/NATS/Topic/Produce/Named/mysubject", Scope: "", Forced: false, Data: nil},
    89  		{Name: "MessageBroker/NATS/Topic/Produce/Named/mysubject", Scope: "OtherTransaction/Go/testing", Forced: false, Data: nil},
    90  		{Name: "OtherTransaction/Go/testing", Scope: "", Forced: true, Data: nil},
    91  		{Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},
    92  		{Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},
    93  		{Name: "OtherTransactionTotalTime/Go/testing", Scope: "", Forced: false, Data: nil},
    94  	})
    95  	app.ExpectSpanEvents(t, []internal.WantEvent{
    96  		{
    97  			Intrinsics: map[string]interface{}{
    98  				"category":      "generic",
    99  				"name":          "OtherTransaction/Go/testing",
   100  				"nr.entryPoint": true,
   101  			},
   102  			UserAttributes:  map[string]interface{}{},
   103  			AgentAttributes: map[string]interface{}{},
   104  		},
   105  		{
   106  			Intrinsics: map[string]interface{}{
   107  				"category": "generic",
   108  				"name":     "MessageBroker/NATS/Topic/Produce/Named/mysubject",
   109  				"parentId": internal.MatchAnything,
   110  			},
   111  			UserAttributes:  map[string]interface{}{},
   112  			AgentAttributes: map[string]interface{}{},
   113  		},
   114  	})
   115  	app.ExpectTxnTraces(t, []internal.WantTxnTrace{{
   116  		MetricName: "OtherTransaction/Go/testing",
   117  		Root: internal.WantTraceSegment{
   118  			SegmentName: "ROOT",
   119  			Attributes:  map[string]interface{}{},
   120  			Children: []internal.WantTraceSegment{{
   121  				SegmentName: "OtherTransaction/Go/testing",
   122  				Attributes:  map[string]interface{}{"exclusive_duration_millis": internal.MatchAnything},
   123  				Children: []internal.WantTraceSegment{
   124  					{
   125  						SegmentName: "MessageBroker/NATS/Topic/Produce/Named/mysubject",
   126  						Attributes:  map[string]interface{}{},
   127  					},
   128  				},
   129  			}},
   130  		},
   131  	},
   132  	})
   133  }
   134  
   135  func TestSubWrapperWithNilApp(t *testing.T) {
   136  	nc, err := nats.Connect(nats.DefaultURL)
   137  	if err != nil {
   138  		t.Fatal("Error connecting to NATS server", err)
   139  	}
   140  	wg := sync.WaitGroup{}
   141  	nc.Subscribe("subject1", SubWrapper(nil, func(msg *nats.Msg) {
   142  		wg.Done()
   143  	}))
   144  	wg.Add(1)
   145  	nc.Publish("subject1", []byte("data"))
   146  	wg.Wait()
   147  }
   148  
   149  func TestSubWrapper(t *testing.T) {
   150  	nc, err := nats.Connect(nats.DefaultURL)
   151  	if err != nil {
   152  		t.Fatal("Error connecting to NATS server", err)
   153  	}
   154  	wg := sync.WaitGroup{}
   155  	app := testApp()
   156  	nc.QueueSubscribe("subject2", "queue1", WgWrapper(&wg, SubWrapper(app, func(msg *nats.Msg) {})))
   157  	wg.Add(1)
   158  	nc.Request("subject2", []byte("data"), time.Second)
   159  	wg.Wait()
   160  
   161  	app.ExpectMetrics(t, []internal.WantMetric{
   162  		{Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},
   163  		{Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},
   164  		{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
   165  		{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/allOther", Scope: "", Forced: false, Data: nil},
   166  		{Name: "OtherTransaction/Go/Message/NATS/Topic/Named/subject2", Scope: "", Forced: true, Data: nil},
   167  		{Name: "OtherTransactionTotalTime/Go/Message/NATS/Topic/Named/subject2", Scope: "", Forced: false, Data: nil},
   168  	})
   169  	app.ExpectTxnEvents(t, []internal.WantEvent{
   170  		{
   171  			Intrinsics: map[string]interface{}{
   172  				"name":     "OtherTransaction/Go/Message/NATS/Topic/Named/subject2",
   173  				"guid":     internal.MatchAnything,
   174  				"priority": internal.MatchAnything,
   175  				"sampled":  internal.MatchAnything,
   176  				"traceId":  internal.MatchAnything,
   177  			},
   178  			AgentAttributes: map[string]interface{}{
   179  				"message.replyTo":    internal.MatchAnything, // starts with _INBOX
   180  				"message.routingKey": "subject2",
   181  				"message.queueName":  "queue1",
   182  			},
   183  			UserAttributes: map[string]interface{}{},
   184  		},
   185  	})
   186  }
   187  
   188  func TestStartPublishSegmentNaming(t *testing.T) {
   189  	testCases := []struct {
   190  		subject string
   191  		metric  string
   192  	}{
   193  		{subject: "", metric: "MessageBroker/NATS/Topic/Produce/Named/Unknown"},
   194  		{subject: "mysubject", metric: "MessageBroker/NATS/Topic/Produce/Named/mysubject"},
   195  		{subject: "_INBOX.asldfkjsldfjskd.ldskfjls", metric: "MessageBroker/NATS/Topic/Produce/Temp"},
   196  	}
   197  
   198  	nc, err := nats.Connect(nats.DefaultURL)
   199  	if nil != err {
   200  		t.Fatal(err)
   201  	}
   202  	defer nc.Close()
   203  
   204  	for _, tc := range testCases {
   205  		app := testApp()
   206  		txn := app.StartTransaction("testing", nil, nil)
   207  		StartPublishSegment(txn, nc, tc.subject).End()
   208  		txn.End()
   209  
   210  		app.ExpectMetrics(t, []internal.WantMetric{
   211  			{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/all", Scope: "", Forced: false, Data: nil},
   212  			{Name: "DurationByCaller/Unknown/Unknown/Unknown/Unknown/allOther", Scope: "", Forced: false, Data: nil},
   213  			{Name: "OtherTransaction/Go/testing", Scope: "", Forced: true, Data: nil},
   214  			{Name: "OtherTransaction/all", Scope: "", Forced: true, Data: nil},
   215  			{Name: "OtherTransactionTotalTime", Scope: "", Forced: true, Data: nil},
   216  			{Name: "OtherTransactionTotalTime/Go/testing", Scope: "", Forced: false, Data: nil},
   217  			{Name: tc.metric, Scope: "", Forced: false, Data: nil},
   218  			{Name: tc.metric, Scope: "OtherTransaction/Go/testing", Forced: false, Data: nil},
   219  		})
   220  	}
   221  }
   222  
   223  // Wrapper function to ensure that the NR wrapper is done recording transaction data before wg.Done() is called
   224  func WgWrapper(wg *sync.WaitGroup, nrWrap func(msg *nats.Msg)) func(msg *nats.Msg) {
   225  	return func(msg *nats.Msg) {
   226  		nrWrap(msg)
   227  		wg.Done()
   228  	}
   229  }