github.com/lulzWill/go-agent@v2.1.2+incompatible/internal/tracing_test.go (about) 1 package internal 2 3 import ( 4 "net/url" 5 "strconv" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/lulzWill/go-agent/internal/crossagent" 11 ) 12 13 func TestStartEndSegment(t *testing.T) { 14 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 15 16 tr := &TxnData{} 17 token := StartSegment(tr, start) 18 stop := start.Add(1 * time.Second) 19 end, err := endSegment(tr, token, stop) 20 if nil != err { 21 t.Error(err) 22 } 23 if end.exclusive != end.duration { 24 t.Error(end.exclusive, end.duration) 25 } 26 if end.duration != 1*time.Second { 27 t.Error(end.duration) 28 } 29 if end.start.Time != start { 30 t.Error(end.start, start) 31 } 32 if end.stop.Time != stop { 33 t.Error(end.stop, stop) 34 } 35 } 36 37 func TestMultipleChildren(t *testing.T) { 38 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 39 tr := &TxnData{} 40 41 t1 := StartSegment(tr, start.Add(1*time.Second)) 42 t2 := StartSegment(tr, start.Add(2*time.Second)) 43 end2, err2 := endSegment(tr, t2, start.Add(3*time.Second)) 44 t3 := StartSegment(tr, start.Add(4*time.Second)) 45 end3, err3 := endSegment(tr, t3, start.Add(5*time.Second)) 46 end1, err1 := endSegment(tr, t1, start.Add(6*time.Second)) 47 t4 := StartSegment(tr, start.Add(7*time.Second)) 48 end4, err4 := endSegment(tr, t4, start.Add(8*time.Second)) 49 50 if nil != err1 || end1.duration != 5*time.Second || end1.exclusive != 3*time.Second { 51 t.Error(end1, err1) 52 } 53 if nil != err2 || end2.duration != end2.exclusive || end2.duration != time.Second { 54 t.Error(end2, err2) 55 } 56 if nil != err3 || end3.duration != end3.exclusive || end3.duration != time.Second { 57 t.Error(end3, err3) 58 } 59 if nil != err4 || end4.duration != end4.exclusive || end4.duration != time.Second { 60 t.Error(end4, err4) 61 } 62 children := TracerRootChildren(tr) 63 if children != 6*time.Second { 64 t.Error(children) 65 } 66 } 67 68 func TestInvalidStart(t *testing.T) { 69 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 70 tr := &TxnData{} 71 72 end, err := endSegment(tr, SegmentStartTime{}, start.Add(1*time.Second)) 73 if err != errMalformedSegment { 74 t.Error(end, err) 75 } 76 StartSegment(tr, start.Add(2*time.Second)) 77 end, err = endSegment(tr, SegmentStartTime{}, start.Add(3*time.Second)) 78 if err != errMalformedSegment { 79 t.Error(end, err) 80 } 81 } 82 83 func TestSegmentAlreadyEnded(t *testing.T) { 84 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 85 tr := &TxnData{} 86 87 t1 := StartSegment(tr, start.Add(1*time.Second)) 88 end, err := endSegment(tr, t1, start.Add(2*time.Second)) 89 if err != nil { 90 t.Error(end, err) 91 } 92 end, err = endSegment(tr, t1, start.Add(3*time.Second)) 93 if err != errSegmentOrder { 94 t.Error(end, err) 95 } 96 } 97 98 func TestSegmentBadStamp(t *testing.T) { 99 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 100 tr := &TxnData{} 101 102 t1 := StartSegment(tr, start.Add(1*time.Second)) 103 t1.Stamp++ 104 end, err := endSegment(tr, t1, start.Add(2*time.Second)) 105 if err != errSegmentOrder { 106 t.Error(end, err) 107 } 108 } 109 110 func TestSegmentBadDepth(t *testing.T) { 111 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 112 tr := &TxnData{} 113 114 t1 := StartSegment(tr, start.Add(1*time.Second)) 115 t1.Depth++ 116 end, err := endSegment(tr, t1, start.Add(2*time.Second)) 117 if err != errSegmentOrder { 118 t.Error(end, err) 119 } 120 } 121 122 func TestSegmentNegativeDepth(t *testing.T) { 123 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 124 tr := &TxnData{} 125 126 t1 := StartSegment(tr, start.Add(1*time.Second)) 127 t1.Depth = -1 128 end, err := endSegment(tr, t1, start.Add(2*time.Second)) 129 if err != errMalformedSegment { 130 t.Error(end, err) 131 } 132 } 133 134 func TestSegmentOutOfOrder(t *testing.T) { 135 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 136 tr := &TxnData{} 137 138 t1 := StartSegment(tr, start.Add(1*time.Second)) 139 t2 := StartSegment(tr, start.Add(2*time.Second)) 140 t3 := StartSegment(tr, start.Add(3*time.Second)) 141 end2, err2 := endSegment(tr, t2, start.Add(4*time.Second)) 142 end3, err3 := endSegment(tr, t3, start.Add(5*time.Second)) 143 t4 := StartSegment(tr, start.Add(6*time.Second)) 144 end4, err4 := endSegment(tr, t4, start.Add(7*time.Second)) 145 end1, err1 := endSegment(tr, t1, start.Add(8*time.Second)) 146 147 if nil != err1 || 148 end1.duration != 7*time.Second || 149 end1.exclusive != 4*time.Second { 150 t.Error(end1, err1) 151 } 152 if nil != err2 || end2.duration != end2.exclusive || end2.duration != 2*time.Second { 153 t.Error(end2, err2) 154 } 155 if err3 != errSegmentOrder { 156 t.Error(end3, err3) 157 } 158 if nil != err4 || end4.duration != end4.exclusive || end4.duration != 1*time.Second { 159 t.Error(end4, err4) 160 } 161 } 162 163 // |-t3-| |-t4-| 164 // |-t2-| |-never-finished---------- 165 // |-t1-| |--never-finished------------------------ 166 // |-------alpha------------------------------------------| 167 // 0 1 2 3 4 5 6 7 8 9 10 11 12 168 func TestLostChildren(t *testing.T) { 169 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 170 tr := &TxnData{} 171 172 alpha := StartSegment(tr, start.Add(1*time.Second)) 173 t1 := StartSegment(tr, start.Add(2*time.Second)) 174 EndBasicSegment(tr, t1, start.Add(3*time.Second), "t1") 175 StartSegment(tr, start.Add(4*time.Second)) 176 t2 := StartSegment(tr, start.Add(5*time.Second)) 177 EndBasicSegment(tr, t2, start.Add(6*time.Second), "t2") 178 StartSegment(tr, start.Add(7*time.Second)) 179 t3 := StartSegment(tr, start.Add(8*time.Second)) 180 EndBasicSegment(tr, t3, start.Add(9*time.Second), "t3") 181 t4 := StartSegment(tr, start.Add(10*time.Second)) 182 EndBasicSegment(tr, t4, start.Add(11*time.Second), "t4") 183 EndBasicSegment(tr, alpha, start.Add(12*time.Second), "alpha") 184 185 metrics := newMetricTable(100, time.Now()) 186 tr.FinalName = "WebTransaction/Go/zip" 187 tr.IsWeb = true 188 MergeBreakdownMetrics(tr, metrics) 189 ExpectMetrics(t, metrics, []WantMetric{ 190 {"Custom/alpha", "", false, []float64{1, 11, 7, 11, 11, 121}}, 191 {"Custom/t1", "", false, []float64{1, 1, 1, 1, 1, 1}}, 192 {"Custom/t2", "", false, []float64{1, 1, 1, 1, 1, 1}}, 193 {"Custom/t3", "", false, []float64{1, 1, 1, 1, 1, 1}}, 194 {"Custom/t4", "", false, []float64{1, 1, 1, 1, 1, 1}}, 195 {"Custom/alpha", tr.FinalName, false, []float64{1, 11, 7, 11, 11, 121}}, 196 {"Custom/t1", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 197 {"Custom/t2", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 198 {"Custom/t3", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 199 {"Custom/t4", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 200 }) 201 } 202 203 // |-t3-| |-t4-| 204 // |-t2-| |-never-finished---------- 205 // |-t1-| |--never-finished------------------------ 206 // |-------root------------------------------------------------- 207 // 0 1 2 3 4 5 6 7 8 9 10 11 12 208 func TestLostChildrenRoot(t *testing.T) { 209 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 210 tr := &TxnData{} 211 212 t1 := StartSegment(tr, start.Add(2*time.Second)) 213 EndBasicSegment(tr, t1, start.Add(3*time.Second), "t1") 214 StartSegment(tr, start.Add(4*time.Second)) 215 t2 := StartSegment(tr, start.Add(5*time.Second)) 216 EndBasicSegment(tr, t2, start.Add(6*time.Second), "t2") 217 StartSegment(tr, start.Add(7*time.Second)) 218 t3 := StartSegment(tr, start.Add(8*time.Second)) 219 EndBasicSegment(tr, t3, start.Add(9*time.Second), "t3") 220 t4 := StartSegment(tr, start.Add(10*time.Second)) 221 EndBasicSegment(tr, t4, start.Add(11*time.Second), "t4") 222 223 children := TracerRootChildren(tr) 224 if children != 4*time.Second { 225 t.Error(children) 226 } 227 228 metrics := newMetricTable(100, time.Now()) 229 tr.FinalName = "WebTransaction/Go/zip" 230 tr.IsWeb = true 231 MergeBreakdownMetrics(tr, metrics) 232 ExpectMetrics(t, metrics, []WantMetric{ 233 {"Custom/t1", "", false, []float64{1, 1, 1, 1, 1, 1}}, 234 {"Custom/t2", "", false, []float64{1, 1, 1, 1, 1, 1}}, 235 {"Custom/t3", "", false, []float64{1, 1, 1, 1, 1, 1}}, 236 {"Custom/t4", "", false, []float64{1, 1, 1, 1, 1, 1}}, 237 {"Custom/t1", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 238 {"Custom/t2", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 239 {"Custom/t3", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 240 {"Custom/t4", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 241 }) 242 } 243 244 func TestSegmentBasic(t *testing.T) { 245 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 246 tr := &TxnData{} 247 248 t1 := StartSegment(tr, start.Add(1*time.Second)) 249 t2 := StartSegment(tr, start.Add(2*time.Second)) 250 EndBasicSegment(tr, t2, start.Add(3*time.Second), "t2") 251 EndBasicSegment(tr, t1, start.Add(4*time.Second), "t1") 252 t3 := StartSegment(tr, start.Add(5*time.Second)) 253 t4 := StartSegment(tr, start.Add(6*time.Second)) 254 EndBasicSegment(tr, t3, start.Add(7*time.Second), "t3") 255 EndBasicSegment(tr, t4, start.Add(8*time.Second), "out-of-order") 256 t5 := StartSegment(tr, start.Add(9*time.Second)) 257 EndBasicSegment(tr, t5, start.Add(10*time.Second), "t1") 258 259 metrics := newMetricTable(100, time.Now()) 260 tr.FinalName = "WebTransaction/Go/zip" 261 tr.IsWeb = true 262 MergeBreakdownMetrics(tr, metrics) 263 ExpectMetrics(t, metrics, []WantMetric{ 264 {"Custom/t1", "", false, []float64{2, 4, 3, 1, 3, 10}}, 265 {"Custom/t2", "", false, []float64{1, 1, 1, 1, 1, 1}}, 266 {"Custom/t3", "", false, []float64{1, 2, 2, 2, 2, 4}}, 267 {"Custom/t1", tr.FinalName, false, []float64{2, 4, 3, 1, 3, 10}}, 268 {"Custom/t2", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 269 {"Custom/t3", tr.FinalName, false, []float64{1, 2, 2, 2, 2, 4}}, 270 }) 271 } 272 273 func parseURL(raw string) *url.URL { 274 u, _ := url.Parse(raw) 275 return u 276 } 277 278 func TestSegmentExternal(t *testing.T) { 279 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 280 tr := &TxnData{} 281 282 t1 := StartSegment(tr, start.Add(1*time.Second)) 283 t2 := StartSegment(tr, start.Add(2*time.Second)) 284 EndExternalSegment(tr, t2, start.Add(3*time.Second), nil, nil) 285 EndExternalSegment(tr, t1, start.Add(4*time.Second), parseURL("http://f1.com"), nil) 286 t3 := StartSegment(tr, start.Add(5*time.Second)) 287 EndExternalSegment(tr, t3, start.Add(6*time.Second), parseURL("http://f1.com"), nil) 288 t4 := StartSegment(tr, start.Add(7*time.Second)) 289 t4.Stamp++ 290 EndExternalSegment(tr, t4, start.Add(8*time.Second), parseURL("http://invalid-token.com"), nil) 291 292 if tr.externalCallCount != 3 { 293 t.Error(tr.externalCallCount) 294 } 295 if tr.externalDuration != 5*time.Second { 296 t.Error(tr.externalDuration) 297 } 298 metrics := newMetricTable(100, time.Now()) 299 tr.FinalName = "WebTransaction/Go/zip" 300 tr.IsWeb = true 301 MergeBreakdownMetrics(tr, metrics) 302 ExpectMetrics(t, metrics, []WantMetric{ 303 {"External/all", "", true, []float64{3, 5, 4, 1, 3, 11}}, 304 {"External/allWeb", "", true, []float64{3, 5, 4, 1, 3, 11}}, 305 {"External/f1.com/all", "", false, []float64{2, 4, 3, 1, 3, 10}}, 306 {"External/unknown/all", "", false, []float64{1, 1, 1, 1, 1, 1}}, 307 {"External/f1.com/all", tr.FinalName, false, []float64{2, 4, 3, 1, 3, 10}}, 308 {"External/unknown/all", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 309 }) 310 311 metrics = newMetricTable(100, time.Now()) 312 tr.FinalName = "OtherTransaction/Go/zip" 313 tr.IsWeb = false 314 MergeBreakdownMetrics(tr, metrics) 315 ExpectMetrics(t, metrics, []WantMetric{ 316 {"External/all", "", true, []float64{3, 5, 4, 1, 3, 11}}, 317 {"External/allOther", "", true, []float64{3, 5, 4, 1, 3, 11}}, 318 {"External/f1.com/all", "", false, []float64{2, 4, 3, 1, 3, 10}}, 319 {"External/unknown/all", "", false, []float64{1, 1, 1, 1, 1, 1}}, 320 {"External/f1.com/all", tr.FinalName, false, []float64{2, 4, 3, 1, 3, 10}}, 321 {"External/unknown/all", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 322 }) 323 } 324 325 func TestSegmentDatastore(t *testing.T) { 326 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 327 tr := &TxnData{} 328 329 t1 := StartSegment(tr, start.Add(1*time.Second)) 330 t2 := StartSegment(tr, start.Add(2*time.Second)) 331 EndDatastoreSegment(EndDatastoreParams{ 332 Tracer: tr, 333 Start: t2, 334 Now: start.Add(3 * time.Second), 335 Product: "MySQL", 336 Operation: "SELECT", 337 Collection: "my_table", 338 }) 339 EndDatastoreSegment(EndDatastoreParams{ 340 Tracer: tr, 341 Start: t1, 342 Now: start.Add(4 * time.Second), 343 Product: "MySQL", 344 Operation: "SELECT", 345 // missing collection 346 }) 347 t3 := StartSegment(tr, start.Add(5*time.Second)) 348 EndDatastoreSegment(EndDatastoreParams{ 349 Tracer: tr, 350 Start: t3, 351 Now: start.Add(6 * time.Second), 352 Product: "MySQL", 353 Operation: "SELECT", 354 // missing collection 355 }) 356 t4 := StartSegment(tr, start.Add(7*time.Second)) 357 t4.Stamp++ 358 EndDatastoreSegment(EndDatastoreParams{ 359 Tracer: tr, 360 Start: t4, 361 Now: start.Add(8 * time.Second), 362 Product: "MySQL", 363 Operation: "invalid-token", 364 }) 365 t5 := StartSegment(tr, start.Add(9*time.Second)) 366 EndDatastoreSegment(EndDatastoreParams{ 367 Tracer: tr, 368 Start: t5, 369 Now: start.Add(10 * time.Second), 370 // missing datastore, collection, and operation 371 }) 372 373 if tr.datastoreCallCount != 4 { 374 t.Error(tr.datastoreCallCount) 375 } 376 if tr.datastoreDuration != 6*time.Second { 377 t.Error(tr.datastoreDuration) 378 } 379 metrics := newMetricTable(100, time.Now()) 380 tr.FinalName = "WebTransaction/Go/zip" 381 tr.IsWeb = true 382 MergeBreakdownMetrics(tr, metrics) 383 ExpectMetrics(t, metrics, []WantMetric{ 384 {"Datastore/all", "", true, []float64{4, 6, 5, 1, 3, 12}}, 385 {"Datastore/allWeb", "", true, []float64{4, 6, 5, 1, 3, 12}}, 386 {"Datastore/MySQL/all", "", true, []float64{3, 5, 4, 1, 3, 11}}, 387 {"Datastore/MySQL/allWeb", "", true, []float64{3, 5, 4, 1, 3, 11}}, 388 {"Datastore/Unknown/all", "", true, []float64{1, 1, 1, 1, 1, 1}}, 389 {"Datastore/Unknown/allWeb", "", true, []float64{1, 1, 1, 1, 1, 1}}, 390 {"Datastore/operation/MySQL/SELECT", "", false, []float64{3, 5, 4, 1, 3, 11}}, 391 {"Datastore/operation/MySQL/SELECT", tr.FinalName, false, []float64{2, 4, 3, 1, 3, 10}}, 392 {"Datastore/operation/Unknown/other", "", false, []float64{1, 1, 1, 1, 1, 1}}, 393 {"Datastore/operation/Unknown/other", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 394 {"Datastore/statement/MySQL/my_table/SELECT", "", false, []float64{1, 1, 1, 1, 1, 1}}, 395 {"Datastore/statement/MySQL/my_table/SELECT", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 396 }) 397 398 metrics = newMetricTable(100, time.Now()) 399 tr.FinalName = "OtherTransaction/Go/zip" 400 tr.IsWeb = false 401 MergeBreakdownMetrics(tr, metrics) 402 ExpectMetrics(t, metrics, []WantMetric{ 403 {"Datastore/all", "", true, []float64{4, 6, 5, 1, 3, 12}}, 404 {"Datastore/allOther", "", true, []float64{4, 6, 5, 1, 3, 12}}, 405 {"Datastore/MySQL/all", "", true, []float64{3, 5, 4, 1, 3, 11}}, 406 {"Datastore/MySQL/allOther", "", true, []float64{3, 5, 4, 1, 3, 11}}, 407 {"Datastore/Unknown/all", "", true, []float64{1, 1, 1, 1, 1, 1}}, 408 {"Datastore/Unknown/allOther", "", true, []float64{1, 1, 1, 1, 1, 1}}, 409 {"Datastore/operation/MySQL/SELECT", "", false, []float64{3, 5, 4, 1, 3, 11}}, 410 {"Datastore/operation/MySQL/SELECT", tr.FinalName, false, []float64{2, 4, 3, 1, 3, 10}}, 411 {"Datastore/operation/Unknown/other", "", false, []float64{1, 1, 1, 1, 1, 1}}, 412 {"Datastore/operation/Unknown/other", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 413 {"Datastore/statement/MySQL/my_table/SELECT", "", false, []float64{1, 1, 1, 1, 1, 1}}, 414 {"Datastore/statement/MySQL/my_table/SELECT", tr.FinalName, false, []float64{1, 1, 1, 1, 1, 1}}, 415 }) 416 } 417 418 func TestDatastoreInstancesCrossAgent(t *testing.T) { 419 var testcases []struct { 420 Name string `json:"name"` 421 SystemHostname string `json:"system_hostname"` 422 DBHostname string `json:"db_hostname"` 423 Product string `json:"product"` 424 Port int `json:"port"` 425 Socket string `json:"unix_socket"` 426 DatabasePath string `json:"database_path"` 427 ExpectedMetric string `json:"expected_instance_metric"` 428 } 429 430 err := crossagent.ReadJSON("datastores/datastore_instances.json", &testcases) 431 if err != nil { 432 t.Fatal(err) 433 } 434 435 start := time.Date(2014, time.November, 28, 1, 1, 0, 0, time.UTC) 436 437 for _, tc := range testcases { 438 portPathOrID := "" 439 if 0 != tc.Port { 440 portPathOrID = strconv.Itoa(tc.Port) 441 } else if "" != tc.Socket { 442 portPathOrID = tc.Socket 443 } else if "" != tc.DatabasePath { 444 portPathOrID = tc.DatabasePath 445 // These tests makes weird assumptions. 446 tc.DBHostname = "localhost" 447 } 448 449 tr := &TxnData{} 450 s := StartSegment(tr, start) 451 EndDatastoreSegment(EndDatastoreParams{ 452 Tracer: tr, 453 Start: s, 454 Now: start.Add(1 * time.Second), 455 Product: tc.Product, 456 Operation: "SELECT", 457 Collection: "my_table", 458 PortPathOrID: portPathOrID, 459 Host: tc.DBHostname, 460 }) 461 462 expect := strings.Replace(tc.ExpectedMetric, 463 tc.SystemHostname, ThisHost, -1) 464 465 metrics := newMetricTable(100, time.Now()) 466 tr.FinalName = "OtherTransaction/Go/zip" 467 tr.IsWeb = false 468 MergeBreakdownMetrics(tr, metrics) 469 data := []float64{1, 1, 1, 1, 1, 1} 470 ExpectMetrics(ExtendValidator(t, tc.Name), metrics, []WantMetric{ 471 {"Datastore/all", "", true, data}, 472 {"Datastore/allOther", "", true, data}, 473 {"Datastore/" + tc.Product + "/all", "", true, data}, 474 {"Datastore/" + tc.Product + "/allOther", "", true, data}, 475 {"Datastore/operation/" + tc.Product + "/SELECT", "", false, data}, 476 {"Datastore/statement/" + tc.Product + "/my_table/SELECT", "", false, data}, 477 {"Datastore/statement/" + tc.Product + "/my_table/SELECT", tr.FinalName, false, data}, 478 {expect, "", false, data}, 479 }) 480 } 481 }