account_openai_compact_test.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. package service
  2. import "testing"
  3. func TestAccountGetOpenAICompactMode(t *testing.T) {
  4. tests := []struct {
  5. name string
  6. account *Account
  7. want string
  8. }{
  9. {
  10. name: "nil account defaults to auto",
  11. want: OpenAICompactModeAuto,
  12. },
  13. {
  14. name: "non openai account defaults to auto",
  15. account: &Account{
  16. Platform: PlatformAnthropic,
  17. Extra: map[string]any{"openai_compact_mode": OpenAICompactModeForceOn},
  18. },
  19. want: OpenAICompactModeAuto,
  20. },
  21. {
  22. name: "missing extra defaults to auto",
  23. account: &Account{
  24. Platform: PlatformOpenAI,
  25. },
  26. want: OpenAICompactModeAuto,
  27. },
  28. {
  29. name: "invalid mode falls back to auto",
  30. account: &Account{
  31. Platform: PlatformOpenAI,
  32. Extra: map[string]any{"openai_compact_mode": " invalid "},
  33. },
  34. want: OpenAICompactModeAuto,
  35. },
  36. {
  37. name: "force on is normalized",
  38. account: &Account{
  39. Platform: PlatformOpenAI,
  40. Extra: map[string]any{"openai_compact_mode": " FORCE_ON "},
  41. },
  42. want: OpenAICompactModeForceOn,
  43. },
  44. {
  45. name: "force off is normalized",
  46. account: &Account{
  47. Platform: PlatformOpenAI,
  48. Extra: map[string]any{"openai_compact_mode": "force_off"},
  49. },
  50. want: OpenAICompactModeForceOff,
  51. },
  52. }
  53. for _, tt := range tests {
  54. t.Run(tt.name, func(t *testing.T) {
  55. if got := tt.account.GetOpenAICompactMode(); got != tt.want {
  56. t.Fatalf("GetOpenAICompactMode() = %q, want %q", got, tt.want)
  57. }
  58. })
  59. }
  60. }
  61. func TestAccountOpenAICompactSupportKnown(t *testing.T) {
  62. tests := []struct {
  63. name string
  64. account *Account
  65. wantSupported bool
  66. wantKnown bool
  67. }{
  68. {
  69. name: "nil account is unknown",
  70. wantSupported: false,
  71. wantKnown: false,
  72. },
  73. {
  74. name: "non openai account is unknown",
  75. account: &Account{
  76. Platform: PlatformAnthropic,
  77. Extra: map[string]any{"openai_compact_supported": true},
  78. },
  79. wantSupported: false,
  80. wantKnown: false,
  81. },
  82. {
  83. name: "force on overrides probe state",
  84. account: &Account{
  85. Platform: PlatformOpenAI,
  86. Extra: map[string]any{
  87. "openai_compact_mode": OpenAICompactModeForceOn,
  88. "openai_compact_supported": false,
  89. },
  90. },
  91. wantSupported: true,
  92. wantKnown: true,
  93. },
  94. {
  95. name: "force off overrides probe state",
  96. account: &Account{
  97. Platform: PlatformOpenAI,
  98. Extra: map[string]any{
  99. "openai_compact_mode": OpenAICompactModeForceOff,
  100. "openai_compact_supported": true,
  101. },
  102. },
  103. wantSupported: false,
  104. wantKnown: true,
  105. },
  106. {
  107. name: "auto true is known supported",
  108. account: &Account{
  109. Platform: PlatformOpenAI,
  110. Extra: map[string]any{"openai_compact_supported": true},
  111. },
  112. wantSupported: true,
  113. wantKnown: true,
  114. },
  115. {
  116. name: "auto false is known unsupported",
  117. account: &Account{
  118. Platform: PlatformOpenAI,
  119. Extra: map[string]any{"openai_compact_supported": false},
  120. },
  121. wantSupported: false,
  122. wantKnown: true,
  123. },
  124. {
  125. name: "auto without probe state remains unknown",
  126. account: &Account{
  127. Platform: PlatformOpenAI,
  128. Extra: map[string]any{},
  129. },
  130. wantSupported: false,
  131. wantKnown: false,
  132. },
  133. {
  134. name: "invalid probe field remains unknown",
  135. account: &Account{
  136. Platform: PlatformOpenAI,
  137. Extra: map[string]any{"openai_compact_supported": "true"},
  138. },
  139. wantSupported: false,
  140. wantKnown: false,
  141. },
  142. }
  143. for _, tt := range tests {
  144. t.Run(tt.name, func(t *testing.T) {
  145. gotSupported, gotKnown := tt.account.OpenAICompactSupportKnown()
  146. if gotSupported != tt.wantSupported || gotKnown != tt.wantKnown {
  147. t.Fatalf("OpenAICompactSupportKnown() = (%v, %v), want (%v, %v)", gotSupported, gotKnown, tt.wantSupported, tt.wantKnown)
  148. }
  149. })
  150. }
  151. }
  152. func TestAccountAllowsOpenAICompact(t *testing.T) {
  153. tests := []struct {
  154. name string
  155. account *Account
  156. want bool
  157. }{
  158. {
  159. name: "nil account does not allow compact",
  160. want: false,
  161. },
  162. {
  163. name: "non openai account does not allow compact",
  164. account: &Account{
  165. Platform: PlatformAnthropic,
  166. },
  167. want: false,
  168. },
  169. {
  170. name: "unknown openai account remains allowed",
  171. account: &Account{
  172. Platform: PlatformOpenAI,
  173. Extra: map[string]any{},
  174. },
  175. want: true,
  176. },
  177. {
  178. name: "supported openai account is allowed",
  179. account: &Account{
  180. Platform: PlatformOpenAI,
  181. Extra: map[string]any{"openai_compact_supported": true},
  182. },
  183. want: true,
  184. },
  185. {
  186. name: "unsupported openai account is rejected",
  187. account: &Account{
  188. Platform: PlatformOpenAI,
  189. Extra: map[string]any{"openai_compact_supported": false},
  190. },
  191. want: false,
  192. },
  193. {
  194. name: "force on is allowed",
  195. account: &Account{
  196. Platform: PlatformOpenAI,
  197. Extra: map[string]any{"openai_compact_mode": OpenAICompactModeForceOn},
  198. },
  199. want: true,
  200. },
  201. {
  202. name: "force off is rejected",
  203. account: &Account{
  204. Platform: PlatformOpenAI,
  205. Extra: map[string]any{"openai_compact_mode": OpenAICompactModeForceOff},
  206. },
  207. want: false,
  208. },
  209. }
  210. for _, tt := range tests {
  211. t.Run(tt.name, func(t *testing.T) {
  212. if got := tt.account.AllowsOpenAICompact(); got != tt.want {
  213. t.Fatalf("AllowsOpenAICompact() = %v, want %v", got, tt.want)
  214. }
  215. })
  216. }
  217. }
  218. func TestAccountGetCompactModelMapping(t *testing.T) {
  219. tests := []struct {
  220. name string
  221. account *Account
  222. want map[string]string
  223. }{
  224. {
  225. name: "nil account returns nil",
  226. want: nil,
  227. },
  228. {
  229. name: "missing credentials returns nil",
  230. account: &Account{
  231. Platform: PlatformOpenAI,
  232. },
  233. want: nil,
  234. },
  235. {
  236. name: "map any is converted",
  237. account: &Account{
  238. Credentials: map[string]any{
  239. "compact_model_mapping": map[string]any{
  240. "gpt-5.4": "gpt-5.4-openai-compact",
  241. "invalid": 1,
  242. },
  243. },
  244. },
  245. want: map[string]string{
  246. "gpt-5.4": "gpt-5.4-openai-compact",
  247. },
  248. },
  249. {
  250. name: "map string string is copied",
  251. account: &Account{
  252. Credentials: map[string]any{
  253. "compact_model_mapping": map[string]string{
  254. "gpt-*": "compact-*",
  255. },
  256. },
  257. },
  258. want: map[string]string{
  259. "gpt-*": "compact-*",
  260. },
  261. },
  262. }
  263. for _, tt := range tests {
  264. t.Run(tt.name, func(t *testing.T) {
  265. got := tt.account.GetCompactModelMapping()
  266. if !equalStringMap(got, tt.want) {
  267. t.Fatalf("GetCompactModelMapping() = %#v, want %#v", got, tt.want)
  268. }
  269. })
  270. }
  271. }
  272. func TestAccountResolveCompactMappedModel(t *testing.T) {
  273. tests := []struct {
  274. name string
  275. credentials map[string]any
  276. requestedModel string
  277. expectedModel string
  278. expectedMatch bool
  279. }{
  280. {
  281. name: "no compact mapping reports unmatched",
  282. credentials: nil,
  283. requestedModel: "gpt-5.4",
  284. expectedModel: "gpt-5.4",
  285. expectedMatch: false,
  286. },
  287. {
  288. name: "exact compact mapping matches",
  289. credentials: map[string]any{
  290. "compact_model_mapping": map[string]any{
  291. "gpt-5.4": "gpt-5.4-openai-compact",
  292. },
  293. },
  294. requestedModel: "gpt-5.4",
  295. expectedModel: "gpt-5.4-openai-compact",
  296. expectedMatch: true,
  297. },
  298. {
  299. name: "exact passthrough counts as match",
  300. credentials: map[string]any{
  301. "compact_model_mapping": map[string]any{
  302. "gpt-5.4": "gpt-5.4",
  303. },
  304. },
  305. requestedModel: "gpt-5.4",
  306. expectedModel: "gpt-5.4",
  307. expectedMatch: true,
  308. },
  309. {
  310. name: "longest wildcard wins",
  311. credentials: map[string]any{
  312. "compact_model_mapping": map[string]any{
  313. "gpt-*": "fallback-compact",
  314. "gpt-5.4*": "gpt-5.4-openai-compact",
  315. "gpt-5.4-mini*": "gpt-5.4-mini-openai-compact",
  316. },
  317. },
  318. requestedModel: "gpt-5.4-mini",
  319. expectedModel: "gpt-5.4-mini-openai-compact",
  320. expectedMatch: true,
  321. },
  322. {
  323. name: "missing compact mapping reports unmatched",
  324. credentials: map[string]any{
  325. "compact_model_mapping": map[string]any{
  326. "gpt-5.3": "gpt-5.3-openai-compact",
  327. },
  328. },
  329. requestedModel: "gpt-5.4",
  330. expectedModel: "gpt-5.4",
  331. expectedMatch: false,
  332. },
  333. }
  334. for _, tt := range tests {
  335. t.Run(tt.name, func(t *testing.T) {
  336. account := &Account{
  337. Platform: PlatformOpenAI,
  338. Credentials: tt.credentials,
  339. }
  340. gotModel, gotMatch := account.ResolveCompactMappedModel(tt.requestedModel)
  341. if gotModel != tt.expectedModel || gotMatch != tt.expectedMatch {
  342. t.Fatalf("ResolveCompactMappedModel(%q) = (%q, %v), want (%q, %v)", tt.requestedModel, gotModel, gotMatch, tt.expectedModel, tt.expectedMatch)
  343. }
  344. })
  345. }
  346. }
  347. func equalStringMap(left, right map[string]string) bool {
  348. if len(left) != len(right) {
  349. return false
  350. }
  351. for key, want := range right {
  352. if got, ok := left[key]; !ok || got != want {
  353. return false
  354. }
  355. }
  356. return true
  357. }