Files
ez-api/internal/service/model_registry_check_test.go
zenfun dea8363e41 refactor(api): split Provider into ProviderGroup and APIKey models
Restructure the provider management system by separating the monolithic
Provider model into two distinct entities:

- ProviderGroup: defines shared upstream configuration (type, base_url,
  google settings, models, status)
- APIKey: represents individual credentials within a group (api_key,
  weight, status, auto_ban, ban settings)

This change also updates:
- Binding model to reference GroupID instead of RouteGroup string
- All CRUD handlers for the new provider-group and api-key endpoints
- Sync service to rebuild provider snapshots from joined tables
- Model registry to aggregate capabilities across group/key pairs
- Access handler to validate namespace existence and subset constraints
- Migration importer to handle the new schema structure
- All related tests to use the new model relationships

BREAKING CHANGE: Provider API endpoints replaced with /provider-groups
and /api-keys endpoints; Binding.RouteGroup replaced with Binding.GroupID
2025-12-24 02:15:52 +08:00

76 lines
2.0 KiB
Go

package service
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/ez-api/ez-api/internal/model"
"github.com/redis/go-redis/v9"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func TestModelRegistry_Check(t *testing.T) {
t.Parallel()
dsn := fmt.Sprintf("file:%s?mode=memory&cache=shared", t.Name())
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})
if err != nil {
t.Fatalf("open sqlite: %v", err)
}
if err := db.AutoMigrate(&model.ProviderGroup{}, &model.APIKey{}, &model.Binding{}, &model.Model{}); err != nil {
t.Fatalf("migrate: %v", err)
}
const latestSHA = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/repos/sst/models.dev/commits/dev" {
http.NotFound(w, r)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"sha":"` + latestSHA + `"}`))
}))
defer srv.Close()
mr := miniredis.RunT(t)
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
// Prefix-matching should treat short current as up-to-date.
mr.HSet("meta:models_meta", "version", "aaaaaaaa")
mr.HSet("meta:models_meta", "upstream_ref", "dev")
svc := NewModelRegistryService(db, rdb, ModelRegistryConfig{
Enabled: true,
RefreshEvery: time.Hour,
ModelsDevAPIBaseURL: srv.URL,
ModelsDevRef: "dev",
Timeout: 5 * time.Second,
})
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
out, err := svc.Check(ctx, "")
if err != nil {
t.Fatalf("check: %v", err)
}
if out.NeedsRefresh {
t.Fatalf("expected needs_refresh=false, got true (current=%q latest=%q)", out.CurrentVersion, out.LatestVersion)
}
mr.HSet("meta:models_meta", "version", "bbbbbbbb")
out, err = svc.Check(ctx, "dev")
if err != nil {
t.Fatalf("check2: %v", err)
}
if !out.NeedsRefresh {
t.Fatalf("expected needs_refresh=true, got false (current=%q latest=%q)", out.CurrentVersion, out.LatestVersion)
}
}