-- | Coverage for 'Pqi.cancel': requesting cancellation through a handle,
-- both on an idle connection and against a running query (which then fails
-- with SQLSTATE @57014@).
--
-- The full 'Either' value is compared — not just success\/failure — so that
-- any divergence in error text is caught.
module Pqi.Conformance.Operation.Cancel
  ( spec,
  )
where

import qualified Pqi
import Pqi.Conformance.Harness
import qualified Pqi.Conformance.Operation.Cancel.Cleanup as Cleanup
import qualified Pqi.Conformance.Operation.Cancel.Stale as Stale
import Pqi.Conformance.Prelude
import Pqi.Conformance.Scenario (drainResults, execScenario)
import Test.Hspec

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
"cancel" do
    String
-> (ByteString -> IO ()) -> SpecWith (Arg (ByteString -> IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"succeeds on an idle connection" \ByteString
conninfo ->
      Adapter
-> ByteString
-> (Connection -> IO (Maybe (Either ByteString ())))
-> IO ()
forall a.
(Eq a, Show a, HasCallStack) =>
Adapter -> ByteString -> (Connection -> IO a) -> IO ()
differential Adapter
adapter ByteString
conninfo \Connection
connection -> do
        handle <- Connection -> IO (Maybe Cancel)
Pqi.getCancel Connection
connection
        for handle Pqi.cancel

    String
-> (ByteString -> IO ()) -> SpecWith (Arg (ByteString -> IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"fails a running query with 57014" \ByteString
conninfo ->
      Adapter
-> ByteString
-> (Connection
    -> IO
         (Bool, Maybe (Either ByteString ()), [ResultObservation],
          Maybe ResultObservation))
-> IO ()
forall a.
(Eq a, Show a, HasCallStack) =>
Adapter -> ByteString -> (Connection -> IO a) -> IO ()
differential Adapter
adapter ByteString
conninfo \Connection
connection -> do
        sent <- Connection -> ByteString -> IO Bool
Pqi.sendQuery Connection
connection ByteString
"select pg_sleep(10)"
        threadDelay 100000
        handle <- Pqi.getCancel connection
        cancelled <- for handle Pqi.cancel
        results <- drainResults connection
        usable <- execScenario "select 1" connection
        pure (sent, cancelled, results, usable)

    String
-> (ByteString -> IO ()) -> SpecWith (Arg (ByteString -> IO ()))
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"leaves the connection usable after cancelling a short-running query" \ByteString
conninfo ->
      Adapter
-> ByteString
-> (Connection
    -> IO
         [(Bool, Maybe (Either ByteString ()), [ResultObservation],
           Maybe ResultObservation)])
-> IO ()
forall a.
(Eq a, Show a, HasCallStack) =>
Adapter -> ByteString -> (Connection -> IO a) -> IO ()
differential Adapter
adapter ByteString
conninfo \Connection
connection -> do
        outcomes <- Int
-> IO
     (Bool, Maybe (Either ByteString ()), [ResultObservation],
      Maybe ResultObservation)
-> IO
     [(Bool, Maybe (Either ByteString ()), [ResultObservation],
       Maybe ResultObservation)]
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
3 do
          sent <- Connection -> ByteString -> IO Bool
Pqi.sendQuery Connection
connection ByteString
"select pg_sleep(0.1)"
          threadDelay 50000
          handle <- Pqi.getCancel connection
          cancelled <- for handle Pqi.cancel
          results <- drainResults connection
          usable <- execScenario "select 1" connection
          pure (sent, cancelled, results, usable)
        pure outcomes

    Adapter -> SpecWith ByteString
Cleanup.spec Adapter
adapter
    Adapter -> SpecWith ByteString
Stale.spec Adapter
adapter