Commit 91831d90 authored by Alfredo Di Napoli's avatar Alfredo Di Napoli

Add tests for updating status

parent 098e87bf
...@@ -899,11 +899,17 @@ test-suite jobqueue-test ...@@ -899,11 +899,17 @@ test-suite jobqueue-test
StrictData StrictData
ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
build-depends: build-depends:
async aeson
, async
, base , base
, containers
, extra , extra
, gargantext , gargantext
, hspec , hspec
, http-client
, http-client-tls
, mtl
, servant-job
, stm , stm
, text , text
default-language: Haskell2010 default-language: Haskell2010
...@@ -126,7 +126,7 @@ library: ...@@ -126,7 +126,7 @@ library:
- Gargantext.Database.Schema.Ngrams - Gargantext.Database.Schema.Ngrams
- Gargantext.Defaults - Gargantext.Defaults
- Gargantext.Utils.Jobs - Gargantext.Utils.Jobs
- Gargantext.Utils.Jobs.API - Gargantext.Utils.Jobs.Internal
- Gargantext.Utils.Jobs.Map - Gargantext.Utils.Jobs.Map
- Gargantext.Utils.Jobs.Monad - Gargantext.Utils.Jobs.Monad
- Gargantext.Utils.Jobs.Queue - Gargantext.Utils.Jobs.Queue
...@@ -517,10 +517,16 @@ tests: ...@@ -517,10 +517,16 @@ tests:
- -rtsopts - -rtsopts
- -with-rtsopts=-N - -with-rtsopts=-N
dependencies: dependencies:
- aeson
- async
- base - base
- containers
- gargantext - gargantext
- mtl
- hspec - hspec
- async - http-client
- http-client-tls
- servant-job
- stm - stm
# garg-doctest: # garg-doctest:
# main: Main.hs # main: Main.hs
......
...@@ -110,7 +110,6 @@ instance Jobs.MonadJobStatus (ReaderT Env (ExceptT GargError IO)) where ...@@ -110,7 +110,6 @@ instance Jobs.MonadJobStatus (ReaderT Env (ExceptT GargError IO)) where
type JobType (ReaderT Env (ExceptT GargError IO)) = GargJob type JobType (ReaderT Env (ExceptT GargError IO)) = GargJob
type JobOutputType (ReaderT Env (ExceptT GargError IO)) = JobLog type JobOutputType (ReaderT Env (ExceptT GargError IO)) = JobLog
type JobEventType (ReaderT Env (ExceptT GargError IO)) = JobLog type JobEventType (ReaderT Env (ExceptT GargError IO)) = JobLog
type JobErrorType (ReaderT Env (ExceptT GargError IO)) = GargError
data MockEnv = MockEnv data MockEnv = MockEnv
{ _menv_firewall :: !FireWall { _menv_firewall :: !FireWall
......
{-# LANGUAGE TypeFamilies, ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies, ScopedTypeVariables #-}
module Gargantext.Utils.Jobs.Internal ( module Gargantext.Utils.Jobs.Internal (
serveJobsAPI serveJobsAPI
-- * Internals for testing
, newJob
) where ) where
import Control.Concurrent import Control.Concurrent
......
...@@ -4,10 +4,13 @@ module Gargantext.Utils.Jobs.Monad ( ...@@ -4,10 +4,13 @@ module Gargantext.Utils.Jobs.Monad (
JobEnv(..) JobEnv(..)
, NumRunners , NumRunners
, JobError(..) , JobError(..)
, JobHandle(..) , JobHandle -- opaque
, MonadJob(..) , MonadJob(..)
-- * Tracking jobs status
, MonadJobStatus(..) , MonadJobStatus(..)
, getLatestJobStatus
-- * Functions -- * Functions
, newJobEnv , newJobEnv
...@@ -24,7 +27,6 @@ module Gargantext.Utils.Jobs.Monad ( ...@@ -24,7 +27,6 @@ module Gargantext.Utils.Jobs.Monad (
, handleIDError , handleIDError
, removeJob , removeJob
, unsafeMkJobHandle , unsafeMkJobHandle
, getLatestJobStatus
) where ) where
import Gargantext.Utils.Jobs.Settings import Gargantext.Utils.Jobs.Settings
...@@ -188,7 +190,12 @@ class MonadJob m (JobType m) (Seq (JobEventType m)) (JobOutputType m) => MonadJo ...@@ -188,7 +190,12 @@ class MonadJob m (JobType m) (Seq (JobEventType m)) (JobOutputType m) => MonadJo
type JobType m :: Type type JobType m :: Type
type JobOutputType m :: Type type JobOutputType m :: Type
type JobEventType m :: Type type JobEventType m :: Type
type JobErrorType m :: Type
instance MonadIO m => MonadJobStatus (ReaderT (JobEnv t (Seq event) a) m) where
type JobType (ReaderT (JobEnv t (Seq event) a) m) = t
type JobOutputType (ReaderT (JobEnv t (Seq event) a) m) = a
type JobEventType (ReaderT (JobEnv t (Seq event) a) m) = event
-- --
-- Tracking jobs status API -- Tracking jobs status API
......
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE NumericUnderscores #-}
module Main where module Main where
import Control.Concurrent import Control.Concurrent
import Control.Concurrent.STM import Control.Concurrent.STM
import Control.Exception
import Control.Monad import Control.Monad
import Control.Monad.Reader
import Control.Monad.Except
import Data.Aeson
import Data.Either import Data.Either
import Data.List import Data.List
import Data.Sequence (Seq)
import GHC.Generics
import GHC.Stack
import Prelude import Prelude
import System.IO.Unsafe
import Network.HTTP.Client.TLS (newTlsManager)
import Network.HTTP.Client (Manager)
import Test.Hspec import Test.Hspec
import qualified Servant.Job.Types as SJ
import qualified Servant.Job.Core as SJ
import Gargantext.Utils.Jobs.Internal (newJob)
import Gargantext.Utils.Jobs.Map import Gargantext.Utils.Jobs.Map
import Gargantext.Utils.Jobs.Monad import Gargantext.Utils.Jobs.Monad hiding (withJob)
import Gargantext.Utils.Jobs.Queue (applyPrios, defaultPrios) import Gargantext.Utils.Jobs.Queue (applyPrios, defaultPrios)
import Gargantext.Utils.Jobs.State import Gargantext.Utils.Jobs.State
...@@ -130,6 +147,108 @@ testFairness = do ...@@ -130,6 +147,108 @@ testFairness = do
r4 <- readTVarIO runningJs r4 <- readTVarIO runningJs
r4 `shouldBe` (Counts 0 0) r4 `shouldBe` (Counts 0 0)
data MyDummyJob
= MyDummyJob
deriving (Show, Eq, Ord, Enum, Bounded)
data MyDummyError
= SomethingWentWrong JobError
deriving (Show)
instance Exception MyDummyError where
toException _ = toException (userError "SomethingWentWrong")
instance ToJSON MyDummyError where
toJSON (SomethingWentWrong _) = String "SomethingWentWrong"
data MyDummyLog =
Step_0
| Step_1
deriving (Show, Eq, Ord, Generic)
instance ToJSON MyDummyLog
newtype MyDummyEnv = MyDummyEnv { _MyDummyEnv :: JobEnv MyDummyJob (Seq MyDummyLog) () }
newtype MyDummyMonad a =
MyDummyMonad { _MyDummyMonad :: ReaderT MyDummyEnv (ExceptT MyDummyError IO) a }
deriving (Functor, Applicative, Monad, MonadIO, MonadReader MyDummyEnv, MonadError MyDummyError)
instance MonadJob MyDummyMonad MyDummyJob (Seq MyDummyLog) () where
getJobEnv = asks _MyDummyEnv
instance MonadJobStatus MyDummyMonad where
type JobType MyDummyMonad = MyDummyJob
type JobOutputType MyDummyMonad = ()
type JobEventType MyDummyMonad = MyDummyLog
testTlsManager :: Manager
testTlsManager = unsafePerformIO newTlsManager
{-# NOINLINE testTlsManager #-}
shouldBeE :: (MonadIO m, HasCallStack, Show a, Eq a) => a -> a -> m ()
shouldBeE a b = liftIO (shouldBe a b)
type TheEnv = JobEnv MyDummyJob (Seq MyDummyLog) ()
withJob :: TheEnv
-> (TheEnv -> JobHandle -> () -> Logger MyDummyLog -> IO (Either MyDummyError ()))
-> IO (Either MyDummyError (SJ.JobStatus 'SJ.Safe MyDummyLog))
withJob myEnv f = do
runExceptT $ flip runReaderT (MyDummyEnv myEnv) $ _MyDummyMonad $ do
newJob @_ @MyDummyError getJobEnv MyDummyJob (\env hdl input logStatus ->
f env hdl input logStatus) (SJ.JobInput () Nothing)
withJob_ :: TheEnv -> (TheEnv -> JobHandle -> () -> Logger MyDummyLog -> IO (Either MyDummyError ())) -> IO ()
withJob_ env f = void (withJob env f)
testFetchJobStatus :: IO ()
testFetchJobStatus = do
k <- genSecret
let settings = defaultJobSettings 2 k
myEnv <- newJobEnv settings defaultPrios testTlsManager
evts <- newMVar []
withJob_ myEnv $ \env hdl _input logStatus -> do
mb_status <- runReaderT (getLatestJobStatus hdl) env
-- now let's log something
logStatus Step_0
mb_status' <- runReaderT (getLatestJobStatus hdl) env
modifyMVar_ evts (\xs -> pure $ mb_status : mb_status' : xs)
pure $ Right ()
threadDelay 500_000
-- Check the events
readMVar evts >>= \expected -> expected `shouldBe` [Nothing, Just Step_0]
testFetchJobStatusNoContention :: IO ()
testFetchJobStatusNoContention = do
k <- genSecret
let settings = defaultJobSettings 2 k
myEnv <- newJobEnv settings defaultPrios testTlsManager
evts1 <- newMVar []
evts2 <- newMVar []
withJob_ myEnv $ \env hdl _input logStatus -> do
logStatus Step_1
mb_status <- runReaderT (getLatestJobStatus hdl) env
modifyMVar_ evts1 (\xs -> pure $ mb_status : xs)
pure $ Right ()
withJob_ myEnv $ \env hdl _input logStatus -> do
logStatus Step_0
mb_status <- runReaderT (getLatestJobStatus hdl) env
modifyMVar_ evts2 (\xs -> pure $ mb_status : xs)
pure $ Right ()
threadDelay 500_000
-- Check the events
readMVar evts1 >>= \expected -> expected `shouldBe` [Just Step_1]
readMVar evts2 >>= \expected -> expected `shouldBe` [Just Step_0]
main :: IO () main :: IO ()
main = hspec $ do main = hspec $ do
describe "job queue" $ do describe "job queue" $ do
...@@ -141,3 +260,8 @@ main = hspec $ do ...@@ -141,3 +260,8 @@ main = hspec $ do
testExceptions testExceptions
it "fairly picks equal-priority-but-different-kind jobs" $ it "fairly picks equal-priority-but-different-kind jobs" $
testFairness testFairness
describe "job status update and tracking" $ do
it "can fetch the latest job status" $
testFetchJobStatus
it "can spin two separate jobs and track their status separately" $
testFetchJobStatusNoContention
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment