Documentation
¶
Overview ¶
Package deviceauthtest provides a shared contract test suite for all core.DeviceAuthorizationStore implementations (RFC 8628). Each backend — in-memory, fs, gorm, gae — exercises the same ~10 behavioral scenarios by handing this package a Factory closure and calling RunAll. Mirrors the existing appstoretest / keystoretest precedent.
Why a shared suite: the per-backend test files had started to drift in small ways (wording on error messages, scope-override coverage, LastPolledAt persistence). Pulling the scenarios into one place enforces the contract uniformly and makes adding a fifth backend a one-line RunAll invocation.
Index ¶
- func RunAll(t *testing.T, factory Factory)
- func TestApproveBindsSubjectAndOverridesScopes(t *testing.T, factory Factory)
- func TestApproveTwiceRejects(t *testing.T, factory Factory)
- func TestCleanupExpired(t *testing.T, factory Factory)
- func TestCollision(t *testing.T, factory Factory)
- func TestCreateAndGet(t *testing.T, factory Factory)
- func TestDeleteRemovesUserCodeIndex(t *testing.T, factory Factory)
- func TestDenyTransitions(t *testing.T, factory Factory)
- func TestNotFound(t *testing.T, factory Factory)
- func TestRestartPersists(t *testing.T, factory Factory)
- func TestUpdatePollingBumpsInterval(t *testing.T, factory Factory)
- type Backend
- type Factory
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RunAll ¶
RunAll runs the complete DeviceAuthorizationStore contract suite against the provided factory. Each scenario gets a fresh Backend via factory(t) so state cannot leak between cases.
func TestApproveBindsSubjectAndOverridesScopes ¶
TestApproveBindsSubjectAndOverridesScopes pins the contract that the approving user's GrantedScopes REPLACE the originally-requested scopes (down-scope at consent, RFC 8628 §3.3-adjacent behavior matching the authorization-code grant's scope semantics).
func TestApproveTwiceRejects ¶
TestApproveTwiceRejects pins that a second approval looks like not-found, not a noisy state-transition error — once the record is approved the user_code is functionally consumed and any further lookup-by-user_code MUST be indistinguishable from "no such code," otherwise the verification UI leaks pending-state information.
func TestCleanupExpired ¶
TestCleanupExpired pins that CleanupExpired removes only expired records and reports the count. The non-expired record MUST survive — a naive "delete all" would prematurely cancel pending authorizations.
func TestCollision ¶
TestCollision pins that re-creating a device_code is rejected. The device_code is the AS-issued unique handle the client polls on; a silently-overwritten record would let a second client hijack the first's pending authorization.
func TestCreateAndGet ¶
TestCreateAndGet pins the happy-path round-trip via both lookup keys and verifies user_code lookup is case- and dash-insensitive.
func TestDeleteRemovesUserCodeIndex ¶
TestDeleteRemovesUserCodeIndex pins that Delete clears BOTH lookup paths. The user_code index is a denormalized secondary key; backends that forget to clean it leak a record reachable by user_code but not by device_code.
func TestDenyTransitions ¶
TestDenyTransitions pins that Deny moves the record into the Denied terminal state; the subsequent poll at /api/token will then map this to RFC 8628 §3.5 access_denied.
func TestNotFound ¶
TestNotFound pins that both lookup keys return ErrDeviceAuthorizationNotFound (not a generic error) when the record does not exist.
func TestRestartPersists ¶
TestRestartPersists pins that a record written via the initial Store handle is visible via a freshly-opened handle over the same backing storage. For persistent backends this is the property the backend exists to provide; for in-memory it degenerates to a same-handle round-trip (Reopen returns the receiver) which is trivially true and kept as a no-op so the scenario set is identical across all backends.
func TestUpdatePollingBumpsInterval ¶
TestUpdatePollingBumpsInterval pins RFC 8628 §3.5 slow_down handling: when the AS observes the client polled faster than the advertised interval, the next poll MUST receive an interval bumped by 5 seconds. Also pins that LastPolledAt is persisted so the next poll can do its own interval check.
Types ¶
type Backend ¶
type Backend struct {
Store core.DeviceAuthorizationStore
Reopen func() core.DeviceAuthorizationStore
}
Backend is the per-test fixture handed to every scenario. Store is the initial handle the test exercises; Reopen returns a fresh handle bound to the same backing storage so the RestartPersists scenario can simulate a process restart.
For persistent backends (fs / gorm / gae) Reopen constructs a new store rooted at the same dir / DB connection / namespace. For the in-memory backend Reopen returns the same instance — there is no underlying storage to reconnect to and the property the scenario pins ("data survives a fresh handle") is trivially true.