graphql-engine/server/tests-hspec/Test/InsertOnConflictSpec.hs
Philip Lykke Carlsen 12c3eddef7 Amendments to the hspec testsuite
This PR proposes some changes to the hspec testsuite:

* It amends the framework to make it easier to test from the ghci REPL
* It introduces a new module `Fixture`, distinguished from `Context` by:
   * using a new concept of `SetupAction`s which bundle setup and teardown actions into one abstraction, making test system state setup more concise, modularized and safe (because the fixture know knows about the ordering of setup actions and can do partial rollbacks)
   * somewhat opinionated, elides the `Options` of `Context`, preferring instead that tests that care about stringification of json numbers manage that themselves.

(Note that this PR builds on #4390, so contains some spurious commits which will become irrelevant once that PR is merged)

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/4630
GitOrigin-RevId: 619c8d985aed0aa42de31d6f16891d0782f4b4b5
2022-06-08 16:36:50 +00:00

146 lines
3.9 KiB
Haskell

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
-- | Tests of the Postgres-specific upsert feature.
module Test.InsertOnConflictSpec (spec) where
import Data.Text
import Data.Text.Encoding (encodeUtf8)
import Harness.Backend.Citus qualified as Citus
import Harness.Backend.Postgres qualified as Postgres
import Harness.GraphqlEngine qualified as GraphqlEngine
import Harness.Quoter.Graphql
import Harness.Quoter.Yaml
import Harness.Test.BackendType qualified as BackendType
import Harness.Test.Fixture
import Harness.Test.Introspection
import Harness.Test.Permissions (Permission (..))
import Harness.Test.Schema
import Harness.TestEnvironment (TestEnvironment)
import Hasura.Prelude
import Test.Hspec
--------------------------------------------------------------------------------
-- Preamble
spec :: SpecWith TestEnvironment
spec = run [postgresFixture, citusFixture] tests
postgresFixture :: Fixture ()
postgresFixture =
(fixture $ Backend BackendType.Postgres)
{ setupTeardown = \(t, _) ->
[ Postgres.setupTablesAction tables t,
Postgres.setupPermissionsAction (permissions "postgres") t
]
}
citusFixture :: Fixture ()
citusFixture =
(fixture $ Backend BackendType.Citus)
{ setupTeardown = \(t, _) ->
[ Citus.setupTablesAction tables t,
Citus.setupPermissionsAction (permissions "citus") t
]
}
tables :: [Table]
tables =
[ (table "foo")
{ tableColumns =
[ column "id" TInt,
column "bar" TStr
],
tablePrimaryKey = ["id"],
tableData =
[ [VInt 0, VStr "initial"]
]
}
]
permissions :: Text -> [Permission]
permissions source =
[ SelectPermission
{ permissionTable = "foo",
permissionSource = source,
permissionRole = "role-select-only",
permissionColumns = ["id", "bar"]
},
InsertPermission
{ permissionTable = "foo",
permissionSource = source,
permissionRole = "role-insert-only",
permissionColumns = ["id", "bar"]
}
]
--------------------------------------------------------------------------------
-- Tests
tests :: SpecWith TestEnvironment
tests =
-- Tests relating to https://github.com/hasura/graphql-engine/issues/8260
describe "The schema for insert mutations with an 'on_conflict' clause" do
describe "When no columns are updateable" do
it "Is still present with an empty enum" testEmptyUpdateColumns
it "Inserts ignoring duplicates" testInsertDoNothing
testEmptyUpdateColumns :: TestEnvironment -> IO ()
testEmptyUpdateColumns env = do
introspectTypes env "role-insert-only"
>>= (`shouldContain` ["hasura_foo_on_conflict"])
introspectEnums env "role-insert-only"
>>= (`shouldContain` [("hasura_foo_update_column", ["_PLACEHOLDER"])])
testInsertDoNothing :: TestEnvironment -> IO ()
testInsertDoNothing env = do
-- We can insert ignoring duplicates
GraphqlEngine.postGraphqlWithHeaders
env
[("X-Hasura-Role", encodeUtf8 "role-insert-only")]
[graphql|
mutation OnConflictDoNothing {
insert_hasura_foo
(
objects: [
{bar: "untouched", id: 0},
{bar: "inserted", id: 1}],
on_conflict: {constraint: foo_pkey, update_columns: []}
)
{
affected_rows
}
}
|]
>>= ( `shouldBe`
[yaml|
data:
insert_hasura_foo:
affected_rows: 1
|]
)
-- The data actually gets stored
GraphqlEngine.postGraphqlWithHeaders
env
[("X-Hasura-Role", encodeUtf8 "role-select-only")]
[graphql|
query ActualData {
hasura_foo {
bar
id
}
}
|]
>>= ( `shouldBe`
[yaml|
data:
hasura_foo:
- bar: "initial"
id: 0
- bar: "inserted"
id: 1
|]
)