2022-04-10 07:47:15 +03:00
|
|
|
module Test.SchemaSpec (spec) where
|
|
|
|
|
2022-08-29 03:20:00 +03:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
2022-10-10 09:58:12 +03:00
|
|
|
import Control.Lens ((%~), (.~), (?~))
|
2022-10-10 05:23:43 +03:00
|
|
|
import Control.Lens.At (at)
|
|
|
|
import Control.Lens.Lens ((&))
|
|
|
|
import Control.Monad (forM_)
|
2022-10-10 09:58:12 +03:00
|
|
|
import Data.Aeson (Value (..), toJSON)
|
2022-10-10 05:23:43 +03:00
|
|
|
import Data.Aeson.Lens (_Object)
|
|
|
|
import Data.Foldable (find)
|
2022-08-29 03:20:00 +03:00
|
|
|
import Data.HashMap.Strict qualified as HashMap
|
|
|
|
import Data.List (sort, sortOn)
|
2022-10-10 05:23:43 +03:00
|
|
|
import Data.List.NonEmpty qualified as NonEmpty
|
|
|
|
import Data.Text qualified as Text
|
2022-08-30 02:51:34 +03:00
|
|
|
import Hasura.Backends.DataConnector.API qualified as API
|
2022-04-10 07:47:15 +03:00
|
|
|
import Servant.API (NamedRoutes)
|
|
|
|
import Servant.Client (Client, (//))
|
2022-09-28 02:41:21 +03:00
|
|
|
import Test.Data (TestData (..))
|
2022-08-04 04:00:48 +03:00
|
|
|
import Test.Expectations (jsonShouldBe)
|
2022-10-10 05:23:43 +03:00
|
|
|
import Test.Hspec (Expectation, Spec, SpecWith, describe, it)
|
2022-04-10 07:47:15 +03:00
|
|
|
import Prelude
|
|
|
|
|
2022-08-29 03:20:00 +03:00
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
2022-10-10 05:23:43 +03:00
|
|
|
spec :: TestData -> Client IO (NamedRoutes API.Routes) -> API.SourceName -> API.Config -> API.Capabilities -> Spec
|
|
|
|
spec TestData {..} api sourceName config API.Capabilities {..} = describe "schema API" $ do
|
|
|
|
it "returns the Chinook tables" $ do
|
|
|
|
let extractTableNames = sort . fmap API._tiName
|
2022-10-11 03:25:07 +03:00
|
|
|
tableNames <- (extractTableNames . API._srTables) <$> (schemaGuard =<< (api // API._schema) sourceName config)
|
2022-07-19 03:37:04 +03:00
|
|
|
|
2022-10-10 05:23:43 +03:00
|
|
|
let expectedTableNames = extractTableNames _tdSchemaTables
|
|
|
|
tableNames `jsonShouldBe` expectedTableNames
|
|
|
|
|
|
|
|
testPerTable "returns the correct columns in the Chinook tables" $ \expectedTable@API.TableInfo {..} -> do
|
2022-10-11 03:25:07 +03:00
|
|
|
tables <- find (\t -> API._tiName t == _tiName) . API._srTables <$> (schemaGuard =<< (api // API._schema) sourceName config)
|
2022-10-10 05:23:43 +03:00
|
|
|
|
|
|
|
-- We remove some properties here so that we don't compare them since they vary between agent implementations
|
|
|
|
let extractJsonForComparison table =
|
|
|
|
let columns = fmap toJSON . sortOn API._ciName $ API._tiColumns table
|
|
|
|
in columns & traverse %~ \column ->
|
|
|
|
column
|
|
|
|
& _Object . at "type" .~ Nothing -- Types can vary between agents since underlying datatypes can change
|
|
|
|
& _Object . at "description" .~ Nothing -- Descriptions are not supported by all agents
|
2022-10-10 09:58:12 +03:00
|
|
|
-- If the agent only supports nullable columns, we make all columns nullable
|
|
|
|
let setExpectedColumnNullability columns =
|
|
|
|
if API._dscColumnNullability _cDataSchema == API.OnlyNullableColumns
|
|
|
|
then columns & traverse %~ (_Object . at "nullable" ?~ Bool True)
|
|
|
|
else columns
|
2022-10-10 05:23:43 +03:00
|
|
|
let actualJsonColumns = extractJsonForComparison <$> tables
|
2022-10-10 09:58:12 +03:00
|
|
|
let expectedJsonColumns = Just . setExpectedColumnNullability $ extractJsonForComparison expectedTable
|
2022-07-19 03:37:04 +03:00
|
|
|
|
2022-10-10 05:23:43 +03:00
|
|
|
actualJsonColumns `jsonShouldBe` expectedJsonColumns
|
2022-08-29 03:20:00 +03:00
|
|
|
|
2022-10-10 09:58:12 +03:00
|
|
|
if API._dscSupportsPrimaryKeys _cDataSchema
|
2022-10-10 05:23:43 +03:00
|
|
|
then testPerTable "returns the correct primary keys for the Chinook tables" $ \API.TableInfo {..} -> do
|
2022-10-11 03:25:07 +03:00
|
|
|
tables <- find (\t -> API._tiName t == _tiName) . API._srTables <$> (schemaGuard =<< (api // API._schema) sourceName config)
|
2022-10-10 05:23:43 +03:00
|
|
|
let actualPrimaryKey = API._tiPrimaryKey <$> tables
|
|
|
|
actualPrimaryKey `jsonShouldBe` Just _tiPrimaryKey
|
|
|
|
else testPerTable "returns no primary keys for the Chinook tables" $ \API.TableInfo {..} -> do
|
2022-10-11 03:25:07 +03:00
|
|
|
tables <- find (\t -> API._tiName t == _tiName) . API._srTables <$> (schemaGuard =<< (api // API._schema) sourceName config)
|
2022-10-10 05:23:43 +03:00
|
|
|
let actualPrimaryKey = API._tiPrimaryKey <$> tables
|
|
|
|
actualPrimaryKey `jsonShouldBe` Just []
|
2022-08-29 03:20:00 +03:00
|
|
|
|
2022-10-10 09:58:12 +03:00
|
|
|
if API._dscSupportsForeignKeys _cDataSchema
|
2022-10-10 05:23:43 +03:00
|
|
|
then testPerTable "returns the correct foreign keys for the Chinook tables" $ \expectedTable@API.TableInfo {..} -> do
|
2022-10-11 03:25:07 +03:00
|
|
|
tables <- find (\t -> API._tiName t == _tiName) . API._srTables <$> (schemaGuard =<< (api // API._schema) sourceName config)
|
2022-08-29 03:20:00 +03:00
|
|
|
|
2022-10-10 05:23:43 +03:00
|
|
|
-- We compare only the constraints and ignore the constraint names since some agents will have
|
|
|
|
-- different constraint names
|
|
|
|
let extractConstraintsForComparison table =
|
|
|
|
sort . HashMap.elems . API.unForeignKeys $ API._tiForeignKeys table
|
|
|
|
let actualConstraints = extractConstraintsForComparison <$> tables
|
|
|
|
let expectedConstraints = Just $ extractConstraintsForComparison expectedTable
|
|
|
|
|
|
|
|
actualConstraints `jsonShouldBe` expectedConstraints
|
|
|
|
else testPerTable "returns no foreign keys for the Chinook tables" $ \API.TableInfo {..} -> do
|
2022-10-11 03:25:07 +03:00
|
|
|
tables <- find (\t -> API._tiName t == _tiName) . API._srTables <$> (schemaGuard =<< (api // API._schema) sourceName config)
|
2022-10-10 05:23:43 +03:00
|
|
|
|
|
|
|
let actualJsonConstraints = API._tiForeignKeys <$> tables
|
|
|
|
actualJsonConstraints `jsonShouldBe` Just (API.ForeignKeys mempty)
|
|
|
|
where
|
|
|
|
testPerTable :: String -> (API.TableInfo -> Expectation) -> SpecWith ()
|
|
|
|
testPerTable description test =
|
|
|
|
describe description $ do
|
|
|
|
forM_ _tdSchemaTables $ \expectedTable@API.TableInfo {..} -> do
|
|
|
|
it (Text.unpack . NonEmpty.last $ API.unTableName _tiName) $
|
|
|
|
test expectedTable
|
2022-10-11 03:25:07 +03:00
|
|
|
|
|
|
|
schemaGuard = API.schemaCase defaultAction pure errorAction
|
|
|
|
defaultAction = fail "Error resolving source schema"
|
|
|
|
errorAction e = fail ("Error resolving source schema: " <> Text.unpack (API.errorResponseJsonText e))
|