grok_search_count_test.go 4.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package service
  2. import (
  3. "testing"
  4. "github.com/stretchr/testify/require"
  5. )
  6. func TestCountGrokNativeSearchCallsFromJSONBytes(t *testing.T) {
  7. t.Parallel()
  8. require.Equal(t, 0, countGrokNativeSearchCallsFromJSONBytes(nil))
  9. require.Equal(t, 0, countGrokNativeSearchCallsFromJSONBytes([]byte(`{"output":[]}`)))
  10. body := []byte(`{"output":[
  11. {"type":"web_search_call","id":"ws1","status":"completed"},
  12. {"type":"x_search_call","id":"xs1"},
  13. {"type":"function_call","name":"tool_search","call_id":"ts1"},
  14. {"type":"function_call","name":"lookup","call_id":"other"}
  15. ]}`)
  16. require.Equal(t, 3, countGrokNativeSearchCallsFromJSONBytes(body))
  17. }
  18. func TestCountGrokNativeSearchCallsFromJSONBytes_PrefersNestedResponse(t *testing.T) {
  19. t.Parallel()
  20. body := []byte(`{"output":[{"type":"web_search_call","id":"duplicate"}],"response":{"output":[{"type":"web_search_call","id":"duplicate"},{"type":"x_search_call","id":"xs1"}]}}`)
  21. require.Equal(t, 2, countGrokNativeSearchCallsFromJSONBytes(body))
  22. }
  23. func TestCountGrokNativeSearchCallsFromJSONBytes_FallsBackWhenNestedOutputNull(t *testing.T) {
  24. t.Parallel()
  25. body := []byte(`{"output":[{"type":"web_search_call","id":"ws1"}],"response":{"output":null}}`)
  26. require.Equal(t, 1, countGrokNativeSearchCallsFromJSONBytes(body))
  27. }
  28. func TestCountGrokNativeSearchCallsFromSSEBodyDedups(t *testing.T) {
  29. t.Parallel()
  30. sse := stringsJoin(
  31. `data: {"type":"response.output_item.done","item":{"type":"web_search_call","id":"ws1","call_id":"c1"}}`,
  32. `data: {"type":"response.output_item.done","item":{"type":"web_search_call","id":"ws1","call_id":"c1"}}`,
  33. `data: {"type":"response.completed","response":{"output":[{"type":"web_search_call","id":"ws1","call_id":"c1"},{"type":"x_search_call","id":"xs1","call_id":"c2"}]}}`,
  34. )
  35. require.Equal(t, 2, countGrokNativeSearchCallsFromSSEBody(sse))
  36. }
  37. func TestCountGrokNativeSearchCallsInSSEDataDedup_LiveStreamPath(t *testing.T) {
  38. t.Parallel()
  39. // Mirrors the live streaming accumulator: item.done then response.completed
  40. // for the same call_id must bill once (regression for ~2× surcharge).
  41. seen := make(map[string]struct{})
  42. done := []byte(`{"type":"response.output_item.done","item":{"type":"web_search_call","id":"ws1","call_id":"c1"}}`)
  43. completed := []byte(`{"type":"response.completed","response":{"output":[{"type":"web_search_call","id":"ws1","call_id":"c1"},{"type":"x_search_call","id":"xs1","call_id":"c2"}]}}`)
  44. require.Equal(t, 1, countGrokNativeSearchCallsInSSEDataDedup(done, seen))
  45. require.Equal(t, 1, countGrokNativeSearchCallsInSSEDataDedup(completed, seen))
  46. // Raw (no-dedup) path still double-counts the same envelope pair.
  47. require.Equal(t, 1, countGrokNativeSearchCallsInSSEData(done))
  48. require.Equal(t, 2, countGrokNativeSearchCallsInSSEData(completed))
  49. }
  50. func TestCountGrokNativeSearchCallsInSSEDataDedup_NoIDStillDedups(t *testing.T) {
  51. t.Parallel()
  52. // Upstream sometimes omits call_id/id; synthetic keys must still prevent 2×.
  53. seen := make(map[string]struct{})
  54. done := []byte(`{"type":"response.output_item.done","item":{"type":"web_search_call"}}`)
  55. completed := []byte(`{"type":"response.completed","response":{"output":[{"type":"web_search_call"}]}}`)
  56. require.Equal(t, 1, countGrokNativeSearchCallsInSSEDataDedup(done, seen))
  57. require.Equal(t, 0, countGrokNativeSearchCallsInSSEDataDedup(completed, seen))
  58. }
  59. func TestCountGrokNativeSearchCallsInSSEDataDedup_MultipleNoIDCalls(t *testing.T) {
  60. t.Parallel()
  61. seen := make(map[string]struct{})
  62. firstDone := []byte(`{"type":"response.output_item.done","item":{"type":"web_search_call"}}`)
  63. secondDone := []byte(`{"type":"response.output_item.done","item":{"type":"web_search_call"}}`)
  64. completed := []byte(`{"type":"response.completed","response":{"output":[{"type":"web_search_call"},{"type":"web_search_call"}]}}`)
  65. require.Equal(t, 1, countGrokNativeSearchCallsInSSEDataDedup(firstDone, seen))
  66. require.Equal(t, 1, countGrokNativeSearchCallsInSSEDataDedup(secondDone, seen))
  67. require.Equal(t, 0, countGrokNativeSearchCallsInSSEDataDedup(completed, seen))
  68. }
  69. func stringsJoin(lines ...string) string {
  70. out := ""
  71. for _, l := range lines {
  72. out += l + "\n\n"
  73. }
  74. return out
  75. }