gemini_upstream_url_test.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. package service
  2. import (
  3. "testing"
  4. "github.com/stretchr/testify/require"
  5. )
  6. func TestBuildGeminiAIStudioModelActionURL(t *testing.T) {
  7. const base = "https://generativelanguage.googleapis.com"
  8. got, err := buildGeminiAIStudioModelActionURL(base, "gemini-2.5-pro", "generateContent", false)
  9. require.NoError(t, err)
  10. require.Equal(t, base+"/v1beta/models/gemini-2.5-pro:generateContent", got)
  11. got, err = buildGeminiAIStudioModelActionURL(base+"/", " gemini-2.5-flash ", "streamGenerateContent", true)
  12. require.NoError(t, err)
  13. require.Equal(t, base+"/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse", got)
  14. got, err = buildGeminiAIStudioModelActionURL(base, "gemini-2.5-pro", "countTokens", false)
  15. require.NoError(t, err)
  16. require.Equal(t, base+"/v1beta/models/gemini-2.5-pro:countTokens", got)
  17. }
  18. // TestBuildGeminiAIStudioModelActionURLRejectsNonConformingModel 锁定不变式:
  19. // 模型名来自客户端(native 路由的 URL 片段 / compat 路由的请求体),
  20. // 只有合规的路径片段才允许拼进上游 URL。
  21. func TestBuildGeminiAIStudioModelActionURLRejectsNonConformingModel(t *testing.T) {
  22. const base = "https://generativelanguage.googleapis.com"
  23. for _, model := range []string{
  24. "../../x/y",
  25. "..",
  26. ".",
  27. "gemini-2.5-pro/../../x",
  28. `..\..\x`,
  29. "gemini-2.5-pro?a=b",
  30. "gemini-2.5-pro#frag",
  31. "gemini-2.5-pro%2f..",
  32. "gemini 2.5 pro",
  33. "gemini\x00pro",
  34. "gemini-2.5-pro@001",
  35. "gemini~pro",
  36. "models/gemini-2.5-pro",
  37. "...",
  38. "",
  39. " ",
  40. } {
  41. t.Run("model_"+model, func(t *testing.T) {
  42. _, err := buildGeminiAIStudioModelActionURL(base, model, "generateContent", false)
  43. require.Error(t, err, "model %q must be rejected", model)
  44. require.False(t, IsSafeGeminiModelPathSegment(model))
  45. })
  46. }
  47. // action 只允许已知取值,避免未来把可变字符串拼进 path。
  48. _, err := buildGeminiAIStudioModelActionURL(base, "gemini-2.5-pro", "deleteModel", false)
  49. require.Error(t, err)
  50. _, err = buildGeminiAIStudioModelActionURL("", "gemini-2.5-pro", "generateContent", false)
  51. require.Error(t, err)
  52. }