pqi-conformance-1.0.17.0: src/library/Pqi/Conformance/Operation/Exec/Interrupted.hs
-- | Coverage for a connection reused after its results were left unread: a
-- slow 'Pqi.exec' cut short by 'timeout', and a 'Pqi.sendQuery' or
-- 'Pqi.sendQueryParams' whose results are never fetched. Each is followed by
-- synchronous calls on the same connection.
--
-- The divergence: @pqi-native@'s synchronous flows sent their query and read
-- up to the first @ReadyForQuery@, which belonged to the earlier query
-- whenever its messages were still unread. The call then returned the
-- earlier query's result, every call after it the result of the one before,
-- and 'Pqi.getResult' afterwards the last call's. @libpq@ discards any
-- results left over from a previous query at the start of each synchronous
-- call (@PQexecStart@ in @fe-exec.c@), and its @PQexec@ cannot be
-- interrupted at all (it is a blocking foreign call, so the exception is
-- delivered once it returns), so each call gets its own result.
--
-- Where it surfaced: @pqi-native@ issue #16, which reported the interrupted
-- case for 'Pqi.execParams' (covered by
-- 'Pqi.Conformance.Operation.ExecParams.Interrupted').
--
-- Why this observation: whether 'timeout' returns early differs by design
-- (the reference cannot be interrupted), so only what the connection does
-- afterwards is compared.
module Pqi.Conformance.Operation.Exec.Interrupted
( spec,
)
where
import qualified Pqi
import Pqi.Conformance.Harness
import Pqi.Conformance.Observation
import Pqi.Conformance.Prelude
import Pqi.Conformance.Scenario
import System.Timeout (timeout)
import Test.Hspec
spec :: Pqi.Adapter -> SpecWith ByteString
spec adapter =
describe "exec" do
describe "after unread results" do
it "of an interrupted exec, the next calls return their own results" \conninfo ->
differential adapter conninfo \connection -> do
_ <- timeout 200_000 (Pqi.exec connection "select 'slow' from pg_sleep (1)")
afterwards connection
it "of a sendQuery, the next calls return their own results" \conninfo ->
differential adapter conninfo \connection -> do
sent <- Pqi.sendQuery connection "select 'pending'"
(sent,) <$> afterwards connection
it "of a sendQueryParams, execParams returns its own result" \conninfo ->
differential adapter conninfo \connection -> do
sent <- Pqi.sendQueryParams connection "select 'pending'" [] Pqi.Text
next <- observed "select 'next'" [] Pqi.Text connection
remaining <- takeResult connection
pure (sent, next, remaining)
-- | Two synchronous calls, then whatever 'Pqi.getResult' still has, and the
-- transaction status.
afterwards ::
Pqi.Connection ->
IO (Maybe ResultObservation, Maybe ResultObservation, Maybe ResultObservation, Pqi.TransactionStatus)
afterwards connection = do
one <- execScenario "select 'one'" connection
two <- execScenario "select 'two'" connection
remaining <- takeResult connection
transactionStatus <- Pqi.transactionStatus connection
pure (one, two, remaining, transactionStatus)