module Pqi.Conformance.Operation.Cancel.Stale
( spec,
)
where
import Control.Exception (bracket)
import qualified Pqi
import qualified Pqi as Lq
import Pqi.Conformance.Observation (ResultObservation (..))
import Pqi.Conformance.Prelude
import Pqi.Conformance.Scenario (drainResults, execScenario, float8Oid)
import System.Timeout (timeout)
import Test.Hspec
iterations :: Int
iterations :: Int
iterations = Int
30
spec :: Pqi.Adapter -> SpecWith ByteString
spec :: Adapter -> SpecWith ByteString
spec Adapter
adapter =
String -> SpecWith ByteString -> SpecWith ByteString
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe String
"stale cancel" do
String
-> (ByteString -> IO ()) -> SpecWith (Arg (ByteString -> IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"does not corrupt the next command when a cancel is sent during pipeline clean-up" \ByteString
conninfo -> do
outcomes <- [Int]
-> (Int -> IO (Int, Maybe (ExecStatus, Maybe ByteString)))
-> IO [(Int, Maybe (ExecStatus, Maybe ByteString))]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for [Int
1 .. Int
iterations] \Int
i -> do
outcome <- Adapter -> ByteString -> IO (Maybe (ExecStatus, Maybe ByteString))
runScenario Adapter
adapter ByteString
conninfo
pure (i, outcome)
let corrupted = [(Int
i, (ExecStatus, Maybe ByteString)
outcome) | (Int
i, Just (ExecStatus, Maybe ByteString)
outcome) <- [(Int, Maybe (ExecStatus, Maybe ByteString))]
outcomes]
corrupted `shouldBe` []
runScenario ::
Pqi.Adapter ->
ByteString ->
IO (Maybe (Lq.ExecStatus, Maybe ByteString))
runScenario :: Adapter -> ByteString -> IO (Maybe (ExecStatus, Maybe ByteString))
runScenario Adapter
adapter ByteString
conninfo =
IO Connection
-> (Connection -> IO ())
-> (Connection -> IO (Maybe (ExecStatus, Maybe ByteString)))
-> IO (Maybe (ExecStatus, Maybe ByteString))
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket (Adapter -> ByteString -> IO Connection
Lq.connectdb Adapter
adapter ByteString
conninfo) Connection -> IO ()
Lq.finish \Connection
connection -> do
_ <- Connection -> IO Bool
Lq.enterPipelineMode Connection
connection
_ <- Lq.sendPrepare connection "s1" "select $1::int" Nothing
_ <- Lq.sendQueryPrepared connection "s1" [Just ("42", Lq.Text)] Lq.Text
_ <- Lq.sendPrepare connection "s2" "select pg_sleep($1)" (Just [float8Oid])
_ <- Lq.sendQueryPrepared connection "s2" [Just ("0.1", Lq.Text)] Lq.Text
_ <- Lq.pipelineSync connection
_ <- timeout 50_000 (drainResults connection)
_ <- drainResults connection
mHandle <- Lq.getCancel connection
_ <- for mHandle Lq.cancel
_ <- drainResults connection
statusBefore <- Lq.pipelineStatus connection
when (statusBefore == Lq.PipelineOn) do
_ <- Lq.pipelineSync connection
_ <- drainResults connection
_ <- Lq.sendFlushRequest connection
_ <- drainResults connection
ok <- Lq.exitPipelineMode connection
unless ok do
_ <- drainResults connection
void (Lq.exitPipelineMode connection)
execScenario "select 99" connection >>= \case
Maybe ResultObservation
Nothing -> Maybe (ExecStatus, Maybe ByteString)
-> IO (Maybe (ExecStatus, Maybe ByteString))
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((ExecStatus, Maybe ByteString)
-> Maybe (ExecStatus, Maybe ByteString)
forall a. a -> Maybe a
Just (ExecStatus
Lq.FatalError, ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
"no-result"))
Just ResultObservation
observation ->
case ResultObservation -> ExecStatus
status ResultObservation
observation of
ExecStatus
Lq.TuplesOk -> Maybe (ExecStatus, Maybe ByteString)
-> IO (Maybe (ExecStatus, Maybe ByteString))
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (ExecStatus, Maybe ByteString)
forall a. Maybe a
Nothing
ExecStatus
status -> Maybe (ExecStatus, Maybe ByteString)
-> IO (Maybe (ExecStatus, Maybe ByteString))
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((ExecStatus, Maybe ByteString)
-> Maybe (ExecStatus, Maybe ByteString)
forall a. a -> Maybe a
Just (ExecStatus
status, Maybe ByteString -> Maybe (Maybe ByteString) -> Maybe ByteString
forall a. a -> Maybe a -> a
fromMaybe Maybe ByteString
forall a. Maybe a
Nothing (FieldCode
-> [(FieldCode, Maybe ByteString)] -> Maybe (Maybe ByteString)
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup FieldCode
Lq.DiagSqlstate (ResultObservation -> [(FieldCode, Maybe ByteString)]
errorFields ResultObservation
observation))))