Files
oci-portal/internal/oci/real_integration_test.go
T

230 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package oci
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"time"
"oci-portal/internal/model"
)
// testKeyDir 指向仓库根的真实 API Key 测试资料目录。
const testKeyDir = "../../../test-api-key"
// keyCase 把测试 key 文件名映射到期望账户类别;expect 为空表示只打印不断言。
type keyCase struct {
name string
expect string
}
func integrationKeyCases(t *testing.T) []keyCase {
t.Helper()
all := []keyCase{
{name: "试用期", expect: model.AccountTypeTrial},
{name: "付费", expect: model.AccountTypePaid},
{name: "免费01", expect: model.AccountTypeFree},
{name: "免费02", expect: model.AccountTypeFree},
{name: "未知01"},
{name: "未知02"},
}
if name := os.Getenv("OCI_TEST_KEY"); name != "" {
for _, k := range all {
if k.name == name {
return []keyCase{k}
}
}
t.Fatalf("OCI_TEST_KEY=%q not found in test-api-key", name)
}
if os.Getenv("OCI_TEST_ALL_KEYS") == "1" {
return all
}
// 默认只使用试用期 key,避免不必要地触碰其他真实账号
return all[:1]
}
func loadTestCredentials(t *testing.T, name string) Credentials {
t.Helper()
iniPath := filepath.Join(testKeyDir, name+"-api-key.ini")
pemPath := filepath.Join(testKeyDir, name+"-api-key.pem")
iniText, err := os.ReadFile(iniPath)
if err != nil {
t.Fatalf("read %s: %v", iniPath, err)
}
pem, err := os.ReadFile(pemPath)
if err != nil {
t.Fatalf("read %s: %v", pemPath, err)
}
cred, err := ParseConfigINI(string(iniText))
if err != nil {
t.Fatalf("parse %s: %v", iniPath, err)
}
cred.PrivateKey = string(pem)
if err := cred.Validate(); err != nil {
t.Fatalf("validate credentials of %s: %v", name, err)
}
return cred
}
// TestRealOCITenantRegionsAndLimits 用试用期 key 验证区域订阅列表和
// 配额查询(均为只读调用)。订阅新区域不可撤销,不做真实测试。
func TestRealOCITenantRegionsAndLimits(t *testing.T) {
if os.Getenv("OCI_INTEGRATION_TEST") != "1" {
t.Skip("set OCI_INTEGRATION_TEST=1 to run real OCI tests")
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
cred := loadTestCredentials(t, "试用期")
client := NewClient()
subs, err := client.ListRegionSubscriptions(ctx, cred)
if err != nil {
t.Fatalf("ListRegionSubscriptions: %v", err)
}
if len(subs) == 0 {
t.Fatal("ListRegionSubscriptions returned empty list, want at least home region")
}
hasHome := false
for _, sub := range subs {
t.Logf("region key=%s name=%s status=%s home=%v", sub.Key, sub.Name, sub.Status, sub.IsHomeRegion)
hasHome = hasHome || sub.IsHomeRegion
}
if !hasHome {
t.Error("no home region in subscriptions")
}
values, err := client.ListLimits(ctx, cred, LimitsQuery{
Service: "compute",
Name: "standard-a1-core-count",
WithAvailability: true,
})
if err != nil {
t.Fatalf("ListLimits: %v", err)
}
if len(values) == 0 {
t.Fatal("ListLimits returned empty list for standard-a1-core-count")
}
for _, v := range values {
used, available := int64(-1), int64(-1)
if v.Used != nil {
used = *v.Used
}
if v.Available != nil {
available = *v.Available
}
t.Logf("limit name=%s scope=%s ad=%s value=%d used=%d available=%d",
v.Name, v.ScopeType, v.AvailabilityDomain, v.Value, used, available)
}
// 模糊过滤应比精确名命中更多配额(a1 与 e2 等系列都含 core-count
fuzzy, err := client.ListLimits(ctx, cred, LimitsQuery{Service: "compute", Name: "core-count"})
if err != nil {
t.Fatalf("ListLimits fuzzy: %v", err)
}
t.Logf("fuzzy core-count matched %d entries", len(fuzzy))
if len(fuzzy) <= len(values) {
t.Errorf("fuzzy matches = %d, want more than exact matches %d", len(fuzzy), len(values))
}
services, err := client.ListLimitServices(ctx, cred, "")
if err != nil {
t.Fatalf("ListLimitServices: %v", err)
}
if len(services) == 0 {
t.Fatal("ListLimitServices returned empty list")
}
hasCompute := false
for _, s := range services {
hasCompute = hasCompute || s.Name == "compute"
}
if !hasCompute {
t.Errorf("services (%d) missing compute", len(services))
}
t.Logf("limit services: %d entries, first=%+v", len(services), services[0])
}
// TestRealOCISubscriptions 用试用期 key 验证订阅列表与订阅详情(只读)。
func TestRealOCISubscriptions(t *testing.T) {
if os.Getenv("OCI_INTEGRATION_TEST") != "1" {
t.Skip("set OCI_INTEGRATION_TEST=1 to run real OCI tests")
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
cred := loadTestCredentials(t, "试用期")
client := NewClient()
subs, err := client.ListSubscriptions(ctx, cred)
if err != nil {
t.Fatalf("ListSubscriptions: %v", err)
}
if len(subs) == 0 {
t.Fatal("ListSubscriptions returned empty list")
}
cloudcmID := ""
for _, sub := range subs {
t.Logf("subscription id=%s service=%s created=%v", sub.ID, sub.ServiceName, sub.TimeCreated)
if strings.EqualFold(sub.ServiceName, cloudcmServiceName) {
cloudcmID = sub.ID
}
}
if cloudcmID == "" {
t.Fatal("no CLOUDCM subscription in list")
}
detail, err := client.GetSubscription(ctx, cred, cloudcmID)
if err != nil {
t.Fatalf("GetSubscription: %v", err)
}
if detail.ID != cloudcmID {
t.Errorf("detail.ID = %q, want %q", detail.ID, cloudcmID)
}
t.Logf("detail service=%s paymentModel=%q tier=%q state=%s currency=%s region=%s promotions=%d",
detail.ServiceName, detail.PaymentModel, detail.SubscriptionTier,
detail.LifecycleState, detail.CloudAmountCurrency, detail.RegionAssignment, len(detail.Promotions))
for _, p := range detail.Promotions {
t.Logf("promotion status=%s amount=%.2f %s expires=%v intentToPay=%v",
p.Status, p.Amount, p.CurrencyUnit, p.TimeExpired, p.IsIntentToPay)
}
if len(detail.Promotions) == 0 {
t.Error("trial subscription has no promotions, want at least one")
}
}
// TestRealOCIVerifyAndClassify 走真实 OCI 验证测活与账户类别判定,
// 必须显式设置 OCI_INTEGRATION_TEST=1 才会执行。
func TestRealOCIVerifyAndClassify(t *testing.T) {
if os.Getenv("OCI_INTEGRATION_TEST") != "1" {
t.Skip("set OCI_INTEGRATION_TEST=1 to run real OCI tests")
}
client := NewClient()
for _, tc := range integrationKeyCases(t) {
t.Run(tc.name, func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
cred := loadTestCredentials(t, tc.name)
info, err := client.ValidateKey(ctx, cred)
if err != nil {
t.Fatalf("ValidateKey: %v", err)
}
t.Logf("tenancy=%s homeRegion=%s", info.Name, info.HomeRegionKey)
profile, err := client.FetchAccountProfile(ctx, cred)
if err != nil {
t.Fatalf("FetchAccountProfile: %v", err)
}
t.Logf("type=%s paymentModel=%q tier=%q promo=%q amount=%.2f service=%s",
profile.AccountType, profile.PaymentModel, profile.SubscriptionTier,
profile.PromotionStatus, profile.PromotionAmount, profile.ServiceName)
if !strings.EqualFold(profile.ServiceName, cloudcmServiceName) {
t.Errorf("ServiceName = %q, want %q", profile.ServiceName, cloudcmServiceName)
}
if tc.expect != "" && profile.AccountType != tc.expect {
t.Errorf("AccountType = %q, want %q", profile.AccountType, tc.expect)
}
})
}
}