Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 100 additions & 4 deletions cmd/multi_service_max_instances_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
package main

import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"net/url"
"path/filepath"
"strings"
"sync"
"testing"

"github.com/LeanerCloud/cloud-commitments-go/pkg/common"
Expand All @@ -12,6 +19,91 @@ import (
"github.com/stretchr/testify/require"
)

// maxInstancesAWSStub is the offline AWS endpoint behind the duplicate check
// (checkDuplicates -> GetExistingCommitments). Every request must match a
// fixture keyed "host Action"; anything else fails the test, so a request that
// would have left the machine is reported instead of silently timing out.
type maxInstancesAWSStub struct {
t *testing.T
mu sync.Mutex
received map[string]int
log *bytes.Buffer
}

// maxInstancesAWSFixtures answer the Query-protocol DescribeReserved* calls
// with an empty existing-commitment list.
var maxInstancesAWSFixtures = map[string]string{
"rds.us-east-1.amazonaws.com DescribeReservedDBInstances": maxInstancesEmptyRDS,
"rds.us-west-2.amazonaws.com DescribeReservedDBInstances": maxInstancesEmptyRDS,
"rds.eu-west-1.amazonaws.com DescribeReservedDBInstances": maxInstancesEmptyRDS,
"elasticache.us-east-1.amazonaws.com DescribeReservedCacheNodes": maxInstancesEmptyElastiCache,
"elasticache.us-west-2.amazonaws.com DescribeReservedCacheNodes": maxInstancesEmptyElastiCache,
"elasticache.eu-west-1.amazonaws.com DescribeReservedCacheNodes": maxInstancesEmptyElastiCache,
}

const (
maxInstancesEmptyRDS = `<DescribeReservedDBInstancesResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">` +
`<DescribeReservedDBInstancesResult><ReservedDBInstances/></DescribeReservedDBInstancesResult>` +
`<ResponseMetadata><RequestId>fixture</RequestId></ResponseMetadata></DescribeReservedDBInstancesResponse>`
maxInstancesEmptyElastiCache = `<DescribeReservedCacheNodesResponse xmlns="http://elasticache.amazonaws.com/doc/2015-02-02/">` +
`<DescribeReservedCacheNodesResult><ReservedCacheNodes/></DescribeReservedCacheNodesResult>` +
`<ResponseMetadata><RequestId>fixture</RequestId></ResponseMetadata></DescribeReservedCacheNodesResponse>`
)

func (s *maxInstancesAWSStub) RoundTrip(r *http.Request) (*http.Response, error) {
b, _ := io.ReadAll(r.Body)
form, _ := url.ParseQuery(string(b))
key := r.URL.Host + " " + form.Get("Action")
s.mu.Lock()
s.received[key]++
s.mu.Unlock()
body, ok := maxInstancesAWSFixtures[key]
status := http.StatusOK
if !ok {
s.t.Errorf("unexpected AWS request %s %s%s", r.Method, key, r.URL.Path)
status, body = http.StatusInternalServerError, "unexpected request"
}
return &http.Response{
StatusCode: status,
Header: http.Header{"Content-Type": []string{"text/xml"}},
Body: io.NopCloser(strings.NewReader(body)),
Request: r,
}, nil
}

// newMaxInstancesAWSConfig returns an aws.Config whose HTTP client is the
// stub and whose credentials are anonymous, so requests are unsigned and need
// no environment.
func newMaxInstancesAWSConfig(t *testing.T) (aws.Config, *maxInstancesAWSStub) {
t.Helper()
stub := &maxInstancesAWSStub{t: t, received: map[string]int{}, log: captureAppLog(t)}
return aws.Config{
Region: "us-east-1",
HTTPClient: &http.Client{Transport: stub},
Credentials: aws.AnonymousCredentials{},
Retryer: func() aws.Retryer { return aws.NopRetryer{} },
}, stub
}

// requireDuplicateChecks asserts the duplicate check really ran against the
// stub: one call per (service, region) pair, no other request, and every
// response parsed.
func (s *maxInstancesAWSStub) requireDuplicateChecks(t *testing.T, pairs int) {
t.Helper()
s.mu.Lock()
defer s.mu.Unlock()
total := 0
for k, n := range s.received {
assert.Contains(t, maxInstancesAWSFixtures, k)
assert.Equalf(t, 1, n, "duplicate-check requests for %s", k)
total += n
}
// A fixture the SDK cannot parse only logs this warning in dry-run, so the
// request count alone would not notice a broken fixture.
assert.NotContains(t, s.log.String(), "Could not check for existing RIs")
require.Equal(t, pairs, total, fmt.Sprintf("duplicate-check requests received: %v", s.received))
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// maxInstancesFixtureServices and maxInstancesFixtureRegions describe the
// multi-service, multi-region fan-out the run-wide cap has to survive. A
// single-service or single-region fixture stays green with the per-region bug
Expand Down Expand Up @@ -77,7 +169,7 @@ func TestMaxInstancesCapsWholeRunAcrossServicesAndRegions(t *testing.T) {
const maxInstances = 10

ctx := context.Background()
awsCfg := aws.Config{Region: "us-east-1"}
awsCfg, awsStub := newMaxInstancesAWSConfig(t)

origCfg := toolCfg
t.Cleanup(func() { toolCfg = origCfg })
Expand All @@ -94,6 +186,7 @@ func TestMaxInstancesCapsWholeRunAcrossServicesAndRegions(t *testing.T) {
accountCache := NewAccountAliasCache(awsCfg)
allRecs, drops, _ := fetchAllRecs(ctx, awsCfg, mockClient, accountCache,
maxInstancesFixtureServices, engineVersionData{}, toolCfg, nil)
awsStub.requireDuplicateChecks(t, len(maxInstancesFixtureServices)*len(maxInstancesFixtureRegions))

pairs := len(maxInstancesFixtureServices) * len(maxInstancesFixtureRegions)
naturalTotal := pairs * countPerFixtureRec
Expand Down Expand Up @@ -149,7 +242,7 @@ func TestMaxInstancesKeepsHighestSavingsNotFirstFetched(t *testing.T) {
)

ctx := context.Background()
awsCfg := aws.Config{Region: "us-east-1"}
awsCfg, awsStub := newMaxInstancesAWSConfig(t)

origCfg := toolCfg
t.Cleanup(func() { toolCfg = origCfg })
Expand All @@ -174,6 +267,7 @@ func TestMaxInstancesKeepsHighestSavingsNotFirstFetched(t *testing.T) {
accountCache := NewAccountAliasCache(awsCfg)
allRecs, drops, _ := fetchAllRecs(ctx, awsCfg, mockClient, accountCache,
maxInstancesFixtureServices, engineVersionData{}, toolCfg, nil)
awsStub.requireDuplicateChecks(t, len(maxInstancesFixtureServices)*len(maxInstancesFixtureRegions))
require.Len(t, allRecs, len(maxInstancesFixtureServices)*len(maxInstancesFixtureRegions))

scored := scoreLimitAndDisplay(allRecs, toolCfg, drops)
Expand Down Expand Up @@ -223,7 +317,7 @@ func TestMaxInstancesNeverPurchasesBelowMinCount(t *testing.T) {
)

ctx := context.Background()
awsCfg := aws.Config{Region: "us-east-1"}
awsCfg, awsStub := newMaxInstancesAWSConfig(t)

origCfg := toolCfg
t.Cleanup(func() { toolCfg = origCfg })
Expand All @@ -243,6 +337,7 @@ func TestMaxInstancesNeverPurchasesBelowMinCount(t *testing.T) {
accountCache := NewAccountAliasCache(awsCfg)
allRecs, drops, _ := fetchAllRecs(ctx, awsCfg, mockClient, accountCache,
maxInstancesFixtureServices, engineVersionData{}, toolCfg, nil)
awsStub.requireDuplicateChecks(t, len(maxInstancesFixtureServices)*len(maxInstancesFixtureRegions))
require.Len(t, allRecs, len(maxInstancesFixtureServices)*len(maxInstancesFixtureRegions))

scored := scoreLimitAndDisplay(allRecs, toolCfg, drops)
Expand Down Expand Up @@ -312,7 +407,7 @@ func TestDropTruncatedBelowMinCount(t *testing.T) {
// run that never asked for one.
func TestMaxInstancesNotAppliedWhenUnset(t *testing.T) {
ctx := context.Background()
awsCfg := aws.Config{Region: "us-east-1"}
awsCfg, awsStub := newMaxInstancesAWSConfig(t)

origCfg := toolCfg
t.Cleanup(func() { toolCfg = origCfg })
Expand All @@ -329,6 +424,7 @@ func TestMaxInstancesNotAppliedWhenUnset(t *testing.T) {
accountCache := NewAccountAliasCache(awsCfg)
allRecs, drops, _ := fetchAllRecs(ctx, awsCfg, mockClient, accountCache,
maxInstancesFixtureServices, engineVersionData{}, toolCfg, nil)
awsStub.requireDuplicateChecks(t, len(maxInstancesFixtureServices)*len(maxInstancesFixtureRegions))

scored := scoreLimitAndDisplay(allRecs, toolCfg, drops)

Expand Down
Loading