Repository navigation
fix(aws-vpclattice): close the real-cloud parity gaps in #1451 - #1551
Conversation
Validate enums and ports, refuse duplicates and in-use deletes, check references, return serviceArns, the default rule and paginated lists, model create-time statuses and target health, and record Lattice calls as CloudTrail management events. Closes stackshy#1451.
NitinKumar004
left a comment
There was a problem hiding this comment.
Thanks for this. It covers the whole of #1451 in one go, and the rules sit in the provider where they belong. I built the head commit (16e3be7) myself and tested it three ways: the AWS CLI against cloudemu serve, the real Terraform AWS provider, and the same CLI script against a development build to confirm each item fails there first. All 19 items behave as described. I found one regression and one leftover leniency, both in the rule code, plus a few small gaps.
Issue coverage
| Item in #1451 | Status | Evidence (CLI against serve; development behaviour in brackets) |
|---|---|---|
| CreateTargetGroup type=BOGUS | Fixed | ValidationException 400 [accepted] |
| DeleteTargetGroup while a rule forwards to it | Fixed | ConflictException 409, for both rule and listener default action [deleted] |
| CreateListener FTP / port 999999 | Fixed | ValidationException for each [accepted] |
| CreateServiceNetwork authType=BOGUS | Fixed | ValidationException [accepted] |
| Duplicate service name | Fixed | ConflictException [accepted] |
| Duplicate service-network name | Fixed | ConflictException [accepted] |
| Duplicate rule priority on a listener | Fixed | ConflictException [accepted, two rules at priority 1] |
| Duplicate SN-service association | Fixed | ConflictException [accepted] |
| SN VPC association with a nonexistent VPC | Fixed | ResourceNotFoundException [accepted] |
| AccessLogSubscription on a nonexistent resource | Fixed | ResourceNotFoundException [accepted] |
| DeleteResourceGateway while referenced | Fixed | covered by provider and SDK tests |
| TargetGroup.serviceArns | Fixed | returns the forwarding service ARN [null] |
| ListRules default rule | Fixed, but see Medium 2 | default rule with isDefault: true is listed first; DeleteRule on it gives ValidationException |
| RegisterTargets immediately HEALTHY | Fixed | INITIAL then HEALTHY with --async-settle (FakeClock tests); unchanged when settle is off |
| PutAuthPolicy malformed JSON | Fixed | ValidationException [accepted] |
BatchUpdateRule NotFound: prefix |
Fixed | failureMessage is rule "..." not found [NotFound: rule ...] |
| List* maxResults / nextToken | Fixed | maxResults=1 returns a page plus a token; all list ops go through one helper |
| Statuses immediately ACTIVE | Fixed | with --async-settle, Terraform waiters for service, target groups and associations waited about 5s, then completed |
| No CloudTrail events | Fixed | LookupEvents shows the Lattice calls (CreateRule, UpdateRule, BatchUpdateRule, ListTargets and so on) with source vpc-lattice.amazonaws.com |
I found no items claimed but not delivered and nothing skipped silently. The PR body and the non-goals page list the sibling gaps it leaves out.
Findings
Medium
1. Rule priority is capped at 100, but AWS allows 1 to 2000. Priorities that work today now fail.
providers/aws/vpclattice/validate.go:28 (maxRulePriority = 100)
The CreateRule and UpdateRule references both give priority a valid range of 1 to 2000. On this branch aws vpc-lattice create-rule --priority 500 returns ValidationException: rule priority 500 is out of range 1-100. On development the same call succeeds, so any CLI or SDK user with a priority from 101 to 2000 hits a new failure that real AWS would not give. The non-goals page (line 4) calls 1 to 100 "the documented one", which is also wrong. The Terraform provider checks 1 to 100 on its own side, so Terraform users never get this far; the CLI and SDKs don't check it.
Fix: set the max to 2000, update the non-goals sentence, and add a test case at 2000 and 2001.
2. UpdateRule and BatchUpdateRule can change the default rule. AWS refuses this.
providers/aws/vpclattice/rules.go:55, called from lines 204 and 296.
The UpdateRule reference says: "You can't modify a default listener rule. To modify a default listener rule, use UpdateListener." On this branch, update-rule --rule-identifier <default rule id> --action '{"fixedResponse":{"statusCode":503}}' succeeds and rewrites the listener's default action. A test that changes the default action through UpdateRule would pass here and fail on AWS. That is the kind of gap #1451 is meant to close, and this PR adds it.
Fix: return a ValidationException for the default rule in UpdateRule, and the same failure entry in BatchUpdateRule, as DeleteRule already does. updateDefaultRule can then go. Update the non-goals bullet to match.
Low
3. A TLS_PASSTHROUGH listener created without a port stores port 0.
providers/aws/vpclattice/validate.go:80
validateListener fills in 80 for HTTP and 443 for HTTPS when the port is omitted, but leaves 0 for TLS_PASSTHROUGH. create-listener --protocol TLS_PASSTHROUGH without --port succeeds, and the listener then comes back with no port. The CreateListener response documents port as 1 to 65535. Either require a port for TLS_PASSTHROUGH (ValidationException) or reject 0 after the defaults are applied.
4. Target health never reports UNUSED.
providers/aws/vpclattice/targets.go:58
The SDK's TargetStatus includes UNUSED ("The target group is not used in a listener rule"). AWS reports that status for targets in a group that no listener or rule forwards to. A target registered in an unattached group still goes INITIAL then HEALTHY here. targetGroupInUse from this PR could answer the question directly. This is fine as a follow-up, but it is worth a line in the non-goals page.
5. Coverage of server/aws/vpclattice is 70.4%.
That's what I measured locally with go test -race -coverprofile; the provider package is at 92.5%. This was about the same before the PR, but it is still well below 90%. The new event_name.go branches (tags, policies, domain verifications, unknown verbs) are the cheapest place to add cases.
AWS docs divergences
- Rule priority range: AWS says 1 to 2000, the PR uses 1 to 100. CreateRule, UpdateRule
- UpdateRule on the default rule: AWS forbids it, the PR allows it. UpdateRule
- TLS_PASSTHROUGH listener port: AWS says 1 to 65535, the PR stores 0 when omitted. CreateListener
- Target status
UNUSEDis not modelled. TargetSummary - Checked and consistent: ListTargets takes maxResults (1 to 100) and nextToken as query parameters; DeleteRule refuses the default rule; ConflictException is 409 and ResourceNotFoundException is 404 on the create and delete paths; ID and ARN shapes (
sn-,svc-,tg-,listener-,rule-,snsa-,snva-, each with 17 characters) match the documented patterns, including the derived default-rule id.
Terraform and CLI
Terraform 1.14.3 with hashicorp/aws 6.68.0, pointed at serve through endpoints { vpclattice, ec2 }. The config had aws_vpc, aws_vpclattice_service_network, aws_vpclattice_service, two aws_vpclattice_target_group (one with a health check), aws_vpclattice_listener (forward default action), aws_vpclattice_listener_rule (path match, weighted forward 60/40 across both groups), aws_vpclattice_service_network_service_association and aws_vpclattice_service_network_vpc_association.
- apply: 9 created, no waiter hang.
plan -detailed-exitcode: 0. - I changed tags on six resources: apply completed with 6 changed, then plan returned 0.
- destroy: 9 destroyed, in the right order (rule, listener, then target groups, so the new in-use check did not get in the way). Every follow-up
get-*returned ResourceNotFoundException. - The same run with
--async-settle: waiters polled CREATE_IN_PROGRESS for about 5s and then completed. Plan returned 0 and destroy was clean. - A side note, not caused by this PR: changing
priorityonaws_vpclattice_listener_ruleleaves drift. Provider 6.68.0 sends UpdateRule with an empty{}body, so the priority is never sent. The CLIupdate-rule --prioritypath works correctly.
CLI: every error case in the table above, against this branch and against development. I also checked a --persist restart: after the restart, serviceArns, the default rule (same id), the in-use refusal on DeleteTargetGroup and the name-uniqueness conflict all still held.
What I verified
- I reviewed the head commit itself, not the PR's self-reported results.
go build ./...andgo veton the touched packages are clean. go test -raceonproviders/aws/vpclatticeandserver/aws/vpclatticepasses (it includes the 50-way concurrent create tests). The CloudTrail, authorization, wiring and snapshot tests inserver/aws,providers/awsandpersistalso pass.go generate .leaves no diff, and gofmt is clean on the touched files.- golangci-lint: CI Lint is green. Locally, linter 2.14 reports extra
goconsthits, mostly route-name strings repeated betweenevent_name.goandhandler.go. They don't fail CI, but reusing the new constants inhandler.gofor the remaining roots would remove them. - All CI checks are green.
- Architecture: validation and state rules are in the provider, and the handler only paginates and maps errors. The VPC lookup is wired once through
SetNetworkinginproviders/aws/aws.go. Settling uses the injected clock andsettle.Set. No new persisted state is added (settle windows are documented as in-memory). The driver interface is unchanged, and there is no mirror concern because the service exists only on AWS.
Verdict
Request changes for the two Medium items. Both are small, contained in validate.go and rules.go, and come with doc-backed fixes. Everything else is solid and I would approve after those two.
| maxPort = 65535 | ||
|
|
||
| minRulePriority = 1 | ||
| maxRulePriority = 100 |
There was a problem hiding this comment.
The CreateRule and UpdateRule API references both give priority a valid range of 1 to 2000 (https://docs.aws.amazon.com/vpc-lattice/latest/APIReference/API_CreateRule.html). With 100 here, aws vpc-lattice create-rule --priority 500 now fails with ValidationException, while it succeeds on development and on AWS. Can this be 2000, with a test at 2000 and 2001?
There was a problem hiding this comment.
Confirmed against the CreateRule / UpdateRule reference (Valid Range 1 to 2000). My 1-100 was a guess that I wrongly called documented. The max is now 2000, with tests at 500, 2000 and 2001 (provider, SDK and CLI), fixed in 6449cc1.
|
|
||
| // updateDefaultRule applies a rule update to the listener's default action; the | ||
| // default rule has no priority or match to change. | ||
| func (m *Mock) updateDefaultRule(l *driver.Listener, priority int32, match, action []byte) (*driver.Rule, error) { |
There was a problem hiding this comment.
The UpdateRule reference says "You can't modify a default listener rule. To modify a default listener rule, use UpdateListener." Here UpdateRule on the default rule succeeds and rewrites the listener's default action, so a test can pass locally and fail on AWS. I'd return a ValidationException for the default rule here and in BatchUpdateRule (line 296), the same way DeleteRule does, and drop this helper.
There was a problem hiding this comment.
Confirmed ("You can't modify a default listener rule. To modify a default listener rule, use UpdateListener."). UpdateRule and BatchUpdateRule on the default rule now return ValidationException (a per-item failure in the batch), and updateDefaultRule is gone. The default action changes only through UpdateListener, and tests check it is untouched after the refused calls. Fixed in 6449cc1.
| - Resource statuses (`CREATE_IN_PROGRESS` to `ACTIVE` for services, target groups, the three association kinds, resource gateways and resource configurations) and target health (`INITIAL` to `HEALTHY`) settle on the mock's clock only when async settling is on (`--async-settle` / `config.WithAsyncSettle`); otherwise they are final immediately. Settle windows are in memory and are not part of snapshots, so a restored resource reports its final state. Only the create-time transition is modeled: there is no `UPDATE_IN_PROGRESS` or `DELETE_IN_PROGRESS`, and no health checking against real targets. | ||
| - A target group's `serviceArns` is derived at read time from the listener default actions and rules that forward to it. Deleting a target group while any of them still forwards to it is rejected with `ConflictException`. A rule or listener action that names a target group that does not exist is still accepted. | ||
| - Every listener has a synthesized default rule (`isDefault` true, name `default`, no priority) built from the listener's default action. `ListRules` and `GetRule` return it, `UpdateRule` on it changes the listener's default action (its priority and match cannot be changed), and `DeleteRule` on it is rejected with `ValidationException`. Its id is derived from the listener id. Whether real VPC Lattice reports a priority for the default rule, and the exact exception for deleting it, are unconfirmed. | ||
| - Rule priority must be 1 to 100 and unique per listener (`ConflictException` on a duplicate, also per item in `BatchUpdateRule`); the range is the documented one but is unconfirmed against the live service. Service names and service network names are unique per account and region (`ConflictException`). Only the `(service network, service)` association pair is checked for duplicates; duplicate VPC and resource associations, duplicate target group names and duplicate listener ports are still accepted. |
There was a problem hiding this comment.
The documented range is 1 to 2000, not 1 to 100 (CreateRule / UpdateRule API reference), so this sentence needs updating along with the constant.
There was a problem hiding this comment.
Updated to 1 to 2000 with the API reference as the source, and the default-rule bullet now matches the new behaviour. Fixed in 6449cc1.
| } | ||
| } | ||
|
|
||
| return port, nil |
There was a problem hiding this comment.
For TLS_PASSTHROUGH with no port this returns 0, so the listener is stored and returned without a valid port (the API documents 1 to 65535). Either require the port for TLS_PASSTHROUGH or reject 0 after the HTTP and HTTPS defaults are applied.
There was a problem hiding this comment.
Took the first option: TLS_PASSTHROUGH without a port is now a ValidationException. The docs give defaults for HTTP and HTTPS only. What real AWS does for TLS_PASSTHROUGH without a port is unconfirmed, and the non-goals page says so. Fixed in 6449cc1.
| index[targetKey(t)] = len(cur) | ||
| cur = append(cur, t) | ||
|
|
||
| m.statusSettle.Begin(targetSettleKey(id, t), targetStatusInitial, m.opts.Clock.Now(), |
There was a problem hiding this comment.
Small follow-up: AWS reports UNUSED for targets in a group that no listener or rule forwards to. targetGroupInUse from this PR could drive that. If it's out of scope here, a line in the non-goals page would help.
There was a problem hiding this comment.
Left out of this PR on purpose: reporting UNUSED would change the default (sync) health for every existing user, whose targets in an unattached group show HEALTHY today. Added to the non-goals page (UNUSED, UNAVAILABLE and UNHEALTHY are not modeled). Happy to do it as a follow-up using targetGroupInUse.
Allow rule priorities 1-2000 as the API reference documents, refuse UpdateRule and BatchUpdateRule on a listener's default rule (UpdateListener changes it), require a port for TLS_PASSTHROUGH listeners, return ResourceNotFoundException from ListListeners for an unknown service, document the unmodeled UNUSED target status, and share the route-root constants between the handler and the CloudTrail operation names.
|
Thanks for the thorough review and for running the CLI and Terraform checks yourself. Round 1 is pushed in 6449cc1:
Re-verified with the AWS CLI against a |
NitinKumar004
left a comment
There was a problem hiding this comment.
Thanks for turning this round so quickly. I rebuilt the new head (6449cc1) and went back over every point from my first review with the AWS CLI against cloudemu serve, then re-ran the Terraform lifecycle. Both Medium items are fixed, and so is the TLS_PASSTHROUGH port. The UNUSED status is now listed as a non-goal. I found no regressions in the delta.
Earlier items
| Item from the first review | Status | Evidence (CLI against serve on 6449cc1) |
|---|---|---|
| Medium 1: rule priority capped at 100 | Fixed | create-rule --priority 101, 500 and 2000 succeed. 2001 gives ValidationException: rule priority 2001 is out of range 1-2000. update-rule to 2001 is refused and 1999 is accepted. The non-goals page now says 1 to 2000 and cites the API reference. |
| Medium 2: UpdateRule / BatchUpdateRule could change the default rule | Fixed | update-rule on the default rule gives ValidationException: a default listener rule cannot be modified; use UpdateListener. In a batch-update-rule that mixes the default rule with a normal rule, the default rule comes back in unsuccessful with failureCode: ValidationException and the normal rule still updates (priority 1500). The listener's default action stays at 404 afterwards. update-listener to 503 then shows up through get-rule on the default rule. updateDefaultRule has been removed. |
| Low 3: TLS_PASSTHROUGH without a port stored as 0 | Fixed | Without --port, the call fails with ValidationException: listener port is required for protocol TLS_PASSTHROUGH. With --port 8443 it succeeds. HTTPS without a port still defaults to 443. An invalid protocol with no port still gets the protocol error. |
| Low 4: target status never UNUSED | Addressed as a non-goal | The non-goals page now lists UNUSED, UNAVAILABLE and UNHEALTHY as not modelled. Keeping the default health unchanged for existing users is a fair reason. |
Low 5: server/aws/vpclattice coverage 70.4% |
Partly | It is 79.5% in my local go test -race -cover run (82.1% in your measurement, which probably used a wider -coverpkg). The provider is at 92.5%. That is a good improvement, but the package is still under 90%. The new not-found sweep is useful, so I'm fine with this as is. |
| Side note: goconst hits for route names | Fixed | The route roots are now shared constants. The 10 goconst hits that remain locally (linter 2.14) are all JSON keys (items, id, successful, failureCode and so on), and CI Lint is green. |
Delta since 16e3be7
validate.go: the max is now 2000.validateListenerreturns early when a port is given, then defaults HTTP and HTTPS and rejects anything else that has no port. The protocol is still validated before this point, so the order of errors is unchanged.rules.go: UpdateRule andbatchUpdateOnereturnerrDefaultRuleImmutable()for the default rule. The batch path still reports it as a per-item failure and does not fail the whole call.listeners.go: ListListeners now returns ResourceNotFoundException for an unknown service. That matches the ListListeners reference, which lists ResourceNotFoundException (404).serviceARNForis lock-free, so calling it underm.mucannot deadlock. The handler is the only caller of ListListeners, so nothing internal depends on the old empty-list behaviour.event_name.go/handler.go: a constants-only refactor. The route map and the CloudTrail noun map use the same keys as before.- Tests: provider tests cover 500, 1000, 2000 and 2001, UpdateRule to 2001, refused default-rule updates through both paths with the default action left unchanged, TLS_PASSTHROUGH without a port, and ListListeners on an unknown service. The SDK tests mirror these and add a not-found sweep over every get, update, delete and list.
Findings
No High or Medium issues.
Low (pre-existing, not from this PR)
ARN-form identifiers in the URL path don't resolve over the wire.
server/aws/vpclattice/handler.go:62 (splitPath(r.URL.Path), unchanged since August)
The API reference accepts either the ID or the ARN for serviceIdentifier (pattern svc-... or arn:...:service/svc-...). The CLI percent-encodes the ARN's / as %2F, but the handler splits the decoded r.URL.Path. As a result, get-service --service-identifier <service ARN> returns ResourceNotFoundException: service "arn:aws:vpc-lattice:us-east-1:000000000000:service" not found, and create-listener with the ARN returns method not allowed. This PR only touches it in one place: list-listeners with an ARN used to return an empty list silently and now returns the same not-found error, which at least makes the problem visible. It is outside #1451, so a follow-up is fine: split r.URL.EscapedPath() and unescape each segment.
AWS docs check on the changed ops
- CreateRule / UpdateRule: priority 1 to 2000, and the default rule can't be modified. The emulator now matches both.
- CreateListener: "For HTTP, the default is 80. For HTTPS, the default is 443." No default is documented for TLS_PASSTHROUGH, so requiring a port is a reasonable reading. The non-goals page says this is unconfirmed against the live service.
- ListListeners: ResourceNotFoundException (404) is listed. That matches.
Terraform and CLI
Terraform with hashicorp/aws 6.68.0 against serve --async-settle. The config had aws_vpc, aws_vpclattice_service_network, aws_vpclattice_service, aws_vpclattice_target_group, two aws_vpclattice_listener (HTTP with a fixed-response default, and TLS_PASSTHROUGH on 8443 forwarding to the group), aws_vpclattice_listener_rule (priority 20, path match, forward), aws_vpclattice_service_network_service_association and aws_vpclattice_service_network_vpc_association.
- apply: 9 added, and the settle waiters finished in about 18s total.
plan -detailed-exitcode: 0. - update: I changed tags on all seven tagged resources and changed the HTTP listener's default action from 404 to 503. This goes through UpdateListener and is unaffected by the new default-rule guard. The apply reported 7 changed, the next plan returned 0, and
list-rulesthen showed the default rule plusrr-ruleat priority 20, with the listener default action at 503. - destroy: 9 destroyed. All seven Lattice resources then returned ResourceNotFoundException from their
get-*call.
CLI: every check in the table above, plus list-rules on a missing listener (ResourceNotFoundException) and an invalid protocol with no port (protocol ValidationException).
What I verified
- I built the head commit myself.
go build ./...passes, andgo vetand gofmt are clean on the touched packages. go test -racepasses onproviders/aws/vpclattice(92.5%) andserver/aws/vpclattice(79.5%).go generate .leaves no diff.- golangci-lint on the touched packages reports only the 10 JSON-key goconst hits described above. CI Lint is green.
- All CI checks on 6449cc1 are green, including Test (4 shards), Race, Lint, Tidy, Structure and Compat matrix.
- No new persisted state, driver change or cross-provider surface was added, so the earlier
--persistand architecture checks still hold. - The commit message is clean, with author Gajendra Malviya and no co-author or attribution trailer.
Verdict
Approve. Both Medium items and the TLS_PASSTHROUGH gap are fixed and covered by tests at the provider and SDK level, and Terraform runs the full lifecycle cleanly. The ARN-in-path issue is older than this PR and can be a separate ticket.
| m.mu.Lock() | ||
| defer m.mu.Unlock() | ||
|
|
||
| if _, err := m.serviceARNFor(serviceID); err != nil { |
There was a problem hiding this comment.
This matches the ListListeners reference (ResourceNotFoundException, 404). A related issue that is older than this PR: the handler splits the decoded r.URL.Path, so a service ARN in the path (the CLI sends arn%3A...%3Aservice%2Fsvc-...) is cut at the /. list-listeners --service-identifier <ARN> now fails with service "arn:aws:vpc-lattice:us-east-1:000000000000:service" not found, and get-service and create-listener with an ARN fail the same way. Splitting r.URL.EscapedPath() and unescaping each segment would fix it. Fine as a follow-up.
Summary
cloudemu servebehave the same.The problem (in plain words)
The emulator said yes to requests that real AWS refuses. It accepted a target group of type
BOGUS, a second service with the same name, a rule priority already in use, and a VPC that does not exist. It let you delete a target group that a rule still forwards to. It also left out things real AWS reports: the default rule, the services using a target group, in-progress statuses and CloudTrail events. A test that passed against cloudemu could then fail against real AWS.How this fixes it
serviceArns, the default rule,nextTokenpagination, clean batch-failure messages.Changes
How it works:
flowchart LR C[AWS CLI / SDK] --> W[server/aws/vpclattice<br/>decode, paginate, map errors] W --> P[providers/aws/vpclattice<br/>validate, uniqueness, references, status] P --> S[(memstore)] P -. VPC lookup .-> V[providers/aws/vpc] W -. operation name .-> T[CloudTrail recorder]typemust be IP, LAMBDA, INSTANCE or ALB, else ValidationExceptionisDefaulttrue, namedefault);UpdateRule,BatchUpdateRuleandDeleteRuleon it are ValidationExceptions, as the API reference says; the default action changes only throughUpdateListenerNotFound:vpc-lattice.amazonaws.com, name derived from method and path)Where unconfirmed against the live service (kept in
docs/coverage/nongoals/vpclattice.md): the exact error message wording, whether the default rule reports a priority, the TLS_PASSTHROUGH port rule, and the exception for a missing VPC (chosen ResourceNotFoundException). Tests assert exception type and HTTP status, not message text.Not changed (sibling gaps, left for #1451): target-group name uniqueness, target-group config protocol enum, duplicate VPC and resource associations, duplicate listener ports,
PutResourcePolicyvalidation, thePutAuthPolicynewline rule, rule and listener actions that name a missing target group, access-log destination checks.One small fix beyond the 19 items, found by the not-found test sweep:
ListListenersfor a service that does not exist returned an empty list; it now returns ResourceNotFoundException like the other list operations.Behaviour change to be aware of: stricter validation can fail tests that relied on the old lenient behaviour. Two existing tests pinned it and were updated (
ListRulesnow includes the default rule; the SDK association test uses a real VPC).Checklist of the maintainers' recurring review points: create paths are atomic under the mock's existing mutex (race-tested with 50 parallel creates), reads return deep copies (race-probed), typed exceptions come only from each operation's modeled set, validation lives in the provider, time and settling go through the injected clock, rejected creates store nothing, no new persisted state, and
TestSnapshotCompletenessstays green.Provider Coverage
Azure, GCP and OCI are not applicable: VPC Lattice exists only on AWS.
Checklist
go test ./...)golangci-lint run --timeout=9m ./...)Integration tests in
cloudemu_test.gowere not added: recent single-service PRs keep SDK round-trip tests beside the service, and this PR does the same (happy to add one if you want it).go generate ./...for coverage;go run ./internal/compatgenfor the compat matrix) and committed the resultTest Plan
providers/aws/vpclattice/vpclattice_test.go) cover every item, with edge cases (own-priority update, batch update with a repeated priority, id versus ARN references, a standalone mock without the VPC service),-racetests with 50 concurrent creates, andFakeClocksettle tests.aws-sdk-go-v2round trips (server/aws/vpclattice/sdk_roundtrip_test.go) assert the typed exception (errors.As) and HTTP status for each rejection, pagination over every list operation with page size 1, andOperationNamefor the REST routes.server/aws/cloudtrail_recording_test.gochecksLookupEventsafter Lattice calls.-race, baseline fromdevelopment):development.Dockerfile, driven by boto3 in a fresh virtualenv with default flags: all typed errors and statuses as above.go installwithcloudemu start,status,stop.init,applyof a service, target group, listener and rule,planshowing no changes, and a cleandestroy.--async-settle(CREATE_IN_PROGRESS to ACTIVE, INITIAL to HEALTHY),--persistrestart, snapshot and rewind,--enforce-authtogether with S3, and 50-way parallel creates with no race reports in the server log.go test ./...,go test -raceon the touched packages,go build -mod=readonly ./..., golangci-lint on the touched packages (0 issues),go generate ./...andgo run ./internal/compatgen(no drift beyond the regenerated Lattice coverage page).providers/aws/vpclattice81.7% to 89.9%;server/aws/vpclattice70.9% to 82.1%.Related Issues
Closes #1451. It covers all 19 items, so every box in the issue can be ticked.