Verified Commit 5c7c0324 authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

Merge branch 'dev' into 594-dev-ngrams-click-fixes

parents f84305d3 c41b6a37
Pipeline #4565 passed with stages
in 37 minutes and 42 seconds
...@@ -12,6 +12,7 @@ variables: ...@@ -12,6 +12,7 @@ variables:
stages: stages:
- stack - stack
- cabal - cabal
- bench
- test - test
stack: stack:
...@@ -34,7 +35,19 @@ cabal: ...@@ -34,7 +35,19 @@ cabal:
- .cabal/ - .cabal/
policy: pull-push policy: pull-push
script: script:
- nix-shell --run "./bin/update-cabal-project $CABAL_STORE_DIR && cabal --store-dir=$CABAL_STORE_DIR v2-build --ghc-options='-O0 -fclear-plugins'" - nix-shell --run "./bin/update-cabal-project $CABAL_STORE_DIR && cabal --store-dir=$CABAL_STORE_DIR v2-build --ghc-options='-O2 -fclear-plugins'"
allow_failure: false
bench:
stage: bench
cache:
key: cabal.project
paths:
- dist-newstyle/
- .cabal/
policy: pull-push
script:
- nix-shell --run "./bin/update-cabal-project $CABAL_STORE_DIR && cabal --store-dir=$CABAL_STORE_DIR v2-bench --ghc-options='-O2 -fclear-plugins'"
allow_failure: false allow_failure: false
test: test:
...@@ -63,11 +76,13 @@ test: ...@@ -63,11 +76,13 @@ test:
nix-shell --run "./bin/update-cabal-project $CABAL_STORE_DIR" nix-shell --run "./bin/update-cabal-project $CABAL_STORE_DIR"
mkdir -p /root/.cache/cabal/logs mkdir -p /root/.cache/cabal/logs
chown -R test:test /root/.cache/cabal/logs/ chown -R test:test /root/.cache/cabal/logs/
nix-shell --run "chown -R test:test /root/.config/ && su -m test -c \"export PATH=$PATH:$TEST_NIX_PATH && cd /builds/gargantext/haskell-gargantext && $CABAL --store-dir=$CABAL_STORE_DIR v2-test --test-show-details=streaming --ghc-options='-O0 -fclear-plugins'\"" chown -R test:test /root/.cache/cabal/packages/hackage.haskell.org/
nix-shell --run "chown -R test:test /root/.config/ && su -m test -c \"export PATH=$PATH:$TEST_NIX_PATH && cd /builds/gargantext/haskell-gargantext && $CABAL --store-dir=$CABAL_STORE_DIR v2-test --test-show-details=streaming --flags test-crypto --ghc-options='-O0 -fclear-plugins'\""
chown -R root:root dist-newstyle/ chown -R root:root dist-newstyle/
chown -R root:root /root/ chown -R root:root /root/
chown -R root:root $CABAL_STORE_DIR chown -R root:root $CABAL_STORE_DIR
chown -R root:root /root/.cache/cabal/logs/ chown -R root:root /root/.cache/cabal/logs/
chown -R root:root /root/.cache/cabal/packages/hackage.haskell.org/
#docs: #docs:
# stage: docs # stage: docs
......
## Version 0.0.6.9.9.7.6.3
* [BACK][TESTS] Make a start on benchmarking, add more tests
## Version 0.0.6.9.9.7.6.2 ## Version 0.0.6.9.9.7.6.2
* [BACK][FIX] CI * [BACK][FIX] CI
......
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
module Main where
import Gargantext.Core.Types.Individu
import Gargantext.Prelude.Crypto.Auth (createPasswordHash)
import Test.Tasty.Bench
main :: IO ()
main = defaultMain
[ bgroup "Benchmarks"
[ bgroup "User creation" [
bench "createPasswordHash" $ whnfIO (createPasswordHash "rabbit")
, bench "toUserHash" $
whnfIO (toUserHash $ NewUser "alfredo" "alfredo@well-typed.com" (GargPassword "rabbit"))
]
]
]
...@@ -18,6 +18,7 @@ module Main where ...@@ -18,6 +18,7 @@ module Main where
import Gargantext.API.Dev (withDevEnv, runCmdDev) import Gargantext.API.Dev (withDevEnv, runCmdDev)
import Gargantext.API.Prelude (GargError) import Gargantext.API.Prelude (GargError)
import Gargantext.Database.Action.User.New (newUsers) import Gargantext.Database.Action.User.New (newUsers)
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Prelude (Cmd'') import Gargantext.Database.Prelude (Cmd'')
import Gargantext.Prelude import Gargantext.Prelude
import System.Environment (getArgs) import System.Environment (getArgs)
...@@ -28,6 +29,6 @@ main = do ...@@ -28,6 +29,6 @@ main = do
(iniPath:mails) <- getArgs (iniPath:mails) <- getArgs
withDevEnv iniPath $ \env -> do withDevEnv iniPath $ \env -> do
x <- runCmdDev env ((newUsers $ map cs mails) :: Cmd'' DevEnv GargError Int64) x <- runCmdDev env ((newUsers $ map cs mails) :: Cmd'' DevEnv GargError [UserId])
putStrLn $ show x putStrLn $ show x
pure () pure ()
...@@ -7,11 +7,12 @@ STORE_DIR="${1:-$DEFAULT_STORE}" ...@@ -7,11 +7,12 @@ STORE_DIR="${1:-$DEFAULT_STORE}"
# README! # README!
# Every time you modify the `stack.yaml` and as result the relevant `cabal.project` # Every time you modify the `stack.yaml` and as result the relevant `cabal.project`
# changes, you have to make sure to update the `expected_cabal_projet_hash` with the # changes, you have to make sure to update the `expected_cabal_project_hash` and
# `sha256sum` result calculated on the `cabal.project`. This ensures the `cabal.project` # `expected_cabal_project_freeze_hash` with the
# stays deterministic so that CI cache can kick in. # `sha256sum` result calculated on the `cabal.project` and `cabal.project.freeze`.
#expected_cabal_project_hash="2754bf61cc7a2aa7b29345ffe34dc1e90a06426f00fc39da9f793cd828be4e15" # This ensures the files stay deterministic so that CI cache can kick in.
expected_cabal_project_hash="5e989e199765ba2dd476208a66e96495ade69eb7cb14c0a448dfebd5748c9b39" expected_cabal_project_hash="eb12c232115b3fffa1f81add7c83d921e5899c7712eddee6100ff8df7305088e"
expected_cabal_project_freeze_hash="b7acfd12c970323ffe2c6684a13130db09d8ec9fa5676a976afed329f1ef3436"
cabal --store-dir=$STORE_DIR v2-update 'hackage.haskell.org,2023-06-24T21:28:46Z' cabal --store-dir=$STORE_DIR v2-update 'hackage.haskell.org,2023-06-24T21:28:46Z'
...@@ -24,9 +25,16 @@ fi ...@@ -24,9 +25,16 @@ fi
stack2cabal --no-run-hpack -p '2023-06-24 21:28:46' stack2cabal --no-run-hpack -p '2023-06-24 21:28:46'
actual_cabal_project_hash=$(sha256sum cabal.project | awk '{printf "%s",$1}') actual_cabal_project_hash=$(sha256sum cabal.project | awk '{printf "%s",$1}')
actual_cabal_project_freeze_hash=$(sha256sum cabal.project.freeze | awk '{printf "%s",$1}')
if [[ $actual_cabal_project_hash != $expected_cabal_project_hash ]]; then if [[ $actual_cabal_project_hash != $expected_cabal_project_hash ]]; then
echo "ERROR! hash mismatch between expected cabal.project and the one computed by stack2cabal." echo "ERROR! hash mismatch between expected cabal.project and the one computed by stack2cabal."
exit 1 exit 1
else else
echo "cabal.project updated successfully." echo "cabal.project updated successfully."
fi fi
if [[ $actual_cabal_project_freeze_hash != $expected_cabal_project_freeze_hash ]]; then
echo "ERROR! hash mismatch between expected cabal.project.freeze and the one computed by stack2cabal."
exit 1
else
echo "cabal.project.freeze updated successfully."
fi
...@@ -66,11 +66,6 @@ source-repository-package ...@@ -66,11 +66,6 @@ source-repository-package
location: https://gitlab.iscpif.fr/amestanogullari/accelerate-utility.git location: https://gitlab.iscpif.fr/amestanogullari/accelerate-utility.git
tag: a3875fe652d3bb5acb522674c22c6c814c1b4ad0 tag: a3875fe652d3bb5acb522674c22c6c814c1b4ad0
source-repository-package
type: git
location: https://gitlab.iscpif.fr/cgenie/haskell-gargantext-prelude
tag: 8f97fef4dfd941d773914ad058d8e02ce2bb1a3e
source-repository-package source-repository-package
type: git type: git
location: https://gitlab.iscpif.fr/cgenie/patches-class.git location: https://gitlab.iscpif.fr/cgenie/patches-class.git
...@@ -111,6 +106,11 @@ source-repository-package ...@@ -111,6 +106,11 @@ source-repository-package
location: https://gitlab.iscpif.fr/gargantext/gargantext-graph.git location: https://gitlab.iscpif.fr/gargantext/gargantext-graph.git
tag: 588e104fe7593210956610cab0041fd16584a4ce tag: 588e104fe7593210956610cab0041fd16584a4ce
source-repository-package
type: git
location: https://gitlab.iscpif.fr/gargantext/haskell-gargantext-prelude
tag: 8f97fef4dfd941d773914ad058d8e02ce2bb1a3e
source-repository-package source-repository-package
type: git type: git
location: https://gitlab.iscpif.fr/gargantext/haskell-igraph.git location: https://gitlab.iscpif.fr/gargantext/haskell-igraph.git
......
...@@ -1205,12 +1205,12 @@ constraints: any.AC-Angle ==1.0, ...@@ -1205,12 +1205,12 @@ constraints: any.AC-Angle ==1.0,
any.hslua-module-text ==0.3.0.1, any.hslua-module-text ==0.3.0.1,
any.hsp ==0.10.0, any.hsp ==0.10.0,
any.hsparql ==0.3.8, any.hsparql ==0.3.8,
any.hspec ==2.7.10, any.hspec ==2.11.1,
any.hspec-attoparsec ==0.1.0.2, any.hspec-attoparsec ==0.1.0.2,
any.hspec-checkers ==0.1.0.2, any.hspec-checkers ==0.1.0.2,
any.hspec-contrib ==0.5.1, any.hspec-contrib ==0.5.1,
any.hspec-core ==2.7.10, any.hspec-core ==2.11.1,
any.hspec-discover ==2.7.10, any.hspec-discover ==2.11.1,
any.hspec-expectations ==0.8.3, any.hspec-expectations ==0.8.3,
any.hspec-expectations-json ==1.0.0.4, any.hspec-expectations-json ==1.0.0.4,
any.hspec-expectations-lifted ==0.10.0, any.hspec-expectations-lifted ==0.10.0,
...@@ -2385,7 +2385,7 @@ constraints: any.AC-Angle ==1.0, ...@@ -2385,7 +2385,7 @@ constraints: any.AC-Angle ==1.0,
any.tasty-focus ==1.0.1, any.tasty-focus ==1.0.1,
any.tasty-golden ==2.3.5, any.tasty-golden ==2.3.5,
any.tasty-hedgehog ==1.1.0.0, any.tasty-hedgehog ==1.1.0.0,
any.tasty-hspec ==1.1.6, any.tasty-hspec ==1.2.0.3,
any.tasty-hunit ==0.10.0.3, any.tasty-hunit ==0.10.0.3,
any.tasty-hunit-compat ==0.2.0.1, any.tasty-hunit-compat ==0.2.0.1,
any.tasty-inspection-testing ==0.1, any.tasty-inspection-testing ==0.1,
......
...@@ -5,7 +5,7 @@ cabal-version: 2.0 ...@@ -5,7 +5,7 @@ cabal-version: 2.0
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
name: gargantext name: gargantext
version: 0.0.6.9.9.7.6.2 version: 0.0.6.9.9.7.6.3
synopsis: Search, map, share synopsis: Search, map, share
description: Please see README.md description: Please see README.md
category: Data category: Data
...@@ -33,6 +33,13 @@ data-files: ...@@ -33,6 +33,13 @@ data-files:
test-data/test_config.ini test-data/test_config.ini
.clippy.dhall .clippy.dhall
-- When enabled, it swaps the hashing algorithm
-- with a quicker (and less secure) version, which
-- runs faster in tests.
flag test-crypto
default: False
manual: True
library library
exposed-modules: exposed-modules:
Gargantext Gargantext
...@@ -105,6 +112,7 @@ library ...@@ -105,6 +112,7 @@ library
Gargantext.Core.Viz.Types Gargantext.Core.Viz.Types
Gargantext.Database.Action.Flow Gargantext.Database.Action.Flow
Gargantext.Database.Action.Flow.Types Gargantext.Database.Action.Flow.Types
Gargantext.Database.Action.User
Gargantext.Database.Action.User.New Gargantext.Database.Action.User.New
Gargantext.Database.Admin.Config Gargantext.Database.Admin.Config
Gargantext.Database.Admin.Trigger.Init Gargantext.Database.Admin.Trigger.Init
...@@ -115,10 +123,12 @@ library ...@@ -115,10 +123,12 @@ library
Gargantext.Database.Query.Table.Node Gargantext.Database.Query.Table.Node
Gargantext.Database.Query.Table.Node.Error Gargantext.Database.Query.Table.Node.Error
Gargantext.Database.Query.Table.Node.UpdateOpaleye Gargantext.Database.Query.Table.Node.UpdateOpaleye
Gargantext.Database.Query.Tree.Root
Gargantext.Database.Query.Table.User Gargantext.Database.Query.Table.User
Gargantext.Database.Schema.Ngrams Gargantext.Database.Schema.Ngrams
Gargantext.System.Logging Gargantext.Database.Schema.User
Gargantext.Defaults Gargantext.Defaults
Gargantext.System.Logging
Gargantext.Utils.Jobs Gargantext.Utils.Jobs
Gargantext.Utils.Jobs.Internal Gargantext.Utils.Jobs.Internal
Gargantext.Utils.Jobs.Map Gargantext.Utils.Jobs.Map
...@@ -281,7 +291,6 @@ library ...@@ -281,7 +291,6 @@ library
Gargantext.Database.Action.Search Gargantext.Database.Action.Search
Gargantext.Database.Action.Share Gargantext.Database.Action.Share
Gargantext.Database.Action.TSQuery Gargantext.Database.Action.TSQuery
Gargantext.Database.Action.User
Gargantext.Database.Admin.Access Gargantext.Database.Admin.Access
Gargantext.Database.Admin.Bashql Gargantext.Database.Admin.Bashql
Gargantext.Database.Admin.Trigger.ContextNodeNgrams Gargantext.Database.Admin.Trigger.ContextNodeNgrams
...@@ -331,7 +340,6 @@ library ...@@ -331,7 +340,6 @@ library
Gargantext.Database.Query.Table.NodesNgramsRepo Gargantext.Database.Query.Table.NodesNgramsRepo
Gargantext.Database.Query.Tree Gargantext.Database.Query.Tree
Gargantext.Database.Query.Tree.Error Gargantext.Database.Query.Tree.Error
Gargantext.Database.Query.Tree.Root
Gargantext.Database.Schema.Context Gargantext.Database.Schema.Context
Gargantext.Database.Schema.ContextNodeNgrams Gargantext.Database.Schema.ContextNodeNgrams
Gargantext.Database.Schema.ContextNodeNgrams2 Gargantext.Database.Schema.ContextNodeNgrams2
...@@ -346,7 +354,6 @@ library ...@@ -346,7 +354,6 @@ library
Gargantext.Database.Schema.NodeNodeNgrams2 Gargantext.Database.Schema.NodeNodeNgrams2
Gargantext.Database.Schema.NodesNgramsRepo Gargantext.Database.Schema.NodesNgramsRepo
Gargantext.Database.Schema.Prelude Gargantext.Database.Schema.Prelude
Gargantext.Database.Schema.User
Gargantext.Database.Types Gargantext.Database.Types
Gargantext.Utils.Aeson Gargantext.Utils.Aeson
Gargantext.Utils.JohnSnowNLP Gargantext.Utils.JohnSnowNLP
...@@ -371,6 +378,8 @@ library ...@@ -371,6 +378,8 @@ library
RecordWildCards RecordWildCards
StrictData StrictData
ghc-options: -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates -Wmissing-signatures -Wunused-binds -Wunused-imports -Werror -freduction-depth=300 -fplugin=Clippy ghc-options: -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates -Wmissing-signatures -Wunused-binds -Wunused-imports -Werror -freduction-depth=300 -fplugin=Clippy
if flag(test-crypto)
cpp-options: -DTEST_CRYPTO
build-depends: build-depends:
HSvm ^>= 0.1.1.3.22 HSvm ^>= 0.1.1.3.22
, KMP ^>= 0.2.0.0 , KMP ^>= 0.2.0.0
...@@ -865,9 +874,9 @@ executable gargantext-upgrade ...@@ -865,9 +874,9 @@ executable gargantext-upgrade
, text ^>= 1.2.4.1 , text ^>= 1.2.4.1
default-language: Haskell2010 default-language: Haskell2010
test-suite garg-test test-suite garg-test-tasty
type: exitcode-stdio-1.0 type: exitcode-stdio-1.0
main-is: Main.hs main-is: tasty/Main.hs
other-modules: other-modules:
Core.Text Core.Text
Core.Text.Corpus.Query Core.Text.Corpus.Query
...@@ -926,6 +935,87 @@ test-suite garg-test ...@@ -926,6 +935,87 @@ test-suite garg-test
, gargantext , gargantext
, gargantext-prelude , gargantext-prelude
, hspec ^>= 2.7.10 , hspec ^>= 2.7.10
, hspec-core
, hspec-expectations >= 0.8 && < 0.9
, http-client ^>= 0.6.4.1
, http-client-tls ^>= 0.3.5.3
, lens >= 5.2.2 && < 5.3
, monad-control >= 1.0.3 && < 1.1
, mtl ^>= 2.2.2
, parsec ^>= 3.1.14.0
, patches-class ^>= 0.1.0.1
, patches-map ^>= 0.1.0.1
, postgres-options >= 0.2 && < 0.3
, postgresql-simple >= 0.6.4 && < 0.7
, quickcheck-instances ^>= 0.3.25.2
, raw-strings-qq
, recover-rtti >= 0.4 && < 0.5
, resource-pool >= 0.2.3.2 && < 0.2.4
, servant-job
, shelly >= 1.9 && < 2
, stm ^>= 2.5.0.1
, tasty ^>= 1.4.2.1
, tasty-hspec
, tasty-hunit
, tasty-quickcheck
, tasty-smallcheck
, text ^>= 1.2.4.1
, time ^>= 1.9.3
, tmp-postgres >= 1.34.1 && < 1.35
, unordered-containers ^>= 0.2.16.0
, validity ^>= 0.11.0.1
default-language: Haskell2010
test-suite garg-test-hspec
type: exitcode-stdio-1.0
main-is: hspec/Main.hs
other-modules:
Database.Operations
Paths_gargantext
hs-source-dirs:
test
default-extensions:
DataKinds
DeriveGeneric
FlexibleContexts
FlexibleInstances
GADTs
GeneralizedNewtypeDeriving
ImportQualifiedPost
MultiParamTypeClasses
NamedFieldPuns
NoImplicitPrelude
OverloadedStrings
RankNTypes
RecordWildCards
StrictData
DataKinds
DeriveGeneric
FlexibleContexts
FlexibleInstances
GeneralizedNewtypeDeriving
ImportQualifiedPost
MultiParamTypeClasses
NoImplicitPrelude
OverloadedStrings
RankNTypes
ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
build-depends:
QuickCheck ^>= 2.14.2
, aeson ^>= 1.5.6.0
, async ^>= 2.2.4
, base ^>= 4.14.3.0
, boolexpr ^>= 0.2
, bytestring ^>= 0.10.12.0
, conduit ^>= 1.3.4.2
, containers ^>= 0.6.5.1
, crawlerArxiv
, duckling ^>= 0.2.0.0
, extra ^>= 1.7.9
, gargantext
, gargantext-prelude
, hspec ^>= 2.7.10
, hspec-core
, hspec-expectations >= 0.8 && < 0.9 , hspec-expectations >= 0.8 && < 0.9
, http-client ^>= 0.6.4.1 , http-client ^>= 0.6.4.1
, http-client-tls ^>= 0.3.5.3 , http-client-tls ^>= 0.3.5.3
...@@ -948,6 +1038,7 @@ test-suite garg-test ...@@ -948,6 +1038,7 @@ test-suite garg-test
, tasty-hspec , tasty-hspec
, tasty-hunit , tasty-hunit
, tasty-quickcheck , tasty-quickcheck
, tasty-smallcheck
, text ^>= 1.2.4.1 , text ^>= 1.2.4.1
, time ^>= 1.9.3 , time ^>= 1.9.3
, tmp-postgres >= 1.34.1 && < 1.35 , tmp-postgres >= 1.34.1 && < 1.35
...@@ -955,3 +1046,15 @@ test-suite garg-test ...@@ -955,3 +1046,15 @@ test-suite garg-test
, validity ^>= 0.11.0.1 , validity ^>= 0.11.0.1
default-language: Haskell2010 default-language: Haskell2010
benchmark garg-bench
main-is: Main.hs
hs-source-dirs: bench
type: exitcode-stdio-1.0
build-depends: base
, bytestring
, gargantext
, gargantext-prelude
, tasty-bench
ghc-options: "-with-rtsopts=-A32m"
if impl(ghc >= 8.6)
ghc-options: "-with-rtsopts=--nonmoving-gc"
{-# LANGUAGE CPP #-}
{-| {-|
Module : Gargantext.Core.Types.Individu Module : Gargantext.Core.Types.Individu
Description : Short description Description : Short description
...@@ -15,11 +17,11 @@ Individu defintions ...@@ -15,11 +17,11 @@ Individu defintions
module Gargantext.Core.Types.Individu module Gargantext.Core.Types.Individu
where where
import Data.Aeson
import Control.Monad.IO.Class (MonadIO) import Control.Monad.IO.Class (MonadIO)
import GHC.Generics (Generic) import Data.Aeson
import Data.Swagger import Data.Swagger
import Data.Text (Text, pack, reverse) import Data.Text (Text, pack, reverse)
import GHC.Generics (Generic)
import Gargantext.Database.Admin.Types.Node (NodeId, UserId) import Gargantext.Database.Admin.Types.Node (NodeId, UserId)
import Gargantext.Prelude hiding (reverse) import Gargantext.Prelude hiding (reverse)
import qualified Gargantext.Prelude.Crypto.Auth as Auth import qualified Gargantext.Prelude.Crypto.Auth as Auth
...@@ -68,8 +70,15 @@ toUserHash :: MonadIO m ...@@ -68,8 +70,15 @@ toUserHash :: MonadIO m
=> NewUser GargPassword => NewUser GargPassword
-> m (NewUser HashPassword) -> m (NewUser HashPassword)
toUserHash (NewUser u m (GargPassword p)) = do toUserHash (NewUser u m (GargPassword p)) = do
h <- Auth.createPasswordHash p salt <- Auth.newSalt
let h = Auth.hashPasswordWithSalt params salt (Auth.mkPassword p)
pure $ NewUser u m h pure $ NewUser u m h
where
#if TEST_CRYPTO
params = Auth.defaultParams { Auth.argon2MemoryCost = 4096 }
#else
params = Auth.defaultParams
#endif
-- TODO remove -- TODO remove
arbitraryUsersHash :: MonadIO m arbitraryUsersHash :: MonadIO m
......
...@@ -16,7 +16,7 @@ module Gargantext.Database.Action.User ...@@ -16,7 +16,7 @@ module Gargantext.Database.Action.User
import Data.Text (Text) import Data.Text (Text)
import Gargantext.Core.Types.Individu (User(..)) import Gargantext.Core.Types.Individu (User(..))
import Gargantext.Database.Admin.Types.Node import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Prelude (Cmd, DBCmd) import Gargantext.Database.Prelude (DBCmd)
import Gargantext.Database.Query.Table.Node import Gargantext.Database.Query.Table.Node
import Gargantext.Database.Query.Table.User import Gargantext.Database.Query.Table.User
import Gargantext.Database.Query.Table.Node.Error import Gargantext.Database.Query.Table.Node.Error
...@@ -24,14 +24,14 @@ import Gargantext.Database.Schema.Node ...@@ -24,14 +24,14 @@ import Gargantext.Database.Schema.Node
import Gargantext.Prelude import Gargantext.Prelude
------------------------------------------------------------------------ ------------------------------------------------------------------------
getUserLightWithId :: HasNodeError err => Int -> Cmd err UserLight getUserLightWithId :: HasNodeError err => UserId -> DBCmd err UserLight
getUserLightWithId i = do getUserLightWithId i = do
candidates <- head <$> getUsersWithId (UserDBId i) candidates <- head <$> getUsersWithId (UserDBId i)
case candidates of case candidates of
Nothing -> nodeError NoUserFound Nothing -> nodeError NoUserFound
Just u -> pure u Just u -> pure u
getUserLightDB :: HasNodeError err => User -> Cmd err UserLight getUserLightDB :: HasNodeError err => User -> DBCmd err UserLight
getUserLightDB u = do getUserLightDB u = do
userId <- getUserId u userId <- getUserId u
userLight <- getUserLightWithId userId userLight <- getUserLightWithId userId
......
...@@ -28,6 +28,7 @@ import Gargantext.Core.Mail ...@@ -28,6 +28,7 @@ import Gargantext.Core.Mail
import Gargantext.Core.Mail.Types (HasMail, mailSettings) import Gargantext.Core.Mail.Types (HasMail, mailSettings)
import Gargantext.Core.Types.Individu import Gargantext.Core.Types.Individu
import Gargantext.Database.Action.Flow (getOrMkRoot) import Gargantext.Database.Action.Flow (getOrMkRoot)
import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Prelude import Gargantext.Database.Prelude
import Gargantext.Database.Query.Table.Node.Error (HasNodeError(..), nodeError, NodeError(..)) import Gargantext.Database.Query.Table.Node.Error (HasNodeError(..), nodeError, NodeError(..))
import Gargantext.Database.Query.Table.User import Gargantext.Database.Query.Table.User
...@@ -41,13 +42,13 @@ import qualified Data.Text as Text ...@@ -41,13 +42,13 @@ import qualified Data.Text as Text
-- be valid (i.e. a valid username needs to be inferred via 'guessUsername'). -- be valid (i.e. a valid username needs to be inferred via 'guessUsername').
newUser :: (CmdM env err m, MonadRandom m, HasNodeError err, HasMail env) newUser :: (CmdM env err m, MonadRandom m, HasNodeError err, HasMail env)
=> EmailAddress => EmailAddress
-> m Int64 -> m UserId
newUser emailAddress = do newUser emailAddress = do
cfg <- view mailSettings cfg <- view mailSettings
pwd <- gargPass pwd <- gargPass
let nur = mkNewUser emailAddress (GargPassword pwd) let nur = mkNewUser emailAddress (GargPassword pwd)
affectedRows <- new_user nur new_user_id <- new_user nur
withNotification (SendEmail True) cfg Invitation $ pure (affectedRows, nur) withNotification (SendEmail True) cfg Invitation $ pure (new_user_id, nur)
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- | A DB-specific action to create a single user. -- | A DB-specific action to create a single user.
...@@ -56,8 +57,12 @@ newUser emailAddress = do ...@@ -56,8 +57,12 @@ newUser emailAddress = do
-- use 'newUser' instead for standard Gargantext code. -- use 'newUser' instead for standard Gargantext code.
new_user :: HasNodeError err new_user :: HasNodeError err
=> NewUser GargPassword => NewUser GargPassword
-> DBCmd err Int64 -> DBCmd err UserId
new_user = new_users . (:[]) new_user rq = do
ur <- new_users [rq]
case head ur of
Nothing -> nodeError MkNode
Just uid -> pure uid
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- | A DB-specific action to bulk-create users. -- | A DB-specific action to bulk-create users.
...@@ -67,17 +72,16 @@ new_user = new_users . (:[]) ...@@ -67,17 +72,16 @@ new_user = new_users . (:[])
new_users :: HasNodeError err new_users :: HasNodeError err
=> [NewUser GargPassword] => [NewUser GargPassword]
-- ^ A list of users to create. -- ^ A list of users to create.
-> DBCmd err Int64 -> DBCmd err [UserId]
new_users us = do new_users us = do
us' <- liftBase $ mapM toUserHash us us' <- liftBase $ mapM toUserHash us
r <- insertUsers $ map toUserWrite us' void $ insertUsers $ map toUserWrite us'
_ <- mapM getOrMkRoot $ map (\u -> UserName (_nu_username u)) us mapM (fmap fst . getOrMkRoot) $ map (\u -> UserName (_nu_username u)) us
pure r
------------------------------------------------------------------------ ------------------------------------------------------------------------
newUsers :: (CmdM env err m, MonadRandom m, HasNodeError err, HasMail env) newUsers :: (CmdM env err m, MonadRandom m, HasNodeError err, HasMail env)
=> [EmailAddress] => [EmailAddress]
-> m Int64 -> m [UserId]
newUsers us = do newUsers us = do
config <- view $ mailSettings config <- view $ mailSettings
us' <- mapM (\ea -> mkNewUser ea . GargPassword <$> gargPass) us us' <- mapM (\ea -> mkNewUser ea . GargPassword <$> gargPass) us
...@@ -102,14 +106,14 @@ guessUserName n = case splitOn "@" n of ...@@ -102,14 +106,14 @@ guessUserName n = case splitOn "@" n of
------------------------------------------------------------------------ ------------------------------------------------------------------------
newUsers' :: HasNodeError err newUsers' :: HasNodeError err
=> MailConfig -> [NewUser GargPassword] -> Cmd err Int64 => MailConfig -> [NewUser GargPassword] -> Cmd err [UserId]
newUsers' cfg us = do newUsers' cfg us = do
us' <- liftBase $ mapM toUserHash us us' <- liftBase $ mapM toUserHash us
r <- insertUsers $ map toUserWrite us' void $ insertUsers $ map toUserWrite us'
_ <- mapM getOrMkRoot $ map (\u -> UserName (_nu_username u)) us urs <- mapM (fmap fst . getOrMkRoot) $ map (\u -> UserName (_nu_username u)) us
_ <- mapM (\u -> mail cfg (Invitation u)) us _ <- mapM (\u -> mail cfg (Invitation u)) us
-- printDebug "newUsers'" us -- printDebug "newUsers'" us
pure r pure urs
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- | Updates a user's password, notifying the user via email, if necessary. -- | Updates a user's password, notifying the user via email, if necessary.
......
...@@ -195,7 +195,7 @@ getDocumentsWithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeDocument ...@@ -195,7 +195,7 @@ getDocumentsWithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeDocument
getListsModelWithParentId :: HasDBid NodeType => NodeId -> Cmd err [Node HyperdataModel] getListsModelWithParentId :: HasDBid NodeType => NodeId -> Cmd err [Node HyperdataModel]
getListsModelWithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeModel) getListsModelWithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeModel)
getCorporaWithParentId :: HasDBid NodeType => NodeId -> Cmd err [Node HyperdataCorpus] getCorporaWithParentId :: HasDBid NodeType => NodeId -> DBCmd err [Node HyperdataCorpus]
getCorporaWithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeCorpus) getCorporaWithParentId n = runOpaQuery $ selectNodesWith' n (Just NodeCorpus)
------------------------------------------------------------------------ ------------------------------------------------------------------------
...@@ -271,7 +271,7 @@ getNodeWith nId _ = do ...@@ -271,7 +271,7 @@ getNodeWith nId _ = do
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- | Sugar to insert Node with NodeType in Database -- | Sugar to insert Node with NodeType in Database
insertDefaultNode :: HasDBid NodeType insertDefaultNode :: HasDBid NodeType
=> NodeType -> ParentId -> UserId -> Cmd err [NodeId] => NodeType -> ParentId -> UserId -> DBCmd err [NodeId]
insertDefaultNode nt p u = insertNode nt Nothing Nothing p u insertDefaultNode nt p u = insertNode nt Nothing Nothing p u
insertDefaultNodeIfNotExists :: HasDBid NodeType insertDefaultNodeIfNotExists :: HasDBid NodeType
...@@ -382,7 +382,7 @@ data CorpusType = CorpusDocument | CorpusContact ...@@ -382,7 +382,7 @@ data CorpusType = CorpusDocument | CorpusContact
class MkCorpus a class MkCorpus a
where where
mk :: HasDBid NodeType => Maybe Name -> Maybe a -> ParentId -> UserId -> Cmd err [NodeId] mk :: HasDBid NodeType => Maybe Name -> Maybe a -> ParentId -> UserId -> DBCmd err [NodeId]
instance MkCorpus HyperdataCorpus instance MkCorpus HyperdataCorpus
where where
......
...@@ -72,7 +72,7 @@ import Gargantext.Database.Admin.Config (nodeTypeId) ...@@ -72,7 +72,7 @@ import Gargantext.Database.Admin.Config (nodeTypeId)
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- TODO: on conflict, nice message -- TODO: on conflict, nice message
insertUsers :: [UserWrite] -> DBCmd err Int64 insertUsers :: [UserWrite] -> DBCmd err Int64
insertUsers us = mkCmd $ \c -> runInsert_ c insert insertUsers us = mkCmd $ \c -> runInsert c insert
where where
insert = Insert userTable us rCount Nothing insert = Insert userTable us rCount Nothing
......
...@@ -23,7 +23,7 @@ import Gargantext.Database.Action.User (getUserId, getUsername) ...@@ -23,7 +23,7 @@ import Gargantext.Database.Action.User (getUserId, getUsername)
import Gargantext.Database.Admin.Config import Gargantext.Database.Admin.Config
import Gargantext.Database.Admin.Types.Hyperdata (HyperdataUser) import Gargantext.Database.Admin.Types.Hyperdata (HyperdataUser)
import Gargantext.Database.Admin.Types.Node import Gargantext.Database.Admin.Types.Node
import Gargantext.Database.Prelude (Cmd, runOpaQuery, DBCmd) import Gargantext.Database.Prelude (runOpaQuery, DBCmd)
import Gargantext.Database.Query.Table.Node import Gargantext.Database.Query.Table.Node
import Gargantext.Database.Query.Table.Node.Error import Gargantext.Database.Query.Table.Node.Error
import Gargantext.Database.Query.Table.User (queryUserTable, UserPoly(..)) import Gargantext.Database.Query.Table.User (queryUserTable, UserPoly(..))
...@@ -34,7 +34,7 @@ import Opaleye (restrict, (.==), Select) ...@@ -34,7 +34,7 @@ import Opaleye (restrict, (.==), Select)
import Opaleye.SqlTypes (sqlStrictText, sqlInt4) import Opaleye.SqlTypes (sqlStrictText, sqlInt4)
getRootId :: (HasNodeError err) => User -> Cmd err NodeId getRootId :: (HasNodeError err) => User -> DBCmd err NodeId
getRootId u = do getRootId u = do
maybeRoot <- head <$> getRoot u maybeRoot <- head <$> getRoot u
case maybeRoot of case maybeRoot of
...@@ -66,7 +66,7 @@ getOrMk_RootWithCorpus :: (HasNodeError err, MkCorpus a) ...@@ -66,7 +66,7 @@ getOrMk_RootWithCorpus :: (HasNodeError err, MkCorpus a)
=> User => User
-> Either CorpusName [CorpusId] -> Either CorpusName [CorpusId]
-> Maybe a -> Maybe a
-> Cmd err (UserId, RootId, CorpusId) -> DBCmd err (UserId, RootId, CorpusId)
getOrMk_RootWithCorpus user cName c = do getOrMk_RootWithCorpus user cName c = do
(userId, rootId) <- getOrMkRoot user (userId, rootId) <- getOrMkRoot user
corpusId'' <- if user == UserName userMaster corpusId'' <- if user == UserName userMaster
......
...@@ -21,7 +21,7 @@ nix: ...@@ -21,7 +21,7 @@ nix:
allow-newer: true allow-newer: true
extra-deps: extra-deps:
- git: https://gitlab.iscpif.fr/cgenie/haskell-gargantext-prelude - git: https://gitlab.iscpif.fr/gargantext/haskell-gargantext-prelude
commit: 8f97fef4dfd941d773914ad058d8e02ce2bb1a3e commit: 8f97fef4dfd941d773914ad058d8e02ce2bb1a3e
- git: https://gitlab.iscpif.fr/gargantext/gargantext-graph.git - git: https://gitlab.iscpif.fr/gargantext/gargantext-graph.git
commit: 588e104fe7593210956610cab0041fd16584a4ce commit: 588e104fe7593210956610cab0041fd16584a4ce
...@@ -58,7 +58,7 @@ extra-deps: ...@@ -58,7 +58,7 @@ extra-deps:
- git: https://gitlab.iscpif.fr/gargantext/crawlers/isidore.git - git: https://gitlab.iscpif.fr/gargantext/crawlers/isidore.git
commit: 3db385e767d2100d8abe900833c6e7de3ac55e1b commit: 3db385e767d2100d8abe900833c6e7de3ac55e1b
- git: https://gitlab.iscpif.fr/gargantext/crawlers/arxiv-api.git - git: https://gitlab.iscpif.fr/gargantext/crawlers/arxiv-api.git
commit: 2d7e5753cbbce248b860b571a0e9885415c846f7 commit: eb130c71fa17adaceed6ff66beefbccb13df51ba
- git: https://gitlab.iscpif.fr/gargantext/crawlers/openalex.git - git: https://gitlab.iscpif.fr/gargantext/crawlers/openalex.git
commit: 1cf872fb3bd0e3e44af31247833c4b6bb7d0dca5 commit: 1cf872fb3bd0e3e44af31247833c4b6bb7d0dca5
# NP libs # NP libs
...@@ -116,6 +116,9 @@ extra-deps: ...@@ -116,6 +116,9 @@ extra-deps:
- hgal-2.0.0.2@sha256:13d58afd0668b9cb881c612eff8488a0e289edd4bbffa893df4beee60cfeb73b,653 - hgal-2.0.0.2@sha256:13d58afd0668b9cb881c612eff8488a0e289edd4bbffa893df4beee60cfeb73b,653
- hsparql-0.3.8 - hsparql-0.3.8
- hstatistics-0.3.1 - hstatistics-0.3.1
- hspec-2.11.1
- hspec-core-2.11.1
- hspec-discover-2.11.1
- hspec-expectations-0.8.3 - hspec-expectations-0.8.3
- json-stream-0.4.2.4@sha256:8b7f17d54a6e1e6311756270f8bcf51e91bab4300945400de66118470dcf51b9,4716 - json-stream-0.4.2.4@sha256:8b7f17d54a6e1e6311756270f8bcf51e91bab4300945400de66118470dcf51b9,4716
- located-base-0.1.1.1@sha256:7c6395f2b6fbf2d5f76c3514f774423838c0ea94e1c6a5530dd3c94b30c9d1c8,1904 - located-base-0.1.1.1@sha256:7c6395f2b6fbf2d5f76c3514f774423838c0ea94e1c6a5530dd3c94b30c9d1c8,1904
...@@ -133,6 +136,7 @@ extra-deps: ...@@ -133,6 +136,7 @@ extra-deps:
- stemmer-0.5.2@sha256:823aec56249ec2619f60a2c0d1384b732894dbbbe642856d337ebfe9629a0efd,4082 - stemmer-0.5.2@sha256:823aec56249ec2619f60a2c0d1384b732894dbbbe642856d337ebfe9629a0efd,4082
- taggy-0.2.1@sha256:7bc55ddba178971dc6052163597f0445a0a2b5b0ca0e84ce651d53d722e3c265,4662 - taggy-0.2.1@sha256:7bc55ddba178971dc6052163597f0445a0a2b5b0ca0e84ce651d53d722e3c265,4662
- taggy-lens-0.1.2@sha256:091ca81d02bd3d7fb493dce0148e1a38f25eb178a1ebd751043a23239e5e3265,3009 - taggy-lens-0.1.2@sha256:091ca81d02bd3d7fb493dce0148e1a38f25eb178a1ebd751043a23239e5e3265,3009
- tasty-hspec-1.2.0.3
- tmp-postgres-1.34.1.0 - tmp-postgres-1.34.1.0
- vector-0.12.3.0@sha256:0ae2c1ba86f0077910be242ec6802cc3d7725fe7b2bea6987201aa3737b239b5,7953 - vector-0.12.3.0@sha256:0ae2c1ba86f0077910be242ec6802cc3d7725fe7b2bea6987201aa3737b239b5,7953
- xmlbf-0.6.1@sha256:57867fcb39e0514d17b3328ff5de8d241a18482fc89bb742d9ed820a6a2a5187,1540 - xmlbf-0.6.1@sha256:57867fcb39e0514d17b3328ff5de8d241a18482fc89bb742d9ed820a6a2a5187,1540
......
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-} {-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -Wno-orphans #-}
module Database.Operations where module Database.Operations (
tests
) where
import Control.Exception import Control.Exception hiding (assert)
import Control.Lens import Control.Lens hiding (elements)
import Control.Monad.Except import Control.Monad.Except
import Control.Monad.Reader import Control.Monad.Reader
import Control.Monad.Trans.Control import Control.Monad.Trans.Control
import Data.IORef
import Data.Pool hiding (withResource) import Data.Pool hiding (withResource)
import Data.String import Data.String
import Database.PostgreSQL.Simple
import Gargantext.Core.Types.Individu import Gargantext.Core.Types.Individu
import Gargantext.Database.Action.User
import Gargantext.Database.Action.User.New import Gargantext.Database.Action.User.New
import Gargantext.Database.Prelude import Gargantext.Database.Prelude
import Gargantext.Database.Query.Table.Node.Error import Gargantext.Database.Query.Table.Node.Error
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Prelude.Config import Gargantext.Prelude.Config
import Prelude import Prelude
import Shelly hiding (FilePath) import Shelly hiding (FilePath, run)
import Test.Tasty import Test.QuickCheck.Monadic
import Test.Tasty.HUnit import Test.Hspec
import Test.Tasty.Hspec import Test.Tasty.HUnit hiding (assert)
import Test.Tasty.QuickCheck
import qualified Data.Pool as Pool import qualified Data.Pool as Pool
import qualified Data.Text as T 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.Postgres.Temp as Tmp import qualified Database.Postgres.Temp as Tmp
import qualified Shelly as SH
import Paths_gargantext import Paths_gargantext
-- | Keeps a log of usernames we have already generated, so that our
-- roundtrip tests won't fail.
uniqueArbitraryNewUser :: Int -> Gen (NewUser GargPassword)
uniqueArbitraryNewUser currentIx = do
ur <- (`mappend` (T.pack (show currentIx) <> "-")) <$> ascii_txt
let email = ur <> "@foo.com"
NewUser <$> pure ur <*> pure email <*> elements arbitraryPassword
where
ascii_txt :: Gen T.Text
ascii_txt = fmap (T.pack . getPrintableString) arbitrary
-- | Test DB settings. -- | Test DB settings.
dbUser, dbPassword, dbName :: String dbUser, dbPassword, dbName :: String
dbUser = "gargantua" dbUser = "gargantua"
dbPassword = "gargantua_test" dbPassword = "gargantua_test"
dbName = "gargandbV5" dbName = "gargandb_test"
newtype Counter = Counter { _Counter :: IORef Int }
deriving Eq
instance Show Counter where
show (Counter _) = "Counter"
emptyCounter :: IO Counter
emptyCounter = Counter <$> newIORef 0
nextCounter :: Counter -> IO Int
nextCounter (Counter ref) = atomicModifyIORef' ref (\old -> (succ old, old))
data TestEnv = TestEnv { data TestEnv = TestEnv {
test_db :: !DBHandle test_db :: !DBHandle
, test_config :: !GargConfig , test_config :: !GargConfig
, test_usernameGen :: !Counter
} }
newtype TestMonad a = TestMonad { runTestMonad :: ReaderT TestEnv IO a } newtype TestMonad a = TestMonad { runTestMonad :: ReaderT TestEnv IO a }
...@@ -52,7 +82,7 @@ newtype TestMonad a = TestMonad { runTestMonad :: ReaderT TestEnv IO a } ...@@ -52,7 +82,7 @@ newtype TestMonad a = TestMonad { runTestMonad :: ReaderT TestEnv IO a }
, MonadBaseControl IO , MonadBaseControl IO
) )
data DBHandle = DBHandle { data DBHandle = DBHandle {
_DBHandle :: Pool PG.Connection _DBHandle :: Pool PG.Connection
, _DBTmp :: Tmp.DB , _DBTmp :: Tmp.DB
} }
...@@ -72,9 +102,6 @@ fakeIniPath = getDataFileName "test-data/test_config.ini" ...@@ -72,9 +102,6 @@ fakeIniPath = getDataFileName "test-data/test_config.ini"
gargDBSchema :: IO FilePath gargDBSchema :: IO FilePath
gargDBSchema = getDataFileName "devops/postgres/schema.sql" gargDBSchema = getDataFileName "devops/postgres/schema.sql"
gargDBExtensionsSchema :: IO FilePath
gargDBExtensionsSchema = getDataFileName "devops/postgres/extensions.sql"
teardown :: TestEnv -> IO () teardown :: TestEnv -> IO ()
teardown TestEnv{..} = do teardown TestEnv{..} = do
destroyAllResources $ _DBHandle test_db destroyAllResources $ _DBHandle test_db
...@@ -87,7 +114,7 @@ bootstrapDB tmpDB pool _cfg = Pool.withResource pool $ \conn -> do ...@@ -87,7 +114,7 @@ bootstrapDB tmpDB pool _cfg = Pool.withResource pool $ \conn -> do
schemaPath <- gargDBSchema schemaPath <- gargDBSchema
let connString = Tmp.toConnectionString tmpDB let connString = Tmp.toConnectionString tmpDB
(res,ec) <- shelly $ silently $ escaping False $ do (res,ec) <- shelly $ silently $ escaping False $ do
result <- run "psql" ["-d", "\"" <> TE.decodeUtf8 connString <> "\"", "<", fromString schemaPath] result <- SH.run "psql" ["-d", "\"" <> TE.decodeUtf8 connString <> "\"", "<", fromString schemaPath]
(result,) <$> lastExitCode (result,) <$> lastExitCode
unless (ec == 0) $ throwIO (userError $ show ec <> ": " <> T.unpack res) unless (ec == 0) $ throwIO (userError $ show ec <> ": " <> T.unpack res)
...@@ -107,26 +134,75 @@ setup = do ...@@ -107,26 +134,75 @@ setup = do
Right db -> do Right db -> do
gargConfig <- fakeIniPath >>= readConfig gargConfig <- fakeIniPath >>= readConfig
pool <- createPool (PG.connectPostgreSQL (Tmp.toConnectionString db)) pool <- createPool (PG.connectPostgreSQL (Tmp.toConnectionString db))
(PG.close) (PG.close) 2 60 2
2
60
2
bootstrapDB db pool gargConfig bootstrapDB db pool gargConfig
pure $ TestEnv (DBHandle pool db) gargConfig ugen <- emptyCounter
pure $ TestEnv (DBHandle pool db) gargConfig ugen
withTestDB :: (TestEnv -> IO ()) -> IO ()
withTestDB = bracket setup teardown
tests :: Spec
tests = sequential $ aroundAll withTestDB $ describe "Database" $ do
describe "Read/Writes" $
describe "User creation" $ do
it "Simple write/read" writeRead01
it "Simple duplicate" mkUserDup
it "Read/Write roundtrip" prop_userCreationRoundtrip
data ExpectedActual a =
Expected a
| Actual a
deriving Show
tests :: TestTree instance Eq a => Eq (ExpectedActual a) where
tests = withResource setup teardown $ (Expected a) == (Actual b) = a == b
\getEnv -> testGroup "Database" [unitTests getEnv] (Actual a) == (Expected b) = a == b
_ == _ = False
unitTests :: IO TestEnv -> TestTree
unitTests getEnv = testGroup "Read/Writes"
[ testCase "Simple write" (write01 getEnv)
]
write01 :: IO TestEnv -> Assertion writeRead01 :: TestEnv -> Assertion
write01 getEnv = do writeRead01 env = do
env <- getEnv
flip runReaderT env $ runTestMonad $ do flip runReaderT env $ runTestMonad $ do
let nur = mkNewUser "alfredo@well-typed.com" (GargPassword "my_secret") let nur1 = mkNewUser "alfredo@well-typed.com" (GargPassword "my_secret")
x <- new_user nur let nur2 = mkNewUser "paul@acme.com" (GargPassword "my_secret")
liftBase $ x `shouldBe` 1
\ No newline at end of file uid1 <- new_user nur1
uid2 <- new_user nur2
liftBase $ uid1 `shouldBe` 1
liftBase $ uid2 `shouldBe` 2
-- Getting the users by username returns the expected IDs
uid1' <- getUserId (UserName "alfredo")
uid2' <- getUserId (UserName "paul")
liftBase $ uid1' `shouldBe` 1
liftBase $ uid2' `shouldBe` 2
mkUserDup :: TestEnv -> Assertion
mkUserDup env = do
let x = flip runReaderT env $ runTestMonad $ do
-- This should fail, because user 'alfredo' exists already.
let nur = mkNewUser "alfredo@well-typed.com" (GargPassword "my_secret")
new_user nur
--
-- SqlError {sqlState = "23505", sqlExecStatus = FatalError
-- , sqlErrorMsg = "duplicate key value violates unique constraint \"auth_user_username_idx1\""
-- , sqlErrorDetail = "Key (username)=(alfredo) already exists.", sqlErrorHint = ""
-- }
--
-- Postgres increments the underlying SERIAL for the user even if the request fails, see
-- https://stackoverflow.com/questions/37204749/serial-in-postgres-is-being-increased-even-though-i-added-on-conflict-do-nothing
-- This means that the next available ID is '3'.
x `shouldThrow` (\SqlError{..} -> sqlErrorDetail == "Key (username)=(alfredo) already exists.")
runEnv :: TestEnv -> TestMonad a -> PropertyM IO a
runEnv env act = run (flip runReaderT env $ runTestMonad act)
prop_userCreationRoundtrip :: TestEnv -> Property
prop_userCreationRoundtrip env = monadicIO $ do
nextAvailableCounter <- run (nextCounter $ test_usernameGen env)
nur <- pick (uniqueArbitraryNewUser nextAvailableCounter)
uid <- runEnv env (new_user nur)
ur' <- runEnv env (getUserId (UserName $ _nu_username nur))
run (Expected uid `shouldBe` Actual ur')
...@@ -18,7 +18,6 @@ module Parsers.Date where ...@@ -18,7 +18,6 @@ module Parsers.Date where
import Test.Hspec import Test.Hspec
import Test.QuickCheck import Test.QuickCheck
import Control.Applicative ((<*>))
import Data.Either (Either(..)) import Data.Either (Either(..))
import Data.Time (ZonedTime(..)) import Data.Time (ZonedTime(..))
import Data.Text (pack, Text) import Data.Text (pack, Text)
......
...@@ -25,7 +25,6 @@ import Test.QuickCheck.Instances () ...@@ -25,7 +25,6 @@ import Test.QuickCheck.Instances ()
import Text.Parsec.Pos import Text.Parsec.Pos
import Text.Parsec.Error (ParseError, Message(..), newErrorMessage) import Text.Parsec.Error (ParseError, Message(..), newErrorMessage)
import Data.Time.LocalTime (ZonedTime (..), TimeZone (..), TimeOfDay(..), LocalTime(..)) import Data.Time.LocalTime (ZonedTime (..), TimeZone (..), TimeOfDay(..), LocalTime(..))
import Data.Eq (Eq(..))
import Data.Either (Either(..)) import Data.Either (Either(..))
deriving instance Eq ZonedTime deriving instance Eq ZonedTime
......
...@@ -228,6 +228,7 @@ instance MonadJobStatus MyDummyMonad where ...@@ -228,6 +228,7 @@ instance MonadJobStatus MyDummyMonad where
markFailure steps mb_msg jh = MyDummyMonad (markFailure steps mb_msg jh) markFailure steps mb_msg jh = MyDummyMonad (markFailure steps mb_msg jh)
markComplete jh = MyDummyMonad (markComplete jh) markComplete jh = MyDummyMonad (markComplete jh)
markFailed mb_msg jh = MyDummyMonad (markFailed mb_msg jh) markFailed mb_msg jh = MyDummyMonad (markFailed mb_msg jh)
addMoreSteps steps jh = MyDummyMonad (addMoreSteps steps jh)
runMyDummyMonad :: Env -> MyDummyMonad a -> IO a runMyDummyMonad :: Env -> MyDummyMonad a -> IO a
runMyDummyMonad env m = do runMyDummyMonad env m = do
......
module Main where
import Gargantext.Prelude
import qualified Database.Operations as DB
import Test.Hspec
-- It's especially important to use Hspec for DB tests, because,
-- unlike 'tasty', 'Hspec' has explicit control over parallelism,
-- and it's important that DB tests are run according to a very
-- precise order, as they are not independent from each other.
-- Unfortunately it's not possibly to use the 'tasty-hspec' adapter
-- because by the time we get a 'TestTree' out of the adapter library,
-- the information about parallelism is lost.
main :: IO ()
main = hspec DB.tests
{-| {--|
Module : Main.hs Module : Main.hs
Description : Main for Gargantext Tests Description : Main for Gargantext Tasty Tests
Copyright : (c) CNRS, 2017-Present Copyright : (c) CNRS, 2017-Present
License : AGPL + CECILL v3 License : AGPL + CECILL v3
Maintainer : team@gargantext.org Maintainer : team@gargantext.org
...@@ -8,6 +8,7 @@ Stability : experimental ...@@ -8,6 +8,7 @@ Stability : experimental
Portability : POSIX Portability : POSIX
-} -}
module Main where
import Gargantext.Prelude import Gargantext.Prelude
...@@ -44,5 +45,4 @@ main = do ...@@ -44,5 +45,4 @@ main = do
, NgramsQuery.tests , NgramsQuery.tests
, CorpusQuery.tests , CorpusQuery.tests
, JSON.tests , JSON.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