github.com/newrelic/go-agent@v3.26.0+incompatible/internal/analytics_events_test.go (about)

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package internal
     5  
     6  import (
     7  	"bytes"
     8  	"strconv"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  var (
    14  	agentRunID = `12345`
    15  )
    16  
    17  type priorityWriter Priority
    18  
    19  func (x priorityWriter) WriteJSON(buf *bytes.Buffer) {
    20  	buf.WriteString(strconv.FormatFloat(float64(x), 'f', -1, 32))
    21  }
    22  
    23  func sampleAnalyticsEvent(priority Priority) analyticsEvent {
    24  	return analyticsEvent{
    25  		priority,
    26  		priorityWriter(priority),
    27  	}
    28  }
    29  
    30  func TestBasic(t *testing.T) {
    31  	events := newAnalyticsEvents(10)
    32  	events.addEvent(sampleAnalyticsEvent(0.5))
    33  	events.addEvent(sampleAnalyticsEvent(0.5))
    34  	events.addEvent(sampleAnalyticsEvent(0.5))
    35  
    36  	json, err := events.CollectorJSON(agentRunID)
    37  	if nil != err {
    38  		t.Fatal(err)
    39  	}
    40  
    41  	expected := `["12345",{"reservoir_size":10,"events_seen":3},[0.5,0.5,0.5]]`
    42  
    43  	if string(json) != expected {
    44  		t.Error(string(json), expected)
    45  	}
    46  	if 3 != events.numSeen {
    47  		t.Error(events.numSeen)
    48  	}
    49  	if 3 != events.NumSaved() {
    50  		t.Error(events.NumSaved())
    51  	}
    52  }
    53  
    54  func TestEmpty(t *testing.T) {
    55  	events := newAnalyticsEvents(10)
    56  	json, err := events.CollectorJSON(agentRunID)
    57  	if nil != err {
    58  		t.Fatal(err)
    59  	}
    60  	if nil != json {
    61  		t.Error(string(json))
    62  	}
    63  	if 0 != events.numSeen {
    64  		t.Error(events.numSeen)
    65  	}
    66  	if 0 != events.NumSaved() {
    67  		t.Error(events.NumSaved())
    68  	}
    69  }
    70  
    71  func TestSampling(t *testing.T) {
    72  	events := newAnalyticsEvents(3)
    73  	events.addEvent(sampleAnalyticsEvent(0.999999))
    74  	events.addEvent(sampleAnalyticsEvent(0.1))
    75  	events.addEvent(sampleAnalyticsEvent(0.9))
    76  	events.addEvent(sampleAnalyticsEvent(0.2))
    77  	events.addEvent(sampleAnalyticsEvent(0.8))
    78  	events.addEvent(sampleAnalyticsEvent(0.3))
    79  
    80  	json, err := events.CollectorJSON(agentRunID)
    81  	if nil != err {
    82  		t.Fatal(err)
    83  	}
    84  	if string(json) != `["12345",{"reservoir_size":3,"events_seen":6},[0.8,0.999999,0.9]]` {
    85  		t.Error(string(json))
    86  	}
    87  	if 6 != events.numSeen {
    88  		t.Error(events.numSeen)
    89  	}
    90  	if 3 != events.NumSaved() {
    91  		t.Error(events.NumSaved())
    92  	}
    93  }
    94  
    95  func TestMergeEmpty(t *testing.T) {
    96  	e1 := newAnalyticsEvents(10)
    97  	e2 := newAnalyticsEvents(10)
    98  	e1.Merge(e2)
    99  	json, err := e1.CollectorJSON(agentRunID)
   100  	if nil != err {
   101  		t.Fatal(err)
   102  	}
   103  	if nil != json {
   104  		t.Error(string(json))
   105  	}
   106  	if 0 != e1.numSeen {
   107  		t.Error(e1.numSeen)
   108  	}
   109  	if 0 != e1.NumSaved() {
   110  		t.Error(e1.NumSaved())
   111  	}
   112  }
   113  
   114  func TestMergeFull(t *testing.T) {
   115  	e1 := newAnalyticsEvents(2)
   116  	e2 := newAnalyticsEvents(3)
   117  
   118  	e1.addEvent(sampleAnalyticsEvent(0.1))
   119  	e1.addEvent(sampleAnalyticsEvent(0.15))
   120  	e1.addEvent(sampleAnalyticsEvent(0.25))
   121  
   122  	e2.addEvent(sampleAnalyticsEvent(0.06))
   123  	e2.addEvent(sampleAnalyticsEvent(0.12))
   124  	e2.addEvent(sampleAnalyticsEvent(0.18))
   125  	e2.addEvent(sampleAnalyticsEvent(0.24))
   126  
   127  	e1.Merge(e2)
   128  	json, err := e1.CollectorJSON(agentRunID)
   129  	if nil != err {
   130  		t.Fatal(err)
   131  	}
   132  	if string(json) != `["12345",{"reservoir_size":2,"events_seen":7},[0.24,0.25]]` {
   133  		t.Error(string(json))
   134  	}
   135  	if 7 != e1.numSeen {
   136  		t.Error(e1.numSeen)
   137  	}
   138  	if 2 != e1.NumSaved() {
   139  		t.Error(e1.NumSaved())
   140  	}
   141  }
   142  
   143  func TestAnalyticsEventMergeFailedSuccess(t *testing.T) {
   144  	e1 := newAnalyticsEvents(2)
   145  	e2 := newAnalyticsEvents(3)
   146  
   147  	e1.addEvent(sampleAnalyticsEvent(0.1))
   148  	e1.addEvent(sampleAnalyticsEvent(0.15))
   149  	e1.addEvent(sampleAnalyticsEvent(0.25))
   150  
   151  	e2.addEvent(sampleAnalyticsEvent(0.06))
   152  	e2.addEvent(sampleAnalyticsEvent(0.12))
   153  	e2.addEvent(sampleAnalyticsEvent(0.18))
   154  	e2.addEvent(sampleAnalyticsEvent(0.24))
   155  
   156  	e1.mergeFailed(e2)
   157  
   158  	json, err := e1.CollectorJSON(agentRunID)
   159  	if nil != err {
   160  		t.Fatal(err)
   161  	}
   162  	if string(json) != `["12345",{"reservoir_size":2,"events_seen":7},[0.24,0.25]]` {
   163  		t.Error(string(json))
   164  	}
   165  	if 7 != e1.numSeen {
   166  		t.Error(e1.numSeen)
   167  	}
   168  	if 2 != e1.NumSaved() {
   169  		t.Error(e1.NumSaved())
   170  	}
   171  	if 1 != e1.failedHarvests {
   172  		t.Error(e1.failedHarvests)
   173  	}
   174  }
   175  
   176  func TestAnalyticsEventMergeFailedLimitReached(t *testing.T) {
   177  	e1 := newAnalyticsEvents(2)
   178  	e2 := newAnalyticsEvents(3)
   179  
   180  	e1.addEvent(sampleAnalyticsEvent(0.1))
   181  	e1.addEvent(sampleAnalyticsEvent(0.15))
   182  	e1.addEvent(sampleAnalyticsEvent(0.25))
   183  
   184  	e2.addEvent(sampleAnalyticsEvent(0.06))
   185  	e2.addEvent(sampleAnalyticsEvent(0.12))
   186  	e2.addEvent(sampleAnalyticsEvent(0.18))
   187  	e2.addEvent(sampleAnalyticsEvent(0.24))
   188  
   189  	e2.failedHarvests = failedEventsAttemptsLimit
   190  
   191  	e1.mergeFailed(e2)
   192  
   193  	json, err := e1.CollectorJSON(agentRunID)
   194  	if nil != err {
   195  		t.Fatal(err)
   196  	}
   197  	if string(json) != `["12345",{"reservoir_size":2,"events_seen":3},[0.15,0.25]]` {
   198  		t.Error(string(json))
   199  	}
   200  	if 3 != e1.numSeen {
   201  		t.Error(e1.numSeen)
   202  	}
   203  	if 2 != e1.NumSaved() {
   204  		t.Error(e1.NumSaved())
   205  	}
   206  	if 0 != e1.failedHarvests {
   207  		t.Error(e1.failedHarvests)
   208  	}
   209  }
   210  
   211  func analyticsEventBenchmarkHelper(b *testing.B, w jsonWriter) {
   212  	events := newAnalyticsEvents(MaxTxnEvents)
   213  	event := analyticsEvent{0, w}
   214  	for n := 0; n < MaxTxnEvents; n++ {
   215  		events.addEvent(event)
   216  	}
   217  
   218  	b.ReportAllocs()
   219  	b.ResetTimer()
   220  
   221  	for n := 0; n < b.N; n++ {
   222  		js, err := events.CollectorJSON(agentRunID)
   223  		if nil != err {
   224  			b.Fatal(err, js)
   225  		}
   226  	}
   227  }
   228  
   229  func BenchmarkTxnEventsCollectorJSON(b *testing.B) {
   230  	event := &TxnEvent{
   231  		FinalName: "WebTransaction/Go/zip/zap",
   232  		Start:     time.Now(),
   233  		Duration:  2 * time.Second,
   234  		Queuing:   1 * time.Second,
   235  		Zone:      ApdexSatisfying,
   236  		Attrs:     nil,
   237  	}
   238  	analyticsEventBenchmarkHelper(b, event)
   239  }
   240  
   241  func BenchmarkCustomEventsCollectorJSON(b *testing.B) {
   242  	now := time.Now()
   243  	ce, err := CreateCustomEvent("myEventType", map[string]interface{}{
   244  		"string": "myString",
   245  		"bool":   true,
   246  		"int64":  int64(123),
   247  	}, now)
   248  	if nil != err {
   249  		b.Fatal(err)
   250  	}
   251  	analyticsEventBenchmarkHelper(b, ce)
   252  }
   253  
   254  func BenchmarkErrorEventsCollectorJSON(b *testing.B) {
   255  	e := TxnErrorFromResponseCode(time.Now(), 503)
   256  	e.Stack = GetStackTrace()
   257  
   258  	txnName := "WebTransaction/Go/zip/zap"
   259  	event := &ErrorEvent{
   260  		ErrorData: e,
   261  		TxnEvent: TxnEvent{
   262  			FinalName: txnName,
   263  			Duration:  3 * time.Second,
   264  			Attrs:     nil,
   265  		},
   266  	}
   267  	analyticsEventBenchmarkHelper(b, event)
   268  }
   269  
   270  func TestSplitFull(t *testing.T) {
   271  	events := newAnalyticsEvents(10)
   272  	for i := 0; i < 15; i++ {
   273  		events.addEvent(sampleAnalyticsEvent(Priority(float32(i) / 10.0)))
   274  	}
   275  	// Test that the capacity cannot exceed the max.
   276  	if 10 != events.capacity() {
   277  		t.Error(events.capacity())
   278  	}
   279  	e1, e2 := events.split()
   280  	j1, err1 := e1.CollectorJSON(agentRunID)
   281  	j2, err2 := e2.CollectorJSON(agentRunID)
   282  	if err1 != nil || err2 != nil {
   283  		t.Fatal(err1, err2)
   284  	}
   285  	if string(j1) != `["12345",{"reservoir_size":5,"events_seen":5},[0.5,0.7,0.6,0.8,0.9]]` {
   286  		t.Error(string(j1))
   287  	}
   288  	if string(j2) != `["12345",{"reservoir_size":5,"events_seen":10},[1.1,1.4,1,1.3,1.2]]` {
   289  		t.Error(string(j2))
   290  	}
   291  }
   292  
   293  func TestSplitNotFullOdd(t *testing.T) {
   294  	events := newAnalyticsEvents(10)
   295  	for i := 0; i < 7; i++ {
   296  		events.addEvent(sampleAnalyticsEvent(Priority(float32(i) / 10.0)))
   297  	}
   298  	e1, e2 := events.split()
   299  	j1, err1 := e1.CollectorJSON(agentRunID)
   300  	j2, err2 := e2.CollectorJSON(agentRunID)
   301  	if err1 != nil || err2 != nil {
   302  		t.Fatal(err1, err2)
   303  	}
   304  	if string(j1) != `["12345",{"reservoir_size":3,"events_seen":3},[0,0.1,0.2]]` {
   305  		t.Error(string(j1))
   306  	}
   307  	if string(j2) != `["12345",{"reservoir_size":4,"events_seen":4},[0.3,0.4,0.5,0.6]]` {
   308  		t.Error(string(j2))
   309  	}
   310  }
   311  
   312  func TestSplitNotFullEven(t *testing.T) {
   313  	events := newAnalyticsEvents(10)
   314  	for i := 0; i < 8; i++ {
   315  		events.addEvent(sampleAnalyticsEvent(Priority(float32(i) / 10.0)))
   316  	}
   317  	e1, e2 := events.split()
   318  	j1, err1 := e1.CollectorJSON(agentRunID)
   319  	j2, err2 := e2.CollectorJSON(agentRunID)
   320  	if err1 != nil || err2 != nil {
   321  		t.Fatal(err1, err2)
   322  	}
   323  	if string(j1) != `["12345",{"reservoir_size":4,"events_seen":4},[0,0.1,0.2,0.3]]` {
   324  		t.Error(string(j1))
   325  	}
   326  	if string(j2) != `["12345",{"reservoir_size":4,"events_seen":4},[0.4,0.5,0.6,0.7]]` {
   327  		t.Error(string(j2))
   328  	}
   329  }
   330  
   331  func TestAnalyticsEventsZeroCapacity(t *testing.T) {
   332  	// Analytics events methods should be safe when configurable harvest
   333  	// settings have an event limit of zero.
   334  	events := newAnalyticsEvents(0)
   335  	if 0 != events.NumSeen() || 0 != events.NumSaved() || 0 != events.capacity() {
   336  		t.Error(events.NumSeen(), events.NumSaved(), events.capacity())
   337  	}
   338  	events.addEvent(sampleAnalyticsEvent(0.5))
   339  	if 1 != events.NumSeen() || 0 != events.NumSaved() || 0 != events.capacity() {
   340  		t.Error(events.NumSeen(), events.NumSaved(), events.capacity())
   341  	}
   342  	js, err := events.CollectorJSON("agentRunID")
   343  	if err != nil || js != nil {
   344  		t.Error(err, string(js))
   345  	}
   346  }