package service import ( "context" "testing" "oci-portal/internal/model" "oci-portal/internal/oci" ) func multiScopeClient() *fakeClient { return &fakeClient{ tenancy: oci.TenancyInfo{Name: "t", HomeRegionKey: "FRA"}, regionSubs: []oci.RegionSubscription{ {Key: "FRA", Name: "eu-frankfurt-1", Status: "READY", IsHomeRegion: true}, {Key: "AMS", Name: "eu-amsterdam-1", Status: "READY"}, }, compartments: []oci.Compartment{ {ID: "ocid1.compartment..a", Name: "instances", LifecycleState: "ACTIVE"}, }, } } func importMultiConfig(t *testing.T, svc *OciConfigService) *model.OciConfig { t.Helper() in := trialImportInput() in.MultiRegion = true in.MultiCompartment = true cfg, err := svc.Import(context.Background(), in) if err != nil { t.Fatalf("Import: %v", err) } return cfg } func TestImportSyncsScopeCaches(t *testing.T) { client := multiScopeClient() svc := newTestService(t, client) cfg := importMultiConfig(t, svc) if !cfg.MultiRegion || !cfg.MultiCompartment { t.Fatalf("cfg switches = %v/%v, want true/true", cfg.MultiRegion, cfg.MultiCompartment) } var regions []model.RegionCache svc.db.Where("oci_config_id = ?", cfg.ID).Find(®ions) if len(regions) != 2 { t.Errorf("region cache rows = %d, want 2", len(regions)) } var comps []model.CompartmentCache svc.db.Where("oci_config_id = ?", cfg.ID).Find(&comps) if len(comps) != 1 || comps[0].OCID != "ocid1.compartment..a" { t.Errorf("compartment cache = %+v, want 1 row ocid1.compartment..a", comps) } } func TestImportWithoutSwitchesSkipsCaches(t *testing.T) { client := multiScopeClient() svc := newTestService(t, client) cfg := importAliveConfig(t, svc) var count int64 svc.db.Model(&model.RegionCache{}).Where("oci_config_id = ?", cfg.ID).Count(&count) if count != 0 { t.Errorf("region cache rows = %d, want 0(未开启不入库)", count) } } func TestCachedRegions(t *testing.T) { tests := []struct { name string prepare func(svc *OciConfigService, cfg *model.OciConfig, client *fakeClient) wantNames []string wantCalls int // 缓存读取阶段期望的 SDK 调用次数 }{ { name: "全 READY 直接用缓存", prepare: func(*OciConfigService, *model.OciConfig, *fakeClient) {}, wantNames: []string{"eu-frankfurt-1", "eu-amsterdam-1"}, wantCalls: 0, }, { name: "存在非 READY 强制实时刷新", prepare: func(svc *OciConfigService, cfg *model.OciConfig, client *fakeClient) { svc.db.Model(&model.RegionCache{}). Where("oci_config_id = ? AND key = ?", cfg.ID, "AMS"). Update("status", "IN_PROGRESS") client.regionSubs[1].Status = "READY" // SDK 已完成 }, wantNames: []string{"eu-frankfurt-1", "eu-amsterdam-1"}, wantCalls: 1, }, { name: "缓存为空实时拉取入库", prepare: func(svc *OciConfigService, cfg *model.OciConfig, client *fakeClient) { svc.db.Where("oci_config_id = ?", cfg.ID).Delete(&model.RegionCache{}) }, wantNames: []string{"eu-frankfurt-1", "eu-amsterdam-1"}, wantCalls: 1, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { client := multiScopeClient() svc := newTestService(t, client) cfg := importMultiConfig(t, svc) tt.prepare(svc, cfg, client) client.regionSubsCalls = 0 views, err := svc.CachedRegions(context.Background(), cfg.ID) if err != nil { t.Fatalf("CachedRegions: %v", err) } got := make([]string, 0, len(views)) for _, v := range views { got = append(got, v.Name) } if len(got) != len(tt.wantNames) { t.Fatalf("regions = %v, want %v", got, tt.wantNames) } if client.regionSubsCalls != tt.wantCalls { t.Errorf("SDK calls = %d, want %d", client.regionSubsCalls, tt.wantCalls) } }) } } func TestCachedRegionsWithoutMultiRegion(t *testing.T) { client := multiScopeClient() svc := newTestService(t, client) cfg := importAliveConfig(t, svc) client.regionSubsCalls = 0 views, err := svc.CachedRegions(context.Background(), cfg.ID) if err != nil { t.Fatalf("CachedRegions: %v", err) } if len(views) != 1 || views[0].Name != "eu-frankfurt-1" || !views[0].IsHomeRegion { t.Errorf("views = %+v, want 仅默认区域且标记主区域", views) } if client.regionSubsCalls != 0 { t.Errorf("SDK calls = %d, want 0(未开启不实时请求)", client.regionSubsCalls) } } func TestCachedCompartments(t *testing.T) { client := multiScopeClient() svc := newTestService(t, client) multiCfg := importMultiConfig(t, svc) comps, err := svc.CachedCompartments(context.Background(), multiCfg.ID) if err != nil { t.Fatalf("CachedCompartments: %v", err) } if len(comps) != 1 || comps[0].ID != "ocid1.compartment..a" { t.Errorf("comps = %+v, want 缓存中的 1 项", comps) } in := trialImportInput() in.Alias = "未开启" plainCfg, err := svc.Import(context.Background(), in) if err != nil { t.Fatalf("Import: %v", err) } comps, err = svc.CachedCompartments(context.Background(), plainCfg.ID) if err != nil { t.Fatalf("CachedCompartments: %v", err) } if len(comps) != 0 { t.Errorf("comps = %+v, want 空(未开启多区间)", comps) } } func TestRegionSubscriptionsReconcilesCache(t *testing.T) { client := multiScopeClient() svc := newTestService(t, client) cfg := importMultiConfig(t, svc) // SDK 侧新订阅一个区域,订阅 Tab 实时读取后缓存应跟进 client.regionSubs = append(client.regionSubs, oci.RegionSubscription{Key: "ICN", Name: "ap-seoul-1", Status: "IN_PROGRESS"}) if _, err := svc.RegionSubscriptions(context.Background(), cfg.ID); err != nil { t.Fatalf("RegionSubscriptions: %v", err) } var rows []model.RegionCache svc.db.Where("oci_config_id = ?", cfg.ID).Find(&rows) if len(rows) != 3 { t.Fatalf("cache rows = %d, want 3(diff 后跟进)", len(rows)) } // 关闭开关的配置不应回写缓存 off := false if _, _, err := svc.Update(context.Background(), cfg.ID, UpdateInput{MultiRegion: &off}); err != nil { t.Fatalf("Update: %v", err) } var count int64 svc.db.Model(&model.RegionCache{}).Where("oci_config_id = ?", cfg.ID).Count(&count) if count != 0 { t.Errorf("cache rows = %d, want 0(关闭开关清空缓存)", count) } }