25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

132 lines
5.5 KiB

  1. package service
  2. import (
  3. "net/http"
  4. "net/url"
  5. "strings"
  6. "testing"
  7. "github.com/QuantumNous/new-api/constant"
  8. "github.com/QuantumNous/new-api/model"
  9. "github.com/stretchr/testify/require"
  10. )
  11. func TestDoubaoVideoAssetAdapter_SupportsAllOperations(t *testing.T) {
  12. adapter := NewDoubaoVideoAssetAdapter()
  13. require.Equal(t, "doubao_video_asset", adapter.Name())
  14. for _, op := range []AssetOperation{
  15. AssetOperationAssetCreate,
  16. AssetOperationAssetList,
  17. AssetOperationAssetGet,
  18. AssetOperationAssetUpdate,
  19. AssetOperationAssetDelete,
  20. AssetOperationAssetGroupCreate,
  21. AssetOperationAssetGroupList,
  22. AssetOperationAssetGroupGet,
  23. AssetOperationAssetGroupUpdate,
  24. AssetOperationAssetGroupDelete,
  25. } {
  26. require.True(t, adapter.Supports(op), "operation %s should be supported", op)
  27. }
  28. }
  29. func TestBuildDoubaoVideoAssetURL(t *testing.T) {
  30. db := setupDoubaoAssetChannelDB(t)
  31. require.NoError(t, db.AutoMigrate(&model.ChannelAssetCredential{}))
  32. channel := &model.Channel{Type: constant.ChannelTypeDoubaoVideo}
  33. rawURL, rawQuery, err := buildDoubaoVideoAssetURL(channel, "ListAssets", "")
  34. require.NoError(t, err)
  35. require.Equal(t, "Action=ListAssets&Version=2024-01-01", rawQuery)
  36. parsed, err := url.Parse(rawURL)
  37. require.NoError(t, err)
  38. require.Equal(t, "/openApi/portrait", parsed.Path)
  39. require.Equal(t, "Action=ListAssets&Version=2024-01-01", parsed.RawQuery)
  40. }
  41. func TestBuildDoubaoVideoAssetURL_DedicatedCredentialBaseWins(t *testing.T) {
  42. db := setupDoubaoAssetChannelDB(t)
  43. require.NoError(t, db.AutoMigrate(&model.ChannelAssetCredential{}))
  44. require.NoError(t, model.UpsertChannelAssetCredential(&model.ChannelAssetCredential{
  45. ChannelId: 26,
  46. AccessKey: "AK",
  47. SecretKey: "SK",
  48. BaseURL: "http://14.103.147.238:19220/openApi/portrait",
  49. }))
  50. channel := &model.Channel{Id: 26, Type: constant.ChannelTypeDoubaoVideo}
  51. rawURL, _, err := buildDoubaoVideoAssetURL(channel, "ListAssets", "")
  52. require.NoError(t, err)
  53. require.Equal(t, "http://14.103.147.238:19220/openApi/portrait?Action=ListAssets&Version=2024-01-01", rawURL)
  54. }
  55. func TestBuildDoubaoVideoAssetURL_HardcodedOverrideWinsOverCredential(t *testing.T) {
  56. db := setupDoubaoAssetChannelDB(t)
  57. require.NoError(t, db.AutoMigrate(&model.ChannelAssetCredential{}))
  58. require.NoError(t, model.UpsertChannelAssetCredential(&model.ChannelAssetCredential{
  59. ChannelId: 26,
  60. AccessKey: "AK",
  61. SecretKey: "SK",
  62. BaseURL: "http://credential.example/openApi/portrait",
  63. }))
  64. old := doubaoVideoAssetEndpointOverride
  65. doubaoVideoAssetEndpointOverride = "http://override.example:19220/openApi/portrait"
  66. defer func() { doubaoVideoAssetEndpointOverride = old }()
  67. channel := &model.Channel{Id: 26, Type: constant.ChannelTypeDoubaoVideo}
  68. rawURL, _, err := buildDoubaoVideoAssetURL(channel, "ListAssets", "")
  69. require.NoError(t, err)
  70. require.Equal(t, "http://override.example:19220/openApi/portrait?Action=ListAssets&Version=2024-01-01", rawURL)
  71. }
  72. func TestBuildDoubaoVideoAssetURL_FallsBackToOfficialDefault(t *testing.T) {
  73. db := setupDoubaoAssetChannelDB(t)
  74. require.NoError(t, db.AutoMigrate(&model.ChannelAssetCredential{}))
  75. channel := &model.Channel{Id: 26, Type: constant.ChannelTypeDoubaoVideo}
  76. rawURL, _, err := buildDoubaoVideoAssetURL(channel, "ListAssets", "")
  77. require.NoError(t, err)
  78. require.Equal(t, "https://ark.cn-beijing.volces.com/openApi/portrait?Action=ListAssets&Version=2024-01-01", rawURL)
  79. }
  80. func TestSignDoubaoVideoAssetRequest_HeaderShape(t *testing.T) {
  81. req, err := http.NewRequest(http.MethodPost, "http://14.103.147.238:19220/openApi/portrait?Action=ListAssets&Version=2024-01-01", nil)
  82. require.NoError(t, err)
  83. signDoubaoVideoAssetRequest(req, "AK-test", "SK-test", []byte(`{"Filter":{"GroupType":"AIGC"}}`), "Action=ListAssets&Version=2024-01-01")
  84. auth := req.Header.Get("Authorization")
  85. require.True(t, strings.HasPrefix(auth, "HMAC-SHA256 Credential=AK-test/"), "got %s", auth)
  86. require.Contains(t, auth, "/cn-beijing/ark/request, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature=")
  87. require.NotEmpty(t, req.Header.Get("X-Date"))
  88. require.Len(t, req.Header.Get("X-Date"), 16)
  89. require.Equal(t, "application/json", req.Header.Get("Content-Type"))
  90. // body hash header must be the hex sha256 of the raw body
  91. require.Regexp(t, `^[0-9a-f]{64}$`, req.Header.Get("X-Content-Sha256"))
  92. }
  93. // The signature must change when any signed input changes (body, key, date).
  94. func TestSignDoubaoVideoAssetRequest_DeterministicPerInputs(t *testing.T) {
  95. build := func(body string) string {
  96. req, _ := http.NewRequest(http.MethodPost, "http://h/openApi/portrait?Action=A&Version=2024-01-01", nil)
  97. signDoubaoVideoAssetRequest(req, "AK", "SK", []byte(body), "Action=A&Version=2024-01-01")
  98. return req.Header.Get("Authorization")
  99. }
  100. sig1 := build(`{"a":1}`)
  101. sig2 := build(`{"a":1}`)
  102. sig3 := build(`{"a":2}`)
  103. require.Equal(t, sig1[strings.Index(sig1, "Signature="):], sig2[strings.Index(sig2, "Signature="):])
  104. require.NotEqual(t, sig1[strings.Index(sig1, "Signature="):], sig3[strings.Index(sig3, "Signature="):])
  105. }
  106. func TestDoubaoVideoAssetAdapter_MissingCredential(t *testing.T) {
  107. db := setupDoubaoAssetChannelDB(t)
  108. require.NoError(t, db.AutoMigrate(&model.ChannelAssetCredential{}))
  109. adapter := NewDoubaoVideoAssetAdapter()
  110. channel := &model.Channel{Id: 999999, Type: constant.ChannelTypeDoubaoVideo}
  111. _, assetErr := adapter.DoAssetRequest(t.Context(), channel, AssetRequest{
  112. Action: AssetActionSpec{Action: "ListAssets", Operation: AssetOperationAssetList},
  113. RawBody: []byte(`{}`),
  114. })
  115. require.NotNil(t, assetErr)
  116. require.Contains(t, assetErr.Message, "AccessKey and SecretKey are required")
  117. }