Commit 5e210c11 authored by Alfredo Di Napoli's avatar Alfredo Di Napoli

Add frontend error for NoListFound

parent 60e1953f
...@@ -47,12 +47,12 @@ backendErrorToFrontendError = \case ...@@ -47,12 +47,12 @@ backendErrorToFrontendError = \case
nodeErrorToFrontendError :: NodeError -> FrontendError nodeErrorToFrontendError :: NodeError -> FrontendError
nodeErrorToFrontendError ne = case ne of nodeErrorToFrontendError ne = case ne of
NoListFound _lid NoListFound lid
-> undefined -> mkFrontendErrShow $ FE_node_error_list_not_found lid
NoRootFound NoRootFound
-> mkFrontendErr' renderedError FE_node_error_root_not_found -> mkFrontendErrShow FE_node_error_root_not_found
NoCorpusFound NoCorpusFound
-> mkFrontendErr' renderedError FE_node_error_corpus_not_found -> mkFrontendErrShow FE_node_error_corpus_not_found
NoUserFound _ur NoUserFound _ur
-> undefined -> undefined
MkNode MkNode
...@@ -79,8 +79,6 @@ nodeErrorToFrontendError ne = case ne of ...@@ -79,8 +79,6 @@ nodeErrorToFrontendError ne = case ne of
-> undefined -> undefined
QueryNoParse _txt QueryNoParse _txt
-> undefined -> undefined
where
renderedError = T.pack (show ne)
-- | Converts a 'FrontendError' into a 'ServerError' that the servant app can -- | Converts a 'FrontendError' into a 'ServerError' that the servant app can
-- return to the frontend. -- return to the frontend.
......
...@@ -22,13 +22,17 @@ module Gargantext.API.Errors.Types ( ...@@ -22,13 +22,17 @@ module Gargantext.API.Errors.Types (
, ToFrontendErrorData(..) , ToFrontendErrorData(..)
-- * Constructing frontend errors -- * Constructing frontend errors
, mkFrontendErr , mkFrontendErrNoDiagnostic
, mkFrontendErrShow
, mkFrontendErr' , mkFrontendErr'
-- * Evidence carrying -- * Evidence carrying
, Dict(..) , Dict(..)
, IsFrontendErrorData(..) , IsFrontendErrorData(..)
-- * Generating test cases
, genFrontendErr
-- * Attaching callstacks to exceptions -- * Attaching callstacks to exceptions
, WithStacktrace(..) , WithStacktrace(..)
) where ) where
...@@ -120,7 +124,8 @@ instance HasJoseError BackendInternalError where ...@@ -120,7 +124,8 @@ instance HasJoseError BackendInternalError where
data BackendErrorCode data BackendErrorCode
= =
-- node errors -- node errors
EC_404__node_error_root_not_found EC_404__node_error_list_not_found
| EC_404__node_error_root_not_found
| EC_404__node_error_corpus_not_found | EC_404__node_error_corpus_not_found
-- tree errors -- tree errors
| EC_404__tree_error_root_not_found | EC_404__tree_error_root_not_found
...@@ -156,6 +161,8 @@ class ( SingI payload ...@@ -156,6 +161,8 @@ class ( SingI payload
) => IsFrontendErrorData payload where ) => IsFrontendErrorData payload where
isFrontendErrorData :: Proxy payload -> Dict IsFrontendErrorData payload isFrontendErrorData :: Proxy payload -> Dict IsFrontendErrorData payload
instance IsFrontendErrorData 'EC_404__node_error_list_not_found where
isFrontendErrorData _ = Dict
instance IsFrontendErrorData 'EC_404__node_error_root_not_found where instance IsFrontendErrorData 'EC_404__node_error_root_not_found where
isFrontendErrorData _ = Dict isFrontendErrorData _ = Dict
instance IsFrontendErrorData 'EC_404__node_error_corpus_not_found where instance IsFrontendErrorData 'EC_404__node_error_corpus_not_found where
...@@ -171,6 +178,10 @@ data NoFrontendErrorData = NoFrontendErrorData ...@@ -171,6 +178,10 @@ data NoFrontendErrorData = NoFrontendErrorData
data family ToFrontendErrorData (payload :: BackendErrorCode) :: Type data family ToFrontendErrorData (payload :: BackendErrorCode) :: Type
newtype instance ToFrontendErrorData 'EC_404__node_error_list_not_found =
FE_node_error_list_not_found { lnf_list_id :: ListId }
deriving (Show, Eq, Generic)
data instance ToFrontendErrorData 'EC_404__node_error_root_not_found = data instance ToFrontendErrorData 'EC_404__node_error_root_not_found =
FE_node_error_root_not_found FE_node_error_root_not_found
deriving (Show, Eq, Generic) deriving (Show, Eq, Generic)
...@@ -187,6 +198,15 @@ data instance ToFrontendErrorData 'EC_404__tree_error_root_not_found = ...@@ -187,6 +198,15 @@ data instance ToFrontendErrorData 'EC_404__tree_error_root_not_found =
-- JSON instances. It's important to have nice and human readable instances. -- JSON instances. It's important to have nice and human readable instances.
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
instance ToJSON (ToFrontendErrorData 'EC_404__node_error_list_not_found) where
toJSON (FE_node_error_list_not_found lid) =
JSON.object [ "list_id" .= toJSON lid ]
instance FromJSON (ToFrontendErrorData 'EC_404__node_error_list_not_found) where
parseJSON = withObject "FE_node_error_list_not_found" $ \o -> do
lnf_list_id <- o .: "list_id"
pure FE_node_error_list_not_found{..}
instance ToJSON (ToFrontendErrorData 'EC_404__node_error_root_not_found) where instance ToJSON (ToFrontendErrorData 'EC_404__node_error_root_not_found) where
toJSON _ = JSON.Null toJSON _ = JSON.Null
...@@ -207,10 +227,18 @@ instance FromJSON (ToFrontendErrorData 'EC_404__tree_error_root_not_found) where ...@@ -207,10 +227,18 @@ instance FromJSON (ToFrontendErrorData 'EC_404__tree_error_root_not_found) where
_rnf_rootId <- o .: "root_id" _rnf_rootId <- o .: "root_id"
pure RootNotFound{..} pure RootNotFound{..}
mkFrontendErr :: IsFrontendErrorData payload -- | Creates an error without attaching a diagnostic to it.
=> ToFrontendErrorData payload mkFrontendErrNoDiagnostic :: IsFrontendErrorData payload
-> FrontendError => ToFrontendErrorData payload
mkFrontendErr et = mkFrontendErr' mempty et -> FrontendError
mkFrontendErrNoDiagnostic et = mkFrontendErr' mempty et
-- | Renders the error by using as a diagnostic the string
-- resulting from 'Show'ing the underlying type.
mkFrontendErrShow :: IsFrontendErrorData payload
=> ToFrontendErrorData payload
-> FrontendError
mkFrontendErrShow et = mkFrontendErr' (T.pack $ show et) et
mkFrontendErr' :: forall payload. IsFrontendErrorData payload mkFrontendErr' :: forall payload. IsFrontendErrorData payload
=> T.Text => T.Text
...@@ -218,24 +246,26 @@ mkFrontendErr' :: forall payload. IsFrontendErrorData payload ...@@ -218,24 +246,26 @@ mkFrontendErr' :: forall payload. IsFrontendErrorData payload
-> FrontendError -> FrontendError
mkFrontendErr' diag pl = FrontendError diag (fromSing $ sing @payload) pl mkFrontendErr' diag pl = FrontendError diag (fromSing $ sing @payload) pl
----------------------------------------------------------------------------
-- Arbitrary instances and test data generation
----------------------------------------------------------------------------
instance Arbitrary BackendErrorCode where instance Arbitrary BackendErrorCode where
arbitrary = arbitraryBoundedEnum arbitrary = arbitraryBoundedEnum
instance Arbitrary FrontendError where genFrontendErr :: BackendErrorCode -> Gen FrontendError
arbitrary = do genFrontendErr be = do
et <- arbitrary txt <- arbitrary
txt <- arbitrary case be of
genFrontendErr txt et EC_404__node_error_list_not_found
-> arbitrary >>= \lid -> pure $ mkFrontendErr' txt $ FE_node_error_list_not_found lid
genFrontendErr :: T.Text -> BackendErrorCode -> Gen FrontendError EC_404__node_error_root_not_found
genFrontendErr txt be = case be of -> pure $ mkFrontendErr' txt FE_node_error_root_not_found
EC_404__node_error_root_not_found EC_404__node_error_corpus_not_found
-> pure $ mkFrontendErr' txt FE_node_error_root_not_found -> pure $ mkFrontendErr' txt FE_node_error_corpus_not_found
EC_404__node_error_corpus_not_found EC_404__tree_error_root_not_found
-> pure $ mkFrontendErr' txt FE_node_error_corpus_not_found -> do rootId <- arbitrary
EC_404__tree_error_root_not_found pure $ mkFrontendErr' txt (RootNotFound rootId)
-> do rootId <- arbitrary
pure $ mkFrontendErr' txt (RootNotFound rootId)
instance ToJSON BackendErrorCode where instance ToJSON BackendErrorCode where
toJSON = JSON.String . T.pack . drop 3 . show toJSON = JSON.String . T.pack . drop 3 . show
...@@ -258,6 +288,9 @@ instance FromJSON FrontendError where ...@@ -258,6 +288,9 @@ instance FromJSON FrontendError where
(fe_diagnostic :: T.Text) <- o .: "diagnostic" (fe_diagnostic :: T.Text) <- o .: "diagnostic"
(fe_type :: BackendErrorCode) <- o .: "type" (fe_type :: BackendErrorCode) <- o .: "type"
case fe_type of case fe_type of
EC_404__node_error_list_not_found -> do
(fe_data :: ToFrontendErrorData 'EC_404__node_error_list_not_found) <- o .: "data"
pure FrontendError{..}
EC_404__node_error_root_not_found -> do EC_404__node_error_root_not_found -> do
(fe_data :: ToFrontendErrorData 'EC_404__node_error_root_not_found) <- o .: "data" (fe_data :: ToFrontendErrorData 'EC_404__node_error_root_not_found) <- o .: "data"
pure FrontendError{..} pure FrontendError{..}
......
...@@ -44,7 +44,7 @@ import Opaleye (DefaultFromField, defaultFromField, SqlInt4, SqlText, SqlTSVecto ...@@ -44,7 +44,7 @@ import Opaleye (DefaultFromField, defaultFromField, SqlInt4, SqlText, SqlTSVecto
import Opaleye qualified as O import Opaleye qualified as O
import Prelude qualified import Prelude qualified
import Servant hiding (Context) import Servant hiding (Context)
import Test.QuickCheck (elements) import Test.QuickCheck (elements, Positive (getPositive))
import Test.QuickCheck.Arbitrary import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Instances.Text () import Test.QuickCheck.Instances.Text ()
import Test.QuickCheck.Instances.Time () import Test.QuickCheck.Instances.Time ()
...@@ -304,8 +304,10 @@ instance FromHttpApiData NodeId where ...@@ -304,8 +304,10 @@ instance FromHttpApiData NodeId where
instance ToHttpApiData NodeId where instance ToHttpApiData NodeId where
toUrlPiece (UnsafeMkNodeId n) = toUrlPiece n toUrlPiece (UnsafeMkNodeId n) = toUrlPiece n
instance ToParamSchema NodeId instance ToParamSchema NodeId
-- | It makes sense to generate only positive ids.
instance Arbitrary NodeId where instance Arbitrary NodeId where
arbitrary = UnsafeMkNodeId <$> arbitrary arbitrary = UnsafeMkNodeId . getPositive <$> arbitrary
type ParentId = NodeId type ParentId = NodeId
type CorpusId = NodeId type CorpusId = NodeId
......
...@@ -38,13 +38,21 @@ jsonEnumRoundtrip d = case d of ...@@ -38,13 +38,21 @@ jsonEnumRoundtrip d = case d of
prop :: Dict EnumBoundedJSON a -> a -> Property prop :: Dict EnumBoundedJSON a -> a -> Property
prop Dict a = counterexample ("Parsed JSON: " <> C8.unpack (encode a)) $ eitherDecode (encode a) === Right a prop Dict a = counterexample ("Parsed JSON: " <> C8.unpack (encode a)) $ eitherDecode (encode a) === Right a
-- | Tests /all/ the 'BackendErrorCode' and their associated 'FrontendError' payloads.
jsonFrontendErrorRoundtrip :: Property
jsonFrontendErrorRoundtrip = conjoin $ map mk_prop [minBound .. maxBound]
where
mk_prop :: BackendErrorCode -> Property
mk_prop code = forAll (genFrontendErr code) $ \a ->
counterexample ("Parsed JSON: " <> C8.unpack (encode a)) $ eitherDecode (encode a) === Right a
tests :: TestTree tests :: TestTree
tests = testGroup "JSON" [ tests = testGroup "JSON" [
testProperty "NodeId roundtrips" (jsonRoundtrip @NodeId) testProperty "NodeId roundtrips" (jsonRoundtrip @NodeId)
, testProperty "RootId roundtrips" (jsonRoundtrip @RootId) , testProperty "RootId roundtrips" (jsonRoundtrip @RootId)
, testProperty "Datafield roundtrips" (jsonRoundtrip @Datafield) , testProperty "Datafield roundtrips" (jsonRoundtrip @Datafield)
, testProperty "WithQuery roundtrips" (jsonRoundtrip @WithQuery) , testProperty "WithQuery roundtrips" (jsonRoundtrip @WithQuery)
, testProperty "FrontendError roundtrips" (jsonRoundtrip @FrontendError) , testProperty "FrontendError roundtrips" jsonFrontendErrorRoundtrip
, testProperty "BackendErrorCode roundtrips" (jsonEnumRoundtrip (Dict @_ @BackendErrorCode)) , testProperty "BackendErrorCode roundtrips" (jsonEnumRoundtrip (Dict @_ @BackendErrorCode))
, testCase "WithQuery frontend compliance" testWithQueryFrontend , testCase "WithQuery frontend compliance" testWithQueryFrontend
, testGroup "Phylo" [ , testGroup "Phylo" [
......
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