package oci import ( "context" "testing" ) // countingClient 只实现被测方法并计数;其余方法经嵌入 nil 接口(不被调用)。 type countingClient struct { Client instCalls int adCalls int launches int } func (f *countingClient) ListInstances(ctx context.Context, cred Credentials, region string) ([]Instance, error) { f.instCalls++ return []Instance{{ID: "i-1", DisplayName: "b"}, {ID: "i-2", DisplayName: "a"}}, nil } func (f *countingClient) ListAvailabilityDomains(ctx context.Context, cred Credentials, region string) ([]string, error) { f.adCalls++ return []string{"ad-1"}, nil } func (f *countingClient) LaunchInstance(ctx context.Context, cred Credentials, in CreateInstanceInput) (Instance, error) { f.launches++ return Instance{ID: "i-new"}, nil } func testCred(tenancy string) Credentials { return Credentials{TenancyOCID: tenancy} } func TestCachedClientHitAndIsolation(t *testing.T) { inner := &countingClient{} c := NewCachedClient(inner) ctx := context.Background() for i := 0; i < 3; i++ { if _, err := c.ListInstances(ctx, testCred("t1"), "r1"); err != nil { t.Fatalf("ListInstances: %v", err) } } if inner.instCalls != 1 { t.Errorf("同 key 三连读回源 %d 次, want 1", inner.instCalls) } // 不同租户 / 区域各自回源 _, _ = c.ListInstances(ctx, testCred("t2"), "r1") _, _ = c.ListInstances(ctx, testCred("t1"), "r2") if inner.instCalls != 3 { t.Errorf("跨租户/区域回源 %d 次, want 3", inner.instCalls) } } func TestCachedClientWriteBusts(t *testing.T) { inner := &countingClient{} c := NewCachedClient(inner) ctx := context.Background() _, _ = c.ListInstances(ctx, testCred("t1"), "r1") _, _ = c.ListAvailabilityDomains(ctx, testCred("t1"), "r1") _, _ = c.ListInstances(ctx, testCred("t2"), "r1") if _, err := c.LaunchInstance(ctx, testCred("t1"), CreateInstanceInput{}); err != nil { t.Fatalf("LaunchInstance: %v", err) } _, _ = c.ListInstances(ctx, testCred("t1"), "r1") _, _ = c.ListAvailabilityDomains(ctx, testCred("t1"), "r1") if inner.instCalls != 3 || inner.adCalls != 2 { t.Errorf("写后同租户应全部回源: inst=%d want 3, ad=%d want 2", inner.instCalls, inner.adCalls) } // 其他租户缓存不受影响 _, _ = c.ListInstances(ctx, testCred("t2"), "r1") if inner.instCalls != 3 { t.Errorf("t2 缓存被误失效: inst=%d want 3", inner.instCalls) } } func TestCachedClientReturnsClone(t *testing.T) { inner := &countingClient{} c := NewCachedClient(inner) ctx := context.Background() first, _ := c.ListInstances(ctx, testCred("t1"), "r1") first[0], first[1] = first[1], first[0] // 调用方就地重排 second, _ := c.ListInstances(ctx, testCred("t1"), "r1") if second[0].ID != "i-1" { t.Errorf("缓存底层数组被调用方污染: second[0]=%s, want i-1", second[0].ID) } } func TestCachedClientInvalidateTenancy(t *testing.T) { inner := &countingClient{} c := NewCachedClient(inner) ctx := context.Background() _, _ = c.ListInstances(ctx, testCred("t1"), "r1") _, _ = c.ListInstances(ctx, testCred("t2"), "r1") c.InvalidateTenancy("t1") _, _ = c.ListInstances(ctx, testCred("t1"), "r1") _, _ = c.ListInstances(ctx, testCred("t2"), "r1") if inner.instCalls != 3 { t.Fatalf("invalidate tenancy calls = %d, want 3", inner.instCalls) } }