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 }