2026-03-14 12:45:10 +08:00
package admin
import (
"context"
"encoding/json"
2026-05-18 19:01:33 +08:00
"io"
2026-03-14 12:45:10 +08:00
"net/http"
"net/http/httptest"
2026-05-18 19:01:33 +08:00
"strings"
2026-03-14 12:45:10 +08:00
"testing"
2026-05-18 19:01:33 +08:00
"github.com/Wei-Shaw/sub2api/internal/config"
2026-10-03 20:24:38 +08:00
"github.com/Wei-Shaw/sub2api/internal/pkg/antigravity"
2026-05-18 19:01:33 +08:00
"github.com/Wei-Shaw/sub2api/internal/pkg/tlsfingerprint"
2026-03-14 12:45:10 +08:00
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/require"
)
type availableModelsAdminService struct {
* stubAdminService
account service . Account
}
func ( s * availableModelsAdminService ) GetAccount ( _ context . Context , id int64 ) ( * service . Account , error ) {
if s . account . ID == id {
acc := s . account
return & acc , nil
}
return s . stubAdminService . GetAccount ( context . Background (), id )
}
func setupAvailableModelsRouter ( adminSvc service . AdminService ) * gin . Engine {
gin . SetMode ( gin . TestMode )
router := gin . New ()
2026-07-14 13:33:42 +08:00
handler := NewAccountHandler ( adminSvc , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil , nil )
2026-03-14 12:45:10 +08:00
router . GET ( "/api/v1/admin/accounts/:id/models" , handler . GetAvailableModels )
return router
}
2026-05-18 19:01:33 +08:00
type syncUpstreamHTTPUpstream struct {
2026-08-22 14:46:40 +09:00
resp * http . Response
responses [] * http . Response
err error
2026-05-18 19:01:33 +08:00
}
func ( u * syncUpstreamHTTPUpstream ) Do ( req * http . Request , proxyURL string , accountID int64 , accountConcurrency int ) ( * http . Response , error ) {
if u . err != nil {
return nil , u . err
}
2026-08-22 14:46:40 +09:00
if len ( u . responses ) > 0 {
resp := u . responses [ 0 ]
u . responses = u . responses [ 1 :]
return resp , nil
}
2026-05-18 19:01:33 +08:00
return u . resp , nil
}
func ( u * syncUpstreamHTTPUpstream ) DoWithTLS ( req * http . Request , proxyURL string , accountID int64 , accountConcurrency int , profile * tlsfingerprint . Profile ) ( * http . Response , error ) {
return u . Do ( req , proxyURL , accountID , accountConcurrency )
}
func setupSyncUpstreamModelsRouter ( adminSvc service . AdminService , upstream service . HTTPUpstream ) * gin . Engine {
gin . SetMode ( gin . TestMode )
router := gin . New ()
accountTestSvc := service . NewAccountTestService (
nil ,
nil ,
nil ,
nil ,
2026-06-29 17:53:19 +08:00
nil ,
2026-05-18 19:01:33 +08:00
upstream ,
& config . Config { Security : config . SecurityConfig { URLAllowlist : config . URLAllowlistConfig { Enabled : false }}},
nil ,
)
2026-07-14 13:33:42 +08:00
handler := NewAccountHandler ( adminSvc , nil , nil , nil , nil , nil , nil , nil , accountTestSvc , nil , nil , nil , nil , nil )
2026-05-18 19:01:33 +08:00
router . POST ( "/api/v1/admin/accounts/:id/models/sync-upstream" , handler . SyncUpstreamModels )
2026-08-26 12:46:31 +09:00
router . POST ( "/api/v1/admin/accounts/models/sync-upstream-preview" , handler . SyncUpstreamModelsPreview )
2026-05-18 19:01:33 +08:00
return router
}
2026-06-29 17:53:19 +08:00
func TestAccountHandlerGetAvailableModels_GrokUsesXAIModels ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 44 ,
Name : "grok-oauth" ,
Platform : service . PlatformGrok ,
Type : service . AccountTypeOAuth ,
Status : service . StatusActive ,
Credentials : map [ string ] any {
"model_mapping" : map [ string ] any {
"grok-4.3" : "grok-4.3" ,
},
},
},
}
router := setupAvailableModelsRouter ( svc )
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodGet , "/api/v1/admin/accounts/44/models" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data [] struct {
ID string `json:"id"`
} `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
require . Len ( t , resp . Data , 1 )
require . Equal ( t , "grok-4.3" , resp . Data [ 0 ]. ID )
}
func TestAccountHandlerGetAvailableModels_GrokDefaultsToXAIModelsWithoutMapping ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 45 ,
Name : "grok-oauth-defaults" ,
Platform : service . PlatformGrok ,
Type : service . AccountTypeOAuth ,
Status : service . StatusActive ,
},
}
router := setupAvailableModelsRouter ( svc )
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodGet , "/api/v1/admin/accounts/45/models" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data [] struct {
ID string `json:"id"`
} `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
require . NotEmpty ( t , resp . Data )
var ids [] string
for _ , model := range resp . Data {
id := model . ID
ids = append ( ids , id )
require . NotContains ( t , strings . ToLower ( id ), "claude" )
}
require . Contains ( t , ids , "grok-4.3" )
require . Contains ( t , ids , "grok-build-0.1" )
}
2026-03-14 12:45:10 +08:00
func TestAccountHandlerGetAvailableModels_OpenAIOAuthUsesExplicitModelMapping ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 42 ,
Name : "openai-oauth" ,
Platform : service . PlatformOpenAI ,
Type : service . AccountTypeOAuth ,
Status : service . StatusActive ,
Credentials : map [ string ] any {
"model_mapping" : map [ string ] any {
"gpt-5" : "gpt-5.1" ,
},
},
},
}
router := setupAvailableModelsRouter ( svc )
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodGet , "/api/v1/admin/accounts/42/models" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data [] struct {
ID string `json:"id"`
} `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
require . Len ( t , resp . Data , 1 )
require . Equal ( t , "gpt-5" , resp . Data [ 0 ]. ID )
}
func TestAccountHandlerGetAvailableModels_OpenAIOAuthPassthroughFallsBackToDefaults ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 43 ,
Name : "openai-oauth-passthrough" ,
Platform : service . PlatformOpenAI ,
Type : service . AccountTypeOAuth ,
Status : service . StatusActive ,
Credentials : map [ string ] any {
"model_mapping" : map [ string ] any {
"gpt-5" : "gpt-5.1" ,
},
},
Extra : map [ string ] any {
"openai_passthrough" : true ,
},
},
}
router := setupAvailableModelsRouter ( svc )
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodGet , "/api/v1/admin/accounts/43/models" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data [] struct {
ID string `json:"id"`
} `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
require . NotEmpty ( t , resp . Data )
require . NotEqual ( t , "gpt-5" , resp . Data [ 0 ]. ID )
}
2026-05-18 19:01:33 +08:00
2026-07-23 13:44:15 +08:00
func TestAccountHandlerGetAvailableModels_OpenAIAPIKeyDefaultsToConcreteGPT56Sol ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 46 ,
Name : "openai-apikey" ,
Platform : service . PlatformOpenAI ,
Type : service . AccountTypeAPIKey ,
Status : service . StatusActive ,
Credentials : map [ string ] any {
"api_key" : "test-key" ,
},
},
}
router := setupAvailableModelsRouter ( svc )
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodGet , "/api/v1/admin/accounts/46/models" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data [] struct {
ID string `json:"id"`
} `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
require . NotEmpty ( t , resp . Data )
require . Equal ( t , "gpt-5.6-sol" , resp . Data [ 0 ]. ID )
}
2026-06-30 21:32:02 +08:00
func TestAccountHandlerGetAvailableModels_OpenAISparkShadowReturnsMappingModels ( t * testing . T ) {
parentID := int64 ( 100 )
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 44 ,
Name : "openai-spark-shadow" ,
Platform : service . PlatformOpenAI ,
Type : service . AccountTypeOAuth ,
Status : service . StatusActive ,
ParentAccountID : & parentID ,
QuotaDimension : service . QuotaDimensionSpark ,
Credentials : map [ string ] any {
"model_mapping" : map [ string ] any {
"gpt-5.3-codex-spark" : "gpt-5.3-codex-spark" ,
},
},
},
}
router := setupAvailableModelsRouter ( svc )
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodGet , "/api/v1/admin/accounts/44/models" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data [] struct {
ID string `json:"id"`
} `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
ids := make ([] string , 0 , len ( resp . Data ))
for _ , m := range resp . Data {
ids = append ( ids , m . ID )
}
require . ElementsMatch ( t , [] string {
"gpt-5.3-codex-spark" ,
}, ids , "影子可用模型由 model_mapping 派生(非写死)" )
}
2026-08-21 02:33:00 +08:00
func TestAccountHandlerGetAvailableModels_GeminiGoogleOneUsesConservativeCatalog ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 45 ,
Name : "google-one" ,
Platform : service . PlatformGemini ,
Type : service . AccountTypeOAuth ,
Status : service . StatusActive ,
Credentials : map [ string ] any {
"oauth_type" : "google_one" ,
},
},
}
router := setupAvailableModelsRouter ( svc )
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodGet , "/api/v1/admin/accounts/45/models" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data [] struct {
ID string `json:"id"`
} `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
ids := make ([] string , 0 , len ( resp . Data ))
for _ , model := range resp . Data {
ids = append ( ids , model . ID )
}
require . ElementsMatch ( t , [] string { "gemini-2.0-flash" , "gemini-2.5-flash" , "gemini-2.5-pro" }, ids )
require . NotContains ( t , ids , "gemini-3.5-flash" )
require . NotContains ( t , ids , "gemini-2.5-flash-image" )
}
2026-10-03 20:24:38 +08:00
func TestAccountHandlerGetAvailableModels_Antigravity ( t * testing . T ) {
defaults := antigravity . DefaultModels ()
known := defaults [ 0 ]
custom := antigravity . ClaudeModel { ID : "claude-custom-alias" , Type : "model" , DisplayName : "claude-custom-alias" }
cases := [] struct {
name string
credentials map [ string ] any
want [] antigravity . ClaudeModel
}{
{ name : "nil credentials" , want : defaults },
{ name : "missing mapping" , credentials : map [ string ] any {}, want : defaults },
{ name : "empty JSON mapping" , credentials : map [ string ] any { "model_mapping" : map [ string ] any {}}, want : defaults },
{ name : "empty string mapping" , credentials : map [ string ] any { "model_mapping" : map [ string ] string {}}, want : defaults },
{ name : "blank key" , credentials : map [ string ] any { "model_mapping" : map [ string ] any { " " : "upstream-model" }}, want : defaults },
2026-10-15 02:06:23 +09:00
{ name : "wildcard only falls back to defaults" , credentials : map [ string ] any { "model_mapping" : map [ string ] any { "claude-*" : "claude-sonnet-4-6" , "gemini-3*" : "gemini-3-flash" }}, want : defaults },
{ name : "JSON mapping keys and metadata skips wildcards" , credentials : map [ string ] any { "model_mapping" : map [ string ] any {
known . ID : known . ID , custom . ID : "upstream-model" , "claude-*" : "claude-sonnet-4-6" ,
2026-10-03 20:24:38 +08:00
}}, want : [] antigravity . ClaudeModel { custom , known }},
2026-10-15 02:06:23 +09:00
{ name : "string mapping keys and metadata skips wildcards" , credentials : map [ string ] any { "model_mapping" : map [ string ] string {
known . ID : known . ID , custom . ID : "upstream-model" , "gemini-*" : "gemini-3-flash" ,
2026-10-03 20:24:38 +08:00
}}, want : [] antigravity . ClaudeModel { custom , known }},
}
for _ , tc := range cases {
t . Run ( tc . name , func ( t * testing . T ) {
for _ , accountType := range [] string { service . AccountTypeOAuth , service . AccountTypeAPIKey } {
t . Run ( accountType , func ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account { ID : 51 , Platform : service . PlatformAntigravity , Type : accountType , Credentials : tc . credentials },
}
rec := httptest . NewRecorder ()
setupAvailableModelsRouter ( svc ). ServeHTTP ( rec , httptest . NewRequest ( http . MethodGet , "/api/v1/admin/accounts/51/models" , nil ))
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data [] antigravity . ClaudeModel `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
require . Equal ( t , tc . want , resp . Data )
})
}
})
}
}
2026-05-18 19:01:33 +08:00
func TestAccountHandlerSyncUpstreamModels_ConfigErrorReturnsBadRequest ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 44 ,
Name : "openai-apikey-missing-key" ,
Platform : service . PlatformOpenAI ,
Type : service . AccountTypeAPIKey ,
Status : service . StatusActive ,
Credentials : map [ string ] any {
"base_url" : "https://openai.example.com/v1" ,
},
},
}
router := setupSyncUpstreamModelsRouter ( svc , & syncUpstreamHTTPUpstream {})
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodPost , "/api/v1/admin/accounts/44/models/sync-upstream" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusBadRequest , rec . Code )
require . Contains ( t , rec . Body . String (), "No OpenAI API key is available" )
}
2026-08-22 14:46:40 +09:00
func TestAccountHandlerSyncUpstreamModelsReturnsCapabilityMetadata ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 48 , Name : "custom-openai" , Platform : service . PlatformOpenAI ,
Type : service . AccountTypeAPIKey , Status : service . StatusActive ,
Credentials : map [ string ] any { "api_key" : "key" , "base_url" : "https://provider.example/v1" },
},
}
upstream := & syncUpstreamHTTPUpstream { resp : & http . Response {
StatusCode : http . StatusOK ,
Header : http . Header { "Content-Type" : [] string { "application/json" }},
Body : io . NopCloser ( strings . NewReader ( `{"models":[{
"id":"custom-thinking-model",
"reasoning":true,
"default_reasoning_level":"high",
"supported_reasoning_levels":["low","high"],
"input_modalities":["text","image"],
"context_window":256000
}]}` )),
}}
router := setupSyncUpstreamModelsRouter ( svc , upstream )
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodPost , "/api/v1/admin/accounts/48/models/sync-upstream" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data service . UpstreamModelCatalog `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
require . Equal ( t , [] string { "custom-thinking-model" }, resp . Data . Models )
metadata := resp . Data . Metadata [ "custom-thinking-model" ]
require . NotNil ( t , metadata . Reasoning )
require . True ( t , * metadata . Reasoning )
require . Equal ( t , [] string { "low" , "high" }, metadata . SupportedReasoningLevels )
require . Equal ( t , [] string { "text" , "image" }, metadata . InputModalities )
}
2026-08-26 12:46:31 +09:00
// Scenario: 创建账号 preview 将具体 mapping 传给 404/405 配置回退。
func TestAccountHandlerSyncUpstreamModelsPreviewUsesProvidedModelMapping ( t * testing . T ) {
upstream := & syncUpstreamHTTPUpstream { responses : [] * http . Response {
{
StatusCode : http . StatusNotFound ,
Header : http . Header { "Content-Type" : [] string { "application/json" }},
Body : io . NopCloser ( strings . NewReader ( `{"error":"not found"}` )),
},
{
StatusCode : http . StatusOK ,
Header : http . Header { "Content-Type" : [] string { "application/json" }},
Body : io . NopCloser ( strings . NewReader ( `{
"configured-provider": {
"api": "https://provider.example/v1",
"models": {
"glm-5.3": {
"id": "glm-5.3",
"reasoning": true,
"reasoning_options": [{"type":"effort","values":["low","high"]}],
"modalities": {"input":["text"],"output":["text"]},
"limit": {"context":1000000,"output":131072}
}
}
}
}` )),
},
}}
router := setupSyncUpstreamModelsRouter ( newStubAdminService (), upstream )
rec := httptest . NewRecorder ()
req := httptest . NewRequest (
http . MethodPost ,
"/api/v1/admin/accounts/models/sync-upstream-preview" ,
strings . NewReader ( `{
"platform":"openai",
"type":"apikey",
"base_url":"https://provider.example/v1",
"api_key":"key",
"model_mapping":{"public-glm":"glm-5.3"}
}` ),
)
req . Header . Set ( "Content-Type" , "application/json" )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data service . UpstreamModelCatalog `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
require . Equal ( t , [] string { "glm-5.3" }, resp . Data . Models )
require . Equal ( t , [] string { "low" , "high" }, resp . Data . Metadata [ "glm-5.3" ]. SupportedReasoningLevels )
}
2026-05-18 19:01:33 +08:00
func TestAccountHandlerSyncUpstreamModels_UpstreamErrorDoesNotExposeBody ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 45 ,
Name : "openai-apikey-upstream-error" ,
Platform : service . PlatformOpenAI ,
Type : service . AccountTypeAPIKey ,
Status : service . StatusActive ,
Credentials : map [ string ] any {
"api_key" : "openai-key" ,
"base_url" : "https://openai.example.com/v1" ,
},
},
}
upstream := & syncUpstreamHTTPUpstream { resp : & http . Response {
StatusCode : http . StatusBadGateway ,
Header : http . Header { "Content-Type" : [] string { "application/json" }},
Body : io . NopCloser ( strings . NewReader ( `{"error":"SECRET_TOKEN should not be exposed"}` )),
}}
router := setupSyncUpstreamModelsRouter ( svc , upstream )
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodPost , "/api/v1/admin/accounts/45/models/sync-upstream" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusBadGateway , rec . Code )
require . Contains ( t , rec . Body . String (), "Upstream model list request failed with HTTP 502" )
require . NotContains ( t , rec . Body . String (), "SECRET_TOKEN" )
}
2026-08-22 14:46:40 +09:00
// Scenario: 能力补全失败显示部分成功。
func TestAccountHandlerSyncUpstreamModels_MetadataEnrichmentFailureReturnsWarning ( t * testing . T ) {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 46 ,
Name : "opencode-id-only-model-list" ,
Platform : service . PlatformOpenAI ,
Type : service . AccountTypeAPIKey ,
Status : service . StatusActive ,
Credentials : map [ string ] any {
"api_key" : "opencode-key" ,
"base_url" : "https://opencode.ai/zen/v1" ,
},
},
}
upstream := & syncUpstreamHTTPUpstream { responses : [] * http . Response {
{
StatusCode : http . StatusOK ,
Header : http . Header { "Content-Type" : [] string { "application/json" }},
Body : io . NopCloser ( strings . NewReader ( `{"data":[{"id":"x-preview-f-free"}]}` )),
},
{
StatusCode : http . StatusBadGateway ,
Header : http . Header { "Content-Type" : [] string { "application/json" }},
Body : io . NopCloser ( strings . NewReader ( `{"error":"registry unavailable"}` )),
},
}}
router := setupSyncUpstreamModelsRouter ( svc , upstream )
rec := httptest . NewRecorder ()
req := httptest . NewRequest ( http . MethodPost , "/api/v1/admin/accounts/46/models/sync-upstream" , nil )
router . ServeHTTP ( rec , req )
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data struct {
Models [] string `json:"models"`
Warnings [] struct {
Code string `json:"code"`
} `json:"warnings"`
} `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
require . Equal ( t , [] string { "x-preview-f-free" }, resp . Data . Models )
require . Len ( t , resp . Data . Warnings , 1 )
require . Equal ( t , "upstream_model_metadata_incomplete" , resp . Data . Warnings [ 0 ]. Code )
}
2026-10-02 13:08:40 +08:00
func TestAccountHandlerGetAvailableModels_TypeSafeOnlyReturnsJev ( t * testing . T ) {
for _ , credentials := range [] map [ string ] any {
{ "api_key" : "ts-secret" },
{ "api_key" : "ts-secret" , "model_mapping" : map [ string ] any { "jev-latest" : "jev-latest" }},
} {
svc := & availableModelsAdminService {
stubAdminService : newStubAdminService (),
account : service . Account {
ID : 46 ,
Name : "typesafe" ,
Platform : service . PlatformTypeSafe ,
Type : service . AccountTypeAPIKey ,
Status : service . StatusActive ,
Credentials : credentials ,
},
}
router := setupAvailableModelsRouter ( svc )
rec := httptest . NewRecorder ()
router . ServeHTTP ( rec , httptest . NewRequest ( http . MethodGet , "/api/v1/admin/accounts/46/models" , nil ))
require . Equal ( t , http . StatusOK , rec . Code )
var resp struct {
Data [] struct {
ID string `json:"id"`
} `json:"data"`
}
require . NoError ( t , json . Unmarshal ( rec . Body . Bytes (), & resp ))
require . Len ( t , resp . Data , 1 )
require . Equal ( t , "jev-latest" , resp . Data [ 0 ]. ID )
}
}