Commit c7f15cf2 authored by Alfredo Di Napoli's avatar Alfredo Di Napoli

Successful first servant client test

parent 3bd9ac0a
...@@ -53,19 +53,6 @@ data MyOptions w = ...@@ -53,19 +53,6 @@ data MyOptions w =
instance ParseRecord (MyOptions Wrapped) instance ParseRecord (MyOptions Wrapped)
deriving instance Show (MyOptions Unwrapped) deriving instance Show (MyOptions Unwrapped)
-- | A plain logger in the IO monad, waiting for more serious logging solutions like
-- the one described in https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/229
instance HasLogger IO where
data instance Logger IO = IOLogger
type instance LogInitParams IO = ()
type instance LogPayload IO = String
initLogger = \() -> pure IOLogger
destroyLogger = \_ -> pure ()
logMsg = \IOLogger lvl msg ->
let pfx = "[" <> show lvl <> "] "
in putStrLn $ pfx <> msg
logTxt lgr lvl msg = logMsg lgr lvl (unpack msg)
main :: IO () main :: IO ()
main = withLogger () $ \ioLogger -> do main = withLogger () $ \ioLogger -> do
MyOptions myMode myPort myIniFile myVersion <- unwrapRecord MyOptions myMode myPort myIniFile myVersion <- unwrapRecord
......
...@@ -956,8 +956,11 @@ test-suite garg-test-tasty ...@@ -956,8 +956,11 @@ test-suite garg-test-tasty
, raw-strings-qq , raw-strings-qq
, recover-rtti >= 0.4 && < 0.5 , recover-rtti >= 0.4 && < 0.5
, resource-pool >= 0.2.3.2 && < 0.2.4 , resource-pool >= 0.2.3.2 && < 0.2.4
, servant-auth
, servant-auth-client
, servant-client , servant-client
, servant-job , servant-job
, servant-server
, shelly >= 1.9 && < 2 , shelly >= 1.9 && < 2
, stm ^>= 2.5.0.1 , stm ^>= 2.5.0.1
, tasty ^>= 1.4.2.1 , tasty ^>= 1.4.2.1
...@@ -1045,8 +1048,11 @@ test-suite garg-test-hspec ...@@ -1045,8 +1048,11 @@ test-suite garg-test-hspec
, raw-strings-qq , raw-strings-qq
, recover-rtti >= 0.4 && < 0.5 , recover-rtti >= 0.4 && < 0.5
, resource-pool >= 0.2.3.2 && < 0.2.4 , resource-pool >= 0.2.3.2 && < 0.2.4
, servant-auth
, servant-auth-client
, servant-client , servant-client
, servant-job , servant-job
, servant-server
, shelly >= 1.9 && < 2 , shelly >= 1.9 && < 2
, stm ^>= 2.5.0.1 , stm ^>= 2.5.0.1
, tasty ^>= 1.4.2.1 , tasty ^>= 1.4.2.1
......
...@@ -184,8 +184,8 @@ newEnv logger port file = do ...@@ -184,8 +184,8 @@ newEnv logger port file = do
when (port /= settings' ^. appPort) $ when (port /= settings' ^. appPort) $
panic "TODO: conflicting settings of port" panic "TODO: conflicting settings of port"
!config_env <- readConfig file !config_env <- readConfig file
prios <- Jobs.readPrios (file <> ".jobs") prios <- withLogger () $ \ioLogger -> Jobs.readPrios ioLogger (file <> ".jobs")
let prios' = Jobs.applyPrios prios Jobs.defaultPrios let prios' = Jobs.applyPrios prios Jobs.defaultPrios
putStrLn $ "Overrides: " <> show prios putStrLn $ "Overrides: " <> show prios
putStrLn $ "New priorities: " <> show prios' putStrLn $ "New priorities: " <> show prios'
......
...@@ -57,12 +57,14 @@ import qualified Gargantext.API.Node.Document.Export.Types as DocumentExport ...@@ -57,12 +57,14 @@ import qualified Gargantext.API.Node.Document.Export.Types as DocumentExport
import qualified Gargantext.API.Public as Public import qualified Gargantext.API.Public as Public
type GargAPI = "api" :> Summary "API " :> GargAPIVersion type GargAPI = MkGargAPI (GargAPIVersion GargAPI')
type MkGargAPI sub = "api" :> Summary "API " :> GargAPIVersion sub
--- | TODO :<|> Summary "Latest API" :> GargAPI' --- | TODO :<|> Summary "Latest API" :> GargAPI'
type GargAPIVersion = "v1.0" type GargAPIVersion sub = "v1.0"
:> Summary "Garg API Version " :> Summary "Garg API Version "
:> GargAPI' :> sub
type GargVersion = "version" type GargVersion = "version"
:> Summary "Backend version" :> Summary "Backend version"
......
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeApplications #-}
module Gargantext.System.Logging ( module Gargantext.System.Logging (
LogLevel(..) LogLevel(..)
...@@ -7,6 +8,7 @@ module Gargantext.System.Logging ( ...@@ -7,6 +8,7 @@ module Gargantext.System.Logging (
, MonadLogger(..) , MonadLogger(..)
, logM , logM
, logLocM , logLocM
, logLoc
, withLogger , withLogger
, withLoggerHoisted , withLoggerHoisted
) where ) where
...@@ -73,6 +75,12 @@ logLocM = [| \level msg -> ...@@ -73,6 +75,12 @@ logLocM = [| \level msg ->
in logM level (formatWithLoc loc msg) in logM level (formatWithLoc loc msg)
|] |]
logLoc :: ExpQ
logLoc = [| \logger level msg ->
let loc = $(getLocTH)
in logTxt logger level (formatWithLoc loc msg)
|]
formatWithLoc :: Loc -> T.Text -> T.Text formatWithLoc :: Loc -> T.Text -> T.Text
formatWithLoc loc msg = "[" <> locationToText <> "] " <> msg formatWithLoc loc msg = "[" <> locationToText <> "] " <> msg
where where
...@@ -109,3 +117,16 @@ withLoggerHoisted :: (MonadBaseControl IO m, HasLogger m) ...@@ -109,3 +117,16 @@ withLoggerHoisted :: (MonadBaseControl IO m, HasLogger m)
-> (Logger m -> IO a) -> (Logger m -> IO a)
-> IO a -> IO a
withLoggerHoisted params act = bracket (initLogger params) destroyLogger act withLoggerHoisted params act = bracket (initLogger params) destroyLogger act
-- | A plain logger in the IO monad, waiting for more serious logging solutions like
-- the one described in https://gitlab.iscpif.fr/gargantext/haskell-gargantext/issues/229
instance HasLogger IO where
data instance Logger IO = IOLogger
type instance LogInitParams IO = ()
type instance LogPayload IO = String
initLogger = \() -> pure IOLogger
destroyLogger = \_ -> pure ()
logMsg = \IOLogger lvl msg ->
let pfx = "[" <> show lvl <> "] "
in putStrLn $ pfx <> msg
logTxt lgr lvl msg = logMsg lgr lvl (T.unpack msg)
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
module Gargantext.Utils.Jobs ( module Gargantext.Utils.Jobs (
-- * Serving the JOBS API -- * Serving the JOBS API
...@@ -14,11 +15,13 @@ import Data.Aeson (ToJSON) ...@@ -14,11 +15,13 @@ import Data.Aeson (ToJSON)
import Prelude import Prelude
import System.Directory (doesFileExist) import System.Directory (doesFileExist)
import Text.Read (readMaybe) import Text.Read (readMaybe)
import qualified Data.Text as T
import Gargantext.API.Admin.EnvTypes import Gargantext.API.Admin.EnvTypes
import Gargantext.API.Prelude import Gargantext.API.Prelude
import qualified Gargantext.Utils.Jobs.Internal as Internal import qualified Gargantext.Utils.Jobs.Internal as Internal
import Gargantext.Utils.Jobs.Monad import Gargantext.Utils.Jobs.Monad
import Gargantext.System.Logging
import qualified Servant.Job.Async as SJ import qualified Servant.Job.Async as SJ
...@@ -75,12 +78,11 @@ parsePrios (x : xs) = (:) <$> go x <*> parsePrios xs ...@@ -75,12 +78,11 @@ parsePrios (x : xs) = (:) <$> go x <*> parsePrios xs
| otherwise -> error $ | otherwise -> error $
"parsePrios: invalid input. " ++ show (prop, valS) "parsePrios: invalid input. " ++ show (prop, valS)
readPrios :: FilePath -> IO [(GargJob, Int)] readPrios :: Logger IO -> FilePath -> IO [(GargJob, Int)]
readPrios fp = do readPrios logger fp = do
exists <- doesFileExist fp exists <- doesFileExist fp
case exists of case exists of
False -> do False -> do
putStrLn $ $(logLoc) logger WARNING $ T.pack $ fp ++ " doesn't exist, using default job priorities."
"Warning: " ++ fp ++ " doesn't exist, using default job priorities."
pure [] pure []
True -> parsePrios . lines =<< readFile fp True -> parsePrios . lines =<< readFile fp
...@@ -21,3 +21,15 @@ PUBMED_API_KEY = "no_key" ...@@ -21,3 +21,15 @@ PUBMED_API_KEY = "no_key"
EN = corenlp://localhost:9000 EN = corenlp://localhost:9000
FR = spacy://localhost:8001 FR = spacy://localhost:8001
All = corenlp://localhost:9000 All = corenlp://localhost:9000
[database]
DB_HOST = 127.0.0.1
[mail]
MAIL_PORT = 25
MAIL_HOST = localhost
MAIL_USER = gargantext
MAIL_PASSWORD =
MAIL_FROM =
# NoAuth | Normal | SSL | TLS | STARTTLS
MAIL_LOGIN_TYPE = Normal
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE BangPatterns #-}
module Test.API.Authentication where module Test.API.Authentication where
import Prelude import Prelude
import Control.Concurrent.MVar
import Data.Proxy import Data.Proxy
import Gargantext.API (makeApp) import Gargantext.API (makeApp)
import Gargantext.API.Admin.EnvTypes (Mode(Mock)) import Gargantext.API.Admin.EnvTypes (Mode(Mock), Env (..))
import Gargantext.API.Admin.Settings (newEnv) import Gargantext.API.Admin.Settings
import Gargantext.API.Routes import Gargantext.API.Routes
import Gargantext.System.Logging import Gargantext.System.Logging
import Network.HTTP.Client hiding (Proxy) import Network.HTTP.Client hiding (Proxy)
import Servant.Client import Servant.Client
import Test.Database.Setup (withTestDB, fakeIniPath) import Test.Database.Setup (withTestDB, fakeIniPath, testEnvToPgConnectionInfo)
import Test.Hspec import Test.Hspec
import qualified Network.Wai.Handler.Warp as Warp import qualified Network.Wai.Handler.Warp as Warp
import Test.Database.Types import Test.Database.Types
import Gargantext.API.Prelude
import qualified Gargantext.Utils.Jobs as Jobs
import qualified Gargantext.Utils.Jobs.Queue as Jobs
import qualified Gargantext.Utils.Jobs.Settings as Jobs
import qualified Gargantext.Utils.Jobs.Monad as Jobs
import qualified Gargantext.Prelude.Mail as Mail
import qualified Gargantext.Prelude.NLP as NLP
import Network.HTTP.Client.TLS (newTlsManager)
import Control.Lens
import Gargantext.API.Admin.Types
import Gargantext.Prelude.Config
import Gargantext.Core.NodeStory
import Gargantext.Database.Prelude
import Gargantext.Core.NLP
import qualified Servant.Job.Async as ServantAsync
import Servant.Auth.Client ()
withGargApp :: (Warp.Port -> IO ()) -> IO () newTestEnv :: TestEnv -> Logger (GargM Env GargError) -> Warp.Port -> IO Env
withGargApp action = do newTestEnv testEnv logger port = do
randomPort <- newEmptyMVar file <- fakeIniPath
!manager_env <- newTlsManager
!settings' <- devSettings devJwkFile <&> appPort .~ port
!config_env <- readConfig file
prios <- withLogger () $ \ioLogger -> Jobs.readPrios ioLogger (file <> ".jobs")
let prios' = Jobs.applyPrios prios Jobs.defaultPrios
!self_url_env <- parseBaseUrl $ "http://0.0.0.0:" <> show port
dbParam <- pure $ testEnvToPgConnectionInfo testEnv
!pool <- newPool dbParam
!nodeStory_env <- readNodeStoryEnv pool
!scrapers_env <- ServantAsync.newJobEnv ServantAsync.defaultSettings manager_env
secret <- Jobs.genSecret
let jobs_settings = (Jobs.defaultJobSettings 1 secret)
& Jobs.l_jsJobTimeout .~ (fromIntegral $ config_env ^. hasConfig ^. gc_js_job_timeout)
& Jobs.l_jsIDTimeout .~ (fromIntegral $ config_env ^. hasConfig ^. gc_js_id_timeout)
!jobs_env <- Jobs.newJobEnv jobs_settings prios' manager_env
!config_mail <- Mail.readConfig file
!nlp_env <- nlpServerMap <$> NLP.readConfig file
pure $ Env
{ _env_settings = settings'
, _env_logger = logger
, _env_pool = pool
, _env_nodeStory = nodeStory_env
, _env_manager = manager_env
, _env_scrapers = scrapers_env
, _env_jobs = jobs_env
, _env_self_url = self_url_env
, _env_config = config_env
, _env_mail = config_mail
, _env_nlp = nlp_env
}
withGargApp :: TestEnv -> (Warp.Port -> IO ()) -> IO ()
withGargApp testEnv action = do
let createApp = do let createApp = do
port <- readMVar randomPort
withLoggerHoisted Mock $ \ioLogger -> do withLoggerHoisted Mock $ \ioLogger -> do
ini <- fakeIniPath env <- newTestEnv testEnv ioLogger 8080
env <- newEnv ioLogger port ini
makeApp env makeApp env
Warp.testWithApplication createApp (\p -> putMVar randomPort p >> action p) Warp.testWithApplication createApp action
withTestDBAndPort :: ((TestEnv, Warp.Port) -> IO ()) -> IO () withTestDBAndPort :: ((TestEnv, Warp.Port) -> IO ()) -> IO ()
withTestDBAndPort action = withTestDBAndPort action =
withTestDB $ \testEnv -> withTestDB $ \testEnv ->
withGargApp $ \port -> withGargApp testEnv $ \port ->
action (testEnv, port) action (testEnv, port)
tests :: Spec tests :: Spec
tests = sequential $ aroundAll withTestDBAndPort $ do tests = sequential $ aroundAll withTestDBAndPort $ do
describe "Authentication" $ do describe "Authentication" $ do
let getVersion = client (Proxy :: Proxy GargVersion) let version_api = client (Proxy :: Proxy (MkGargAPI (GargAPIVersion GargVersion)))
baseUrl <- runIO $ parseBaseUrl "http://localhost" baseUrl <- runIO $ parseBaseUrl "http://localhost"
manager <- runIO $ newManager defaultManagerSettings manager <- runIO $ newManager defaultManagerSettings
let clientEnv port = mkClientEnv manager (baseUrl { baseUrlPort = port }) let clientEnv port = mkClientEnv manager (baseUrl { baseUrlPort = port })
...@@ -47,5 +98,5 @@ tests = sequential $ aroundAll withTestDBAndPort $ do ...@@ -47,5 +98,5 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
-- testing scenarios start here -- testing scenarios start here
describe "GET /version" $ do describe "GET /version" $ do
it "requires no auth" $ \(_testEnv, port) -> do it "requires no auth" $ \(_testEnv, port) -> do
result <- runClientM getVersion (clientEnv port) result <- runClientM version_api (clientEnv port)
result `shouldBe` (Right "foo") result `shouldBe` (Right "0.0.6.9.9.7.7")
{-# LANGUAGE TupleSections #-} {-# LANGUAGE TupleSections #-}
module Test.Database.Setup ( module Test.Database.Setup (
withTestDB withTestDB
, fakeIniPath , fakeIniPath
, testEnvToPgConnectionInfo
) where ) where
import Control.Exception hiding (assert) import Control.Exception hiding (assert)
import Control.Monad import Control.Monad
import Data.Maybe (fromMaybe)
import Data.Monoid
import Data.Pool hiding (withResource) import Data.Pool hiding (withResource)
import Data.String import Data.String
import Gargantext.Prelude.Config import Gargantext.Prelude.Config
...@@ -17,6 +20,7 @@ import qualified Data.Text as T ...@@ -17,6 +20,7 @@ import qualified Data.Text as T
import qualified Data.Text.Encoding as TE import qualified Data.Text.Encoding as TE
import qualified Database.PostgreSQL.Simple as PG import qualified Database.PostgreSQL.Simple as PG
import qualified Database.PostgreSQL.Simple.Options as Client import qualified Database.PostgreSQL.Simple.Options as Client
import qualified Database.PostgreSQL.Simple.Options as Opts
import qualified Database.Postgres.Temp as Tmp import qualified Database.Postgres.Temp as Tmp
import qualified Shelly as SH import qualified Shelly as SH
...@@ -73,3 +77,16 @@ setup = do ...@@ -73,3 +77,16 @@ setup = do
withTestDB :: (TestEnv -> IO ()) -> IO () withTestDB :: (TestEnv -> IO ()) -> IO ()
withTestDB = bracket setup teardown withTestDB = bracket setup teardown
testEnvToPgConnectionInfo :: TestEnv -> PG.ConnectInfo
testEnvToPgConnectionInfo TestEnv{..} =
PG.ConnectInfo { PG.connectHost = "0.0.0.0"
, PG.connectPort = fromIntegral $ fromMaybe 5432
$ getLast
$ Opts.port
$ Tmp.toConnectionOptions
$ _DBTmp test_db
, PG.connectUser = dbUser
, PG.connectPassword = dbPassword
, PG.connectDatabase = dbName
}
...@@ -42,5 +42,5 @@ main :: IO () ...@@ -42,5 +42,5 @@ main :: IO ()
main = do main = do
hSetBuffering stdout NoBuffering hSetBuffering stdout NoBuffering
bracket startCoreNLPServer stopCoreNLPServer $ \_ -> hspec $ do bracket startCoreNLPServer stopCoreNLPServer $ \_ -> hspec $ do
DB.tests
API.tests API.tests
DB.tests
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