expect.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. package internal
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "runtime"
  6. )
  7. var (
  8. // Unfortunately, the resolution of time.Now() on Windows is coarse: Two
  9. // sequential calls to time.Now() may return the same value, and tests
  10. // which expect non-zero durations may fail. To avoid adding sleep
  11. // statements or mocking time.Now(), those tests are skipped on Windows.
  12. doDurationTests = runtime.GOOS != `windows`
  13. )
  14. // Validator is used for testing.
  15. type Validator interface {
  16. Error(...interface{})
  17. }
  18. func validateStringField(v Validator, fieldName, v1, v2 string) {
  19. if v1 != v2 {
  20. v.Error(fieldName, v1, v2)
  21. }
  22. }
  23. type addValidatorField struct {
  24. field interface{}
  25. original Validator
  26. }
  27. func (a addValidatorField) Error(fields ...interface{}) {
  28. fields = append([]interface{}{a.field}, fields...)
  29. a.original.Error(fields...)
  30. }
  31. // ExtendValidator is used to add more context to a validator.
  32. func ExtendValidator(v Validator, field interface{}) Validator {
  33. return addValidatorField{
  34. field: field,
  35. original: v,
  36. }
  37. }
  38. // WantMetric is a metric expectation. If Data is nil, then any data values are
  39. // acceptable.
  40. type WantMetric struct {
  41. Name string
  42. Scope string
  43. Forced interface{} // true, false, or nil
  44. Data []float64
  45. }
  46. // WantError is a traced error expectation.
  47. type WantError struct {
  48. TxnName string
  49. Msg string
  50. Klass string
  51. Caller string
  52. URL string
  53. UserAttributes map[string]interface{}
  54. AgentAttributes map[string]interface{}
  55. }
  56. func uniquePointer() *struct{} {
  57. s := struct{}{}
  58. return &s
  59. }
  60. var (
  61. // MatchAnything is for use when matching attributes.
  62. MatchAnything = uniquePointer()
  63. )
  64. // WantEvent is a transaction or error event expectation.
  65. type WantEvent struct {
  66. Intrinsics map[string]interface{}
  67. UserAttributes map[string]interface{}
  68. AgentAttributes map[string]interface{}
  69. }
  70. // WantTxnTrace is a transaction trace expectation.
  71. type WantTxnTrace struct {
  72. MetricName string
  73. CleanURL string
  74. NumSegments int
  75. UserAttributes map[string]interface{}
  76. AgentAttributes map[string]interface{}
  77. }
  78. // WantSlowQuery is a slowQuery expectation.
  79. type WantSlowQuery struct {
  80. Count int32
  81. MetricName string
  82. Query string
  83. TxnName string
  84. TxnURL string
  85. DatabaseName string
  86. Host string
  87. PortPathOrID string
  88. Params map[string]interface{}
  89. }
  90. // HarvestTestinger is implemented by the app. It sets an empty test harvest
  91. // and modifies the connect reply if a callback is provided.
  92. type HarvestTestinger interface {
  93. HarvestTesting(replyfn func(*ConnectReply))
  94. }
  95. // HarvestTesting allows integration packages to test instrumentation.
  96. func HarvestTesting(app interface{}, replyfn func(*ConnectReply)) {
  97. ta, ok := app.(HarvestTestinger)
  98. if !ok {
  99. panic("HarvestTesting type assertion failure")
  100. }
  101. ta.HarvestTesting(replyfn)
  102. }
  103. // Expect exposes methods that allow for testing whether the correct data was
  104. // captured.
  105. type Expect interface {
  106. ExpectCustomEvents(t Validator, want []WantEvent)
  107. ExpectErrors(t Validator, want []WantError)
  108. ExpectErrorEvents(t Validator, want []WantEvent)
  109. ExpectErrorEventsPresent(t Validator, want []WantEvent)
  110. ExpectErrorEventsAbsent(t Validator, names []string)
  111. ExpectTxnEvents(t Validator, want []WantEvent)
  112. ExpectTxnEventsPresent(t Validator, want []WantEvent)
  113. ExpectTxnEventsAbsent(t Validator, names []string)
  114. ExpectMetrics(t Validator, want []WantMetric)
  115. ExpectMetricsPresent(t Validator, want []WantMetric)
  116. ExpectTxnTraces(t Validator, want []WantTxnTrace)
  117. ExpectSlowQueries(t Validator, want []WantSlowQuery)
  118. ExpectSpanEvents(t Validator, want []WantEvent)
  119. ExpectSpanEventsPresent(t Validator, want []WantEvent)
  120. ExpectSpanEventsAbsent(t Validator, names []string)
  121. ExpectSpanEventsCount(t Validator, c int)
  122. }
  123. func expectMetricField(t Validator, id metricID, v1, v2 float64, fieldName string) {
  124. if v1 != v2 {
  125. t.Error("metric fields do not match", id, v1, v2, fieldName)
  126. }
  127. }
  128. // ExpectMetricsPresent allows testing of metrics with requiring an exact match
  129. func ExpectMetricsPresent(t Validator, mt *metricTable, expect []WantMetric) {
  130. expectedIds := make(map[metricID]struct{})
  131. for _, e := range expect {
  132. id := metricID{Name: e.Name, Scope: e.Scope}
  133. expectedIds[id] = struct{}{}
  134. m := mt.metrics[id]
  135. if nil == m {
  136. t.Error("unable to find metric", id)
  137. continue
  138. }
  139. if b, ok := e.Forced.(bool); ok {
  140. if b != (forced == m.forced) {
  141. t.Error("metric forced incorrect", b, m.forced, id)
  142. }
  143. }
  144. if nil != e.Data {
  145. expectMetricField(t, id, e.Data[0], m.data.countSatisfied, "countSatisfied")
  146. expectMetricField(t, id, e.Data[1], m.data.totalTolerated, "totalTolerated")
  147. expectMetricField(t, id, e.Data[2], m.data.exclusiveFailed, "exclusiveFailed")
  148. expectMetricField(t, id, e.Data[3], m.data.min, "min")
  149. expectMetricField(t, id, e.Data[4], m.data.max, "max")
  150. expectMetricField(t, id, e.Data[5], m.data.sumSquares, "sumSquares")
  151. }
  152. }
  153. }
  154. // ExpectMetrics allows testing of metrics. It passes if mt exactly matches expect.
  155. func ExpectMetrics(t Validator, mt *metricTable, expect []WantMetric) {
  156. if len(mt.metrics) != len(expect) {
  157. t.Error("metric counts do not match expectations", len(mt.metrics), len(expect))
  158. }
  159. expectedIds := make(map[metricID]struct{})
  160. for _, e := range expect {
  161. id := metricID{Name: e.Name, Scope: e.Scope}
  162. expectedIds[id] = struct{}{}
  163. m := mt.metrics[id]
  164. if nil == m {
  165. t.Error("unable to find metric", id)
  166. continue
  167. }
  168. if b, ok := e.Forced.(bool); ok {
  169. if b != (forced == m.forced) {
  170. t.Error("metric forced incorrect", b, m.forced, id)
  171. }
  172. }
  173. if nil != e.Data {
  174. expectMetricField(t, id, e.Data[0], m.data.countSatisfied, "countSatisfied")
  175. expectMetricField(t, id, e.Data[1], m.data.totalTolerated, "totalTolerated")
  176. expectMetricField(t, id, e.Data[2], m.data.exclusiveFailed, "exclusiveFailed")
  177. expectMetricField(t, id, e.Data[3], m.data.min, "min")
  178. expectMetricField(t, id, e.Data[4], m.data.max, "max")
  179. expectMetricField(t, id, e.Data[5], m.data.sumSquares, "sumSquares")
  180. }
  181. }
  182. for id := range mt.metrics {
  183. if _, ok := expectedIds[id]; !ok {
  184. t.Error("expected metrics does not contain", id.Name, id.Scope)
  185. }
  186. }
  187. }
  188. func expectAttributesPresent(v Validator, exists map[string]interface{}, expect map[string]interface{}) {
  189. for key, val := range expect {
  190. found, ok := exists[key]
  191. if !ok {
  192. v.Error("expected attribute not found: ", key)
  193. continue
  194. }
  195. if val == MatchAnything {
  196. continue
  197. }
  198. v1 := fmt.Sprint(found)
  199. v2 := fmt.Sprint(val)
  200. if v1 != v2 {
  201. v.Error("value difference", fmt.Sprintf("key=%s", key), v1, v2)
  202. }
  203. }
  204. }
  205. func expectAttributes(v Validator, exists map[string]interface{}, expect map[string]interface{}) {
  206. // TODO: This params comparison can be made smarter: Alert differences
  207. // based on sub/super set behavior.
  208. if len(exists) != len(expect) {
  209. v.Error("attributes length difference", len(exists), len(expect))
  210. }
  211. for key, val := range expect {
  212. found, ok := exists[key]
  213. if !ok {
  214. v.Error("expected attribute not found: ", key)
  215. continue
  216. }
  217. if val == MatchAnything {
  218. continue
  219. }
  220. v1 := fmt.Sprint(found)
  221. v2 := fmt.Sprint(val)
  222. if v1 != v2 {
  223. v.Error("value difference", fmt.Sprintf("key=%s", key), v1, v2)
  224. }
  225. }
  226. for key, val := range exists {
  227. _, ok := expect[key]
  228. if !ok {
  229. v.Error("unexpected attribute present: ", key, val)
  230. continue
  231. }
  232. }
  233. }
  234. // ExpectCustomEvents allows testing of custom events. It passes if cs exactly matches expect.
  235. func ExpectCustomEvents(v Validator, cs *customEvents, expect []WantEvent) {
  236. if len(cs.events.events) != len(expect) {
  237. v.Error("number of custom events does not match", len(cs.events.events),
  238. len(expect))
  239. return
  240. }
  241. for i, e := range expect {
  242. event, ok := cs.events.events[i].jsonWriter.(*CustomEvent)
  243. if !ok {
  244. v.Error("wrong custom event")
  245. } else {
  246. expectEvent(v, event, e)
  247. }
  248. }
  249. }
  250. func expectEventAbsent(v Validator, e json.Marshaler, names []string) {
  251. js, err := e.MarshalJSON()
  252. if nil != err {
  253. v.Error("unable to marshal event", err)
  254. return
  255. }
  256. var event []map[string]interface{}
  257. err = json.Unmarshal(js, &event)
  258. if nil != err {
  259. v.Error("unable to parse event json", err)
  260. return
  261. }
  262. intrinsics := event[0]
  263. userAttributes := event[1]
  264. agentAttributes := event[2]
  265. for _, name := range names {
  266. if _, ok := intrinsics[name]; ok {
  267. v.Error("unexpected key found", name)
  268. }
  269. if _, ok := userAttributes[name]; ok {
  270. v.Error("unexpected key found", name)
  271. }
  272. if _, ok := agentAttributes[name]; ok {
  273. v.Error("unexpected key found", name)
  274. }
  275. }
  276. }
  277. func expectEventPresent(v Validator, e json.Marshaler, expect WantEvent) {
  278. js, err := e.MarshalJSON()
  279. if nil != err {
  280. v.Error("unable to marshal event", err)
  281. return
  282. }
  283. var event []map[string]interface{}
  284. err = json.Unmarshal(js, &event)
  285. if nil != err {
  286. v.Error("unable to parse event json", err)
  287. return
  288. }
  289. intrinsics := event[0]
  290. userAttributes := event[1]
  291. agentAttributes := event[2]
  292. if nil != expect.Intrinsics {
  293. expectAttributesPresent(v, intrinsics, expect.Intrinsics)
  294. }
  295. if nil != expect.UserAttributes {
  296. expectAttributesPresent(v, userAttributes, expect.UserAttributes)
  297. }
  298. if nil != expect.AgentAttributes {
  299. expectAttributesPresent(v, agentAttributes, expect.AgentAttributes)
  300. }
  301. }
  302. func expectEvent(v Validator, e json.Marshaler, expect WantEvent) {
  303. js, err := e.MarshalJSON()
  304. if nil != err {
  305. v.Error("unable to marshal event", err)
  306. return
  307. }
  308. var event []map[string]interface{}
  309. err = json.Unmarshal(js, &event)
  310. if nil != err {
  311. v.Error("unable to parse event json", err)
  312. return
  313. }
  314. intrinsics := event[0]
  315. userAttributes := event[1]
  316. agentAttributes := event[2]
  317. if nil != expect.Intrinsics {
  318. expectAttributes(v, intrinsics, expect.Intrinsics)
  319. }
  320. if nil != expect.UserAttributes {
  321. expectAttributes(v, userAttributes, expect.UserAttributes)
  322. }
  323. if nil != expect.AgentAttributes {
  324. expectAttributes(v, agentAttributes, expect.AgentAttributes)
  325. }
  326. }
  327. // Second attributes have priority.
  328. func mergeAttributes(a1, a2 map[string]interface{}) map[string]interface{} {
  329. a := make(map[string]interface{})
  330. for k, v := range a1 {
  331. a[k] = v
  332. }
  333. for k, v := range a2 {
  334. a[k] = v
  335. }
  336. return a
  337. }
  338. // ExpectErrorEventsPresent allows testing of events with requiring an exact match
  339. func ExpectErrorEventsPresent(v Validator, events *errorEvents, expect []WantEvent) {
  340. for i, e := range expect {
  341. event, ok := events.events.events[i].jsonWriter.(*ErrorEvent)
  342. if !ok {
  343. v.Error("wrong span event in ExpectErrorEventsPresent")
  344. } else {
  345. expectEventPresent(v, event, e)
  346. }
  347. }
  348. }
  349. // ExpectErrorEventsAbsent allows testing that a set of attribute names are absent from the event data
  350. func ExpectErrorEventsAbsent(v Validator, events *errorEvents, names []string) {
  351. for _, eventHarvested := range events.events.events {
  352. event, ok := eventHarvested.jsonWriter.(*ErrorEvent)
  353. if !ok {
  354. v.Error("wrong span event in ExpectErrorEventsAbsent")
  355. } else {
  356. expectEventAbsent(v, event, names)
  357. }
  358. }
  359. }
  360. // ExpectErrorEvents allows testing of error events. It passes if events exactly matches expect.
  361. func ExpectErrorEvents(v Validator, events *errorEvents, expect []WantEvent) {
  362. if len(events.events.events) != len(expect) {
  363. v.Error("number of custom events does not match",
  364. len(events.events.events), len(expect))
  365. return
  366. }
  367. for i, e := range expect {
  368. event, ok := events.events.events[i].jsonWriter.(*ErrorEvent)
  369. if !ok {
  370. v.Error("wrong error event")
  371. } else {
  372. if nil != e.Intrinsics {
  373. e.Intrinsics = mergeAttributes(map[string]interface{}{
  374. // The following intrinsics should always be present in
  375. // error events:
  376. "type": "TransactionError",
  377. "timestamp": MatchAnything,
  378. "duration": MatchAnything,
  379. }, e.Intrinsics)
  380. }
  381. expectEvent(v, event, e)
  382. }
  383. }
  384. }
  385. // ExpectSpanEventsCount allows us to count how many events the system generated
  386. func ExpectSpanEventsCount(v Validator, events *spanEvents, c int) {
  387. len := len(events.events.events)
  388. if len != c {
  389. v.Error(fmt.Sprintf("expected %d span events, found %d", c, len))
  390. }
  391. }
  392. // ExpectSpanEventsPresent allows us to test for the presence and value of events
  393. // without also requiring an exact match
  394. func ExpectSpanEventsPresent(v Validator, events *spanEvents, expect []WantEvent) {
  395. for i, e := range expect {
  396. event, ok := events.events.events[i].jsonWriter.(*SpanEvent)
  397. if !ok {
  398. v.Error("wrong span event in ExpectSpanEventsPresent")
  399. } else {
  400. expectEventPresent(v, event, e)
  401. }
  402. }
  403. }
  404. // ExpectSpanEventsAbsent allows us to ensure that a set of attribute names are absent
  405. // from the event data
  406. func ExpectSpanEventsAbsent(v Validator, events *spanEvents, names []string) {
  407. for _, eventHarvested := range events.events.events {
  408. event, ok := eventHarvested.jsonWriter.(*SpanEvent)
  409. if !ok {
  410. v.Error("wrong span event in ExpectSpanEventsAbsent")
  411. } else {
  412. expectEventAbsent(v, event, names)
  413. }
  414. }
  415. }
  416. // ExpectSpanEvents allows testing of span events. It passes if events exactly matches expect.
  417. func ExpectSpanEvents(v Validator, events *spanEvents, expect []WantEvent) {
  418. if len(events.events.events) != len(expect) {
  419. v.Error("number of span events does not match",
  420. len(events.events.events), len(expect))
  421. return
  422. }
  423. for i, e := range expect {
  424. event, ok := events.events.events[i].jsonWriter.(*SpanEvent)
  425. if !ok {
  426. v.Error("wrong span event")
  427. } else {
  428. if nil != e.Intrinsics {
  429. e.Intrinsics = mergeAttributes(map[string]interface{}{
  430. // The following intrinsics should always be present in
  431. // span events:
  432. "type": "Span",
  433. "timestamp": MatchAnything,
  434. "duration": MatchAnything,
  435. }, e.Intrinsics)
  436. }
  437. expectEvent(v, event, e)
  438. }
  439. }
  440. }
  441. // ExpectTxnEventsPresent allows us to test for the presence and value of events
  442. // without also requiring an exact match
  443. func ExpectTxnEventsPresent(v Validator, events *txnEvents, expect []WantEvent) {
  444. for i, e := range expect {
  445. event, ok := events.events.events[i].jsonWriter.(*TxnEvent)
  446. if !ok {
  447. v.Error("wrong txn event in ExpectTxnEventsPresent")
  448. } else {
  449. expectEventPresent(v, event, e)
  450. }
  451. }
  452. }
  453. // ExpectTxnEventsAbsent allows us to ensure that a set of attribute names are absent
  454. // from the event data
  455. func ExpectTxnEventsAbsent(v Validator, events *txnEvents, names []string) {
  456. for _, eventHarvested := range events.events.events {
  457. event, ok := eventHarvested.jsonWriter.(*TxnEvent)
  458. if !ok {
  459. v.Error("wrong txn event in ExpectTxnEventsAbsent")
  460. } else {
  461. expectEventAbsent(v, event, names)
  462. }
  463. }
  464. }
  465. // ExpectTxnEvents allows testing of txn events.
  466. func ExpectTxnEvents(v Validator, events *txnEvents, expect []WantEvent) {
  467. if len(events.events.events) != len(expect) {
  468. v.Error("number of txn events does not match",
  469. len(events.events.events), len(expect))
  470. return
  471. }
  472. for i, e := range expect {
  473. event, ok := events.events.events[i].jsonWriter.(*TxnEvent)
  474. if !ok {
  475. v.Error("wrong txn event")
  476. } else {
  477. if nil != e.Intrinsics {
  478. e.Intrinsics = mergeAttributes(map[string]interface{}{
  479. // The following intrinsics should always be present in
  480. // txn events:
  481. "type": "Transaction",
  482. "timestamp": MatchAnything,
  483. "duration": MatchAnything,
  484. "error": MatchAnything,
  485. }, e.Intrinsics)
  486. }
  487. expectEvent(v, event, e)
  488. }
  489. }
  490. }
  491. func expectError(v Validator, err *tracedError, expect WantError) {
  492. caller := topCallerNameBase(err.ErrorData.Stack)
  493. validateStringField(v, "caller", expect.Caller, caller)
  494. validateStringField(v, "txnName", expect.TxnName, err.FinalName)
  495. validateStringField(v, "klass", expect.Klass, err.Klass)
  496. validateStringField(v, "msg", expect.Msg, err.Msg)
  497. validateStringField(v, "URL", expect.URL, err.CleanURL)
  498. js, errr := err.MarshalJSON()
  499. if nil != errr {
  500. v.Error("unable to marshal error json", errr)
  501. return
  502. }
  503. var unmarshalled []interface{}
  504. errr = json.Unmarshal(js, &unmarshalled)
  505. if nil != errr {
  506. v.Error("unable to unmarshal error json", errr)
  507. return
  508. }
  509. attributes := unmarshalled[4].(map[string]interface{})
  510. agentAttributes := attributes["agentAttributes"].(map[string]interface{})
  511. userAttributes := attributes["userAttributes"].(map[string]interface{})
  512. if nil != expect.UserAttributes {
  513. expectAttributes(v, userAttributes, expect.UserAttributes)
  514. }
  515. if nil != expect.AgentAttributes {
  516. expectAttributes(v, agentAttributes, expect.AgentAttributes)
  517. }
  518. }
  519. // ExpectErrors allows testing of errors.
  520. func ExpectErrors(v Validator, errors harvestErrors, expect []WantError) {
  521. if len(errors) != len(expect) {
  522. v.Error("number of errors mismatch", len(errors), len(expect))
  523. return
  524. }
  525. for i, e := range expect {
  526. expectError(v, errors[i], e)
  527. }
  528. }
  529. func countSegments(node []interface{}) int {
  530. count := 1
  531. children := node[4].([]interface{})
  532. for _, c := range children {
  533. node := c.([]interface{})
  534. count += countSegments(node)
  535. }
  536. return count
  537. }
  538. func expectTxnTrace(v Validator, got json.Marshaler, expect WantTxnTrace) {
  539. js, err := got.MarshalJSON()
  540. if nil != err {
  541. v.Error("unable to marshal txn trace json", err)
  542. return
  543. }
  544. var unmarshalled []interface{}
  545. err = json.Unmarshal(js, &unmarshalled)
  546. if nil != err {
  547. v.Error("unable to unmarshal error json", err)
  548. return
  549. }
  550. duration := unmarshalled[1].(float64)
  551. name := unmarshalled[2].(string)
  552. cleanURL := unmarshalled[3].(string)
  553. traceData := unmarshalled[4].([]interface{})
  554. rootNode := traceData[3].([]interface{})
  555. attributes := traceData[4].(map[string]interface{})
  556. userAttributes := attributes["userAttributes"].(map[string]interface{})
  557. agentAttributes := attributes["agentAttributes"].(map[string]interface{})
  558. validateStringField(v, "metric name", expect.MetricName, name)
  559. validateStringField(v, "request url", expect.CleanURL, cleanURL)
  560. if doDurationTests && 0 == duration {
  561. v.Error("zero trace duration")
  562. }
  563. if nil != expect.UserAttributes {
  564. expectAttributes(v, userAttributes, expect.UserAttributes)
  565. }
  566. if nil != expect.AgentAttributes {
  567. expectAttributes(v, agentAttributes, expect.AgentAttributes)
  568. }
  569. numSegments := countSegments(rootNode)
  570. // The expectation segment count does not include the two root nodes.
  571. numSegments -= 2
  572. if expect.NumSegments != numSegments {
  573. v.Error("wrong number of segments", expect.NumSegments, numSegments)
  574. }
  575. }
  576. // ExpectTxnTraces allows testing of transaction traces.
  577. func ExpectTxnTraces(v Validator, traces *harvestTraces, want []WantTxnTrace) {
  578. if len(want) != traces.Len() {
  579. v.Error("number of traces do not match", len(want), traces.Len())
  580. }
  581. actual := traces.slice()
  582. for i, expected := range want {
  583. expectTxnTrace(v, actual[i], expected)
  584. }
  585. }
  586. func expectSlowQuery(t Validator, slowQuery *slowQuery, want WantSlowQuery) {
  587. if slowQuery.Count != want.Count {
  588. t.Error("wrong Count field", slowQuery.Count, want.Count)
  589. }
  590. validateStringField(t, "MetricName", slowQuery.DatastoreMetric, want.MetricName)
  591. validateStringField(t, "Query", slowQuery.ParameterizedQuery, want.Query)
  592. validateStringField(t, "TxnEvent.FinalName", slowQuery.TxnEvent.FinalName, want.TxnName)
  593. validateStringField(t, "TxnEvent.CleanURL", slowQuery.TxnEvent.CleanURL, want.TxnURL)
  594. validateStringField(t, "DatabaseName", slowQuery.DatabaseName, want.DatabaseName)
  595. validateStringField(t, "Host", slowQuery.Host, want.Host)
  596. validateStringField(t, "PortPathOrID", slowQuery.PortPathOrID, want.PortPathOrID)
  597. expectAttributes(t, map[string]interface{}(slowQuery.QueryParameters), want.Params)
  598. }
  599. // ExpectSlowQueries allows testing of slow queries.
  600. func ExpectSlowQueries(t Validator, slowQueries *slowQueries, want []WantSlowQuery) {
  601. if len(want) != len(slowQueries.priorityQueue) {
  602. t.Error("wrong number of slow queries",
  603. "expected", len(want), "got", len(slowQueries.priorityQueue))
  604. return
  605. }
  606. for _, s := range want {
  607. idx, ok := slowQueries.lookup[s.Query]
  608. if !ok {
  609. t.Error("unable to find slow query", s.Query)
  610. continue
  611. }
  612. expectSlowQuery(t, slowQueries.priorityQueue[idx], s)
  613. }
  614. }