graphql-engine/server/lib/api-tests/test/Test/DataConnector/AggregateQuerySpec.hs
Tom Harding f05f746b94 Extract the test harness from the Hspec tests
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6095
Co-authored-by: Gil Mizrahi <8547573+soupi@users.noreply.github.com>
GitOrigin-RevId: 51693f7324e62e201a2bdc701255cf6c730745e2
2022-10-04 08:31:26 +00:00

442 lines
13 KiB
Haskell

{-# LANGUAGE QuasiQuotes #-}
module Test.DataConnector.AggregateQuerySpec
( spec,
)
where
import Data.Aeson qualified as Aeson
import Harness.Backend.DataConnector qualified as DataConnector
import Harness.GraphqlEngine qualified as GraphqlEngine
import Harness.Quoter.Graphql (graphql)
import Harness.Quoter.Yaml (yaml)
import Harness.Test.BackendType (BackendType (..), defaultBackendTypeString, defaultSource)
import Harness.Test.Fixture qualified as Fixture
import Harness.TestEnvironment (TestEnvironment)
import Harness.TestEnvironment qualified as TE
import Harness.Yaml (shouldReturnYaml)
import Hasura.Prelude
import Test.Hspec (SpecWith, describe, it)
spec :: SpecWith TestEnvironment
spec =
Fixture.runWithLocalTestEnvironment
( ( \(DataConnector.TestSourceConfig backendType backendConfig sourceConfig _md) ->
(Fixture.fixture $ Fixture.Backend backendType)
{ Fixture.setupTeardown =
\(testEnv, _) -> [DataConnector.setupFixtureAction (sourceMetadata backendType sourceConfig) backendConfig testEnv]
}
)
<$> DataConnector.backendConfigs
)
tests
sourceMetadata :: BackendType -> Aeson.Value -> Aeson.Value
sourceMetadata backendType config =
let source = defaultSource backendType
backendTypeString = defaultBackendTypeString backendType
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 opts = describe "Aggregate Query Tests" $ do
describe "Nodes Tests" $ do
it "works with simple query" $ \(testEnvironment, _) ->
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
testEnvironment
[graphql|
query getAlbum {
Album_aggregate(limit: 2) {
nodes {
AlbumId
Title
}
}
}
|]
)
[yaml|
data:
Album_aggregate:
nodes:
- AlbumId: 1
Title: For Those About To Rock We Salute You
- AlbumId: 2
Title: Balls to the Wall
|]
it "works with multiple nodes fields" $ \(testEnvironment, _) ->
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
testEnvironment
[graphql|
query getAlbum {
Album_aggregate(limit: 2) {
AlbumIds: nodes {
AlbumId
}
Titles: nodes {
Title
}
}
}
|]
)
[yaml|
data:
Album_aggregate:
AlbumIds:
- AlbumId: 1
- AlbumId: 2
Titles:
- Title: For Those About To Rock We Salute You
- Title: Balls to the Wall
|]
it "works with object relations" $ \(testEnvironment, _) -> do
-- NOTE: Ordering is required due to datasets non-matching orders
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
testEnvironment
[graphql|
query getAlbum {
Album_aggregate(order_by: {AlbumId: asc}, limit: 2) {
nodes {
AlbumId
Artist {
Name
}
}
}
}
|]
)
[yaml|
data:
Album_aggregate:
nodes:
- AlbumId: 1
Artist:
Name: AC/DC
- AlbumId: 2
Artist:
Name: Accept
|]
it "works with array relations" $ \(testEnvironment, _) ->
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
testEnvironment
[graphql|
query getArtist {
Artist_aggregate(limit: 2) {
nodes {
ArtistId
Albums: Albums_aggregate {
nodes {
Title
}
}
}
}
}
|]
)
[yaml|
data:
Artist_aggregate:
nodes:
- ArtistId: 1
Albums:
nodes:
- Title: For Those About To Rock We Salute You
- Title: Let There Be Rock
- ArtistId: 2
Albums:
nodes:
- Title: Balls to the Wall
- Title: Restless and Wild
|]
describe "Aggregate Tests" $ do
it "works with count queries" $ \(testEnvironment, _) ->
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
testEnvironment
[graphql|
query getInvoices {
Invoice_aggregate {
aggregate {
count
countColumn: count(column: BillingState)
countColumnDistinct: count(column: BillingState, distinct: true)
}
}
}
|]
)
[yaml|
data:
Invoice_aggregate:
aggregate:
count: 412
countColumn: 210
countColumnDistinct: 25
|]
it "works with single column queries" $ \(testEnvironment, _) -> do
-- NOTE: This test is specialized for the reference agent to support more statistical functions.
-- This should really be derived from the agent's capabilities.
let referenceQuery =
[graphql|
query getInvoices {
Invoice_aggregate {
aggregate {
max { Total }
min { Total }
stddev { Total }
stddev_pop { Total }
stddev_samp { Total }
sum { Total }
var_pop { Total }
var_samp { Total }
variance { Total }
}
}
}
|]
generalQuery =
[graphql|
query getInvoices {
Invoice_aggregate {
aggregate {
max { Total }
min { Total }
sum { Total }
}
}
}
|]
referenceResults =
[yaml|
data:
Invoice_aggregate:
aggregate:
max:
Total: 25.86
min:
Total: 0.99
stddev:
Total: 4.745319693568103
stddev_pop:
Total: 4.739557311729622
stddev_samp:
Total: 4.745319693568103
sum:
Total: 2328.600000000004
var_pop:
Total: 22.463403511169727
var_samp:
Total: 22.518058994165273
variance:
Total: 22.518058994165273
|]
generalResults =
[yaml|
data:
Invoice_aggregate:
aggregate:
max:
Total: 25.86
min:
Total: 0.99
sum:
Total: 2328.6
|]
if (TE.backendType testEnvironment == Just Fixture.DataConnectorReference)
then
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
testEnvironment
referenceQuery
)
referenceResults
else
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
testEnvironment
generalQuery
)
generalResults
it "min and max works on string fields" $ \(testEnvironment, _) ->
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
testEnvironment
[graphql|
query getArtists {
Artist_aggregate {
aggregate {
max {
Name
}
min {
Name
}
}
}
}
|]
)
[yaml|
data:
Artist_aggregate:
aggregate:
max:
Name: Zeca Pagodinho
min:
Name: A Cor Do Som
|]
it "works across array relationships from regular queries" $ \(testEnvironment, _) -> do
-- NOTE: Ordering is added to allow SQLite chinook dataset to return ordered results
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
testEnvironment
[graphql|
query getInvoices {
Invoice(limit: 5, order_by: {InvoiceId: asc}) {
InvoiceId
InvoiceLines_aggregate {
aggregate {
count
}
}
}
}
|]
)
[yaml|
data:
Invoice:
- InvoiceId: 1
InvoiceLines_aggregate:
aggregate:
count: 2
- InvoiceId: 2
InvoiceLines_aggregate:
aggregate:
count: 4
- InvoiceId: 3
InvoiceLines_aggregate:
aggregate:
count: 6
- InvoiceId: 4
InvoiceLines_aggregate:
aggregate:
count: 9
- InvoiceId: 5
InvoiceLines_aggregate:
aggregate:
count: 14
|]
it "works across array relationships from aggregate queries via nodes" $ \(testEnvironment, _) -> do
-- NOTE: Ordering present so that out-of-order rows are sorted for SQLite
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
testEnvironment
[graphql|
query getInvoices {
Invoice_aggregate(limit: 5, order_by: {InvoiceId: asc}) {
nodes {
InvoiceId
InvoiceLines_aggregate {
aggregate {
count
}
}
}
}
}
|]
)
[yaml|
data:
Invoice_aggregate:
nodes:
- InvoiceId: 1
InvoiceLines_aggregate:
aggregate:
count: 2
- InvoiceId: 2
InvoiceLines_aggregate:
aggregate:
count: 4
- InvoiceId: 3
InvoiceLines_aggregate:
aggregate:
count: 6
- InvoiceId: 4
InvoiceLines_aggregate:
aggregate:
count: 9
- InvoiceId: 5
InvoiceLines_aggregate:
aggregate:
count: 14
|]