优化结构
This commit is contained in:
@@ -56,10 +56,17 @@ type IntegrationConfigRepo interface {
|
||||
DeleteIntegrationConfig(context.Context, string, string) error
|
||||
}
|
||||
|
||||
type IntegrationConfigUsecase struct{ repo IntegrationConfigRepo }
|
||||
type IntegrationConnectionTester interface {
|
||||
TestIntegration(context.Context, *IntegrationConfig) error
|
||||
}
|
||||
|
||||
func NewIntegrationConfigUsecase(repo IntegrationConfigRepo) *IntegrationConfigUsecase {
|
||||
return &IntegrationConfigUsecase{repo: repo}
|
||||
type IntegrationConfigUsecase struct {
|
||||
repo IntegrationConfigRepo
|
||||
tester IntegrationConnectionTester
|
||||
}
|
||||
|
||||
func NewIntegrationConfigUsecase(repo IntegrationConfigRepo, tester IntegrationConnectionTester) *IntegrationConfigUsecase {
|
||||
return &IntegrationConfigUsecase{repo: repo, tester: tester}
|
||||
}
|
||||
|
||||
func (uc *IntegrationConfigUsecase) List(ctx context.Context, kind string) ([]*IntegrationConfig, error) {
|
||||
@@ -106,6 +113,42 @@ func (uc *IntegrationConfigUsecase) Save(ctx context.Context, config *Integratio
|
||||
return uc.repo.SaveIntegrationConfig(ctx, config)
|
||||
}
|
||||
|
||||
// Test validates and probes a candidate configuration without persisting it.
|
||||
// The adapter may resolve masked secret values from the active runtime store.
|
||||
func (uc *IntegrationConfigUsecase) Test(ctx context.Context, config *IntegrationConfig) error {
|
||||
if config == nil {
|
||||
return errors.New("集成配置请求为空")
|
||||
}
|
||||
config.Kind = normalizeIntegrationPart(config.Kind)
|
||||
config.Provider = normalizeIntegrationPart(config.Provider)
|
||||
if config.Kind != IntegrationKindMQ && config.Kind != IntegrationKindWebSocket {
|
||||
return errors.New("仅支持测试消息队列和 WebSocket 集成")
|
||||
}
|
||||
if config.Kind == "" || config.Provider == "" || len(config.Kind) > 32 || len(config.Provider) > 64 {
|
||||
return errors.New("集成配置 kind 或 provider 无效")
|
||||
}
|
||||
if !json.Valid(config.Values) {
|
||||
return errors.New("集成配置必须是合法 JSON")
|
||||
}
|
||||
values := map[string]any{}
|
||||
if err := json.Unmarshal(config.Values, &values); err != nil {
|
||||
return errors.New("集成配置必须是 JSON 对象")
|
||||
}
|
||||
if definition, ok := IntegrationDefinition(config.Kind, config.Provider); ok {
|
||||
values = mergeIntegrationDefaults(definition.Defaults, values)
|
||||
}
|
||||
if err := ValidateIntegrationConfig(config.Kind, config.Provider, values); err != nil {
|
||||
return err
|
||||
}
|
||||
encoded, _ := json.Marshal(values)
|
||||
config.Enabled = true
|
||||
config.Values = encoded
|
||||
if uc.tester == nil {
|
||||
return errors.New("集成连接测试器未初始化")
|
||||
}
|
||||
return uc.tester.TestIntegration(ctx, config)
|
||||
}
|
||||
|
||||
func (uc *IntegrationConfigUsecase) Delete(ctx context.Context, kind, provider string) error {
|
||||
kind, provider = normalizeIntegrationPart(kind), normalizeIntegrationPart(provider)
|
||||
if kind == "" || provider == "" {
|
||||
|
||||
@@ -1,6 +1,39 @@
|
||||
package biz
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type integrationConfigRepoTestDouble struct {
|
||||
saves int
|
||||
}
|
||||
|
||||
func (*integrationConfigRepoTestDouble) ListIntegrationConfigs(context.Context, string) ([]*IntegrationConfig, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (*integrationConfigRepoTestDouble) FindIntegrationConfig(context.Context, string, string) (*IntegrationConfig, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (r *integrationConfigRepoTestDouble) SaveIntegrationConfig(context.Context, *IntegrationConfig) error {
|
||||
r.saves++
|
||||
return nil
|
||||
}
|
||||
func (*integrationConfigRepoTestDouble) DeleteIntegrationConfig(context.Context, string, string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type integrationConnectionTesterDouble struct {
|
||||
calls int
|
||||
config *IntegrationConfig
|
||||
}
|
||||
|
||||
func (t *integrationConnectionTesterDouble) TestIntegration(_ context.Context, config *IntegrationConfig) error {
|
||||
t.calls++
|
||||
t.config = config
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestCommunicationIntegrationDefinitionsAndValidation(t *testing.T) {
|
||||
for _, target := range []struct{ kind, provider string }{
|
||||
@@ -30,3 +63,36 @@ func TestCommunicationIntegrationValidationRejectsInvalidValues(t *testing.T) {
|
||||
t.Fatal("invalid websocket path was accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegrationConfigTestDoesNotPersistCandidate(t *testing.T) {
|
||||
repo := &integrationConfigRepoTestDouble{}
|
||||
tester := &integrationConnectionTesterDouble{}
|
||||
usecase := NewIntegrationConfigUsecase(repo, tester)
|
||||
raw, _ := json.Marshal(map[string]any{"path": "/candidate"})
|
||||
|
||||
err := usecase.Test(context.Background(), &IntegrationConfig{
|
||||
Kind: " WebSocket ",
|
||||
Provider: " Melody ",
|
||||
Enabled: false,
|
||||
Values: raw,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if repo.saves != 0 {
|
||||
t.Fatalf("candidate config was persisted %d times", repo.saves)
|
||||
}
|
||||
if tester.calls != 1 || tester.config == nil {
|
||||
t.Fatalf("connection tester calls = %d, config = %#v", tester.calls, tester.config)
|
||||
}
|
||||
if tester.config.Kind != IntegrationKindWebSocket || tester.config.Provider != "melody" || !tester.config.Enabled {
|
||||
t.Fatalf("tested config = %#v", tester.config)
|
||||
}
|
||||
values := map[string]any{}
|
||||
if err = json.Unmarshal(tester.config.Values, &values); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if values["path"] != "/candidate" || values["write_wait"] != "10s" {
|
||||
t.Fatalf("tested values = %#v", values)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user