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

Add more tests

parent 7093c642
...@@ -22,7 +22,6 @@ Script to start gargantext with different modes (Dev, Prod, Mock). ...@@ -22,7 +22,6 @@ Script to start gargantext with different modes (Dev, Prod, Mock).
module Main where module Main where
import Data.String (String)
import Data.Text (unpack) import Data.Text (unpack)
import Data.Version (showVersion) import Data.Version (showVersion)
import Gargantext.API (startGargantext) -- , startGargantextMock) import Gargantext.API (startGargantext) -- , startGargantextMock)
......
...@@ -982,6 +982,8 @@ test-suite garg-test-hspec ...@@ -982,6 +982,8 @@ test-suite garg-test-hspec
other-modules: other-modules:
Test.API Test.API
Test.API.Authentication Test.API.Authentication
Test.API.Private
Test.API.Setup
Test.Database.Operations Test.Database.Operations
Test.Database.Operations.DocumentSearch Test.Database.Operations.DocumentSearch
Test.Database.Setup Test.Database.Setup
......
...@@ -13,6 +13,7 @@ Portability : POSIX ...@@ -13,6 +13,7 @@ Portability : POSIX
module Gargantext.API.Admin.Auth.Types module Gargantext.API.Admin.Auth.Types
where where
import Control.Lens hiding (elements, to)
import Data.Aeson.TH (deriveJSON) import Data.Aeson.TH (deriveJSON)
import Data.Swagger import Data.Swagger
import Data.Text (Text) import Data.Text (Text)
...@@ -130,4 +131,7 @@ data ForgotPasswordGet = ForgotPasswordGet {_fpGet_password :: Password} ...@@ -130,4 +131,7 @@ data ForgotPasswordGet = ForgotPasswordGet {_fpGet_password :: Password}
deriving (Generic ) deriving (Generic )
$(deriveJSON (unPrefix "_fpGet_") ''ForgotPasswordGet) $(deriveJSON (unPrefix "_fpGet_") ''ForgotPasswordGet)
instance ToSchema ForgotPasswordGet where instance ToSchema ForgotPasswordGet where
declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_fpGet_") declareNamedSchema = genericDeclareNamedSchema (unPrefixSwagger "_fpGet_")
makeLenses ''AuthValid
makeLenses ''AuthResponse
...@@ -59,7 +59,7 @@ import qualified Gargantext.API.Public as Public ...@@ -59,7 +59,7 @@ import qualified Gargantext.API.Public as Public
type GargAPI = MkGargAPI (GargAPIVersion GargAPI') type GargAPI = MkGargAPI (GargAPIVersion GargAPI')
type MkGargAPI sub = "api" :> Summary "API " :> GargAPIVersion sub type MkGargAPI sub = "api" :> Summary "API " :> sub
--- | TODO :<|> Summary "Latest API" :> GargAPI' --- | TODO :<|> Summary "Latest API" :> GargAPI'
type GargAPIVersion sub = "v1.0" type GargAPIVersion sub = "v1.0"
...@@ -87,8 +87,9 @@ type GargAPI' = ...@@ -87,8 +87,9 @@ type GargAPI' =
:<|> "public" :> Public.API :<|> "public" :> Public.API
type GargPrivateAPI = SA.Auth '[SA.JWT, SA.Cookie] AuthenticatedUser type MkProtectedAPI sub = SA.Auth '[SA.JWT, SA.Cookie] AuthenticatedUser :> sub
:> GargPrivateAPI'
type GargPrivateAPI = MkProtectedAPI GargPrivateAPI'
type GargAdminAPI type GargAdminAPI
-- Roots endpoint -- Roots endpoint
......
...@@ -4,7 +4,9 @@ module Test.API where ...@@ -4,7 +4,9 @@ module Test.API where
import Prelude import Prelude
import Test.Hspec import Test.Hspec
import qualified Test.API.Authentication as Auth import qualified Test.API.Authentication as Auth
import qualified Test.API.Private as Private
tests :: Spec tests :: Spec
tests = describe "API" $ tests = describe "API" $ do
Auth.tests Auth.tests
Private.tests
...@@ -3,36 +3,18 @@ ...@@ -3,36 +3,18 @@
{-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns #-}
module Test.API.Authentication where module Test.API.Authentication (
tests
, auth_api
) where
import Prelude import Prelude
import Data.Proxy import Data.Proxy
import Gargantext.API (makeApp)
import Gargantext.API.Admin.EnvTypes (Mode(Mock), Env (..))
import Gargantext.API.Admin.Settings
import Gargantext.API.Routes import Gargantext.API.Routes
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, testEnvToPgConnectionInfo)
import Test.Hspec import Test.Hspec
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 () import Servant.Auth.Client ()
import Gargantext.API.Admin.Auth.Types import Gargantext.API.Admin.Auth.Types
import Gargantext.Core.Types.Individu import Gargantext.Core.Types.Individu
...@@ -40,58 +22,15 @@ import Control.Monad ...@@ -40,58 +22,15 @@ import Control.Monad
import Control.Monad.Reader import Control.Monad.Reader
import Gargantext.Database.Action.User.New import Gargantext.Database.Action.User.New
import Gargantext.Core.Types import Gargantext.Core.Types
import Test.API.Setup (withTestDBAndPort)
import qualified Data.Text as T
import Control.Lens
newTestEnv :: TestEnv -> Logger (GargM Env GargError) -> Warp.Port -> IO Env auth_api :: AuthRequest -> ClientM AuthResponse
newTestEnv testEnv logger port = do auth_api = client (Proxy :: Proxy (MkGargAPI (GargAPIVersion AuthAPI)))
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
withLoggerHoisted Mock $ \ioLogger -> do
env <- newTestEnv testEnv ioLogger 8080
makeApp env
Warp.testWithApplication createApp action
withTestDBAndPort :: ((TestEnv, Warp.Port) -> IO ()) -> IO () cannedToken :: T.Text
withTestDBAndPort action = cannedToken = "eyJhbGciOiJIUzUxMiJ9.eyJkYXQiOnsiaWQiOjF9fQ.t49zZSqkPAulEkYEh4pW17H2uwrkyPTdZKwHyG3KUJ0hzU2UUoPBNj8vdv087RCVBJ4tXgxNbP4j0RBv3gxdqg"
withTestDB $ \testEnv ->
withGargApp testEnv $ \port ->
action (testEnv, port)
tests :: Spec tests :: Spec
tests = sequential $ aroundAll withTestDBAndPort $ do tests = sequential $ aroundAll withTestDBAndPort $ do
...@@ -108,30 +47,26 @@ tests = sequential $ aroundAll withTestDBAndPort $ do ...@@ -108,30 +47,26 @@ tests = sequential $ aroundAll withTestDBAndPort $ do
result `shouldBe` (Right "0.0.6.9.9.7.7") result `shouldBe` (Right "0.0.6.9.9.7.7")
describe "POST /api/v1.0/auth" $ do describe "POST /api/v1.0/auth" $ do
let auth_api = client (Proxy :: Proxy (MkGargAPI (GargAPIVersion AuthAPI)))
it "requires no auth and authenticates the user 'alice'" $ \(testEnv, port) -> do it "requires no auth and authenticates the user 'alice'" $ \(testEnv, port) -> do
-- Let's create two users, Alice & Bob. Alice shouldn't be able to see -- Let's create the Alice user.
-- Bob's private data and vice-versa.
void $ flip runReaderT testEnv $ runTestMonad $ do void $ flip runReaderT testEnv $ runTestMonad $ do
let nur1 = mkNewUser "alice@gargan.text" (GargPassword "alice") void $ new_user $ mkNewUser "alice@gargan.text" (GargPassword "alice")
let nur2 = mkNewUser "bob@gargan.text" (GargPassword "bob")
void $ new_user nur1
void $ new_user nur2
let authPayload = AuthRequest "alice" (GargPassword "alice") let authPayload = AuthRequest "alice" (GargPassword "alice")
result <- runClientM (auth_api authPayload) (clientEnv port) result0 <- runClientM (auth_api authPayload) (clientEnv port)
let expected = AuthResponse { let expected = AuthResponse {
_authRes_valid = Just $ _authRes_valid = Just $
AuthValid { AuthValid {
_authVal_token = "eyJhbGciOiJIUzUxMiJ9.eyJkYXQiOnsiaWQiOjF9fQ.t49zZSqkPAulEkYEh4pW17H2uwrkyPTdZKwHyG3KUJ0hzU2UUoPBNj8vdv087RCVBJ4tXgxNbP4j0RBv3gxdqg" _authVal_token = cannedToken
, _authVal_tree_id = NodeId 1 , _authVal_tree_id = NodeId 1
, _authVal_user_id = 1 , _authVal_user_id = 1
} }
, _authRes_inval = Nothing , _authRes_inval = Nothing
} }
let result = over (_Right . authRes_valid . _Just . authVal_token) (const cannedToken) result0
result `shouldBe` (Right expected) result `shouldBe` (Right expected)
it "denies login for user 'alice' if password is invalid" $ \(_testEnv, port) -> do it "denies login for user 'alice' if password is invalid" $ \(_testEnv, port) -> do
......
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module Test.API.Private where
import Control.Monad
import Control.Monad.Reader
import Data.Maybe
import Data.Proxy
import Gargantext.API.Admin.Auth.Types
import Gargantext.API.Routes
import Gargantext.Core.Types.Individu
import Gargantext.Database.Action.User.New
import Network.HTTP.Client hiding (Proxy)
import Prelude
import Servant
import Servant.Auth.Client ()
import Servant.Client
import Test.API.Authentication (auth_api)
import Test.API.Setup (withTestDBAndPort)
import Test.Database.Types
import Test.Hspec
import qualified Data.Text.Encoding as TE
import qualified Servant.Auth.Client as SA
tests :: Spec
tests = sequential $ aroundAll withTestDBAndPort $ do
describe "Private API" $ do
baseUrl <- runIO $ parseBaseUrl "http://localhost"
manager <- runIO $ newManager defaultManagerSettings
let clientEnv port = mkClientEnv manager (baseUrl { baseUrlPort = port })
describe "GET /api/v1.0/user" $ do
-- FIXME(adn): unclear if this is useful at all. Doesn't do permission checking.
it "doesn't allow someone with an invalid token to show the results" $ \(testEnv, port) -> do
-- Let's create two users, Alice & Bob. Alice shouldn't be able to see
-- Bob's private data and vice-versa.
void $ flip runReaderT testEnv $ runTestMonad $ do
let nur1 = mkNewUser "alice@gargan.text" (GargPassword "alice")
let nur2 = mkNewUser "bob@gargan.text" (GargPassword "bob")
void $ new_user nur1
void $ new_user nur2
let ( roots_api :<|> _nodes_api
) = client (Proxy :: Proxy (MkProtectedAPI GargAdminAPI)) (SA.Token "bogus")
let ( admin_user_api_get :<|> _) = roots_api
result <- runClientM admin_user_api_get (clientEnv port)
length result `shouldBe` 0
-- FIXME(adn): unclear if this is useful at all. Doesn't do permission checking.
it "allows 'alice' to see the results" $ \(_testEnv, port) -> do
let authPayload = AuthRequest "alice" (GargPassword "alice")
Right result <- runClientM (auth_api authPayload) (clientEnv port)
let token = _authVal_token $ fromJust (_authRes_valid result)
let ( roots_api :<|> _nodes_api
) = client (Proxy :: Proxy (MkProtectedAPI GargAdminAPI)) (SA.Token $ TE.encodeUtf8 $ token)
let ( admin_user_api_get :<|> _) = roots_api
_nodes <- runClientM admin_user_api_get (clientEnv port)
pendingWith "currently useless"
{-# LANGUAGE BangPatterns #-}
module Test.API.Setup where
import Prelude
import Gargantext.API (makeApp)
import Gargantext.API.Admin.EnvTypes (Mode(Mock), Env (..))
import Gargantext.API.Admin.Settings
import Gargantext.System.Logging
import Servant.Client
import Test.Database.Setup (withTestDB, fakeIniPath, testEnvToPgConnectionInfo)
import qualified Network.Wai.Handler.Warp as Warp
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 ()
newTestEnv :: TestEnv -> Logger (GargM Env GargError) -> Warp.Port -> IO Env
newTestEnv testEnv logger port = do
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
withLoggerHoisted Mock $ \ioLogger -> do
env <- newTestEnv testEnv ioLogger 8080
makeApp env
Warp.testWithApplication createApp action
withTestDBAndPort :: ((TestEnv, Warp.Port) -> IO ()) -> IO ()
withTestDBAndPort action =
withTestDB $ \testEnv ->
withGargApp testEnv $ \port ->
action (testEnv, port)
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