Use Dataset Clones for all SQLite tests

[GDC-718]: https://hasurahq.atlassian.net/browse/GDC-718?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/7743
GitOrigin-RevId: 6c3577c1d4ffd2212a72b6e1a24e0e384f2db046
This commit is contained in:
Daniel Chambers 2023-02-02 15:26:29 +11:00 committed by hasura-bot
parent 1fe7fe43b8
commit b012f2ebc7
23 changed files with 344 additions and 252 deletions

View File

@ -25,12 +25,13 @@ services:
ports: ports:
- "65007:8100" - "65007:8100"
volumes: volumes:
- "./sqlite/test/db.chinook.sqlite:/db.chinook.sqlite" - "./sqlite/dataset_templates:/app/sqlite/dataset_templates"
- "./sqlite/test/db.sqlite:/db.sqlite"
environment: environment:
METRICS: y METRICS: y
PRETTY_PRINT_LOGS: y PRETTY_PRINT_LOGS: y
LOG_LEVEL: debug LOG_LEVEL: debug
DATASETS: y
DATASET_DELETE: y
healthcheck: healthcheck:
test: test:
- CMD - CMD

View File

@ -69,7 +69,7 @@ services:
depends_on: depends_on:
- reference-agent - reference-agent
image: "hasura/dc-agent-tests:${HASURA_VERSION}" image: "hasura/dc-agent-tests:${HASURA_VERSION}"
command: ["tests-dc-api", 'test', '-u', 'http://reference-agent:8100', '-s', '{}'] command: ["tests-dc-api", 'test', '--agent-base-url', 'http://reference-agent:8100']
restart: on-failure restart: on-failure
swagger-ui: swagger-ui:

View File

@ -1,4 +1,4 @@
node_modules node_modules
dist dist
./*.sqlite ./*.sqlite
./dataset_clones/ dataset_clones/

View File

@ -66,7 +66,7 @@ function mkTemplatePath(name: string): string {
if(name != safeName) { if(name != safeName) {
throw(Error(`Template name ${name} is not valid.`)); throw(Error(`Template name ${name} is not valid.`));
} }
return path.join(DATASET_TEMPLATES, safeName); return path.join(DATASET_TEMPLATES, safeName + ".sqlite");
} }
function mkClonePath(name: string): string { function mkClonePath(name: string): string {
@ -75,5 +75,5 @@ function mkClonePath(name: string): string {
if(name != safeName) { if(name != safeName) {
throw(Error(`Template name ${name} is not valid.`)); throw(Error(`Template name ${name} is not valid.`));
} }
return path.join(DATASET_CLONES, safeName); return path.join(DATASET_CLONES, safeName + ".sqlite");
} }

View File

@ -79,7 +79,7 @@ addSource =
name: myfoobar name: myfoobar
replace_configuration: false replace_configuration: false
configuration: configuration:
db: /db.chinook.sqlite value: {}
|] |]
listSourceKinds :: Value listSourceKinds :: Value

View File

@ -13,13 +13,11 @@ import Data.Aeson qualified as Aeson
import Data.Aeson.Lens (key, _Array) import Data.Aeson.Lens (key, _Array)
import Data.List.NonEmpty qualified as NE import Data.List.NonEmpty qualified as NE
import Data.Vector qualified as Vector import Data.Vector qualified as Vector
import Harness.Backend.DataConnector.Chinook qualified as Chinook
import Harness.Backend.DataConnector.Chinook.Reference qualified as Reference import Harness.Backend.DataConnector.Chinook.Reference qualified as Reference
import Harness.Backend.DataConnector.Chinook.Sqlite qualified as Sqlite import Harness.Backend.DataConnector.Chinook.Sqlite qualified as Sqlite
import Harness.GraphqlEngine qualified as GraphqlEngine import Harness.GraphqlEngine qualified as GraphqlEngine
import Harness.Quoter.Graphql (graphql) import Harness.Quoter.Graphql (graphql)
import Harness.Quoter.Yaml (yaml) import Harness.Quoter.Yaml (yaml)
import Harness.Test.BackendType (BackendTypeConfig)
import Harness.Test.Fixture qualified as Fixture import Harness.Test.Fixture qualified as Fixture
import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment) import Harness.TestEnvironment (GlobalTestEnvironment, TestEnvironment)
import Harness.TestEnvironment qualified as TE import Harness.TestEnvironment qualified as TE
@ -33,67 +31,14 @@ spec :: SpecWith GlobalTestEnvironment
spec = spec =
Fixture.runWithLocalTestEnvironment Fixture.runWithLocalTestEnvironment
( NE.fromList ( NE.fromList
[ (Fixture.fixture $ Fixture.Backend Reference.backendTypeMetadata) [ Reference.chinookFixture,
{ Fixture.setupTeardown = \(testEnvironment, _) -> Sqlite.chinookFixture
[ Chinook.setupAction (sourceMetadata Reference.backendTypeMetadata Reference.sourceConfiguration) Reference.agentConfig testEnvironment
]
},
(Fixture.fixture $ Fixture.Backend Sqlite.backendTypeMetadata)
{ Fixture.setupTeardown = \(testEnvironment, _) ->
[ Chinook.setupAction (sourceMetadata Sqlite.backendTypeMetadata Sqlite.sourceConfiguration) Sqlite.agentConfig testEnvironment
]
}
] ]
) )
tests tests
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
sourceMetadata :: BackendTypeConfig -> Aeson.Value -> Aeson.Value
sourceMetadata backendTypeMetadata config =
let source = Fixture.backendSourceName backendTypeMetadata
backendTypeString = Fixture.backendTypeString backendTypeMetadata
in [yaml|
name : *source
kind: *backendTypeString
tables:
- table: [Album]
object_relationships:
- name: Artist
using:
manual_configuration:
remote_table: [Artist]
column_mapping:
ArtistId: ArtistId
- table: [Artist]
array_relationships:
- name: Albums
using:
manual_configuration:
remote_table: [Album]
column_mapping:
ArtistId: ArtistId
- table: [Invoice]
array_relationships:
- name: InvoiceLines
using:
manual_configuration:
remote_table: [InvoiceLine]
column_mapping:
InvoiceId: InvoiceId
- table: [InvoiceLine]
object_relationships:
- name: Invoice
using:
manual_configuration:
remote_table: [Invoice]
column_mapping:
InvoiceId: InvoiceId
configuration: *config
|]
--------------------------------------------------------------------------------
tests :: Fixture.Options -> SpecWith (TestEnvironment, a) tests :: Fixture.Options -> SpecWith (TestEnvironment, a)
tests opts = describe "Aggregate Query Tests" $ do tests opts = describe "Aggregate Query Tests" $ do
nodeTests opts nodeTests opts

View File

@ -22,7 +22,7 @@ import Data.Aeson.KeyMap qualified as KM
import Data.Aeson.Lens import Data.Aeson.Lens
import Data.List.NonEmpty qualified as NE import Data.List.NonEmpty qualified as NE
import Data.Vector qualified as Vector import Data.Vector qualified as Vector
import Harness.Backend.DataConnector.Chinook (ChinookTestEnv) import Harness.Backend.DataConnector.Chinook (ChinookTestEnv, NameFormatting (..))
import Harness.Backend.DataConnector.Chinook qualified as Chinook import Harness.Backend.DataConnector.Chinook qualified as Chinook
import Harness.Backend.DataConnector.Chinook.Reference qualified as Reference import Harness.Backend.DataConnector.Chinook.Reference qualified as Reference
import Harness.Backend.DataConnector.Chinook.Sqlite qualified as Sqlite import Harness.Backend.DataConnector.Chinook.Sqlite qualified as Sqlite
@ -47,15 +47,15 @@ spec = do
Fixture.runWithLocalTestEnvironmentSingleSetup Fixture.runWithLocalTestEnvironmentSingleSetup
( NE.fromList ( NE.fromList
[ Fixture [ Fixture
{ name = Fixture.Backend Reference.backendTypeMetadata, { name = Fixture.Backend Reference.backendTypeConfig,
mkLocalTestEnvironment = \_ -> pure $ Chinook.ChinookTestEnv Reference.sourceConfiguration id id id, mkLocalTestEnvironment = Reference.mkChinookStaticTestEnvironment,
setupTeardown = \(testEnv, _localEnv) -> setupTeardown = \(testEnv, _localEnv) ->
[emptySetupAction testEnv], [emptySetupAction testEnv],
customOptions = Nothing customOptions = Nothing
}, },
Fixture Fixture
{ name = Fixture.Backend Sqlite.backendTypeMetadata, { name = Fixture.Backend Sqlite.backendTypeConfig,
mkLocalTestEnvironment = \_ -> pure $ Chinook.ChinookTestEnv Sqlite.sourceConfiguration id id Sqlite.formatForeignKeyName, mkLocalTestEnvironment = Sqlite.mkChinookCloneTestEnvironment,
setupTeardown = \(testEnv, _localEnv) -> setupTeardown = \(testEnv, _localEnv) ->
[emptySetupAction testEnv], [emptySetupAction testEnv],
customOptions = Nothing customOptions = Nothing
@ -66,20 +66,8 @@ spec = do
Fixture.runWithLocalTestEnvironmentSingleSetup Fixture.runWithLocalTestEnvironmentSingleSetup
( NE.fromList ( NE.fromList
[ Fixture [ Reference.chinookFixture,
{ name = Fixture.Backend Reference.backendTypeMetadata, Sqlite.chinookFixture
mkLocalTestEnvironment = \_ -> pure $ Chinook.ChinookTestEnv Reference.sourceConfiguration id id id,
setupTeardown = \(testEnv, _localEnv) ->
[Chinook.setupAction Chinook.referenceSourceConfig Reference.agentConfig testEnv],
customOptions = Nothing
},
Fixture
{ name = Fixture.Backend Sqlite.backendTypeMetadata,
mkLocalTestEnvironment = \_ -> pure $ Chinook.ChinookTestEnv Sqlite.sourceConfiguration id id Sqlite.formatForeignKeyName,
setupTeardown = \(testEnv, _localEnv) ->
[Chinook.setupAction Chinook.sqliteSourceConfig Sqlite.agentConfig testEnv],
customOptions = Nothing
}
] ]
) )
schemaInspectionTests schemaInspectionTests
@ -89,7 +77,7 @@ spec = do
schemaInspectionTests :: Fixture.Options -> SpecWith (TestEnvironment, ChinookTestEnv) schemaInspectionTests :: Fixture.Options -> SpecWith (TestEnvironment, ChinookTestEnv)
schemaInspectionTests opts = describe "Schema and Source Inspection" $ do schemaInspectionTests opts = describe "Schema and Source Inspection" $ do
describe "get_source_tables" $ do describe "get_source_tables" $ do
it "success" $ \(testEnvironment, Chinook.ChinookTestEnv {..}) -> do it "success" $ \(testEnvironment, Chinook.ChinookTestEnv {nameFormatting = NameFormatting {..}}) -> do
let sortYamlArray :: J.Value -> IO J.Value let sortYamlArray :: J.Value -> IO J.Value
sortYamlArray (J.Array a) = pure $ J.Array (Vector.fromList (sort (Vector.toList a))) sortYamlArray (J.Array a) = pure $ J.Array (Vector.fromList (sort (Vector.toList a)))
sortYamlArray _ = fail "Should return Array" sortYamlArray _ = fail "Should return Array"
@ -97,17 +85,17 @@ schemaInspectionTests opts = describe "Schema and Source Inspection" $ do
case BackendType.backendSourceName <$> getBackendTypeConfig testEnvironment of case BackendType.backendSourceName <$> getBackendTypeConfig testEnvironment of
Nothing -> pendingWith "Backend not found for testEnvironment" Nothing -> pendingWith "Backend not found for testEnvironment"
Just sourceString -> do Just sourceString -> do
let album = formatTableName ["Album"] let album = _nfFormatTableName ["Album"]
artist = formatTableName ["Artist"] artist = _nfFormatTableName ["Artist"]
customer = formatTableName ["Customer"] customer = _nfFormatTableName ["Customer"]
employee = formatTableName ["Employee"] employee = _nfFormatTableName ["Employee"]
genre = formatTableName ["Genre"] genre = _nfFormatTableName ["Genre"]
invoice = formatTableName ["Invoice"] invoice = _nfFormatTableName ["Invoice"]
invoiceLine = formatTableName ["InvoiceLine"] invoiceLine = _nfFormatTableName ["InvoiceLine"]
mediaType = formatTableName ["MediaType"] mediaType = _nfFormatTableName ["MediaType"]
playlist = formatTableName ["Playlist"] playlist = _nfFormatTableName ["Playlist"]
playlistTrack = formatTableName ["PlaylistTrack"] playlistTrack = _nfFormatTableName ["PlaylistTrack"]
track = formatTableName ["Track"] track = _nfFormatTableName ["Track"]
shouldReturnYamlF shouldReturnYamlF
sortYamlArray sortYamlArray
opts opts
@ -134,7 +122,7 @@ schemaInspectionTests opts = describe "Schema and Source Inspection" $ do
|] |]
describe "get_table_info" $ do describe "get_table_info" $ do
it "success" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {..}) -> do it "success" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {nameFormatting = NameFormatting {..}}) -> do
let removeDescriptions (J.Object o) = J.Object (KM.delete "description" (removeDescriptions <$> o)) let removeDescriptions (J.Object o) = J.Object (KM.delete "description" (removeDescriptions <$> o))
removeDescriptions (J.Array a) = J.Array (removeDescriptions <$> a) removeDescriptions (J.Array a) = J.Array (removeDescriptions <$> a)
removeDescriptions x = x removeDescriptions x = x
@ -153,12 +141,12 @@ schemaInspectionTests opts = describe "Schema and Source Inspection" $ do
case BackendType.backendSourceName <$> getBackendTypeConfig testEnvironment of case BackendType.backendSourceName <$> getBackendTypeConfig testEnvironment of
Nothing -> pendingWith "Backend not found for testEnvironment" Nothing -> pendingWith "Backend not found for testEnvironment"
Just sourceString -> do Just sourceString -> do
let album = formatTableName ["Album"] let album = _nfFormatTableName ["Album"]
artist = formatTableName ["Artist"] artist = _nfFormatTableName ["Artist"]
albumId = formatColumnName "AlbumId" albumId = _nfFormatColumnName "AlbumId"
artistId = formatColumnName "ArtistId" artistId = _nfFormatColumnName "ArtistId"
title = formatColumnName "Title" title = _nfFormatColumnName "Title"
artistForeignKeys = formatForeignKeyName "Artist" artistForeignKeys = _nfFormatForeignKeyName "Artist"
shouldReturnYamlF shouldReturnYamlF
(pure . removeDescriptions) (pure . removeDescriptions)
opts opts
@ -341,12 +329,12 @@ schemaCrudTests opts = describe "A series of actions to setup and teardown a sou
|] |]
describe "<kind>_track_table" $ do describe "<kind>_track_table" $ do
it "success" $ \(testEnvironment, Chinook.ChinookTestEnv {..}) -> do it "success" $ \(testEnvironment, Chinook.ChinookTestEnv {nameFormatting = NameFormatting {..}}) -> do
case (backendTypeString &&& backendSourceName) <$> TestEnvironment.getBackendTypeConfig testEnvironment of case (backendTypeString &&& backendSourceName) <$> TestEnvironment.getBackendTypeConfig testEnvironment of
Nothing -> pendingWith "Backend Type not found in testEnvironment" Nothing -> pendingWith "Backend Type not found in testEnvironment"
Just (backendType, sourceName) -> do Just (backendType, sourceName) -> do
let actionType = backendType <> "_track_table" let actionType = backendType <> "_track_table"
album = formatTableName ["Album"] album = _nfFormatTableName ["Album"]
shouldReturnYaml shouldReturnYaml
opts opts
( GraphqlEngine.postMetadata ( GraphqlEngine.postMetadata
@ -363,15 +351,15 @@ schemaCrudTests opts = describe "A series of actions to setup and teardown a sou
|] |]
describe "<kind>_create_object_relationship" $ do describe "<kind>_create_object_relationship" $ do
it "success" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {..}) -> do it "success" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {nameFormatting = NameFormatting {..}}) -> do
let foreignKeySupport = (getBackendTypeConfig testEnvironment >>= BackendType.parseCapabilities) <&> API._dscSupportsForeignKeys . API._cDataSchema let foreignKeySupport = (getBackendTypeConfig testEnvironment >>= BackendType.parseCapabilities) <&> API._dscSupportsForeignKeys . API._cDataSchema
case (backendTypeString &&& backendSourceName) <$> getBackendTypeConfig testEnvironment of case (backendTypeString &&& backendSourceName) <$> getBackendTypeConfig testEnvironment of
Nothing -> pendingWith "Backend Type not found in testEnvironment" Nothing -> pendingWith "Backend Type not found in testEnvironment"
Just (backendType, sourceName) -> do Just (backendType, sourceName) -> do
let actionType = backendType <> "_track_table" let actionType = backendType <> "_track_table"
artistTable = formatTableName ["Artist"] artistTable = _nfFormatTableName ["Artist"]
albumTable = formatTableName ["Album"] albumTable = _nfFormatTableName ["Album"]
artistId = formatColumnName "ArtistId" artistId = _nfFormatColumnName "ArtistId"
GraphqlEngine.postMetadata_ GraphqlEngine.postMetadata_
testEnvironment testEnvironment
[yaml| [yaml|
@ -406,7 +394,7 @@ schemaCrudTests opts = describe "A series of actions to setup and teardown a sou
|] |]
describe "<kind>_create_array_relationship" $ do describe "<kind>_create_array_relationship" $ do
it "success" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {..}) -> do it "success" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {nameFormatting = NameFormatting {..}}) -> do
let foreignKeySupport = (getBackendTypeConfig testEnvironment >>= BackendType.parseCapabilities) <&> API._dscSupportsForeignKeys . API._cDataSchema let foreignKeySupport = (getBackendTypeConfig testEnvironment >>= BackendType.parseCapabilities) <&> API._dscSupportsForeignKeys . API._cDataSchema
when when
(foreignKeySupport == Just False) (foreignKeySupport == Just False)
@ -415,9 +403,9 @@ schemaCrudTests opts = describe "A series of actions to setup and teardown a sou
Nothing -> pendingWith "Backend Type not found in testEnvironment" Nothing -> pendingWith "Backend Type not found in testEnvironment"
Just (backendType, sourceName) -> do Just (backendType, sourceName) -> do
let actionType = backendType <> "_create_array_relationship" let actionType = backendType <> "_create_array_relationship"
albumTable = formatTableName ["Album"] albumTable = _nfFormatTableName ["Album"]
artistTable = formatTableName ["Artist"] artistTable = _nfFormatTableName ["Artist"]
artistId = formatColumnName "ArtistId" artistId = _nfFormatColumnName "ArtistId"
shouldReturnYaml shouldReturnYaml
opts opts
( GraphqlEngine.postMetadata ( GraphqlEngine.postMetadata
@ -440,14 +428,14 @@ schemaCrudTests opts = describe "A series of actions to setup and teardown a sou
|] |]
describe "export_metadata" $ do describe "export_metadata" $ do
it "produces the expected metadata structure" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {..}) -> do it "produces the expected metadata structure" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {nameFormatting = NameFormatting {..}, ..}) -> do
case ((fold . backendServerUrl) &&& backendTypeString &&& backendSourceName) <$> TestEnvironment.getBackendTypeConfig testEnvironment of case ((fold . backendServerUrl) &&& backendTypeString &&& backendSourceName) <$> TestEnvironment.getBackendTypeConfig testEnvironment of
Nothing -> pendingWith "Backend Type not found in testEnvironment" Nothing -> pendingWith "Backend Type not found in testEnvironment"
Just (agentUrl, (backendType, sourceName)) -> do Just (agentUrl, (backendType, sourceName)) -> do
let foreignKeySupport = (getBackendTypeConfig testEnvironment >>= BackendType.parseCapabilities) <&> API._dscSupportsForeignKeys . API._cDataSchema let foreignKeySupport = (getBackendTypeConfig testEnvironment >>= BackendType.parseCapabilities) <&> API._dscSupportsForeignKeys . API._cDataSchema
albumTable = formatTableName ["Album"] albumTable = _nfFormatTableName ["Album"]
artistTable = formatTableName ["Artist"] artistTable = _nfFormatTableName ["Artist"]
artistId = formatColumnName "ArtistId" artistId = _nfFormatColumnName "ArtistId"
shouldReturnYaml shouldReturnYaml
opts opts
( GraphqlEngine.postMetadata ( GraphqlEngine.postMetadata
@ -500,7 +488,7 @@ schemaCrudTests opts = describe "A series of actions to setup and teardown a sou
|] |]
describe "<kind>_drop_relationship" $ do describe "<kind>_drop_relationship" $ do
it "success" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {..}) -> do it "success" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {nameFormatting = NameFormatting {..}}) -> do
let foreignKeySupport = (getBackendTypeConfig testEnvironment >>= BackendType.parseCapabilities) <&> API._dscSupportsForeignKeys . API._cDataSchema let foreignKeySupport = (getBackendTypeConfig testEnvironment >>= BackendType.parseCapabilities) <&> API._dscSupportsForeignKeys . API._cDataSchema
when when
(foreignKeySupport == Just False) (foreignKeySupport == Just False)
@ -509,7 +497,7 @@ schemaCrudTests opts = describe "A series of actions to setup and teardown a sou
Nothing -> pendingWith "Backend Type not found in testEnvironment" Nothing -> pendingWith "Backend Type not found in testEnvironment"
Just (backendType, sourceName) -> do Just (backendType, sourceName) -> do
let actionType = backendType <> "_drop_relationship" let actionType = backendType <> "_drop_relationship"
artistTable = formatTableName ["Artist"] artistTable = _nfFormatTableName ["Artist"]
shouldReturnYaml shouldReturnYaml
opts opts
( GraphqlEngine.postMetadata ( GraphqlEngine.postMetadata
@ -527,7 +515,7 @@ schemaCrudTests opts = describe "A series of actions to setup and teardown a sou
|] |]
describe "<kind>_untrack_table" $ do describe "<kind>_untrack_table" $ do
it "success" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {..}) -> do it "success" $ \(testEnvironment@TestEnvironment {}, Chinook.ChinookTestEnv {nameFormatting = NameFormatting {..}}) -> do
let foreignKeySupport = (getBackendTypeConfig testEnvironment >>= BackendType.parseCapabilities) <&> API._dscSupportsForeignKeys . API._cDataSchema let foreignKeySupport = (getBackendTypeConfig testEnvironment >>= BackendType.parseCapabilities) <&> API._dscSupportsForeignKeys . API._cDataSchema
when when
(foreignKeySupport == Just False) (foreignKeySupport == Just False)
@ -536,7 +524,7 @@ schemaCrudTests opts = describe "A series of actions to setup and teardown a sou
Nothing -> pendingWith "Backend Type not found in testEnvironment" Nothing -> pendingWith "Backend Type not found in testEnvironment"
Just (backendType, sourceName) -> do Just (backendType, sourceName) -> do
let actionType = backendType <> "_untrack_table" let actionType = backendType <> "_untrack_table"
artistTable = formatTableName ["Artist"] artistTable = _nfFormatTableName ["Artist"]
shouldReturnYaml shouldReturnYaml
opts opts
( GraphqlEngine.postMetadata ( GraphqlEngine.postMetadata

View File

@ -25,7 +25,6 @@ where
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Data.List.NonEmpty qualified as NE import Data.List.NonEmpty qualified as NE
import Harness.Backend.DataConnector.Chinook qualified as Chinook
import Harness.Backend.DataConnector.Chinook.Reference qualified as Reference import Harness.Backend.DataConnector.Chinook.Reference qualified as Reference
import Harness.Backend.DataConnector.Chinook.Sqlite qualified as Sqlite import Harness.Backend.DataConnector.Chinook.Sqlite qualified as Sqlite
import Harness.GraphqlEngine qualified as GraphqlEngine import Harness.GraphqlEngine qualified as GraphqlEngine
@ -46,14 +45,8 @@ spec :: SpecWith GlobalTestEnvironment
spec = spec =
Fixture.runWithLocalTestEnvironment Fixture.runWithLocalTestEnvironment
( NE.fromList ( NE.fromList
[ (Fixture.fixture $ Fixture.Backend Reference.backendTypeMetadata) [ Reference.chinookFixture,
{ Fixture.setupTeardown = \(testEnv, _) -> Sqlite.chinookFixture
[Chinook.setupAction Chinook.referenceSourceConfig Reference.agentConfig testEnv]
},
(Fixture.fixture $ Fixture.Backend Sqlite.backendTypeMetadata)
{ Fixture.setupTeardown = \(testEnv, _) ->
[Chinook.setupAction Chinook.sqliteSourceConfig Sqlite.agentConfig testEnv]
}
] ]
) )
tests tests
@ -169,7 +162,7 @@ paginationTests :: Fixture.Options -> SpecWith (TestEnvironment, a)
paginationTests opts = paginationTests opts =
describe "Pagination" $ do describe "Pagination" $ do
it "works with pagination" $ \(testEnvironment, _) -> do it "works with pagination" $ \(testEnvironment, _) -> do
-- NOTE: We order by in this pagination test to ensure that the rows are ordered correctly (which they are not in db.chinook.sqlite) -- NOTE: We order by in this pagination test to ensure that the rows are ordered correctly (which they are not in Sqlite Chinook)
shouldReturnYaml shouldReturnYaml
opts opts
( GraphqlEngine.postGraphql ( GraphqlEngine.postGraphql

View File

@ -24,14 +24,8 @@ spec :: SpecWith GlobalTestEnvironment
spec = spec =
Fixture.runWithLocalTestEnvironment Fixture.runWithLocalTestEnvironment
( NE.fromList ( NE.fromList
[ (Fixture.fixture $ Fixture.Backend Reference.backendTypeMetadata) [ Reference.chinookFixture,
{ Fixture.setupTeardown = \(testEnv, _) -> Sqlite.chinookFixture
[Chinook.setupAction Chinook.referenceSourceConfig Reference.agentConfig testEnv]
},
(Fixture.fixture $ Fixture.Backend Sqlite.backendTypeMetadata)
{ Fixture.setupTeardown = \(testEnv, _) ->
[Chinook.setupAction Chinook.sqliteSourceConfig Sqlite.agentConfig testEnv]
}
] ]
) )
tests tests

View File

@ -10,6 +10,7 @@ module Command
SandwichArguments (..), SandwichArguments (..),
TestConfig (..), TestConfig (..),
AgentOptions (..), AgentOptions (..),
AgentConfig (..),
NameCasing (..), NameCasing (..),
ExportDataConfig (..), ExportDataConfig (..),
ExportFormat (..), ExportFormat (..),
@ -55,9 +56,13 @@ data SensitiveOutputHandling
data AgentOptions = AgentOptions data AgentOptions = AgentOptions
{ _aoAgentBaseUrl :: BaseUrl, { _aoAgentBaseUrl :: BaseUrl,
_aoAgentConfig :: Maybe API.Config _aoAgentConfig :: AgentConfig
} }
data AgentConfig
= ManualConfig API.Config
| DatasetConfig (Maybe API.Config)
data NameCasing data NameCasing
= PascalCase = PascalCase
| Lowercase | Lowercase
@ -181,15 +186,23 @@ agentOptionsParser =
<> metavar "URL" <> metavar "URL"
<> help "The base URL of the Data Connector agent to be tested" <> help "The base URL of the Data Connector agent to be tested"
) )
<*> optional <*> ( ManualConfig
( option <$> option
configValue configValue
( long "agent-config" ( long "agent-config"
<> short 's' <> metavar "JSON"
<> metavar "JSON" <> help "The configuration JSON to be sent to the agent via the X-Hasura-DataConnector-Config header. If omitted, datasets will be used to load test data and provide this configuration dynamically"
<> help "The configuration JSON to be sent to the agent via the X-Hasura-DataConnector-Config header. If omitted, datasets will be used to load test data and provide this configuration dynamically" )
) <|> DatasetConfig
) <$> optional
( option
configValue
( long "merge-agent-config"
<> metavar "JSON"
<> help "Datasets will be used to load test data and provide configuration JSON to be sent to the agent via the X-Hasura-DataConnector-Config header. This config will be merged with the dataset-provided config before being sent to the agent."
)
)
)
exportDataConfigParser :: Parser ExportDataConfig exportDataConfigParser :: Parser ExportDataConfig
exportDataConfigParser = exportDataConfigParser =

View File

@ -2,7 +2,7 @@ module Main (main) where
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Command (AgentOptions (..), Command (..), SandwichArguments (..), TestOptions (..), parseCommandLine) import Command (AgentConfig (..), AgentOptions (..), Command (..), SandwichArguments (..), TestOptions (..), parseCommandLine)
import Control.Exception (bracket) import Control.Exception (bracket)
import Data.Aeson.Text (encodeToLazyText) import Data.Aeson.Text (encodeToLazyText)
import Data.Foldable (for_) import Data.Foldable (for_)
@ -12,7 +12,7 @@ import Hasura.Backends.DataConnector.API (openApiSchema)
import Hasura.Backends.DataConnector.API qualified as API import Hasura.Backends.DataConnector.API qualified as API
import Servant.Client ((//)) import Servant.Client ((//))
import System.Environment (withArgs) import System.Environment (withArgs)
import Test.AgentAPI (guardCapabilitiesResponse, guardSchemaResponse) import Test.AgentAPI (guardCapabilitiesResponse, guardSchemaResponse, mergeAgentConfig)
import Test.AgentClient (AgentIOClient (..), introduceAgentClient, mkAgentClientConfig, mkAgentIOClient) import Test.AgentClient (AgentIOClient (..), introduceAgentClient, mkAgentClientConfig, mkAgentIOClient)
import Test.AgentDatasets (DatasetCloneInfo (..), chinookTemplate, createClone, deleteClone, usesDataset) import Test.AgentDatasets (DatasetCloneInfo (..), chinookTemplate, createClone, deleteClone, usesDataset)
import Test.AgentTestContext (AgentTestContext (..), introduceAgentTestContext) import Test.AgentTestContext (AgentTestContext (..), introduceAgentTestContext)
@ -46,18 +46,18 @@ tests testData capabilitiesResponse@API.CapabilitiesResponse {..} = do
for_ (API._cMetrics _crCapabilities) \m -> Test.Specs.MetricsSpec.spec m for_ (API._cMetrics _crCapabilities) \m -> Test.Specs.MetricsSpec.spec m
for_ (API._cExplain _crCapabilities) \_ -> Test.Specs.ExplainSpec.spec testData _crCapabilities for_ (API._cExplain _crCapabilities) \_ -> Test.Specs.ExplainSpec.spec testData _crCapabilities
getChinookSchema :: API.Capabilities -> Maybe API.Config -> AgentIOClient -> IO API.SchemaResponse getChinookSchema :: API.Capabilities -> AgentConfig -> AgentIOClient -> IO API.SchemaResponse
getChinookSchema API.Capabilities {..} manuallyProvidedConfig (AgentIOClient agentClient) = do getChinookSchema API.Capabilities {..} manuallyProvidedConfig (AgentIOClient agentClient) = do
case manuallyProvidedConfig of case manuallyProvidedConfig of
Just config -> (agentClient // API._schema) testSourceName config >>= guardSchemaResponse ManualConfig config -> (agentClient // API._schema) testSourceName config >>= guardSchemaResponse
Nothing -> DatasetConfig mergeConfig ->
if isJust _cDatasets if isJust _cDatasets
then then
bracket bracket
(createClone agentClient chinookTemplate) (createClone agentClient chinookTemplate)
(deleteClone agentClient) (deleteClone agentClient)
( \DatasetCloneInfo {..} -> ( \DatasetCloneInfo {..} ->
(agentClient // API._schema) testSourceName _dciAgentConfig >>= guardSchemaResponse (agentClient // API._schema) testSourceName (mergeAgentConfig _dciAgentConfig mergeConfig) >>= guardSchemaResponse
) )
else fail $ "The agent does not support datasets, therefore an agent configuration must be provided on the command line (--agent-config)" else fail $ "The agent does not support datasets, therefore an agent configuration must be provided on the command line (--agent-config)"

View File

@ -9,20 +9,22 @@ The executable also has the ability to export the OpenAPI spec of the Data Conne
### Running Tests ### Running Tests
First, start your Data Connector agent and ensure it is populated with the [Chinook data set](https://github.com/lerocha/chinook-database/). For example, you could start the Reference Agent by following the instructions in [its README](../../dc-agents/reference/README.md). First, start your Data Connector agent and ensure it is populated with the [Chinook data set](https://github.com/lerocha/chinook-database/). For example, you could start the Reference Agent by following the instructions in [its README](../../dc-agents/reference/README.md).
To run the tests against the agent (for example), you must specify the agent's URL on the command line (`-u`), as well as the agent's configuration JSON (`-s`, sent in the `X-Hasura-DataConnector-Config` header): To run the tests against the agent (for example), you must specify the agent's URL on the command line (`--agent-base-url`), as well as the agent's configuration JSON (`--agent-config`, sent in the `X-Hasura-DataConnector-Config` header):
``` ```
cabal run test:tests-dc-api -- test -u "http://localhost:8100" -s '{}' cabal run test:tests-dc-api -- test --agent-base-url "http://localhost:8100" --agent-config '{}'
``` ```
The test suite will discover what capabilities the agent has by querying it. It will then tailor the tests that it will run to match only those capabilities that the agent has said it supports. The test suite will discover what capabilities the agent has by querying it. It will then tailor the tests that it will run to match only those capabilities that the agent has said it supports.
If your agent supports the datasets capability, you can omit the `--agent-config` argument and the test suite will clone the Chinook dataset template on the agent to run its test against. If you need to specify some additional configuration to be added to the cloned dataset's configuration, you can specify it using `--merge-agent-config`.
The test suite is implemented using the [Sandwich](https://codedownio.github.io/sandwich/) test framework. The standard Sandwich command line arguments can be passed by suffixing your command line with `sandwich` and then all following args will be passed to Sandwich. The test suite is implemented using the [Sandwich](https://codedownio.github.io/sandwich/) test framework. The standard Sandwich command line arguments can be passed by suffixing your command line with `sandwich` and then all following args will be passed to Sandwich.
For example, to run the Terminal UI mode of Sandwich, you could run: For example, to run the Terminal UI mode of Sandwich, you could run:
``` ```
cabal run test:tests-dc-api -- test -u "http://localhost:8100" -s '{}' sandwich --tui cabal run test:tests-dc-api -- test --agent-base-url "http://localhost:8100" --agent-config '{}' sandwich --tui
``` ```
By default Sandwich will write test results into a `test_runs` folder. Every test has a folder that will contain debug information, for example: By default Sandwich will write test results into a `test_runs` folder. Every test has a folder that will contain debug information, for example:

View File

@ -21,12 +21,15 @@ module Test.AgentAPI
explain, explain,
getMetrics, getMetrics,
getSourceNameAndConfig, getSourceNameAndConfig,
mergeAgentConfig,
) )
where where
import Command (AgentConfig (..))
import Control.Monad.Catch (MonadThrow) import Control.Monad.Catch (MonadThrow)
import Control.Monad.IO.Class (MonadIO) import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Reader (MonadReader) import Control.Monad.Reader (MonadReader)
import Data.Aeson.KeyMap qualified as KeyMap
import Data.Maybe (isJust) import Data.Maybe (isJust)
import Data.Text (Text) import Data.Text (Text)
import Hasura.Backends.DataConnector.API qualified as API import Hasura.Backends.DataConnector.API qualified as API
@ -108,13 +111,20 @@ supportsDatasets = isJust . API._cDatasets . API._crCapabilities
getSourceNameAndConfig :: (HasAgentTestContext context, HasDatasetContext context, MonadReader context m, MonadThrow m) => m (API.SourceName, API.Config) getSourceNameAndConfig :: (HasAgentTestContext context, HasDatasetContext context, MonadReader context m, MonadThrow m) => m (API.SourceName, API.Config)
getSourceNameAndConfig = do getSourceNameAndConfig = do
AgentTestContext {..} <- getAgentTestContext AgentTestContext {..} <- getAgentTestContext
case _atcManualConfig of case _atcAgentConfig of
Just config -> pure (_atcSourceName, config) ManualConfig config -> pure (_atcSourceName, config)
Nothing -> DatasetConfig mergeConfig ->
if supportsDatasets _atcCapabilitiesResponse if supportsDatasets _atcCapabilitiesResponse
then do then do
cloneInfo <- _dcClone <$> getDatasetContext cloneInfo <- _dcClone <$> getDatasetContext
case cloneInfo of case cloneInfo of
Just DatasetCloneInfo {..} -> pure (_atcSourceName, _dciAgentConfig) Just DatasetCloneInfo {..} ->
let mergedConfig = mergeAgentConfig _dciAgentConfig mergeConfig
in pure (_atcSourceName, mergedConfig)
Nothing -> expectationFailure "Expected a dataset clone to have been created, because the agent supports datasets, but one wasn't" Nothing -> expectationFailure "Expected a dataset clone to have been created, because the agent supports datasets, but one wasn't"
else expectationFailure "An agent configuration is required to be provided if the agent does not support datasets" else expectationFailure "An agent configuration is required to be provided if the agent does not support datasets"
mergeAgentConfig :: API.Config -> Maybe API.Config -> API.Config
mergeAgentConfig (API.Config configA) mergeConfig =
let configB = maybe mempty API.unConfig mergeConfig
in API.Config $ KeyMap.union configA configB

View File

@ -8,6 +8,7 @@ module Test.AgentTestContext
) )
where where
import Command (AgentConfig)
import Control.Monad.Reader.Class (MonadReader) import Control.Monad.Reader.Class (MonadReader)
import GHC.Stack (HasCallStack) import GHC.Stack (HasCallStack)
import Hasura.Backends.DataConnector.API qualified as API import Hasura.Backends.DataConnector.API qualified as API
@ -20,7 +21,7 @@ data AgentTestContext = AgentTestContext
_atcCapabilitiesResponse :: API.CapabilitiesResponse, _atcCapabilitiesResponse :: API.CapabilitiesResponse,
-- | This is the configuration passed by the user on the command line which will -- | This is the configuration passed by the user on the command line which will
-- be used in preference to any dataset clone's config if it is specified -- be used in preference to any dataset clone's config if it is specified
_atcManualConfig :: Maybe API.Config _atcAgentConfig :: AgentConfig
} }
introduceAgentTestContext :: forall context m. (Monad m) => AgentTestContext -> SpecFree (LabelValue "agent-test-context" AgentTestContext :> context) m () -> SpecFree context m () introduceAgentTestContext :: forall context m. (Monad m) => AgentTestContext -> SpecFree (LabelValue "agent-test-context" AgentTestContext :> context) m () -> SpecFree context m ()

View File

@ -3,24 +3,27 @@
-- | Chinook Based Agent Fixtures used in DataConnector specific -- | Chinook Based Agent Fixtures used in DataConnector specific
-- Specs. -- Specs.
module Harness.Backend.DataConnector.Chinook module Harness.Backend.DataConnector.Chinook
( setupAction, ( ChinookTestEnv (..),
referenceSourceConfig, NameFormatting (..),
sqliteSourceConfig, mkChinookCloneTestEnvironment,
mkChinookStaticTestEnvironment,
setupChinookSourceAction,
setupCustomSourceAction,
testRoleName, testRoleName,
ChinookTestEnv (..),
) )
where where
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Control.Monad.Managed (Managed)
import Data.Aeson qualified as Aeson import Data.Aeson qualified as Aeson
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Harness.Backend.DataConnector.Chinook.Reference qualified as Reference import Harness.DataConnectorAgent (createManagedClone)
import Harness.Backend.DataConnector.Chinook.Sqlite qualified as Sqlite
import Harness.GraphqlEngine qualified as GraphqlEngine import Harness.GraphqlEngine qualified as GraphqlEngine
import Harness.Quoter.Yaml (yaml) import Harness.Quoter.Yaml (yaml)
import Harness.Test.Fixture qualified as Fixture import Harness.Test.Fixture qualified as Fixture
import Harness.TestEnvironment (TestEnvironment) import Harness.TestEnvironment (TestEnvironment, getBackendTypeConfig)
import Hasura.Backends.DataConnector.API qualified as API
import Hasura.Prelude import Hasura.Prelude
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -28,26 +31,78 @@ import Hasura.Prelude
data ChinookTestEnv = ChinookTestEnv data ChinookTestEnv = ChinookTestEnv
{ -- | Default configuration JSON for the backend source. { -- | Default configuration JSON for the backend source.
backendSourceConfig :: Aeson.Value, backendSourceConfig :: Aeson.Value,
-- | Can be used to apply custom formatting to table names. Eg., -- | Default configuration for the backend config that sets the agent configuration
-- adjusting the casing. backendAgentConfig :: Aeson.Value,
formatTableName :: [Text] -> [Text], -- | Name formatting functions to correct for backend-specific naming rules
-- | Can be used to apply custom formatting to column names. Eg., nameFormatting :: NameFormatting
-- adjusting the casing.
formatColumnName :: Text -> Text,
formatForeignKeyName :: Text -> Text
} }
setupAction :: Aeson.Value -> Aeson.Value -> TestEnvironment -> Fixture.SetupAction data NameFormatting = NameFormatting
setupAction sourceMetadata backendConfig' testEnv = { -- | Can be used to apply custom formatting to table names. Eg.,
-- adjusting the casing.
_nfFormatTableName :: [Text] -> [Text],
-- | Can be used to apply custom formatting to column names. Eg.,
-- adjusting the casing.
_nfFormatColumnName :: Text -> Text,
_nfFormatForeignKeyName :: Text -> Text
}
--------------------------------------------------------------------------------
-- | Create a test environment that uses agent dataset cloning to clone a copy of the Chinook
-- DB for the test and use that as the source config configured in HGE.
-- This should be used with agents that support datasets.
mkChinookCloneTestEnvironment :: NameFormatting -> TestEnvironment -> Managed ChinookTestEnv
mkChinookCloneTestEnvironment nameFormatting testEnv = do
backendTypeConfig <- getBackendTypeConfig testEnv `onNothing` fail "Unable to find backend type config in this test environment"
agentUrl <- Fixture.backendServerUrl backendTypeConfig `onNothing` fail ("Backend " <> show (Fixture.backendType backendTypeConfig) <> " does not have a server url")
cloneConfig <- API._dccrConfig <$> createManagedClone agentUrl testEnv (API.DatasetTemplateName "Chinook")
let agentBackendConfig = mkAgentBackendConfig backendTypeConfig
let cloneConfigValue = Aeson.Object $ API.unConfig cloneConfig
let sourceConfig =
[yaml|
value: *cloneConfigValue
template:
timeout:
|]
pure $ ChinookTestEnv sourceConfig agentBackendConfig nameFormatting
-- | Create a test environment that uses the source config specified to connect to a specific DB on the agent
-- that contains the Chinook dataset.
-- This should be used with agents that do not support datasets.
mkChinookStaticTestEnvironment :: NameFormatting -> Aeson.Value -> TestEnvironment -> Managed ChinookTestEnv
mkChinookStaticTestEnvironment nameFormatting sourceConfig testEnv = do
backendTypeConfig <- getBackendTypeConfig testEnv `onNothing` fail "Unable to find backend type config in this test environment"
let agentBackendConfig = mkAgentBackendConfig backendTypeConfig
pure $ ChinookTestEnv sourceConfig agentBackendConfig nameFormatting
--------------------------------------------------------------------------------
-- | Sets up a source in HGE using the source returned by 'mkSourceMetadata'
setupCustomSourceAction ::
-- | Function that makes a source metadata, taking the 'BackendTypeConfig' and source's configuration as its input parameters
(Fixture.BackendTypeConfig -> Aeson.Value -> Aeson.Value) ->
(TestEnvironment, ChinookTestEnv) ->
Fixture.SetupAction Fixture.SetupAction
(setup sourceMetadata backendConfig' testEnv) setupCustomSourceAction mkSourceMetadata testEnvs@(testEnv, _chinookTestEnv) =
Fixture.SetupAction
(setupCustomSource mkSourceMetadata testEnvs)
(const $ teardown testEnv) (const $ teardown testEnv)
-- | Setup the schema given source metadata and backend config. -- | Sets up a source in HGE that contains tracked Chinook tables (see 'mkChinookSourceMetadata')
setup :: Aeson.Value -> Aeson.Value -> TestEnvironment -> IO () setupChinookSourceAction :: (TestEnvironment, ChinookTestEnv) -> Fixture.SetupAction
setup sourceMetadata backendConfig' testEnvironment = do setupChinookSourceAction = setupCustomSourceAction mkChinookSourceMetadata
setupCustomSource ::
-- | Function that makes a source metadata, taking the 'BackendTypeConfig' and source's configuration as its input parameters
(Fixture.BackendTypeConfig -> Aeson.Value -> Aeson.Value) ->
(TestEnvironment, ChinookTestEnv) ->
IO ()
setupCustomSource mkSourceMetadata (testEnv, ChinookTestEnv {..}) = do
backendTypeConfig <- getBackendTypeConfig testEnv `onNothing` fail "Unable to find backend type config in this test environment"
let sourceMetadata = mkSourceMetadata backendTypeConfig backendSourceConfig
-- Clear and reconfigure the metadata -- Clear and reconfigure the metadata
GraphqlEngine.setSource testEnvironment sourceMetadata (Just backendConfig') GraphqlEngine.setSource testEnv sourceMetadata (Just backendAgentConfig)
-- | Teardown the schema and tracking in the most expected way. -- | Teardown the schema and tracking in the most expected way.
teardown :: TestEnvironment -> IO () teardown :: TestEnvironment -> IO ()
@ -56,15 +111,21 @@ teardown testEnvironment = do
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
referenceSourceConfig :: Aeson.Value mkAgentBackendConfig :: Fixture.BackendTypeConfig -> Aeson.Value
referenceSourceConfig = mkChinookSourceConfig Reference.backendTypeMetadata Reference.sourceConfiguration mkAgentBackendConfig backendTypeConfig =
let backendType = Fixture.backendTypeString backendTypeConfig
uri = Fixture.backendServerUrl backendTypeConfig
in [yaml|
dataconnector:
*backendType:
uri: *uri
|]
sqliteSourceConfig :: Aeson.Value --------------------------------------------------------------------------------
sqliteSourceConfig = mkChinookSourceConfig Sqlite.backendTypeMetadata Sqlite.sourceConfiguration
-- | Build a standard Chinook Source given an Agent specific @configuration@ field. -- | Build a standard Chinook Source given an Agent specific @configuration@ field.
mkChinookSourceConfig :: Fixture.BackendTypeConfig -> Aeson.Value -> Aeson.Value mkChinookSourceMetadata :: Fixture.BackendTypeConfig -> Aeson.Value -> Aeson.Value
mkChinookSourceConfig backendTypeMetadata config = mkChinookSourceMetadata backendTypeMetadata config =
let source = Fixture.backendSourceName backendTypeMetadata let source = Fixture.backendSourceName backendTypeMetadata
backendTypeString = Fixture.backendTypeString backendTypeMetadata backendTypeString = Fixture.backendTypeString backendTypeMetadata
in [yaml| in [yaml|
@ -126,7 +187,7 @@ tables:
using: using:
manual_configuration: manual_configuration:
remote_table: [Customer] remote_table: [Customer]
column_mapping: column_mapping:
EmployeeId: SupportRepId EmployeeId: SupportRepId
select_permissions: select_permissions:
- role: test-role - role: test-role
@ -161,7 +222,22 @@ tables:
SupportRep: SupportRep:
Country: Country:
_ceq: [ "$", "Country" ] _ceq: [ "$", "Country" ]
- table: [Invoice]
array_relationships:
- name: InvoiceLines
using:
manual_configuration:
remote_table: [InvoiceLine]
column_mapping:
InvoiceId: InvoiceId
- table: [InvoiceLine]
object_relationships:
- name: Invoice
using:
manual_configuration:
remote_table: [Invoice]
column_mapping:
InvoiceId: InvoiceId
configuration: configuration:
*config *config

View File

@ -4,23 +4,28 @@
-- --
-- NOTE: This module is intended to be imported qualified. -- NOTE: This module is intended to be imported qualified.
module Harness.Backend.DataConnector.Chinook.Reference module Harness.Backend.DataConnector.Chinook.Reference
( agentConfig, ( backendTypeConfig,
sourceConfiguration, mkChinookStaticTestEnvironment,
backendTypeMetadata, chinookFixture,
) )
where where
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Control.Monad.Managed (Managed)
import Data.Aeson qualified as Aeson import Data.Aeson qualified as Aeson
import Harness.Backend.DataConnector.Chinook (ChinookTestEnv, NameFormatting (..))
import Harness.Backend.DataConnector.Chinook qualified as Chinook
import Harness.Quoter.Yaml (yaml) import Harness.Quoter.Yaml (yaml)
import Harness.Test.BackendType qualified as BackendType import Harness.Test.BackendType qualified as BackendType
import Harness.Test.Fixture (Fixture (..), FixtureName (..))
import Harness.TestEnvironment (TestEnvironment)
import Hasura.Prelude import Hasura.Prelude
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
backendTypeMetadata :: BackendType.BackendTypeConfig backendTypeConfig :: BackendType.BackendTypeConfig
backendTypeMetadata = backendTypeConfig =
BackendType.BackendTypeConfig BackendType.BackendTypeConfig
{ backendType = BackendType.DataConnectorReference, { backendType = BackendType.DataConnectorReference,
backendSourceName = "chinook_reference", backendSourceName = "chinook_reference",
@ -75,21 +80,27 @@ backendTypeMetadata =
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- | Reference Agent @backend_configs@ field. mkChinookStaticTestEnvironment :: TestEnvironment -> Managed ChinookTestEnv
agentConfig :: Aeson.Value mkChinookStaticTestEnvironment = Chinook.mkChinookStaticTestEnvironment nameFormatting sourceConfiguration
agentConfig =
let backendType = BackendType.backendTypeString backendTypeMetadata nameFormatting :: NameFormatting
in [yaml| nameFormatting = NameFormatting id id id
dataconnector:
*backendType:
uri: "http://127.0.0.1:65005/"
|]
-- | Reference Agent specific @sources@ entry @configuration@ field. -- | Reference Agent specific @sources@ entry @configuration@ field.
sourceConfiguration :: Aeson.Value sourceConfiguration :: Aeson.Value
sourceConfiguration = sourceConfiguration =
[yaml| [yaml|
value: {} value: {}
template: template:
timeout: timeout:
|] |]
chinookFixture :: Fixture ChinookTestEnv
chinookFixture =
Fixture
{ name = Backend backendTypeConfig,
mkLocalTestEnvironment = mkChinookStaticTestEnvironment,
setupTeardown = \testEnvs ->
[Chinook.setupChinookSourceAction testEnvs],
customOptions = Nothing
}

View File

@ -4,24 +4,27 @@
-- --
-- NOTE: This module is intended to be imported qualified. -- NOTE: This module is intended to be imported qualified.
module Harness.Backend.DataConnector.Chinook.Sqlite module Harness.Backend.DataConnector.Chinook.Sqlite
( agentConfig, ( backendTypeConfig,
sourceConfiguration, mkChinookCloneTestEnvironment,
backendTypeMetadata, chinookFixture,
formatForeignKeyName,
) )
where where
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Data.Aeson qualified as Aeson import Control.Monad.Managed (Managed)
import Harness.Backend.DataConnector.Chinook (ChinookTestEnv, NameFormatting (..))
import Harness.Backend.DataConnector.Chinook qualified as Chinook
import Harness.Quoter.Yaml (yaml) import Harness.Quoter.Yaml (yaml)
import Harness.Test.BackendType qualified as BackendType import Harness.Test.BackendType qualified as BackendType
import Harness.Test.Fixture (Fixture (..), FixtureName (..))
import Harness.TestEnvironment
import Hasura.Prelude import Hasura.Prelude
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
backendTypeMetadata :: BackendType.BackendTypeConfig backendTypeConfig :: BackendType.BackendTypeConfig
backendTypeMetadata = backendTypeConfig =
BackendType.BackendTypeConfig BackendType.BackendTypeConfig
{ backendType = BackendType.DataConnectorSqlite, { backendType = BackendType.DataConnectorSqlite,
backendSourceName = "chinook_sqlite", backendSourceName = "chinook_sqlite",
@ -94,28 +97,24 @@ backendTypeMetadata =
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- | Reference Agent @backend_configs@ field. mkChinookCloneTestEnvironment :: TestEnvironment -> Managed ChinookTestEnv
agentConfig :: Aeson.Value mkChinookCloneTestEnvironment = Chinook.mkChinookCloneTestEnvironment nameFormatting
agentConfig =
let backendType = BackendType.backendTypeString backendTypeMetadata
in [yaml|
dataconnector:
*backendType:
uri: "http://127.0.0.1:65007/"
|]
-- | Sqlite Agent specific @sources@ entry @configuration@ field. nameFormatting :: NameFormatting
sourceConfiguration :: Aeson.Value nameFormatting = NameFormatting id id formatForeignKeyName
sourceConfiguration =
[yaml|
value:
db: "/db.chinook.sqlite"
template:
timeout:
|]
-- | Construct foreign key relationship names. -- | Construct foreign key relationship names.
formatForeignKeyName :: Text -> Text formatForeignKeyName :: Text -> Text
formatForeignKeyName = \case formatForeignKeyName = \case
"Artist" -> "ArtistId->Artist.ArtistId" "Artist" -> "ArtistId->Artist.ArtistId"
x -> x x -> x
chinookFixture :: Fixture ChinookTestEnv
chinookFixture =
Fixture
{ name = Backend backendTypeConfig,
mkLocalTestEnvironment = mkChinookCloneTestEnvironment,
setupTeardown = \testEnvs ->
[Chinook.setupChinookSourceAction testEnvs],
customOptions = Nothing
}

View File

@ -14,9 +14,11 @@ where
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
import Data.Aeson qualified as Aeson import Data.Aeson qualified as Aeson
import Data.Aeson.KeyMap qualified as KeyMap
import Data.Text qualified as Text import Data.Text qualified as Text
import Data.Text.Extended qualified as Text (commaSeparated) import Data.Text.Extended qualified as Text (commaSeparated)
import Data.Time qualified as Time import Data.Time qualified as Time
import Harness.DataConnectorAgent (createClone, deleteClone)
import Harness.Exceptions import Harness.Exceptions
import Harness.GraphqlEngine qualified as GraphqlEngine import Harness.GraphqlEngine qualified as GraphqlEngine
import Harness.Quoter.Yaml (yaml) import Harness.Quoter.Yaml (yaml)
@ -25,7 +27,8 @@ import Harness.Test.Fixture qualified as Fixture
import Harness.Test.Permissions qualified as Permissions import Harness.Test.Permissions qualified as Permissions
import Harness.Test.Schema (SchemaName) import Harness.Test.Schema (SchemaName)
import Harness.Test.Schema qualified as Schema import Harness.Test.Schema qualified as Schema
import Harness.TestEnvironment (TestEnvironment) import Harness.TestEnvironment (TestEnvironment (..))
import Hasura.Backends.DataConnector.API qualified as API
import Hasura.Prelude import Hasura.Prelude
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -83,18 +86,18 @@ setupTablesAction ts env =
(const $ teardown ts (env, ())) (const $ teardown ts (env, ()))
-- | Metadata source information for the default Sqlite instance. -- | Metadata source information for the default Sqlite instance.
sourceMetadata :: Aeson.Value sourceMetadata :: API.Config -> Aeson.Value
sourceMetadata = sourceMetadata (API.Config config) =
let source = Fixture.backendSourceName backendTypeMetadata let source = Fixture.backendSourceName backendTypeMetadata
backendType = BackendType.backendTypeString backendTypeMetadata backendType = BackendType.backendTypeString backendTypeMetadata
explicitMainConfig = KeyMap.insert "explicit_main_schema" (Aeson.Bool True) config
in [yaml| in [yaml|
name: *source name: *source
kind: *backendType kind: *backendType
tables: [] tables: []
configuration: configuration:
db: "/db.sqlite" value: *explicitMainConfig
explicit_main_schema: true |]
|]
backendConfig :: Aeson.Value backendConfig :: Aeson.Value
backendConfig = backendConfig =
@ -102,15 +105,20 @@ backendConfig =
in [yaml| in [yaml|
dataconnector: dataconnector:
*backendType: *backendType:
uri: "http://127.0.0.1:65007/" uri: *sqliteAgentUri
|] |]
sqliteAgentUri :: String
sqliteAgentUri = "http://127.0.0.1:65007/"
-- | Setup the schema in the most expected way. -- | Setup the schema in the most expected way.
-- NOTE: Certain test modules may warrant having their own local version. -- NOTE: Certain test modules may warrant having their own local version.
setup :: [Schema.Table] -> (TestEnvironment, ()) -> IO () setup :: [Schema.Table] -> (TestEnvironment, ()) -> IO ()
setup tables (testEnvironment, _) = do setup tables (testEnvironment, _) = do
-- Create the database clone
cloneConfig <- API._dccrConfig <$> createClone sqliteAgentUri testEnvironment (API.DatasetTemplateName "Empty")
-- Clear and reconfigure the metadata -- Clear and reconfigure the metadata
GraphqlEngine.setSource testEnvironment sourceMetadata (Just backendConfig) GraphqlEngine.setSource testEnvironment (sourceMetadata cloneConfig) (Just backendConfig)
-- Setup and track tables -- Setup and track tables
for_ tables $ \table -> do for_ tables $ \table -> do
createTable testEnvironment table createTable testEnvironment table
@ -164,11 +172,15 @@ teardown (reverse -> tables) (testEnvironment, _) = do
( forFinally_ tables $ \table -> ( forFinally_ tables $ \table ->
Schema.untrackRelationships table testEnvironment Schema.untrackRelationships table testEnvironment
) )
-- Then teardown tables ( finally
( forFinally_ tables $ \table -> -- Then teardown tables
finally ( forFinally_ tables $ \table ->
(untrackTable testEnvironment table) finally
(dropTable testEnvironment table) (untrackTable testEnvironment table)
(dropTable testEnvironment table)
)
-- Then delete the db clone
(deleteClone sqliteAgentUri testEnvironment)
) )
-- | Call the Metadata API and pass in a Raw SQL statement to the -- | Call the Metadata API and pass in a Raw SQL statement to the

View File

@ -0,0 +1,43 @@
module Harness.DataConnectorAgent
( createClone,
deleteClone,
createManagedClone,
)
where
import Control.Exception.Lifted (finally, throwIO)
import Control.Monad.Managed (MonadManaged, managed)
import Harness.TestEnvironment (TestEnvironment (..))
import Hasura.Backends.DataConnector.API qualified as API
import Hasura.Prelude
import Network.HTTP.Client qualified as Http
import Servant (NamedRoutes, Proxy (..))
import Servant.Client (Client, ClientM, client, mkClientEnv, parseBaseUrl, runClientM, (//))
runDataConnectorAgentRequests :: String -> (Client ClientM (NamedRoutes API.Routes) -> ClientM a) -> IO a
runDataConnectorAgentRequests agentUri runWithClient = do
clientEnv <- mkClientEnv <$> Http.newManager Http.defaultManagerSettings <*> parseBaseUrl agentUri
results <- flip runClientM clientEnv $ do
runWithClient $ client (Proxy @(NamedRoutes API.Routes))
results `onLeft` throwIO
createClone :: String -> TestEnvironment -> API.DatasetTemplateName -> IO API.DatasetCreateCloneResponse
createClone agentUri TestEnvironment {..} templateName = runDataConnectorAgentRequests agentUri $ \dcClient -> do
let cloneName = API.DatasetCloneName (tshow uniqueTestId)
(dcClient // API._datasets // API._createClone) cloneName (API.DatasetCreateCloneRequest templateName)
deleteClone :: String -> TestEnvironment -> IO API.DatasetDeleteCloneResponse
deleteClone agentUri TestEnvironment {..} = runDataConnectorAgentRequests agentUri $ \dcClient -> do
let cloneName = API.DatasetCloneName (tshow uniqueTestId)
(dcClient // API._datasets // API._deleteClone) cloneName
withClone :: String -> TestEnvironment -> API.DatasetTemplateName -> (API.DatasetCreateCloneResponse -> IO a) -> IO a
withClone agentUri TestEnvironment {..} templateName useClone = runDataConnectorAgentRequests agentUri $ \dcClient -> do
let cloneName = API.DatasetCloneName (tshow uniqueTestId)
response <- (dcClient // API._datasets // API._createClone) cloneName (API.DatasetCreateCloneRequest templateName)
finally
(liftIO $ useClone response)
((dcClient // API._datasets // API._deleteClone) cloneName)
createManagedClone :: MonadManaged m => String -> TestEnvironment -> API.DatasetTemplateName -> m API.DatasetCreateCloneResponse
createManagedClone agentUri testEnvironment templateName = managed (withClone agentUri testEnvironment templateName)

View File

@ -290,7 +290,7 @@ startServerThread = do
dataconnector: dataconnector:
foobar: foobar:
display_name: FOOBARDB display_name: FOOBARDB
uri: "http://localhost:65007" |] uri: "http://localhost:65005" |]
thread <- thread <-
Async.async Async.async
( runApp ( runApp

View File

@ -26,12 +26,14 @@ library
, hedgehog , hedgehog
, hspec , hspec
, hspec-core , hspec-core
, http-client
, http-conduit , http-conduit
, http-types , http-types
, insert-ordered-containers , insert-ordered-containers
, lens , lens
, lens-aeson , lens-aeson
, libyaml , libyaml
, lifted-base
, managed , managed
, morpheus-graphql , morpheus-graphql
, mtl , mtl
@ -51,6 +53,7 @@ library
, safe , safe
, safe-exceptions , safe-exceptions
, servant-server , servant-server
, servant-client
, sop-core , sop-core
, stm , stm
, string-interpolate , string-interpolate
@ -125,6 +128,7 @@ library
Harness.Backend.Postgres Harness.Backend.Postgres
Harness.Backend.Sqlserver Harness.Backend.Sqlserver
Harness.Constants Harness.Constants
Harness.DataConnectorAgent
Harness.Env Harness.Env
Harness.Exceptions Harness.Exceptions
Harness.GraphqlEngine Harness.GraphqlEngine