package mock import ( "context" "fmt" "time" "github.com/ocdp/cluster-service/internal/domain/entity" "github.com/ocdp/cluster-service/internal/domain/repository" ) // HelmClientMock Helm 客户端 Mock 实现 type HelmClientMock struct { // Mock 数据存储 releases map[string]map[string]*entity.Instance // clusterID -> releaseName -> instance history map[string]map[string][]*entity.ReleaseHistory // clusterID -> releaseName -> []history estimates map[string]map[string]*repository.ResourceEstimate // clusterID -> releaseName -> estimate } // NewHelmClientMock 创建 Mock 实现 func NewHelmClientMock() repository.HelmClient { return &HelmClientMock{ releases: make(map[string]map[string]*entity.Instance), history: make(map[string]map[string][]*entity.ReleaseHistory), estimates: make(map[string]map[string]*repository.ResourceEstimate), } } func (c *HelmClientMock) SetResourceEstimate(clusterID, namespace, releaseName string, estimate *repository.ResourceEstimate) { if c.estimates[clusterID] == nil { c.estimates[clusterID] = make(map[string]*repository.ResourceEstimate) } c.estimates[clusterID][fmt.Sprintf("%s/%s", namespace, releaseName)] = estimate } func (c *HelmClientMock) Install(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) error { // 初始化集群数据 if c.releases[cluster.ID] == nil { c.releases[cluster.ID] = make(map[string]*entity.Instance) c.history[cluster.ID] = make(map[string][]*entity.ReleaseHistory) } // 检查是否已存在 key := fmt.Sprintf("%s/%s", instance.Namespace, instance.Name) if _, exists := c.releases[cluster.ID][key]; exists { return entity.ErrInstanceExists } // Mock 安装 instance.Status = entity.StatusDeployed instance.Revision = 1 instance.UpdatedAt = time.Now() c.releases[cluster.ID][key] = instance // 添加历史记录 c.history[cluster.ID][key] = []*entity.ReleaseHistory{ { Revision: 1, Updated: time.Now(), Status: entity.StatusDeployed, Chart: fmt.Sprintf("%s-%s", instance.Chart, instance.Version), AppVersion: instance.Version, Description: "Install complete", }, } return nil } func (c *HelmClientMock) Upgrade(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) error { key := fmt.Sprintf("%s/%s", instance.Namespace, instance.Name) existing, exists := c.releases[cluster.ID][key] if !exists { return entity.ErrInstanceNotFound } // Mock 升级 instance.Revision = existing.Revision + 1 instance.Status = entity.StatusDeployed instance.UpdatedAt = time.Now() c.releases[cluster.ID][key] = instance // 添加历史记录 history := &entity.ReleaseHistory{ Revision: instance.Revision, Updated: time.Now(), Status: entity.StatusDeployed, Chart: fmt.Sprintf("%s-%s", instance.Chart, instance.Version), AppVersion: instance.Version, Description: "Upgrade complete", } c.history[cluster.ID][key] = append(c.history[cluster.ID][key], history) return nil } func (c *HelmClientMock) Uninstall(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) error { key := fmt.Sprintf("%s/%s", namespace, releaseName) if _, exists := c.releases[cluster.ID][key]; !exists { return entity.ErrInstanceNotFound } // Mock 卸载 delete(c.releases[cluster.ID], key) return nil } func (c *HelmClientMock) Rollback(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string, revision int) error { key := fmt.Sprintf("%s/%s", namespace, releaseName) instance, exists := c.releases[cluster.ID][key] if !exists { return entity.ErrInstanceNotFound } // 检查历史记录是否存在 histories := c.history[cluster.ID][key] if revision > len(histories) || revision < 1 { return fmt.Errorf("revision %d not found", revision) } // Mock 回滚 instance.Revision = len(histories) + 1 instance.Status = entity.StatusDeployed instance.UpdatedAt = time.Now() c.releases[cluster.ID][key] = instance // 添加回滚历史记录 history := &entity.ReleaseHistory{ Revision: instance.Revision, Updated: time.Now(), Status: entity.StatusDeployed, Chart: instance.Chart, AppVersion: instance.Version, Description: fmt.Sprintf("Rollback to revision %d", revision), } c.history[cluster.ID][key] = append(c.history[cluster.ID][key], history) return nil } func (c *HelmClientMock) GetStatus(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) (*entity.Instance, error) { key := fmt.Sprintf("%s/%s", namespace, releaseName) instance, exists := c.releases[cluster.ID][key] if !exists { return nil, entity.ErrInstanceNotFound } return instance, nil } func (c *HelmClientMock) GetHistory(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) ([]*entity.ReleaseHistory, error) { key := fmt.Sprintf("%s/%s", namespace, releaseName) if _, exists := c.releases[cluster.ID][key]; !exists { return nil, entity.ErrInstanceNotFound } histories := c.history[cluster.ID][key] if histories == nil { return []*entity.ReleaseHistory{}, nil } return histories, nil } func (c *HelmClientMock) List(ctx context.Context, cluster *entity.Cluster, namespace string) ([]*entity.Instance, error) { clusterReleases := c.releases[cluster.ID] if clusterReleases == nil { return []*entity.Instance{}, nil } instances := make([]*entity.Instance, 0) for key, instance := range clusterReleases { // 如果指定了 namespace,只返回该 namespace 的 if namespace != "" && namespace != "all" { keyNamespace := instance.Namespace if keyNamespace != namespace { continue } } instances = append(instances, c.releases[cluster.ID][key]) } return instances, nil } func (c *HelmClientMock) GetValues(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) (map[string]interface{}, error) { key := fmt.Sprintf("%s/%s", namespace, releaseName) instance, exists := c.releases[cluster.ID][key] if !exists { return nil, entity.ErrInstanceNotFound } return instance.Values, nil } func (c *HelmClientMock) GetChartDefaultValues(chartPath string) (map[string]interface{}, error) { return map[string]interface{}{ "replicaCount": 1, "image": map[string]interface{}{ "repository": "nginx", "tag": "latest", }, }, nil } func (c *HelmClientMock) EstimateInstanceResources(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) (*repository.ResourceEstimate, error) { clusterID := "" if cluster != nil { clusterID = cluster.ID } key := fmt.Sprintf("%s/%s", instance.Namespace, instance.Name) if c.estimates[clusterID] != nil { if estimate := c.estimates[clusterID][key]; estimate != nil { return estimate, nil } } return &repository.ResourceEstimate{}, nil }