package store import ( "testing" "time" ) func TestProposalRecoverySQLBindsParticipantAndExpiresAtReadBoundary(t *testing.T) { for query, fragments := range map[string][]string{ ProposalExpireSQL: {"state = 'OPEN'", "expires_at <= $2", "revision = revision + 1"}, ProposalParticipantExpireSQL: {"response = 'PENDING'", "response = 'TIMED_OUT'", "proposals.state = 'EXPIRED'", "proposals.expires_at <= $2"}, ProposalRecoverySelectSQL: {"proposal_id = $1", "player_id = $2", "EXISTS"}, ProposalParticipantsSelectSQL: {"proposal_id = $1", "ORDER BY player_id"}, ProposalResponseIdempotencyInsertSQL: {"ON CONFLICT (scope, idempotency_key) DO NOTHING", "payload_digest"}, ProposalResponseIdempotencyDeleteSQL: {"DELETE FROM idempotency_keys", "scope = $1", "idempotency_key = $2"}, ProposalLockSQL: {"proposal_id = $1", "FOR UPDATE"}, ProposalParticipantLockSQL: {"proposal_id = $1", "player_id = $2", "FOR UPDATE"}, ProposalParticipantRespondSQL: {"response = 'PENDING'", "responded_at"}, ProposalRevisionBumpSQL: {"revision = revision + 1", "state = 'OPEN'"}, ProposalDeclineActorCancelSQL: {"SET state = 'CANCELLED'", "player_id = $2", "state = 'PROPOSED'"}, ProposalDeclineRequeueSQL: {"SET state = 'QUEUED'", "state = 'PROPOSED'", "player_id <> $3"}, ProposalAbortRequeueSQL: {"SET state = 'QUEUED'", "state = 'PROPOSED'", "proposal_participants"}, ProposalExpireRequeueSQL: {"SET state = 'QUEUED'", "state = 'PROPOSED'", "response = 'ACCEPTED'", "state = 'EXPIRED'"}, ProposalTimeoutTicketExpireSQL: {"SET state = 'EXPIRED'", "response = 'TIMED_OUT'", "state = 'PROPOSED'"}, ProposalCooldownEventsSQL: {"kind IN ('PROPOSAL_DECLINED', 'PROPOSAL_TIMEOUT')", "starts_at >= $3", "starts_at <= $4", "ORDER BY starts_at"}, ProposalCooldownInsertSQL: {"INSERT INTO penalties", "starts_at", "ends_at", "ON CONFLICT (penalty_id) DO NOTHING"}, ProposalTimedOutParticipantsSQL: {"response = 'TIMED_OUT'", "responded_at = $2", "ORDER BY player_id"}, OpenProposalForCancelledTicketSQL: {"proposal_participants", "state = 'OPEN'"}, } { for _, fragment := range fragments { if !contains(query, fragment) { t.Fatalf("query %q missing %q", query, fragment) } } } } func TestProposalRecoveryRejectsMissingAuthorityInputs(t *testing.T) { if _, err := GetProposal(nil, nil, "player-1", "proposal-1", time.Unix(1000, 0)); err == nil { t.Fatal("nil database accepted") } if _, err := GetProposal(nil, nil, "", "proposal-1", time.Unix(1000, 0)); err == nil { t.Fatal("empty player accepted") } }