Parity grade: A · SDK aws-sdk-go-v2/service/redshiftdata@v1.43.4 · last audited 2026-08-10 (cf439a0b1)
| Metric | Value |
|---|---|
| Operations audited | 12 (7 ok, 1 partial, 4 gap) |
| Feature families | 2 (2 ok) |
| Known gaps | 8 |
| Deferred items | 1 |
| Resource leaks | clean |
- CancelStatement can never succeed against this backend: ExecuteStatement/BatchExecuteStatement set Status=FINISHED synchronously, so by the time a client calls CancelStatement the statement is always already terminal and CancelStatement always returns ErrTerminalState (ValidationException). This matches real AWS semantics ("To be canceled, a query must be running") given the backend's synchronous-completion design. Not fixed this pass -- would require modeling async statement execution (a state machine with a delay before reaching FINISHED), which is a larger behavioral change beyond a wire-shape/bug-fix pass.
- ValidateConnectionTarget (models.go) enforces "exactly one of ClusterIdentifier/WorkgroupName" per real AWS constraints but is never called from any handler. ExecuteStatement/BatchExecuteStatement handlers are intentionally permissive (see TestHandler_ExecuteStatement_AllowsBothClusterAndWorkgroup / AllowsNeitherClusterNorWorkgroup in handler_statements_validation_test.go) -- this looks like a deliberate relaxation for ease of testing rather than an oversight, so left as-is. Re-review if strict AWS-parity validation becomes a priority.
- DescribeStatement does not return RedshiftPid (optional field, always absent instead of 0); DbGroups not returned by ExecuteStatement/BatchExecuteStatement. Both are optional wire fields the real client zero-values when absent, so not a functional gap, just lower fidelity -- no group/pid registry exists in this mock to source real values from.
- SessionKeepAliveSeconds is accepted on ExecuteStatement/BatchExecuteStatement's wire (unmarshalled into the request struct) but is accepted-then-silently-dropped: it never reaches the backend call and has no effect. Session keep-alive/expiry requires modeling time-bounded session lifetimes this in-memory backend does not have; inventing it risks fabricating undocumented AWS semantics not verifiable without a live cluster (same reasoning as rdsdata's typeHint gap). Relatedly, this mock does NOT mint a fresh SessionId when SessionKeepAliveSeconds>0 and no SessionId is supplied (real AWS would start a new session and return its id) -- SessionId here is pure passthrough of whatever the caller already provided, since there's no session-scoped state (temp tables, transaction visibility, etc.) that a minted id would actually gate. (ClientToken was in this same category through last pass -- now fixed, see ExecuteStatement/BatchExecuteStatement rows and idempotency.go.)
- RoleLevel is parsed on ListStatements' and ListSessions' request bodies but never applied as a filter (accepted-then-silently-dropped: decoded into the request struct but never placed on ListStatementsFilter/ListSessionsFilter, so it never reaches the backend at all): real semantics are "true (default) = all statements/sessions this IAM role has run, false = only this IAM session's," but this mock has no per-caller-identity or per-IAM-session model, so there is no signal to filter on. All statements/sessions are visible regardless of RoleLevel, matching the "true" default in effect at all times.
- ActiveStatementsExceededException/ActiveSessionsExceededException/ExecuteStatementException (modeled on ExecuteStatement's error deserializer) and BatchExecuteStatementException (BatchExecuteStatement's), DatabaseConnectionException/QueryTimeoutException (CancelStatement's), and ActiveWaitingRequestsExceededException (DescribeStatement's/GetStatementResult's/GetStatementResultV2's -- previously missing from this gap entry entirely) are all real modeled exception types, confirmed this pass by grepping each operation's awsAwsjson11_deserializeOpError function in aws-sdk-go-v2/service/redshiftdata@v1.43.4's deserializers.go for its strings.EqualFold(...) cases (NOT literal
case "X":labels). All are unreachable by design in this backend: ExecuteStatement/BatchExecuteStatement always complete synchronously and successfully against in-memory demo data (no real cluster connection to fail, no concurrent-statement/session limit tracked, no waiting-request queue). Deliberately NOT implemented this pass: inventing trigger conditions (e.g. an arbitrary "N active statements" cap, or making some ClusterIdentifier/SecretArn values fail with DatabaseConnectionException) would fabricate gopherstack-only behavior with no real-AWS trigger to field-diff against -- consistent with rdsdata's precedent of leaving unreachable-by-design SDK exceptions undone rather than guessing. - ListStatements items include several fields (ClusterIdentifier, WorkgroupName, Database, DbUser, HasResultSet, Duration) that don't exist on the real StatementData shape at all. The AWS SDK's JSON deserializer silently discards unknown keys, so this is harmless today, but flagged in case a future SDK version repurposes one of those key names.
- ListSessions (new this pass) never returns Status=BUSY or Status=CLOSED, and never returns SessionAliveSeconds/SessionTtl/CurrentStatementId at all: this backend executes every statement synchronously to a terminal state (no mid-flight window to observe BUSY/CurrentStatementId) and does not track SessionKeepAliveSeconds expiry (no SessionTtl to compare "now" against, so CLOSED can never be derived). Modeling any of these would require the same async-execution and keep-alive state machine already flagged as out-of-scope for CancelStatement/ClientToken/SessionKeepAliveSeconds above -- not invented here for the same reason. ListSessions also can't see sessions that were only ever referenced via SessionKeepAliveSeconds without an explicit SessionId (this mock doesn't mint one, see ExecuteStatement's note).
- none