github.com/lulzWill/go-agent@v2.1.2+incompatible/internal/attributes_test.go (about)

     1  package internal
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"strconv"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/lulzWill/go-agent/internal/crossagent"
    11  )
    12  
    13  type AttributeTestcase struct {
    14  	Testname string `json:"testname"`
    15  	Config   struct {
    16  		AttributesEnabled        bool     `json:"attributes.enabled"`
    17  		AttributesInclude        []string `json:"attributes.include"`
    18  		AttributesExclude        []string `json:"attributes.exclude"`
    19  		BrowserAttributesEnabled bool     `json:"browser_monitoring.attributes.enabled"`
    20  		BrowserAttributesInclude []string `json:"browser_monitoring.attributes.include"`
    21  		BrowserAttributesExclude []string `json:"browser_monitoring.attributes.exclude"`
    22  		ErrorAttributesEnabled   bool     `json:"error_collector.attributes.enabled"`
    23  		ErrorAttributesInclude   []string `json:"error_collector.attributes.include"`
    24  		ErrorAttributesExclude   []string `json:"error_collector.attributes.exclude"`
    25  		EventsAttributesEnabled  bool     `json:"transaction_events.attributes.enabled"`
    26  		EventsAttributesInclude  []string `json:"transaction_events.attributes.include"`
    27  		EventsAttributesExclude  []string `json:"transaction_events.attributes.exclude"`
    28  		TracerAttributesEnabled  bool     `json:"transaction_tracer.attributes.enabled"`
    29  		TracerAttributesInclude  []string `json:"transaction_tracer.attributes.include"`
    30  		TracerAttributesExclude  []string `json:"transaction_tracer.attributes.exclude"`
    31  	} `json:"config"`
    32  	Key                  string   `json:"input_key"`
    33  	InputDestinations    []string `json:"input_default_destinations"`
    34  	ExpectedDestinations []string `json:"expected_destinations"`
    35  }
    36  
    37  var (
    38  	destTranslate = map[string]destinationSet{
    39  		"attributes":         DestAll,
    40  		"transaction_events": destTxnEvent,
    41  		"transaction_tracer": destTxnTrace,
    42  		"error_collector":    destError,
    43  		"browser_monitoring": destBrowser,
    44  	}
    45  )
    46  
    47  func destinationsFromArray(dests []string) destinationSet {
    48  	d := destNone
    49  	for _, s := range dests {
    50  		if x, ok := destTranslate[s]; ok {
    51  			d |= x
    52  		}
    53  	}
    54  	return d
    55  }
    56  
    57  func destToString(d destinationSet) string {
    58  	if 0 == d {
    59  		return "none"
    60  	}
    61  	out := ""
    62  	for _, ds := range []struct {
    63  		Name string
    64  		Dest destinationSet
    65  	}{
    66  		{Name: "event", Dest: destTxnEvent},
    67  		{Name: "trace", Dest: destTxnTrace},
    68  		{Name: "error", Dest: destError},
    69  		{Name: "browser", Dest: destBrowser},
    70  	} {
    71  		if 0 != d&ds.Dest {
    72  			if "" == out {
    73  				out = ds.Name
    74  			} else {
    75  				out = out + "," + ds.Name
    76  			}
    77  		}
    78  	}
    79  	return out
    80  }
    81  
    82  func runAttributeTestcase(t *testing.T, js json.RawMessage) {
    83  	var tc AttributeTestcase
    84  
    85  	tc.Config.AttributesEnabled = true
    86  	tc.Config.BrowserAttributesEnabled = false
    87  	tc.Config.ErrorAttributesEnabled = true
    88  	tc.Config.EventsAttributesEnabled = true
    89  	tc.Config.TracerAttributesEnabled = true
    90  
    91  	if err := json.Unmarshal(js, &tc); nil != err {
    92  		t.Error(err)
    93  		return
    94  	}
    95  
    96  	input := AttributeConfigInput{
    97  		Attributes: AttributeDestinationConfig{
    98  			Enabled: tc.Config.AttributesEnabled,
    99  			Include: tc.Config.AttributesInclude,
   100  			Exclude: tc.Config.AttributesExclude,
   101  		},
   102  		ErrorCollector: AttributeDestinationConfig{
   103  			Enabled: tc.Config.ErrorAttributesEnabled,
   104  			Include: tc.Config.ErrorAttributesInclude,
   105  			Exclude: tc.Config.ErrorAttributesExclude,
   106  		},
   107  		TransactionEvents: AttributeDestinationConfig{
   108  			Enabled: tc.Config.EventsAttributesEnabled,
   109  			Include: tc.Config.EventsAttributesInclude,
   110  			Exclude: tc.Config.EventsAttributesExclude,
   111  		},
   112  		browserMonitoring: AttributeDestinationConfig{
   113  			Enabled: tc.Config.BrowserAttributesEnabled,
   114  			Include: tc.Config.BrowserAttributesInclude,
   115  			Exclude: tc.Config.BrowserAttributesExclude,
   116  		},
   117  		TransactionTracer: AttributeDestinationConfig{
   118  			Enabled: tc.Config.TracerAttributesEnabled,
   119  			Include: tc.Config.TracerAttributesInclude,
   120  			Exclude: tc.Config.TracerAttributesExclude,
   121  		},
   122  	}
   123  
   124  	cfg := CreateAttributeConfig(input, true)
   125  
   126  	inputDests := destinationsFromArray(tc.InputDestinations)
   127  	expectedDests := destinationsFromArray(tc.ExpectedDestinations)
   128  
   129  	out := applyAttributeConfig(cfg, tc.Key, inputDests)
   130  
   131  	if out != expectedDests {
   132  		t.Error(tc.Testname, destToString(expectedDests),
   133  			destToString(out))
   134  	}
   135  }
   136  
   137  func TestCrossAgentAttributes(t *testing.T) {
   138  	var tcs []json.RawMessage
   139  
   140  	err := crossagent.ReadJSON("attribute_configuration.json", &tcs)
   141  	if err != nil {
   142  		t.Fatal(err)
   143  	}
   144  
   145  	for _, tc := range tcs {
   146  		runAttributeTestcase(t, tc)
   147  	}
   148  }
   149  
   150  func TestWriteAttributeValueJSON(t *testing.T) {
   151  	buf := &bytes.Buffer{}
   152  	w := jsonFieldsWriter{buf: buf}
   153  
   154  	buf.WriteByte('{')
   155  	writeAttributeValueJSON(&w, "a", nil)
   156  	writeAttributeValueJSON(&w, "a", `escape\me!`)
   157  	writeAttributeValueJSON(&w, "a", true)
   158  	writeAttributeValueJSON(&w, "a", false)
   159  	writeAttributeValueJSON(&w, "a", uint8(1))
   160  	writeAttributeValueJSON(&w, "a", uint16(2))
   161  	writeAttributeValueJSON(&w, "a", uint32(3))
   162  	writeAttributeValueJSON(&w, "a", uint64(4))
   163  	writeAttributeValueJSON(&w, "a", uint(5))
   164  	writeAttributeValueJSON(&w, "a", uintptr(6))
   165  	writeAttributeValueJSON(&w, "a", int8(-1))
   166  	writeAttributeValueJSON(&w, "a", int16(-2))
   167  	writeAttributeValueJSON(&w, "a", int32(-3))
   168  	writeAttributeValueJSON(&w, "a", int64(-4))
   169  	writeAttributeValueJSON(&w, "a", int(-5))
   170  	writeAttributeValueJSON(&w, "a", float32(1.5))
   171  	writeAttributeValueJSON(&w, "a", float64(4.56))
   172  	buf.WriteByte('}')
   173  
   174  	expect := CompactJSONString(`{
   175  		"a":null,
   176  		"a":"escape\\me!",
   177  		"a":true,
   178  		"a":false,
   179  		"a":1,
   180  		"a":2,
   181  		"a":3,
   182  		"a":4,
   183  		"a":5,
   184  		"a":6,
   185  		"a":-1,
   186  		"a":-2,
   187  		"a":-3,
   188  		"a":-4,
   189  		"a":-5,
   190  		"a":1.5,
   191  		"a":4.56
   192  		}`)
   193  	js := buf.String()
   194  	if js != expect {
   195  		t.Error(js, expect)
   196  	}
   197  }
   198  
   199  func TestUserAttributeValLength(t *testing.T) {
   200  	cfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   201  	attrs := NewAttributes(cfg)
   202  
   203  	atLimit := strings.Repeat("a", attributeValueLengthLimit)
   204  	tooLong := atLimit + "a"
   205  
   206  	err := AddUserAttribute(attrs, `escape\me`, tooLong, DestAll)
   207  	if err != nil {
   208  		t.Error(err)
   209  	}
   210  	js := userAttributesStringJSON(attrs, DestAll, nil)
   211  	if `{"escape\\me":"`+atLimit+`"}` != js {
   212  		t.Error(js)
   213  	}
   214  }
   215  
   216  func TestUserAttributeKeyLength(t *testing.T) {
   217  	cfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   218  	attrs := NewAttributes(cfg)
   219  
   220  	lengthyKey := strings.Repeat("a", attributeKeyLengthLimit+1)
   221  	err := AddUserAttribute(attrs, lengthyKey, 123, DestAll)
   222  	if _, ok := err.(invalidAttributeKeyErr); !ok {
   223  		t.Error(err)
   224  	}
   225  	js := userAttributesStringJSON(attrs, DestAll, nil)
   226  	if `{}` != js {
   227  		t.Error(js)
   228  	}
   229  }
   230  
   231  func TestNumUserAttributesLimit(t *testing.T) {
   232  	cfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   233  	attrs := NewAttributes(cfg)
   234  
   235  	for i := 0; i < attributeUserLimit; i++ {
   236  		s := strconv.Itoa(i)
   237  		err := AddUserAttribute(attrs, s, s, DestAll)
   238  		if err != nil {
   239  			t.Fatal(err)
   240  		}
   241  	}
   242  
   243  	err := AddUserAttribute(attrs, "cant_add_me", 123, DestAll)
   244  	if _, ok := err.(userAttributeLimitErr); !ok {
   245  		t.Fatal(err)
   246  	}
   247  
   248  	js := userAttributesStringJSON(attrs, DestAll, nil)
   249  	var out map[string]string
   250  	err = json.Unmarshal([]byte(js), &out)
   251  	if nil != err {
   252  		t.Fatal(err)
   253  	}
   254  	if len(out) != attributeUserLimit {
   255  		t.Error(len(out))
   256  	}
   257  	if strings.Contains(js, "cant_add_me") {
   258  		t.Fatal(js)
   259  	}
   260  
   261  	// Now test that replacement works when the limit is reached.
   262  	err = AddUserAttribute(attrs, "0", "BEEN_REPLACED", DestAll)
   263  	if nil != err {
   264  		t.Fatal(err)
   265  	}
   266  	js = userAttributesStringJSON(attrs, DestAll, nil)
   267  	if !strings.Contains(js, "BEEN_REPLACED") {
   268  		t.Fatal(js)
   269  	}
   270  }
   271  
   272  func TestExtraAttributesIncluded(t *testing.T) {
   273  	cfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   274  	attrs := NewAttributes(cfg)
   275  
   276  	err := AddUserAttribute(attrs, "a", 1, DestAll)
   277  	if nil != err {
   278  		t.Error(err)
   279  	}
   280  	js := userAttributesStringJSON(attrs, DestAll, map[string]interface{}{"b": 2})
   281  	if `{"b":2,"a":1}` != js {
   282  		t.Error(js)
   283  	}
   284  }
   285  
   286  func TestExtraAttributesPrecedence(t *testing.T) {
   287  	cfg := CreateAttributeConfig(sampleAttributeConfigInput, true)
   288  	attrs := NewAttributes(cfg)
   289  
   290  	err := AddUserAttribute(attrs, "a", 1, DestAll)
   291  	if nil != err {
   292  		t.Error(err)
   293  	}
   294  	js := userAttributesStringJSON(attrs, DestAll, map[string]interface{}{"a": 2})
   295  	if `{"a":2}` != js {
   296  		t.Error(js)
   297  	}
   298  }
   299  
   300  func TestIncludeDisabled(t *testing.T) {
   301  	input := sampleAttributeConfigInput
   302  	input.Attributes.Include = append(input.Attributes.Include, "include_me")
   303  	cfg := CreateAttributeConfig(input, false)
   304  	attrs := NewAttributes(cfg)
   305  
   306  	err := AddUserAttribute(attrs, "include_me", 1, destNone)
   307  	if nil != err {
   308  		t.Error(err)
   309  	}
   310  	js := userAttributesStringJSON(attrs, DestAll, nil)
   311  	if `{}` != js {
   312  		t.Error(js)
   313  	}
   314  }