修改配置编辑不了的问题
This commit is contained in:
1 parent
22b504e53e
commit
2a2f78c81e
42 files changed
+1082
-178
No files matched your search
@@ -79,14 +79,6 @@ func New(options Options) (*App, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.Backend == postgres.BackendPostgres && options.ProviderRegistry == nil {
|
||||
if err := validateProductionProviderConfiguration(getenv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if allowUnconfiguredProviders(getenv) {
|
||||
log.Printf("WARNING: %s is enabled; the Go API will start with unconfigured providers, and generation/quote requests will remain unavailable until credentials are added and the process is restarted", "ZHINIAN_ALLOW_UNCONFIGURED_PROVIDERS")
|
||||
}
|
||||
}
|
||||
database, err := postgres.Open(ctx, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -245,6 +237,9 @@ func New(options Options) (*App, error) {
|
||||
|
||||
billingService := billing.NewService(billingStore, nil).SetEnabled(strings.TrimSpace(getenv("ZHINIAN_BILLING_REQUIRED")) != "0")
|
||||
runtimeSettings := defaultSettingsService(getenv)
|
||||
if config.Backend == postgres.BackendPostgres {
|
||||
runtimeSettings = databaseSettingsService(getenv, database.Store)
|
||||
}
|
||||
billingAccounts := settingsBillingAccountStore{service: runtimeSettings}
|
||||
templateService := templates.NewService(templateCatalog, nil, nil)
|
||||
logService := options.Logs
|
||||
@@ -258,26 +253,20 @@ func New(options Options) (*App, error) {
|
||||
miscHandler, err := httpapi.NewMiscHandler(httpapi.MiscDependencies{
|
||||
Platform: platformAuthorizer, Templates: templateService, PromptAssembler: prompt.Assemble,
|
||||
Settings: runtimeSettings, Logs: logService, Public: publicAuthenticator,
|
||||
Capabilities: capabilitySummary(getenv), PublicOrigin: publicBaseURL,
|
||||
Capabilities: runtimeCapabilitySummary(getenv, runtimeSettings), PublicOrigin: publicBaseURL,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
providerRegistry := options.ProviderRegistry
|
||||
if providerRegistry == nil {
|
||||
providerRegistry = buildProviderRegistry(getenv)
|
||||
}
|
||||
var unavailableProviders map[string]string
|
||||
if config.Backend == postgres.BackendPostgres {
|
||||
unavailableProviders = providerUnavailableMessages(getenv)
|
||||
var providerResolver jobs.ProviderResolver
|
||||
if options.ProviderRegistry != nil {
|
||||
providerResolver = options.ProviderRegistry
|
||||
} else {
|
||||
providerResolver = newRuntimeProviderResolver(getenv, runtimeSettings)
|
||||
}
|
||||
jobService := jobs.NewService(jobStore, nil)
|
||||
jobBuilder := jobs.ProviderJobBuilder{
|
||||
ImageProvider: imageProvider(getenv), VideoProvider: videoProvider(getenv),
|
||||
ImageModel: imageModel(getenv), VideoModel: videoModel(getenv), ImageEngine: imageEngine(getenv), VideoEngine: videoEngine(getenv),
|
||||
ImageEngines: providerImageTargets(getenv), VideoEngines: providerVideoTargets(getenv), UnavailableProviders: unavailableProviders, NewID: applicationJobID,
|
||||
}
|
||||
jobBuilder := runtimeProviderJobBuilder{fallback: getenv, settings: runtimeSettings, enforceAvailability: config.Backend == postgres.BackendPostgres}
|
||||
usageService := usage.Service{
|
||||
Repository: usageRepository,
|
||||
OrganizationOptions: usage.OrganizationOptionSourceFunc(func(ctx context.Context, requester usage.Requester) ([]usage.Option, error) {
|
||||
@@ -306,7 +295,7 @@ func New(options Options) (*App, error) {
|
||||
}
|
||||
webhookBridge := orchestration.NewWebhookBridge(webhook.NewDeliverer(webhookSender, getenv("ZHINIAN_WEBHOOK_SECRET"), nil))
|
||||
outputs := orchestration.NewAssetOutputRegistrar(assetService, orchestration.ResolveProviderOutputURLs)
|
||||
providerProcessor := jobs.ProviderProcessor{Providers: providerRegistry, Store: jobStore}
|
||||
providerProcessor := jobs.ProviderProcessor{Providers: providerResolver, Store: jobStore}
|
||||
settlementProcessor := orchestration.NewSettlementProcessor(providerProcessor, ledger, settlementState, nil)
|
||||
processor := orchestration.NewOutputRegisteringProcessor(settlementProcessor, outputs, jobState)
|
||||
artifacts := orchestration.NewAssetArtifacts(assetService)
|
||||
@@ -330,7 +319,7 @@ func New(options Options) (*App, error) {
|
||||
workerLoop.Start(ctx)
|
||||
}
|
||||
|
||||
foundation := httpapi.NewHandler(readiness, httpapi.WithHealthDetails(runtimeHealthDetails(getenv)))
|
||||
foundation := httpapi.NewHandler(readiness, httpapi.WithHealthDetailsProvider(runtimeHealthDetailsProvider(getenv, runtimeSettings)))
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/api/auth/me", authMe)
|
||||
mux.Handle("/api/auth/password", authPassword)
|
||||
|
||||
@@ -77,15 +77,14 @@ func TestApplicationRejectsInvalidProductionDatabaseConfiguration(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProductionProviderBootstrapFlagAllowsApplicationComposition(t *testing.T) {
|
||||
func TestProductionApplicationCanStartBeforeProviderSettingsAreConfigured(t *testing.T) {
|
||||
app, err := application.New(application.Options{Getenv: applicationEnv(map[string]string{
|
||||
"NODE_ENV": "production",
|
||||
"ZHINIAN_DATA_BACKEND": "postgres",
|
||||
"DATABASE_URL": "postgres://user:password@127.0.0.1:5432/zhinian",
|
||||
"ZHINIAN_ALLOW_UNCONFIGURED_PROVIDERS": "true",
|
||||
"NODE_ENV": "production",
|
||||
"ZHINIAN_DATA_BACKEND": "postgres",
|
||||
"DATABASE_URL": "postgres://user:password@127.0.0.1:5432/zhinian",
|
||||
})})
|
||||
if err != nil {
|
||||
t.Fatalf("New() with provider bootstrap flag = %v", err)
|
||||
t.Fatalf("New() without provider credentials = %v", err)
|
||||
}
|
||||
app.Close()
|
||||
}
|
||||
|
||||
@@ -59,10 +59,6 @@ func parseBool(value string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func allowUnconfiguredProviders(getenv postgres.Getenv) bool {
|
||||
return parseBool(getenv("ZHINIAN_ALLOW_UNCONFIGURED_PROVIDERS"))
|
||||
}
|
||||
|
||||
func applicationJobID() string {
|
||||
return applicationID("job")
|
||||
}
|
||||
@@ -143,6 +139,10 @@ func bailianNativeBaseURL(getenv postgres.Getenv) string {
|
||||
func buildProviderRegistry(getenv postgres.Getenv) jobs.ProviderRegistry {
|
||||
client := &http.Client{Timeout: durationEnv(getenv, "ZHINIAN_PROVIDER_TIMEOUT_MS", 30*time.Second)}
|
||||
maximum := positiveInt64Env(getenv, "ZHINIAN_PROVIDER_MAX_RESPONSE_BYTES", 2<<20)
|
||||
return buildProviderRegistryWithClient(getenv, client, maximum)
|
||||
}
|
||||
|
||||
func buildProviderRegistryWithClient(getenv postgres.Getenv, client *http.Client, maximum int64) jobs.ProviderRegistry {
|
||||
return jobs.ProviderRegistry{
|
||||
"volcengine-visual": providers.NewVolcengine(providers.Config{
|
||||
BaseURL: firstNonEmpty(getenv("VOLCENGINE_VISUAL_ENDPOINT"), "https://visual.volcengineapi.com"),
|
||||
@@ -164,6 +164,7 @@ func providerImageTargets(getenv postgres.Getenv) map[string]jobs.ProviderTarget
|
||||
"evolink": {
|
||||
Provider: "evolink",
|
||||
Model: firstNonEmpty(getenv("EVOLINK_IMAGE_MODEL"), "gpt-image-2"),
|
||||
Settings: map[string]any{"quality": firstNonEmpty(getenv("EVOLINK_IMAGE_QUALITY"), "medium")},
|
||||
},
|
||||
"bailian": {
|
||||
Provider: "bailian",
|
||||
@@ -207,29 +208,6 @@ func providerUnavailableMessages(getenv postgres.Getenv) map[string]string {
|
||||
return missing
|
||||
}
|
||||
|
||||
func validateProductionProviderConfiguration(getenv postgres.Getenv) error {
|
||||
if allowUnconfiguredProviders(getenv) {
|
||||
return nil
|
||||
}
|
||||
missing := make([]string, 0, 4)
|
||||
if strings.TrimSpace(getenv("VOLCENGINE_ACCESS_KEY_ID")) == "" || strings.TrimSpace(getenv("VOLCENGINE_SECRET_ACCESS_KEY")) == "" {
|
||||
missing = append(missing, "即梦 VOLCENGINE_ACCESS_KEY_ID/VOLCENGINE_SECRET_ACCESS_KEY")
|
||||
}
|
||||
if strings.TrimSpace(getenv("EVOLINK_API_KEY")) == "" {
|
||||
missing = append(missing, "EvoLink EVOLINK_API_KEY")
|
||||
}
|
||||
if bailianAPIKey(getenv) == "" {
|
||||
missing = append(missing, "百炼 BAILIAN_API_KEY/DASHSCOPE_API_KEY")
|
||||
}
|
||||
if strings.TrimSpace(getenv("SEEDANCE_API_KEY")) == "" {
|
||||
missing = append(missing, "Seedance SEEDANCE_API_KEY")
|
||||
}
|
||||
if len(missing) == 0 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("生产环境缺少真实服务商凭据:%s", strings.Join(missing, ";"))
|
||||
}
|
||||
|
||||
func defaultWebhookSender(getenv postgres.Getenv) (*webhook.HTTPSender, error) {
|
||||
return webhook.NewPublicHTTPSender(
|
||||
durationEnv(getenv, "ZHINIAN_WEBHOOK_TIMEOUT_MS", 10*time.Second),
|
||||
@@ -272,6 +250,8 @@ func bailianVideoCapabilityLimits() map[string]any {
|
||||
func runtimeHealthDetails(getenv postgres.Getenv) httpapi.HealthDetails {
|
||||
image := imageEngine(getenv)
|
||||
imageLabel := map[string]string{"jimeng": "即梦", "evolink": "EvoLink", "bailian": "阿里云百炼"}[image]
|
||||
video := videoEngine(getenv)
|
||||
videoLabel := map[string]string{"seedance": "Seedance", "bailian": "阿里云百炼"}[video]
|
||||
visualConfigured := strings.TrimSpace(getenv("VOLCENGINE_ACCESS_KEY_ID")) != "" && strings.TrimSpace(getenv("VOLCENGINE_SECRET_ACCESS_KEY")) != ""
|
||||
auth, _ := ParseAuthConfig(getenv)
|
||||
bailianKey := bailianAPIKey(getenv)
|
||||
@@ -290,7 +270,7 @@ func runtimeHealthDetails(getenv postgres.Getenv) httpapi.HealthDetails {
|
||||
AuthMode: authMode,
|
||||
Capabilities: []any{
|
||||
map[string]any{"id": "image.generate", "label": "图片生成 4.6", "engine": image, "engineLabel": imageLabel, "reqKey": imageModel(getenv)},
|
||||
map[string]any{"id": "video.generate", "label": "Seedance 视频生成", "engine": "seedance", "engineLabel": "Seedance", "reqKey": firstNonEmpty(getenv("SEEDANCE_MODEL"), "doubao-seedance-2-0-260128")},
|
||||
map[string]any{"id": "video.generate", "label": "视频生成", "engine": video, "engineLabel": videoLabel, "reqKey": videoModel(getenv)},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -330,6 +310,103 @@ func defaultSettingsService(getenv postgres.Getenv) *settings.Service {
|
||||
return settings.New(path, runtimeEnvironment(getenv), nil)
|
||||
}
|
||||
|
||||
func databaseSettingsService(getenv postgres.Getenv, repository settings.RuntimeSettingsRepository) *settings.Service {
|
||||
path := firstNonEmpty(getenv("ZHINIAN_SETTINGS_FILE"), ".env.local")
|
||||
return settings.NewWithRuntimeRepository(path, runtimeEnvironment(getenv), repository, nil)
|
||||
}
|
||||
|
||||
func runtimeSettingsGetenv(ctx context.Context, fallback postgres.Getenv, service *settings.Service) (postgres.Getenv, error) {
|
||||
values, err := service.RuntimeValues(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mergedSettingsGetenv(values, fallback), nil
|
||||
}
|
||||
|
||||
func cachedRuntimeSettingsGetenv(fallback postgres.Getenv, service *settings.Service) postgres.Getenv {
|
||||
return mergedSettingsGetenv(service.CachedRuntimeValues(), fallback)
|
||||
}
|
||||
|
||||
func mergedSettingsGetenv(values map[string]string, fallback postgres.Getenv) postgres.Getenv {
|
||||
return func(name string) string {
|
||||
if value, ok := values[name]; ok {
|
||||
return value
|
||||
}
|
||||
return fallback(name)
|
||||
}
|
||||
}
|
||||
|
||||
type runtimeProviderResolver struct {
|
||||
fallback postgres.Getenv
|
||||
settings *settings.Service
|
||||
client *http.Client
|
||||
maximum int64
|
||||
}
|
||||
|
||||
func newRuntimeProviderResolver(fallback postgres.Getenv, service *settings.Service) *runtimeProviderResolver {
|
||||
return &runtimeProviderResolver{
|
||||
fallback: fallback, settings: service,
|
||||
client: &http.Client{Timeout: durationEnv(fallback, "ZHINIAN_PROVIDER_TIMEOUT_MS", 30*time.Second)},
|
||||
maximum: positiveInt64Env(fallback, "ZHINIAN_PROVIDER_MAX_RESPONSE_BYTES", 2<<20),
|
||||
}
|
||||
}
|
||||
|
||||
func (resolver *runtimeProviderResolver) Resolve(ctx context.Context, name string) (providers.Adapter, error) {
|
||||
getenv, err := runtimeSettingsGetenv(ctx, resolver.fallback, resolver.settings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buildProviderRegistryWithClient(getenv, resolver.client, resolver.maximum)[name], nil
|
||||
}
|
||||
|
||||
type runtimeProviderJobBuilder struct {
|
||||
fallback postgres.Getenv
|
||||
settings *settings.Service
|
||||
enforceAvailability bool
|
||||
}
|
||||
|
||||
func (builder runtimeProviderJobBuilder) Build(ctx context.Context, owner, client, capability, idempotency string, body map[string]any) (jobs.CreateCommand, error) {
|
||||
getenv, err := runtimeSettingsGetenv(ctx, builder.fallback, builder.settings)
|
||||
if err != nil {
|
||||
return jobs.CreateCommand{}, fmt.Errorf("load runtime provider settings: %w", err)
|
||||
}
|
||||
return configuredProviderJobBuilder(getenv, builder.enforceAvailability).Build(ctx, owner, client, capability, idempotency, body)
|
||||
}
|
||||
|
||||
func configuredProviderJobBuilder(getenv postgres.Getenv, enforceAvailability bool) jobs.ProviderJobBuilder {
|
||||
var unavailable map[string]string
|
||||
if enforceAvailability {
|
||||
unavailable = providerUnavailableMessages(getenv)
|
||||
}
|
||||
return jobs.ProviderJobBuilder{
|
||||
ImageProvider: imageProvider(getenv), VideoProvider: videoProvider(getenv),
|
||||
ImageModel: imageModel(getenv), VideoModel: videoModel(getenv), ImageEngine: imageEngine(getenv), VideoEngine: videoEngine(getenv),
|
||||
ImageEngines: providerImageTargets(getenv), VideoEngines: providerVideoTargets(getenv), UnavailableProviders: unavailable, NewID: applicationJobID,
|
||||
}
|
||||
}
|
||||
|
||||
func runtimeCapabilitySummary(fallback postgres.Getenv, service *settings.Service) func(context.Context) (any, error) {
|
||||
return func(ctx context.Context) (any, error) {
|
||||
getenv, err := runtimeSettingsGetenv(ctx, fallback, service)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load runtime provider settings: %w", err)
|
||||
}
|
||||
return capabilitySummary(getenv)(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func runtimeHealthDetailsProvider(fallback postgres.Getenv, service *settings.Service) func(context.Context) httpapi.HealthDetails {
|
||||
return func(ctx context.Context) httpapi.HealthDetails {
|
||||
refreshContext, cancel := context.WithTimeout(ctx, 250*time.Millisecond)
|
||||
defer cancel()
|
||||
getenv, err := runtimeSettingsGetenv(refreshContext, fallback, service)
|
||||
if err != nil {
|
||||
getenv = cachedRuntimeSettingsGetenv(fallback, service)
|
||||
}
|
||||
return runtimeHealthDetails(getenv)
|
||||
}
|
||||
}
|
||||
|
||||
type settingsBillingAccountStore struct{ service *settings.Service }
|
||||
|
||||
func (store settingsBillingAccountStore) Load(ctx context.Context) (billing.AccountConfig, error) {
|
||||
|
||||
@@ -3,7 +3,10 @@ package application
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
@@ -12,10 +15,11 @@ import (
|
||||
|
||||
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/assets"
|
||||
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/billing"
|
||||
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/providers"
|
||||
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/settings"
|
||||
)
|
||||
|
||||
func TestDefaultSettingsServicePersistsRestartRequiredWithoutPartialHotReload(t *testing.T) {
|
||||
func TestDefaultSettingsServiceAppliesProviderSettingsWithoutRestart(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), ".env.local")
|
||||
key := "IMAGE_GENERATE_ENGINE"
|
||||
service := defaultSettingsService(func(name string) string {
|
||||
@@ -29,7 +33,7 @@ func TestDefaultSettingsServicePersistsRestartRequiredWithoutPartialHotReload(t
|
||||
t.Fatal(err)
|
||||
}
|
||||
payload, ok := value.(settings.Payload)
|
||||
if !ok || !payload.RestartRequired {
|
||||
if !ok || payload.RestartRequired {
|
||||
t.Fatalf("payload=%#v", value)
|
||||
}
|
||||
}
|
||||
@@ -78,6 +82,7 @@ func TestRuntimeHealthDetailsMatchTypeScriptDefaultsAndConfiguredModes(t *testin
|
||||
"VOLCENGINE_ACCESS_KEY_ID": "access",
|
||||
"VOLCENGINE_SECRET_ACCESS_KEY": "secret",
|
||||
"SEEDANCE_API_KEY": "seedance-key",
|
||||
"VIDEO_GENERATE_ENGINE": "seedance",
|
||||
"ZHINIAN_AUTH_REQUIRED": "true",
|
||||
"ZHINIAN_AUTH_SESSION_SECRET": "session-secret",
|
||||
}
|
||||
@@ -95,6 +100,88 @@ func TestRuntimeHealthDetailsMatchTypeScriptDefaultsAndConfiguredModes(t *testin
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntimeProviderJobBuilderRefreshesDatabaseSettings(t *testing.T) {
|
||||
settingsPath := filepath.Join(t.TempDir(), ".env.local")
|
||||
fallback := func(name string) string {
|
||||
if name == "ZHINIAN_SETTINGS_FILE" {
|
||||
return settingsPath
|
||||
}
|
||||
return ""
|
||||
}
|
||||
repository := &applicationRuntimeSettingsRepository{values: map[string]string{
|
||||
"EVOLINK_API_KEY": "evolink-secret",
|
||||
"EVOLINK_IMAGE_MODEL": "database-image-model",
|
||||
"EVOLINK_IMAGE_QUALITY": "high",
|
||||
"IMAGE_GENERATE_ENGINE": "evolink",
|
||||
}}
|
||||
service := databaseSettingsService(fallback, repository)
|
||||
builder := runtimeProviderJobBuilder{fallback: fallback, settings: service, enforceAvailability: true}
|
||||
command, err := builder.Build(context.Background(), "owner", "", "image.generate", "", map[string]any{"prompt": "draw"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var request providers.Request
|
||||
if err := json.Unmarshal(command.Job.RequestPayload, &request); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if command.Job.Provider != "evolink" || command.Job.ReqKey != "database-image-model" || request.Settings["quality"] != "high" {
|
||||
t.Fatalf("job=%#v request=%#v", command.Job, request)
|
||||
}
|
||||
repository.values = map[string]string{
|
||||
"BAILIAN_API_KEY": "bailian-secret",
|
||||
"BAILIAN_IMAGE_MODEL": "database-bailian-model",
|
||||
"IMAGE_GENERATE_ENGINE": "bailian",
|
||||
}
|
||||
command, err = builder.Build(context.Background(), "owner", "", "image.generate", "", map[string]any{"prompt": "draw again"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if command.Job.Provider != "bailian" || command.Job.ReqKey != "database-bailian-model" {
|
||||
t.Fatalf("refreshed job=%#v", command.Job)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntimeProviderResolverUsesLatestDatabaseCredential(t *testing.T) {
|
||||
var authorizations []string
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) {
|
||||
authorizations = append(authorizations, request.Header.Get("Authorization"))
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"id":"task-1","status":"queued"}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
settingsPath := filepath.Join(t.TempDir(), ".env.local")
|
||||
fallback := func(name string) string {
|
||||
if name == "ZHINIAN_SETTINGS_FILE" {
|
||||
return settingsPath
|
||||
}
|
||||
return ""
|
||||
}
|
||||
repository := &applicationRuntimeSettingsRepository{values: map[string]string{
|
||||
"EVOLINK_API_KEY": "database-secret-1",
|
||||
"EVOLINK_BASE_URL": server.URL,
|
||||
}}
|
||||
service := databaseSettingsService(fallback, repository)
|
||||
resolver := newRuntimeProviderResolver(fallback, service)
|
||||
adapter, err := resolver.Resolve(context.Background(), "evolink")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := adapter.Submit(context.Background(), providers.Request{Capability: "image.generate", Prompt: "draw"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
repository.values["EVOLINK_API_KEY"] = "database-secret-2"
|
||||
adapter, err = resolver.Resolve(context.Background(), "evolink")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := adapter.Submit(context.Background(), providers.Request{Capability: "image.generate", Prompt: "draw again"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(authorizations, []string{"Bearer database-secret-1", "Bearer database-secret-2"}) {
|
||||
t.Fatalf("authorizations=%#v", authorizations)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRuntimeHealthDetailsReportConfiguredProvidersAndImageEngine(t *testing.T) {
|
||||
values := map[string]string{
|
||||
"IMAGE_GENERATE_ENGINE": "bailian",
|
||||
@@ -110,31 +197,6 @@ func TestRuntimeHealthDetailsReportConfiguredProvidersAndImageEngine(t *testing.
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateProductionProviderConfigurationRequiresAllRealCredentials(t *testing.T) {
|
||||
if err := validateProductionProviderConfiguration(func(string) string { return "" }); err == nil {
|
||||
t.Fatal("validateProductionProviderConfiguration() unexpectedly succeeded")
|
||||
} else if !strings.Contains(err.Error(), "EVOLINK_API_KEY") || !strings.Contains(err.Error(), "SEEDANCE_API_KEY") {
|
||||
t.Fatalf("error = %v", err)
|
||||
}
|
||||
values := map[string]string{
|
||||
"VOLCENGINE_ACCESS_KEY_ID": "access",
|
||||
"VOLCENGINE_SECRET_ACCESS_KEY": "secret",
|
||||
"EVOLINK_API_KEY": "evolink",
|
||||
"BAILIAN_API_KEY": "bailian",
|
||||
"SEEDANCE_API_KEY": "seedance",
|
||||
}
|
||||
if err := validateProductionProviderConfiguration(func(name string) string { return values[name] }); err != nil {
|
||||
t.Fatalf("validateProductionProviderConfiguration() error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateProductionProviderConfigurationCanBeSkippedForBootstrap(t *testing.T) {
|
||||
values := map[string]string{"ZHINIAN_ALLOW_UNCONFIGURED_PROVIDERS": "true"}
|
||||
if err := validateProductionProviderConfiguration(func(name string) string { return values[name] }); err != nil {
|
||||
t.Fatalf("validateProductionProviderConfiguration() with bootstrap flag = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderUnavailableMessagesIdentifyOnlyMissingCredentials(t *testing.T) {
|
||||
values := map[string]string{
|
||||
"VOLCENGINE_ACCESS_KEY_ID": "access",
|
||||
@@ -214,6 +276,26 @@ func TestPrefixedBlobStoreKeepsApplicationStoragePathStable(t *testing.T) {
|
||||
|
||||
type recordingBlobStore struct{ putKey, readKey, deleteKey string }
|
||||
|
||||
type applicationRuntimeSettingsRepository struct{ values map[string]string }
|
||||
|
||||
func (repository *applicationRuntimeSettingsRepository) LoadRuntimeSettings(context.Context, []string) (map[string]string, error) {
|
||||
values := map[string]string{}
|
||||
for key, value := range repository.values {
|
||||
values[key] = value
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func (repository *applicationRuntimeSettingsRepository) SaveRuntimeSettings(_ context.Context, values map[string]string) error {
|
||||
if repository.values == nil {
|
||||
repository.values = map[string]string{}
|
||||
}
|
||||
for key, value := range values {
|
||||
repository.values[key] = value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *recordingBlobStore) Put(_ context.Context, key string, _ io.Reader, _ int64, _ string) (assets.StoredObject, error) {
|
||||
s.putKey = key
|
||||
return assets.StoredObject{Key: key, URL: "https://cdn.example/" + key}, nil
|
||||
|
||||
Reference in new issue
Block a user