mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
test: characterize RDS DB subnet group lifecycle before extraction
This commit is contained in:
@@ -503,3 +503,166 @@ func TestModifyDBSubnetGroup_RejectsAnUnknownName(t *testing.T) {
|
||||
assert.Equal(t, awserrors.ErrorDBSubnetGroupNotFound, awserrors.ValidErrorCodeFromError(err),
|
||||
"the code has to survive resolution or the client sees a 500")
|
||||
}
|
||||
|
||||
// AWS's delete is not idempotent: a repeat, or a delete of a name never
|
||||
// created, reports the group's own not-found fault rather than success.
|
||||
func TestDeleteDBSubnetGroup_RepeatReportsNotFound(t *testing.T) {
|
||||
t.Parallel()
|
||||
h := newCreateHarness(t, testBaseDomain)
|
||||
_, err := h.svc.CreateDBSubnetGroup(t.Context(), subnetGroupInput(testSubnetGroup, "subnet-alpha"), testAccountID)
|
||||
require.NoError(t, err)
|
||||
|
||||
input := &rds.DeleteDBSubnetGroupInput{DBSubnetGroupName: aws.String(testSubnetGroup)}
|
||||
_, err = h.svc.DeleteDBSubnetGroup(t.Context(), input, testAccountID)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = h.svc.DeleteDBSubnetGroup(t.Context(), input, testAccountID)
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, awserrors.ErrorDBSubnetGroupNotFound, awserrors.ValidErrorCodeFromError(err),
|
||||
"the code has to survive resolution or the client sees a 500")
|
||||
}
|
||||
|
||||
// Identity is the name within one account: another account neither sees nor
|
||||
// deletes the group, and may hold its own group of the same name.
|
||||
func TestDBSubnetGroup_NameIsScopedToTheAccount(t *testing.T) {
|
||||
t.Parallel()
|
||||
const otherAccount = "210987654321"
|
||||
h := newCreateHarness(t, testBaseDomain)
|
||||
_, err := h.svc.CreateDBSubnetGroup(t.Context(), subnetGroupInput(testSubnetGroup, "subnet-alpha"), testAccountID)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = h.svc.DescribeDBSubnetGroups(t.Context(),
|
||||
&rds.DescribeDBSubnetGroupsInput{DBSubnetGroupName: aws.String(testSubnetGroup)}, otherAccount)
|
||||
assert.Equal(t, awserrors.ErrorDBSubnetGroupNotFound, awserrors.ValidErrorCodeFromError(err))
|
||||
_, err = h.svc.DeleteDBSubnetGroup(t.Context(),
|
||||
&rds.DeleteDBSubnetGroupInput{DBSubnetGroupName: aws.String(testSubnetGroup)}, otherAccount)
|
||||
assert.Equal(t, awserrors.ErrorDBSubnetGroupNotFound, awserrors.ValidErrorCodeFromError(err))
|
||||
|
||||
_, err = h.svc.CreateDBSubnetGroup(t.Context(), subnetGroupInput(testSubnetGroup, "subnet-zebra"), otherAccount)
|
||||
require.NoError(t, err)
|
||||
|
||||
out, err := h.svc.DescribeDBSubnetGroups(t.Context(), &rds.DescribeDBSubnetGroupsInput{}, testAccountID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, out.DBSubnetGroups, 1)
|
||||
require.Len(t, out.DBSubnetGroups[0].Subnets, 1)
|
||||
assert.Equal(t, "subnet-alpha", aws.StringValue(out.DBSubnetGroups[0].Subnets[0].SubnetIdentifier),
|
||||
"the other account's create must not overwrite this one")
|
||||
}
|
||||
|
||||
// The group is read once, at placement: changing its subnets afterwards
|
||||
// shapes later placements only and never moves an instance already placed.
|
||||
func TestModifyDBSubnetGroup_LeavesAPlacedInstanceWhereItIs(t *testing.T) {
|
||||
t.Parallel()
|
||||
h := newCreateHarness(t, testBaseDomain)
|
||||
_, err := h.svc.CreateDBSubnetGroup(t.Context(), subnetGroupInput(testSubnetGroup, "subnet-zebra"), testAccountID)
|
||||
require.NoError(t, err)
|
||||
|
||||
input := validCreateInput()
|
||||
input.DBSubnetGroupName = aws.String(testSubnetGroup)
|
||||
_, err = h.svc.CreateDBInstance(t.Context(), input, testAccountID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "subnet-zebra", h.record(t, testDBInstanceID).SubnetID)
|
||||
|
||||
_, err = h.svc.ModifyDBSubnetGroup(t.Context(),
|
||||
modifySubnetGroupInput(testSubnetGroup, "subnet-alpha", "subnet-zebra"), testAccountID)
|
||||
require.NoError(t, err)
|
||||
|
||||
rec := h.record(t, testDBInstanceID)
|
||||
assert.Equal(t, "subnet-zebra", rec.SubnetID, "a fresh placement would now pick subnet-alpha")
|
||||
assert.Equal(t, testSubnetGroup, rec.DBSubnetGroupName)
|
||||
}
|
||||
|
||||
// Only instances hold a group in use: a snapshot records the group's name for
|
||||
// a later restore, but does not block the group's delete.
|
||||
func TestDeleteDBSubnetGroup_IsNotBlockedByASnapshotNamingIt(t *testing.T) {
|
||||
t.Parallel()
|
||||
h := newCreateHarness(t, testBaseDomain)
|
||||
_, err := h.svc.CreateDBSubnetGroup(t.Context(), subnetGroupInput(testSubnetGroup, "subnet-alpha"), testAccountID)
|
||||
require.NoError(t, err)
|
||||
|
||||
kv, err := h.svc.bucket(t.Context(), testAccountID)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, putJSON(t.Context(), kv, DBSnapshotKey("orders-snap"), &DBSnapshotRecord{
|
||||
DBSnapshotIdentifier: "orders-snap",
|
||||
AccountID: testAccountID,
|
||||
Status: SnapshotStatusAvailable,
|
||||
DBSubnetGroupName: testSubnetGroup,
|
||||
}))
|
||||
|
||||
_, err = h.svc.DeleteDBSubnetGroup(t.Context(),
|
||||
&rds.DeleteDBSubnetGroupInput{DBSubnetGroupName: aws.String(testSubnetGroup)}, testAccountID)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Restore is the second consumer of the group's placement: an unknown group
|
||||
// fails it with the group's own fault before anything is reserved.
|
||||
func TestRestoreDBInstanceFromDBSnapshot_RejectsAnUnknownSubnetGroup(t *testing.T) {
|
||||
t.Parallel()
|
||||
h := newSnapshotHarness(t, false)
|
||||
h.seedSnapshot(t)
|
||||
|
||||
input := restoreInput()
|
||||
input.DBSubnetGroupName = aws.String("absent")
|
||||
_, err := h.svc.RestoreDBInstanceFromDBSnapshot(t.Context(), input, testAccountID)
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, awserrors.ErrorDBSubnetGroupNotFound, awserrors.ValidErrorCodeFromError(err),
|
||||
"the code has to survive resolution or the client sees a 500")
|
||||
assert.False(t, h.instanceExists(t, testRestoredID), "a rejected restore must reserve nothing")
|
||||
}
|
||||
|
||||
// Tags live on the group's own record, so they are reached through its ARN and
|
||||
// go when the group does.
|
||||
func TestDBSubnetGroup_TagsAreReachedThroughItsARN(t *testing.T) {
|
||||
t.Parallel()
|
||||
h := newCreateHarness(t, testBaseDomain)
|
||||
input := subnetGroupInput(testSubnetGroup, "subnet-alpha")
|
||||
input.Tags = awsTags("env", "prod")
|
||||
_, err := h.svc.CreateDBSubnetGroup(t.Context(), input, testAccountID)
|
||||
require.NoError(t, err)
|
||||
|
||||
arn := aws.String(FormatARN(ResourceKindDBSubnetGroup, testRegion, testAccountID, testSubnetGroup))
|
||||
out, err := h.svc.ListTagsForResource(t.Context(), &rds.ListTagsForResourceInput{ResourceName: arn}, testAccountID)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, out.TagList, 1)
|
||||
assert.Equal(t, "env", aws.StringValue(out.TagList[0].Key))
|
||||
assert.Equal(t, "prod", aws.StringValue(out.TagList[0].Value))
|
||||
|
||||
_, err = h.svc.DeleteDBSubnetGroup(t.Context(),
|
||||
&rds.DeleteDBSubnetGroupInput{DBSubnetGroupName: aws.String(testSubnetGroup)}, testAccountID)
|
||||
require.NoError(t, err)
|
||||
_, err = h.svc.ListTagsForResource(t.Context(), &rds.ListTagsForResourceInput{ResourceName: arn}, testAccountID)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), awserrors.ErrorDBSubnetGroupNotFound)
|
||||
}
|
||||
|
||||
// The stored shape outlives any move of the code that writes it, so a record
|
||||
// written before a relocation must still decode after it.
|
||||
func TestDBSubnetGroupRecord_PersistedFieldNames(t *testing.T) {
|
||||
t.Parallel()
|
||||
h := newCreateHarness(t, testBaseDomain)
|
||||
input := subnetGroupInput(testSubnetGroup, "subnet-alpha")
|
||||
input.Tags = awsTags("env", "prod")
|
||||
_, err := h.svc.CreateDBSubnetGroup(t.Context(), input, testAccountID)
|
||||
require.NoError(t, err)
|
||||
|
||||
kv, err := h.svc.bucket(t.Context(), testAccountID)
|
||||
require.NoError(t, err)
|
||||
js, err := kv.KV(t.Context())
|
||||
require.NoError(t, err)
|
||||
entry, err := js.Get(t.Context(), DBSubnetGroupKey(testSubnetGroup))
|
||||
require.NoError(t, err)
|
||||
|
||||
var raw map[string]json.RawMessage
|
||||
require.NoError(t, json.Unmarshal(entry.Value(), &raw))
|
||||
keys := make([]string, 0, len(raw))
|
||||
for k := range raw {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
assert.ElementsMatch(t, []string{
|
||||
"name", "accountId", "description", "subnets", "vpcId", "tags", "createdAt", "updatedAt",
|
||||
}, keys)
|
||||
|
||||
var subnets []map[string]string
|
||||
require.NoError(t, json.Unmarshal(raw["subnets"], &subnets))
|
||||
assert.Equal(t, []map[string]string{{"subnetId": "subnet-alpha", "availabilityZone": testZone}}, subnets)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user