decoders_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. package source
  2. import (
  3. "testing"
  4. "github.com/opencost/opencost/core/pkg/util"
  5. "github.com/stretchr/testify/require"
  6. )
  7. // vecs is a helper to build a slice of vectors from raw values. The timestamps
  8. // are monotonically increasing so that "last value" semantics are exercised.
  9. func vecs(values ...float64) []*util.Vector {
  10. out := make([]*util.Vector, 0, len(values))
  11. for i, v := range values {
  12. out = append(out, &util.Vector{Timestamp: float64(i), Value: v})
  13. }
  14. return out
  15. }
  16. func TestDecodeInferenceTokensResult(t *testing.T) {
  17. cases := []struct {
  18. name string
  19. metric map[string]any
  20. values []*util.Vector
  21. expectedKey string
  22. expectedVal float64
  23. }{
  24. {
  25. name: "uses last value with model and namespace",
  26. metric: map[string]any{"model_name": "llama3", "namespace": "default"},
  27. values: vecs(10, 20, 42),
  28. expectedKey: "llama3:default",
  29. expectedVal: 42,
  30. },
  31. {
  32. name: "empty values defaults to zero",
  33. metric: map[string]any{"model_name": "llama3", "namespace": "default"},
  34. values: vecs(),
  35. expectedKey: "llama3:default",
  36. expectedVal: 0,
  37. },
  38. {
  39. name: "single value",
  40. metric: map[string]any{"model_name": "mistral", "namespace": "team-a"},
  41. values: vecs(7),
  42. expectedKey: "mistral:team-a",
  43. expectedVal: 7,
  44. },
  45. {
  46. name: "missing labels yields separator-only key",
  47. metric: map[string]any{},
  48. values: vecs(5),
  49. expectedKey: ":",
  50. expectedVal: 5,
  51. },
  52. }
  53. for _, tc := range cases {
  54. t.Run(tc.name, func(t *testing.T) {
  55. result := NewQueryResult(tc.metric, tc.values, nil)
  56. decoded := DecodeInferenceTokensResult(result)
  57. require.NotNil(t, decoded)
  58. require.Len(t, decoded.Values, 1)
  59. val, ok := decoded.Values[tc.expectedKey]
  60. require.True(t, ok, "expected key %q to be present", tc.expectedKey)
  61. require.Equal(t, tc.expectedVal, val)
  62. })
  63. }
  64. }
  65. func TestDecodeInferenceProcessingTimeResult(t *testing.T) {
  66. cases := []struct {
  67. name string
  68. metric map[string]any
  69. values []*util.Vector
  70. expectedKey string
  71. expectedVal float64
  72. }{
  73. {
  74. name: "uses last value with model and namespace",
  75. metric: map[string]any{"model_name": "llama3", "namespace": "default"},
  76. values: vecs(1.5, 2.5, 3.75),
  77. expectedKey: "llama3:default",
  78. expectedVal: 3.75,
  79. },
  80. {
  81. name: "empty values defaults to zero",
  82. metric: map[string]any{"model_name": "llama3", "namespace": "default"},
  83. values: vecs(),
  84. expectedKey: "llama3:default",
  85. expectedVal: 0,
  86. },
  87. {
  88. name: "missing labels yields separator-only key",
  89. metric: map[string]any{},
  90. values: vecs(9.9),
  91. expectedKey: ":",
  92. expectedVal: 9.9,
  93. },
  94. }
  95. for _, tc := range cases {
  96. t.Run(tc.name, func(t *testing.T) {
  97. result := NewQueryResult(tc.metric, tc.values, nil)
  98. decoded := DecodeInferenceProcessingTimeResult(result)
  99. require.NotNil(t, decoded)
  100. require.Len(t, decoded.Values, 1)
  101. val, ok := decoded.Values[tc.expectedKey]
  102. require.True(t, ok, "expected key %q to be present", tc.expectedKey)
  103. require.Equal(t, tc.expectedVal, val)
  104. })
  105. }
  106. }
  107. func TestDecodeInferenceCacheConfigResult(t *testing.T) {
  108. cases := []struct {
  109. name string
  110. metric map[string]any
  111. values []*util.Vector
  112. expectedKey string
  113. expectedEnabled bool
  114. }{
  115. {
  116. name: "positive value means prefix caching enabled",
  117. metric: map[string]any{"model_name": "llama3", "namespace": "default"},
  118. values: vecs(1),
  119. expectedKey: "llama3:default",
  120. expectedEnabled: true,
  121. },
  122. {
  123. name: "zero value means prefix caching disabled",
  124. metric: map[string]any{"model_name": "llama3", "namespace": "default"},
  125. values: vecs(0),
  126. expectedKey: "llama3:default",
  127. expectedEnabled: false,
  128. },
  129. {
  130. name: "negative value means prefix caching disabled",
  131. metric: map[string]any{"model_name": "llama3", "namespace": "default"},
  132. values: vecs(-1),
  133. expectedKey: "llama3:default",
  134. expectedEnabled: false,
  135. },
  136. {
  137. name: "uses last value to determine enabled",
  138. metric: map[string]any{"model_name": "mistral", "namespace": "team-a"},
  139. values: vecs(1, 0, 1),
  140. expectedKey: "mistral:team-a",
  141. expectedEnabled: true,
  142. },
  143. {
  144. name: "empty values defaults to disabled",
  145. metric: map[string]any{"model_name": "llama3", "namespace": "default"},
  146. values: vecs(),
  147. expectedKey: "llama3:default",
  148. expectedEnabled: false,
  149. },
  150. }
  151. for _, tc := range cases {
  152. t.Run(tc.name, func(t *testing.T) {
  153. result := NewQueryResult(tc.metric, tc.values, nil)
  154. decoded := DecodeInferenceCacheConfigResult(result)
  155. require.NotNil(t, decoded)
  156. require.Len(t, decoded.Configs, 1)
  157. config, ok := decoded.Configs[tc.expectedKey]
  158. require.True(t, ok, "expected key %q to be present", tc.expectedKey)
  159. require.NotNil(t, config)
  160. require.Equal(t, tc.expectedEnabled, config.PrefixCachingEnabled)
  161. })
  162. }
  163. }