graphql-engine/server/tests-hspec/Test/BasicFieldsSpec.hs
Antoine Leblanc dc4a286c64 Prepare test suite for remote servers tests
## Description

This PR adds all the scaffolding for tests that require remote servers. It is mostly a refactor of `Feature`; where we listed for each test a list of individual backends, we now provide a list of `Context`s, that allows for tests to specify not only how it should be setup, but also what state needs to be carried around throughout the test. This will be useful when launching custom remote servers.

Additionally, this PR:
- cleans the way we generate logs in the engine as part of the tests
- cleans the cabal file
- introduce a few more helpers for sending commands to the engine (such as `postMetadata_`)
- allows for headers in queries sent to the engine (to support permissions tests)
- adds basic code to start / stop a "remote" server

This PR is a pre-requisite of #3567.

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/3573
Co-authored-by: jkachmar <8461423+jkachmar@users.noreply.github.com>
GitOrigin-RevId: 05f808c6b85729dbb3ea6648c3e10a3c16b641ef
2022-02-14 17:25:28 +00:00

413 lines
7.8 KiB
Haskell

{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
-- | Test querying an entity for a couple fields.
module Test.BasicFieldsSpec (spec) where
import Harness.Backend.BigQuery qualified as BigQuery
import Harness.Backend.Citus qualified as Citus
import Harness.Backend.Mysql qualified as Mysql
import Harness.Backend.Postgres qualified as Postgres
import Harness.Backend.Sqlserver qualified as Sqlserver
import Harness.GraphqlEngine qualified as GraphqlEngine
import Harness.Quoter.Graphql (graphql)
import Harness.Quoter.Sql (sql)
import Harness.Quoter.Yaml (shouldReturnYaml, yaml)
import Harness.State (State)
import Harness.Test.Feature qualified as Feature
import Test.Hspec (SpecWith, it)
import Prelude
--------------------------------------------------------------------------------
-- Preamble
spec :: SpecWith State
spec =
Feature.run
[ Feature.Context
{ name = "MySQL",
setup = mysqlSetup,
teardown = mysqlTeardown,
options = Feature.defaultOptions
},
Feature.Context
{ name = "PostgreSQL",
setup = postgresSetup,
teardown = postgresTeardown,
options = Feature.defaultOptions
},
Feature.Context
{ name = "Citus",
setup = citusSetup,
teardown = citusTeardown,
options = Feature.defaultOptions
},
Feature.Context
{ name = "SQLServer",
setup = sqlserverSetup,
teardown = sqlserverTeardown,
options = Feature.defaultOptions
},
Feature.Context
{ name = "BigQuery",
setup = bigquerySetup,
teardown = bigqueryTeardown,
options =
Feature.Options
{ stringifyNumbers = True
}
}
]
tests
--------------------------------------------------------------------------------
-- MySQL backend
mysqlSetup :: State -> IO ()
mysqlSetup state = do
-- Clear and reconfigure the metadata
GraphqlEngine.setSource state Mysql.defaultSourceMetadata
-- Setup tables
Mysql.run_
[sql|
CREATE TABLE hasura.author
(
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(45) UNIQUE KEY
);
|]
Mysql.run_
[sql|
INSERT INTO hasura.author
(name)
VALUES
( 'Author 1'),
( 'Author 2');
|]
-- Track the tables
GraphqlEngine.postMetadata_
state
[yaml|
type: mysql_track_table
args:
source: mysql
table:
schema: hasura
name: author
|]
mysqlTeardown :: (State, ()) -> IO ()
mysqlTeardown _ = do
Mysql.run_
[sql|
DROP TABLE hasura.author;
|]
--------------------------------------------------------------------------------
-- PostgreSQL backend
postgresSetup :: State -> IO ()
postgresSetup state = do
-- Clear and reconfigure the metadata
GraphqlEngine.setSource state Postgres.defaultSourceMetadata
-- Setup tables
Postgres.run_
[sql|
CREATE TABLE hasura.author
(
id SERIAL PRIMARY KEY,
name VARCHAR(45) UNIQUE
);
|]
Postgres.run_
[sql|
INSERT INTO hasura.author
(name)
VALUES
( 'Author 1'),
( 'Author 2');
|]
-- Track the tables
GraphqlEngine.postMetadata_
state
[yaml|
type: postgres_track_table
args:
source: postgres
table:
schema: hasura
name: author
|]
postgresTeardown :: (State, ()) -> IO ()
postgresTeardown _ = do
Postgres.run_
[sql|
DROP TABLE hasura.author;
|]
--------------------------------------------------------------------------------
-- Citus backend
citusSetup :: State -> IO ()
citusSetup state = do
-- Clear and reconfigure the metadata
GraphqlEngine.setSource state Citus.defaultSourceMetadata
-- Setup tables
Citus.run_
[sql|
CREATE TABLE hasura.author
(
id SERIAL PRIMARY KEY,
name VARCHAR(45) UNIQUE
);
|]
Citus.run_
[sql|
INSERT INTO hasura.author
(name)
VALUES
( 'Author 1'),
( 'Author 2');
|]
-- Track the tables
GraphqlEngine.postMetadata_
state
[yaml|
type: citus_track_table
args:
source: citus
table:
schema: hasura
name: author
|]
citusTeardown :: (State, ()) -> IO ()
citusTeardown _ = do
Citus.run_
[sql|
DROP TABLE IF EXISTS hasura.author;
|]
--------------------------------------------------------------------------------
-- SQL Server backend
sqlserverSetup :: State -> IO ()
sqlserverSetup state = do
-- Clear and reconfigure the metadata
GraphqlEngine.setSource state Sqlserver.defaultSourceMetadata
-- Setup tables
Sqlserver.run_
[sql|
CREATE TABLE hasura.author
(
id INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED,
name NVARCHAR(45) NOT NULL UNIQUE NONCLUSTERED
);
|]
Sqlserver.run_
[sql|
INSERT INTO hasura.author
(name)
VALUES
('Author 1'),
('Author 2');
|]
-- Track the tables
GraphqlEngine.postMetadata_
state
[yaml|
type: mssql_track_table
args:
source: mssql
table:
schema: hasura
name: author
|]
sqlserverTeardown :: (State, ()) -> IO ()
sqlserverTeardown _ = do
Sqlserver.run_
[sql|
DROP TABLE hasura.author;
|]
--------------------------------------------------------------------------------
-- BigQuery backend
bigquerySetup :: State -> IO ()
bigquerySetup state = do
-- Clear and reconfigure the metadata
serviceAccount <- BigQuery.getServiceAccount
projectId <- BigQuery.getProjectId
GraphqlEngine.postMetadata_
state
[yaml|
type: replace_metadata
args:
version: 3
sources:
- name: bigquery
kind: bigquery
tables: []
configuration:
service_account: *serviceAccount
project_id: *projectId
datasets: [hasura]
|]
-- Setup tables
BigQuery.run_
serviceAccount
projectId
[sql|
CREATE TABLE hasura.author
(
id INT64,
name STRING
);
|]
BigQuery.run_
serviceAccount
projectId
[sql|
INSERT INTO hasura.author
(id, name)
VALUES
(1, 'Author 1'),
(2, 'Author 2');
|]
-- Track the tables
GraphqlEngine.postMetadata_
state
[yaml|
type: bigquery_track_table
args:
source: bigquery
table:
dataset: hasura
name: author
|]
bigqueryTeardown :: (State, ()) -> IO ()
bigqueryTeardown _ = do
serviceAccount <- BigQuery.getServiceAccount
projectId <- BigQuery.getProjectId
BigQuery.run_
serviceAccount
projectId
[sql|
DROP TABLE hasura.author;
|]
--------------------------------------------------------------------------------
-- Tests
tests :: Feature.Options -> SpecWith State
tests opts = do
it "Author fields" $ \state ->
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
state
[graphql|
query {
hasura_author(order_by:[{id:asc}]) {
name
id
}
}
|]
)
[yaml|
data:
hasura_author:
- name: Author 1
id: 1
- name: Author 2
id: 2
|]
it "Use operationName" $ \state ->
shouldReturnYaml
opts
( GraphqlEngine.postGraphqlYaml
state
[yaml|
operationName: chooseThisOne
query: |
query ignoreThisOne {
MyQuery {
name
}
}
query chooseThisOne {
hasura_author(order_by:[{id:asc}]) {
id
name
}
}
|]
)
[yaml|
data:
hasura_author:
- name: Author 1
id: 1
- name: Author 2
id: 2
|]
it "Missing field" $ \state -> do
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
state
[graphql|
query {
hasura_author {
id
name
notPresentCol
}
}
|]
)
[yaml|
errors:
- extensions:
code: validation-failed
path: $.selectionSet.hasura_author.selectionSet.notPresentCol
message: |-
field "notPresentCol" not found in type: 'hasura_author'
|]
it "Missing table" $ \state ->
shouldReturnYaml
opts
( GraphqlEngine.postGraphql
state
[graphql|
query {
random {
id
name
}
}
|]
)
[yaml|
errors:
- extensions:
code: validation-failed
path: $.selectionSet.random
message: |-
field "random" not found in type: 'query_root'
|]