test(spec): inline config into test suite

Previously, information about each test-suite was repeated in 3 separate
places:
- as a label and as implicit knowledge in the test-suite itself,
- as a comment in Main.hs, and
- as a configuration in SpecHelper.hs.

With this change, there will be a single source of truth in the test
suite itself. This will allow a single test-suite to easily test
multiple different configurations.
This commit is contained in:
Wolfgang Walther
2026-06-02 06:49:15 +00:00
parent 7803960cd1
commit 268ab00ed9
52 changed files with 280 additions and 439 deletions
+27 -7
View File
@@ -1,19 +1,39 @@
module Feature.Auth.AsymmetricJwtSpec where module Feature.Auth.AsymmetricJwtSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Text.Heredoc
import PostgREST.Config (AppConfig (..), parseSecret)
import Protolude import Protolude
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) -- these tests will stop working 9999999999s after the UNIX EPOCH
spec = describe "server started with asymmetric JWK" $ spec :: SpecWithConfig
spec withConfig =
let
auth = authHeaderJWT "eyJhbGciOiJSUzI1NiJ9.eyJyb2xlIjogInBvc3RncmVzdF90ZXN0X2F1dGhvciJ9Cg.CBOYWDvqgAR0YYnZnyDGTQi6AJLc2Pds6_eV3YuBG6I36mj_h05eLhkEKNEDA5ZteMzCiY83P60rC_xtxVd7B6vo3BeF5uoanPS3rrbuHzKPwzsrgrD_CqvEuJ4n7Q9epkQiLsNkcexneENZDRqFjbwZx3DrXiCWwlK3Ytr5NAIGxmy0od-0xNpb2U1nXQyO_Q3mumWFViRt4tmFn_3goDHNKG3Ha_AzImfUNvHnWL78kAc4rbn15vLtWXD8PwtSnZaB4lY4V6RfsaW937srQsmRetvytM1i_bHBnjkjQLAqGbXPyItjtlXPs0uGNBadE8-wgkLtfmSCC4v2DjUthw"
jwk = encodeUtf8 [str|{"alg":"RS256","e":"AQAB","key_ops":["verify"],"kty":"RSA","n":"0etQ2Tg187jb04MWfpuogYGV75IFrQQBxQaGH75eq_FpbkyoLcEpRUEWSbECP2eeFya2yZ9vIO5ScD-lPmovePk4Aa4SzZ8jdjhmAbNykleRPCxMg0481kz6PQhnHRUv3nF5WP479CnObJKqTVdEagVL66oxnX9VhZG9IZA7k0Th5PfKQwrKGyUeTGczpOjaPqbxlunP73j9AfnAt4XCS8epa-n3WGz1j-wfpr_ys57Aq-zBCfqP67UYzNpeI1AoXsJhD9xSDOzvJgFRvc3vm2wjAW4LEMwi48rCplamOpZToIHEPIaPzpveYQwDnB1HFTR1ove9bpKJsHmi-e2uzQ","use":"sig"}|]
jwks = encodeUtf8 [str|{"keys": [{"alg":"RS256","e":"AQAB","key_ops":["verify"],"kty":"RSA","n":"0etQ2Tg187jb04MWfpuogYGV75IFrQQBxQaGH75eq_FpbkyoLcEpRUEWSbECP2eeFya2yZ9vIO5ScD-lPmovePk4Aa4SzZ8jdjhmAbNykleRPCxMg0481kz6PQhnHRUv3nF5WP479CnObJKqTVdEagVL66oxnX9VhZG9IZA7k0Th5PfKQwrKGyUeTGczpOjaPqbxlunP73j9AfnAt4XCS8epa-n3WGz1j-wfpr_ys57Aq-zBCfqP67UYzNpeI1AoXsJhD9xSDOzvJgFRvc3vm2wjAW4LEMwi48rCplamOpZToIHEPIaPzpveYQwDnB1HFTR1ove9bpKJsHmi-e2uzQ","use":"sig"}]}|]
in
describe "server started with asymmetric JWK" $ do
-- this test will stop working 9999999999s after the UNIX EPOCH context "secret provided as JWK" $ withConfig (
it "succeeds with jwt token signed with an asymmetric key" $ do baseCfg {
let auth = authHeaderJWT "eyJhbGciOiJSUzI1NiJ9.eyJyb2xlIjogInBvc3RncmVzdF90ZXN0X2F1dGhvciJ9Cg.CBOYWDvqgAR0YYnZnyDGTQi6AJLc2Pds6_eV3YuBG6I36mj_h05eLhkEKNEDA5ZteMzCiY83P60rC_xtxVd7B6vo3BeF5uoanPS3rrbuHzKPwzsrgrD_CqvEuJ4n7Q9epkQiLsNkcexneENZDRqFjbwZx3DrXiCWwlK3Ytr5NAIGxmy0od-0xNpb2U1nXQyO_Q3mumWFViRt4tmFn_3goDHNKG3Ha_AzImfUNvHnWL78kAc4rbn15vLtWXD8PwtSnZaB4lY4V6RfsaW937srQsmRetvytM1i_bHBnjkjQLAqGbXPyItjtlXPs0uGNBadE8-wgkLtfmSCC4v2DjUthw" configJwtSecret = Just jwk
, configJWKS = rightToMaybe $ parseSecret jwk
}
) $ it "succeeds with jwt token signed with an asymmetric key" $
request methodGet "/authors_only" [auth] ""
`shouldRespondWith` 200
context "secret provided as JWKSet" $ withConfig (
baseCfg {
configJwtSecret = Just jwks
, configJWKS = rightToMaybe $ parseSecret jwks
}
) $ it "succeeds with jwt token signed with an asymmetric key" $
request methodGet "/authors_only" [auth] "" request methodGet "/authors_only" [auth] ""
`shouldRespondWith` 200 `shouldRespondWith` 200
@@ -1,7 +1,5 @@
module Feature.Auth.AudienceJwtSecretSpec where module Feature.Auth.AudienceJwtSecretSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
@@ -9,8 +7,16 @@ import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
spec :: SpecWith ((), Application) import PostgREST.Config (AppConfig (..), parseSecret)
spec = describe "test handling of aud claims in JWT when the jwt-aud config is set" $ do
spec :: SpecWithConfig
spec withConfig = withConfig (
baseCfg {
configJwtSecret = Just generateSecret
, configJwtAudience = Just "youraudience"
, configJWKS = rightToMaybe $ parseSecret generateSecret
}
) $ describe "test handling of aud claims in JWT when the jwt-aud config is set" $ do
context "when the audience claim is a string" $ do context "when the audience claim is a string" $ do
-- this test will stop working 9999999999s after the UNIX EPOCH -- this test will stop working 9999999999s after the UNIX EPOCH
@@ -147,8 +153,8 @@ spec = describe "test handling of aud claims in JWT when the jwt-aud config is s
it "succeeds without a JWT" $ it "succeeds without a JWT" $
get "/has_count_column" `shouldRespondWith` 200 get "/has_count_column" `shouldRespondWith` 200
disabledSpec :: SpecWith ((), Application) disabledSpec :: SpecWithConfig
disabledSpec = describe "test handling of aud claims in JWT when the jwt-aud config is not set" $ do disabledSpec withConfig = withConfig baseCfg $ describe "test handling of aud claims in JWT when the jwt-aud config is not set" $ do
context "when the audience claim is a string" $ do context "when the audience claim is a string" $ do
it "ignores the audience claim and suceeds" $ do it "ignores the audience claim and suceeds" $ do
+2 -4
View File
@@ -1,7 +1,5 @@
module Feature.Auth.AuthSpec where module Feature.Auth.AuthSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -10,8 +8,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "authorization" $ do spec withConfig = withConfig baseCfg $ describe "authorization" $ do
let single = ("Accept","application/vnd.pgrst.object+json") let single = ("Accept","application/vnd.pgrst.object+json")
it "denies access to tables that anonymous does not own" $ it "denies access to tables that anonymous does not own" $
@@ -1,16 +1,21 @@
module Feature.Auth.BinaryJwtSecretSpec where module Feature.Auth.BinaryJwtSecretSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import PostgREST.Config (AppConfig (..), parseSecret)
import Protolude import Protolude
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "server started with binary JWT secret" $ spec withConfig = withConfig (
baseCfg {
configJwtSecret = Just generateSecret
, configJWKS = rightToMaybe $ parseSecret generateSecret
}
) $ describe "server started with binary JWT secret" $
-- this test will stop working 9999999999s after the UNIX EPOCH -- this test will stop working 9999999999s after the UNIX EPOCH
it "succeeds with jwt token encoded with a binary secret" $ do it "succeeds with jwt token encoded with a binary secret" $ do
+4 -4
View File
@@ -1,17 +1,17 @@
module Feature.Auth.NoAnonSpec where module Feature.Auth.NoAnonSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "server started without anonymous role" $ do spec withConfig = withConfig (baseCfg { configDbAnonRole = Nothing }) $ describe "server started without anonymous role" $ do
it "behaves normally on attempted auth" $ do it "behaves normally on attempted auth" $ do
-- token body: { "role": "postgrest_test_author" } -- token body: { "role": "postgrest_test_author" }
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA" let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicG9zdGdyZXN0X3Rlc3RfYXV0aG9yIn0.Xod-F15qsGL0WhdOCr2j3DdKuTw9QJERVgoFD3vGaWA"
+9 -4
View File
@@ -1,17 +1,22 @@
module Feature.Auth.NoJwtSecretSpec where module Feature.Auth.NoJwtSecretSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "server started without JWT secret" $ do spec withConfig = withConfig (
baseCfg {
configJwtSecret = Nothing
, configJWKS = Nothing
}
) $ describe "server started without JWT secret" $ do
it "responds with error on attempted auth" $ do it "responds with error on attempted auth" $ do
-- token body: { "role": "postgrest_test_author" } -- token body: { "role": "postgrest_test_author" }
+3 -3
View File
@@ -5,7 +5,6 @@
module Feature.ConcurrentSpec where module Feature.ConcurrentSpec where
import Control.Concurrent.Async (mapConcurrently) import Control.Concurrent.Async (mapConcurrently)
import Network.Wai (Application)
import Control.Monad.Base import Control.Monad.Base
import Control.Monad.Trans.Control import Control.Monad.Trans.Control
@@ -17,9 +16,10 @@ import Test.Hspec.Wai.Internal
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "Querying in parallel" $ describe "Querying in parallel" $
it "should not raise 'transaction in progress' error" $ it "should not raise 'transaction in progress' error" $
raceTest 10 $ raceTest 10 $
+3 -4
View File
@@ -1,15 +1,14 @@
module Feature.CorsSpec where module Feature.CorsSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Protolude import Protolude
import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "CORS" $ do describe "CORS" $ do
it "replies naively and permissively to preflight request" $ it "replies naively and permissively to preflight request" $
request methodOptions "/" request methodOptions "/"
+4 -3
View File
@@ -1,16 +1,17 @@
module Feature.ExtraSearchPathSpec where module Feature.ExtraSearchPathSpec where
import Network.HTTP.Types import Network.HTTP.Types
import Network.Wai (Application)
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "extra search path" $ do spec withConfig = withConfig (baseCfg { configDbExtraSearchPath = ["public", "extensions", "EXTRA \"@/\\#~_-"] }) $ describe "extra search path" $ do
it "finds the ltree <@ operator on the public schema" $ it "finds the ltree <@ operator on the public schema" $
request methodGet "/ltree_sample?path=cd.Top.Science.Astronomy" [] "" request methodGet "/ltree_sample?path=cd.Top.Science.Astronomy" [] ""
+3 -4
View File
@@ -1,15 +1,14 @@
module Feature.NoSuperuserSpec where module Feature.NoSuperuserSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Protolude import Protolude
import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "No Superuser" $ do describe "No Superuser" $ do
it "proves that the authenticator role is not a superuser" $ do it "proves that the authenticator role is not a superuser" $ do
request methodGet "/rpc/is_superuser" request methodGet "/rpc/is_superuser"
+7 -4
View File
@@ -1,15 +1,18 @@
module Feature.ObservabilitySpec where module Feature.ObservabilitySpec where
import Network.Wai (Application) import Data.CaseInsensitive (mk)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Protolude import PostgREST.Config (AppConfig (..))
spec :: SpecWith ((), Application) import Protolude
spec = import SpecHelper
spec :: SpecWithConfig
spec withConfig = withConfig (baseCfg { configServerTraceHeader = Just $ mk "X-Request-Id" }) $
describe "Observability" $ do describe "Observability" $ do
it "includes the server trace header on the response" $ do it "includes the server trace header on the response" $ do
request methodHead "/" request methodHead "/"
@@ -1,16 +1,18 @@
module Feature.OpenApi.DisabledOpenApiSpec where module Feature.OpenApi.DisabledOpenApiSpec where
import Network.HTTP.Types import Network.HTTP.Types
import Network.Wai (Application)
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import Protolude import PostgREST.Config (AppConfig (..), OpenAPIMode (..))
spec :: SpecWith ((), Application) import Protolude
spec = import SpecHelper
spec :: SpecWithConfig
spec withConfig = withConfig (baseCfg { configOpenApiMode = OADisabled }) $
describe "Disabled OpenApi" $ do describe "Disabled OpenApi" $ do
it "responds with 404" $ it "responds with 404" $
request methodGet "/" request methodGet "/"
@@ -4,19 +4,26 @@ import Control.Lens ((^?))
import Data.Aeson.Lens import Data.Aeson.Lens
import Data.Aeson.QQ import Data.Aeson.QQ
import Data.List.NonEmpty (fromList)
import Network.HTTP.Types import Network.HTTP.Types
import Network.Wai (Application)
import Network.Wai.Test (SResponse (..)) import Network.Wai.Test (SResponse (..))
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai import Test.Hspec.Wai
import PostgREST.Config (AppConfig (..), OpenAPIMode (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "OpenAPI Ignore Privileges" $ do spec withConfig = withConfig (
baseCfg {
configOpenApiMode = OAIgnorePriv
, configDbSchemas = fromList ["test", "v1"]
}
) $ describe "OpenAPI Ignore Privileges" $ do
it "root path returns a valid openapi spec" $ do it "root path returns a valid openapi spec" $ do
validateOpenApiResponse [("Accept", "application/openapi+json")] validateOpenApiResponse [("Accept", "application/openapi+json")]
request methodHead "/" request methodHead "/"
+2 -3
View File
@@ -2,7 +2,6 @@ module Feature.OpenApi.OpenApiSpec where
import Control.Lens ((^?)) import Control.Lens ((^?))
import Data.Aeson.Types (Value (..)) import Data.Aeson.Types (Value (..))
import Network.Wai (Application)
import Network.Wai.Test (SResponse (..)) import Network.Wai.Test (SResponse (..))
import Data.Aeson.Lens import Data.Aeson.Lens
@@ -15,8 +14,8 @@ import PostgREST.Version (docsVersion)
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "OpenAPI" $ do spec withConfig = withConfig baseCfg $ describe "OpenAPI" $ do
it "root path returns a valid openapi spec" $ do it "root path returns a valid openapi spec" $ do
validateOpenApiResponse [("Accept", "application/openapi+json")] validateOpenApiResponse [("Accept", "application/openapi+json")]
request methodHead "/" request methodHead "/"
+4 -3
View File
@@ -1,13 +1,14 @@
module Feature.OpenApi.ProxySpec where module Feature.OpenApi.ProxySpec where
import Network.Wai (Application)
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import PostgREST.Config (AppConfig (..))
import Protolude import Protolude
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig (baseCfg { configOpenApiServerProxyUri = Just "https://postgrest.com/openapi.json" }) $
describe "GET / with proxy" $ describe "GET / with proxy" $
it "returns a valid openapi spec with proxy" $ it "returns a valid openapi spec with proxy" $
validateOpenApiResponse [("Accept", "application/openapi+json")] validateOpenApiResponse [("Accept", "application/openapi+json")]
+7 -4
View File
@@ -1,16 +1,19 @@
module Feature.OpenApi.RootSpec where module Feature.OpenApi.RootSpec where
import Network.HTTP.Types import Network.HTTP.Types
import Network.Wai (Application)
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import Protolude hiding (get) import PostgREST.Config (AppConfig (..))
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
spec :: SpecWith ((), Application) import Protolude hiding (get)
spec = import SpecHelper
spec :: SpecWithConfig
spec withConfig = withConfig (baseCfg { configDbRootSpec = Just $ QualifiedIdentifier mempty "root" }) $
describe "root spec function" $ do describe "root spec function" $ do
it "accepts application/openapi+json" $ do it "accepts application/openapi+json" $ do
request methodGet "/" request methodGet "/"
@@ -5,16 +5,18 @@ import Control.Lens ((^?))
import Data.Aeson.Lens import Data.Aeson.Lens
import Data.Aeson.QQ import Data.Aeson.QQ
import Network.Wai (Application)
import Network.Wai.Test (SResponse (..)) import Network.Wai.Test (SResponse (..))
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai import Test.Hspec.Wai
import Protolude hiding (get) import PostgREST.Config (AppConfig (..))
spec :: SpecWith ((), Application) import Protolude hiding (get)
spec = import SpecHelper
spec :: SpecWithConfig
spec withConfig = withConfig (baseCfg { configOpenApiSecurityActive = True }) $
describe "Security active" $ describe "Security active" $
it "includes security and security definitions" $ do it "includes security and security definitions" $ do
r <- simpleBody <$> get "/" r <- simpleBody <$> get "/"
+2 -3
View File
@@ -1,6 +1,5 @@
module Feature.OptionsSpec where module Feature.OptionsSpec where
import Network.Wai (Application)
import Network.Wai.Test (SResponse (..)) import Network.Wai.Test (SResponse (..))
import Network.HTTP.Types import Network.HTTP.Types
@@ -10,8 +9,8 @@ import Test.Hspec.Wai
import Protolude import Protolude
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "Allow header" $ do spec withConfig = withConfig baseCfg $ describe "Allow header" $ do
context "a table" $ do context "a table" $ do
it "includes read/write methods for writeable table" $ do it "includes read/write methods for writeable table" $ do
r <- request methodOptions "/items" [] "" r <- request methodOptions "/items" [] ""
@@ -1,16 +1,16 @@
module Feature.Query.AggregateFunctionsSpec where module Feature.Query.AggregateFunctionsSpec where
import Network.Wai (Application)
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
allowed :: SpecWith ((), Application) allowed :: SpecWithConfig
allowed = allowed withConfig = withConfig (baseCfg { configDbAggregates = True }) $
describe "aggregate functions" $ do describe "aggregate functions" $ do
context "performing a count without specifying a field" $ do context "performing a count without specifying a field" $ do
it "returns the count of all rows when no other fields are selected" $ it "returns the count of all rows when no other fields are selected" $
@@ -306,8 +306,8 @@ allowed =
{ matchStatus = 400 { matchStatus = 400
, matchHeaders = [matchContentTypeJson] } , matchHeaders = [matchContentTypeJson] }
disallowed :: SpecWith ((), Application) disallowed :: SpecWithConfig
disallowed = disallowed withConfig = withConfig baseCfg $
describe "attempting to use an aggregate when aggregate functions are disallowed" $ do describe "attempting to use an aggregate when aggregate functions are disallowed" $ do
it "prevents the use of aggregates" $ it "prevents the use of aggregates" $
get "/project_invoices?select=invoice_total.sum()" `shouldRespondWith` get "/project_invoices?select=invoice_total.sum()" `shouldRespondWith`
+2 -4
View File
@@ -1,7 +1,5 @@
module Feature.Query.AndOrParamsSpec where module Feature.Query.AndOrParamsSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -10,8 +8,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "and/or params used for complex boolean logic" $ do describe "and/or params used for complex boolean logic" $ do
context "used with GET" $ do context "used with GET" $ do
context "or param" $ do context "or param" $ do
+2 -4
View File
@@ -1,7 +1,5 @@
module Feature.Query.ComputedRelsSpec where module Feature.Query.ComputedRelsSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -10,8 +8,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "computed relationships" $ do spec withConfig = withConfig baseCfg $ describe "computed relationships" $ do
it "can define a many-to-one relationship with SETOF and ROWS 1 and embed" $ it "can define a many-to-one relationship with SETOF and ROWS 1 and embed" $
get "/videogames?select=name,designer:computed_designers(name)" get "/videogames?select=name,designer:computed_designers(name)"
`shouldRespondWith` `shouldRespondWith`
+2 -4
View File
@@ -1,7 +1,5 @@
module Feature.Query.CustomMediaSpec where module Feature.Query.CustomMediaSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Network.Wai.Test (SResponse (simpleBody, simpleHeaders, simpleStatus)) import Network.Wai.Test (SResponse (simpleBody, simpleHeaders, simpleStatus))
import Test.Hspec import Test.Hspec
@@ -12,8 +10,8 @@ import Text.Heredoc (str)
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "custom media types" $ do spec withConfig = withConfig baseCfg $ describe "custom media types" $ do
context "for tables with aggregate" $ do context "for tables with aggregate" $ do
it "can query if there's an aggregate defined for the table" $ do it "can query if there's an aggregate defined for the table" $ do
r <- request methodGet "/lines" (acceptHdrs "application/vnd.twkb") "" r <- request methodGet "/lines" (acceptHdrs "application/vnd.twkb") ""
+2 -4
View File
@@ -1,7 +1,5 @@
module Feature.Query.DeleteSpec where module Feature.Query.DeleteSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -10,8 +8,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "Deleting" $ do describe "Deleting" $ do
context "existing record" $ do context "existing record" $ do
it "succeeds with 204 and deletion count" $ it "succeeds with 204 and deletion count" $
@@ -1,7 +1,5 @@
module Feature.Query.EmbedDisambiguationSpec where module Feature.Query.EmbedDisambiguationSpec where
import Network.Wai (Application)
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
@@ -9,8 +7,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "resource embedding disambiguation" $ do describe "resource embedding disambiguation" $ do
context "ambiguous requests that give 300 Multiple Choices" $ do context "ambiguous requests that give 300 Multiple Choices" $ do
it "errs when there are o2m and m2m cardinalities to the target table" $ it "errs when there are o2m and m2m cardinalities to the target table" $
@@ -1,7 +1,6 @@
module Feature.Query.EmbedInnerJoinSpec where module Feature.Query.EmbedInnerJoinSpec where
import Network.HTTP.Types import Network.HTTP.Types
import Network.Wai (Application)
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -10,8 +9,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "Embedding with an inner join" $ do describe "Embedding with an inner join" $ do
context "many-to-one relationships" $ do context "many-to-one relationships" $ do
it "ignores null embeddings while the default left join doesn't" $ do it "ignores null embeddings while the default left join doesn't" $ do
+2 -4
View File
@@ -1,7 +1,5 @@
module Feature.Query.ErrorSpec where module Feature.Query.ErrorSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -10,8 +8,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
pgErrorCodeMapping :: SpecWith ((), Application) pgErrorCodeMapping :: SpecWithConfig
pgErrorCodeMapping = do pgErrorCodeMapping withConfig = withConfig baseCfg $ do
describe "PostreSQL error code mappings" $ do describe "PostreSQL error code mappings" $ do
it "should return 500 for cardinality_violation" $ it "should return 500 for cardinality_violation" $
get "/bad_subquery" `shouldRespondWith` 500 get "/bad_subquery" `shouldRespondWith` 500
+2 -3
View File
@@ -1,7 +1,6 @@
module Feature.Query.InsertSpec where module Feature.Query.InsertSpec where
import Data.List (lookup) import Data.List (lookup)
import Network.Wai (Application)
import Network.Wai.Test (SResponse (simpleHeaders)) import Network.Wai.Test (SResponse (simpleHeaders))
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai.Matcher (bodyEquals) import Test.Hspec.Wai.Matcher (bodyEquals)
@@ -14,8 +13,8 @@ import Text.Heredoc
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = do spec withConfig = withConfig baseCfg $ do
describe "Posting new record" $ do describe "Posting new record" $ do
context "disparate json types" $ do context "disparate json types" $ do
it "accepts disparate json types" $ do it "accepts disparate json types" $ do
+2 -4
View File
@@ -1,7 +1,5 @@
module Feature.Query.JsonOperatorSpec where module Feature.Query.JsonOperatorSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -10,8 +8,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "json and jsonb operators" $ do spec withConfig = withConfig baseCfg $ describe "json and jsonb operators" $ do
context "Shaping response with select parameter" $ do context "Shaping response with select parameter" $ do
it "obtains a json subfield one level with casting" $ it "obtains a json subfield one level with casting" $
get "/complex_items?id=eq.1&select=settings->>foo::json" `shouldRespondWith` get "/complex_items?id=eq.1&select=settings->>foo::json" `shouldRespondWith`
@@ -3,20 +3,22 @@ module Feature.Query.MultipleSchemaSpec where
import Control.Lens ((^?)) import Control.Lens ((^?))
import Data.Aeson.Lens import Data.Aeson.Lens
import Data.Aeson.QQ import Data.Aeson.QQ
import Data.List.NonEmpty (fromList)
import Network.HTTP.Types import Network.HTTP.Types
import Network.Wai (Application)
import Network.Wai.Test (SResponse (simpleHeaders), simpleBody) import Network.Wai.Test (SResponse (simpleHeaders), simpleBody)
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude import Protolude
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig (baseCfg { configDbSchemas = fromList ["v1", "v2", "SPECIAL \"@/\\#~_-"] }) $ describe "PostGIS features" $
describe "multiple schemas in single instance" $ do describe "multiple schemas in single instance" $ do
context "Reading tables on different schemas" $ do context "Reading tables on different schemas" $ do
it "succeeds in reading table from default schema v1 if no schema is selected via header" $ it "succeeds in reading table from default schema v1 if no schema is selected via header" $
+2 -4
View File
@@ -1,7 +1,5 @@
module Feature.Query.NullsStripSpec where module Feature.Query.NullsStripSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -10,8 +8,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "Stripping null values from JSON response" $ do describe "Stripping null values from JSON response" $ do
let arrayStrip = ("Accept", "application/vnd.pgrst.array+json;nulls=stripped") let arrayStrip = ("Accept", "application/vnd.pgrst.array+json;nulls=stripped")
let singularStrip = ("Accept", "application/vnd.pgrst.object+json;nulls=stripped") let singularStrip = ("Accept", "application/vnd.pgrst.object+json;nulls=stripped")
+9 -7
View File
@@ -1,16 +1,18 @@
module Feature.Query.PgSafeUpdateSpec where module Feature.Query.PgSafeUpdateSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import Protolude hiding (get, put) import PostgREST.Config (AppConfig (..))
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
spec :: SpecWith ((), Application) import Protolude hiding (get, put)
spec = import SpecHelper
spec :: SpecWithConfig
spec withConfig = withConfig (baseCfg { configDbPreRequest = Just $ QualifiedIdentifier "test" "load_safeupdate" }) $
describe "Enabling pg-safeupdate" $ do describe "Enabling pg-safeupdate" $ do
context "Full table update" $ do context "Full table update" $ do
it "does not update and throws error if no condition is present" $ it "does not update and throws error if no condition is present" $
@@ -48,8 +50,8 @@ spec =
`shouldRespondWith` `shouldRespondWith`
204 204
disabledSpec :: SpecWith ((), Application) disabledSpec :: SpecWithConfig
disabledSpec = disabledSpec withConfig = withConfig baseCfg $
describe "Disabling pg-safeupdate" $ do describe "Disabling pg-safeupdate" $ do
context "Full table update" $ do context "Full table update" $ do
it "works if no condition is present" $ it "works if no condition is present" $
+6 -5
View File
@@ -3,7 +3,6 @@
module Feature.Query.PlanSpec where module Feature.Query.PlanSpec where
import Control.Lens ((^?)) import Control.Lens ((^?))
import Network.Wai (Application)
import Network.Wai.Test (SResponse (..)) import Network.Wai.Test (SResponse (..))
import Data.Aeson.Lens import Data.Aeson.Lens
@@ -15,11 +14,13 @@ import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = do spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $ do
describe "read table/view plan" $ do describe "read table/view plan" $ do
it "outputs the total cost for a single filter on a table" $ do it "outputs the total cost for a single filter on a table" $ do
r <- request methodGet "/projects?id=in.(1,2,3)" r <- request methodGet "/projects?id=in.(1,2,3)"
@@ -529,8 +530,8 @@ spec = do
totalCost `shouldSatisfy` (> 67.0) totalCost `shouldSatisfy` (> 67.0)
aggregateQty `shouldSatisfy` (> 1) aggregateQty `shouldSatisfy` (> 1)
disabledSpec :: SpecWith ((), Application) disabledSpec :: SpecWithConfig
disabledSpec = disabledSpec withConfig = withConfig baseCfg $
it "doesn't work if db-plan-enabled=false(the default)" $ do it "doesn't work if db-plan-enabled=false(the default)" $ do
request methodGet "/projects?id=in.(1,2,3)" request methodGet "/projects?id=in.(1,2,3)"
(acceptHdrs "application/vnd.pgrst.plan") "" (acceptHdrs "application/vnd.pgrst.plan") ""
+4 -4
View File
@@ -1,17 +1,17 @@
module Feature.Query.PostGISSpec where module Feature.Query.PostGISSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "PostGIS features" $ spec withConfig = withConfig (baseCfg { configDbExtraSearchPath = ["public", "extensions", "EXTRA \"@/\\#~_-"] }) $ describe "PostGIS features" $
context "GeoJSON output" $ do context "GeoJSON output" $ do
it "works for a table that has a geometry column" $ it "works for a table that has a geometry column" $
request methodGet "/shops" request methodGet "/shops"
@@ -1,7 +1,5 @@
module Feature.Query.Preferences.HandlingSpec where module Feature.Query.Preferences.HandlingSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -10,8 +8,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "test Prefer: handling" $ do describe "test Prefer: handling" $ do
context "check behaviour of Prefer: handling=strict" $ do context "check behaviour of Prefer: handling=strict" $ do
it "throws error when handling=strict and invalid prefs are given" $ it "throws error when handling=strict and invalid prefs are given" $
@@ -1,17 +1,15 @@
module Feature.Query.Preferences.MaxAffectedSpec where module Feature.Query.Preferences.MaxAffectedSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $ describe "test Prefer: max-affected" $ do
describe "test Prefer: max-affected" $ do
context "test Prefer: max-affected with handling=strict" $ do context "test Prefer: max-affected with handling=strict" $ do
it "should fail if items deleted more than 10" $ it "should fail if items deleted more than 10" $
request methodDelete "/items?id=lt.15" request methodDelete "/items?id=lt.15"
@@ -1,18 +1,17 @@
module Feature.Query.Preferences.TimezoneSpec where module Feature.Query.Preferences.TimezoneSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
enabledSpec :: SpecWith ((), Application) enabledSpec :: SpecWithConfig
enabledSpec = enabledSpec withConfig = withConfig baseCfg $ describe "test Prefer: timezone with db-timezone-enabled is true" $ do
describe "test Prefer: timezone with db-timezone-enabled is true" $ do
context "test Prefer: timezone=America/Los_Angeles" $ do context "test Prefer: timezone=America/Los_Angeles" $ do
it "should change timezone with handling=strict" $ it "should change timezone with handling=strict" $
request methodGet "/timestamps" request methodGet "/timestamps"
@@ -62,8 +61,8 @@ enabledSpec =
, "Preference-Applied" <:> "handling=lenient"]} , "Preference-Applied" <:> "handling=lenient"]}
disabledSpec :: SpecWith ((), Application) disabledSpec :: SpecWithConfig
disabledSpec = disabledSpec withConfig = withConfig (baseCfg { configDbTimezoneEnabled = False }) $
describe "test Prefer: timezone with db-timezone-enabled is false" $ do describe "test Prefer: timezone with db-timezone-enabled is false" $ do
context "test Prefer: timezone=America/Los_Angeles when timezone is disabled" $ do context "test Prefer: timezone=America/Los_Angeles when timezone is disabled" $ do
it "should throw error with handling=strict" $ it "should throw error with handling=strict" $
+4 -4
View File
@@ -1,17 +1,17 @@
module Feature.Query.QueryLimitedSpec where module Feature.Query.QueryLimitedSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig (baseCfg { configDbMaxRows = Just 2 }) $
describe "Requesting many items with server limits(max-rows) enabled" $ do describe "Requesting many items with server limits(max-rows) enabled" $ do
it "restricts results" $ it "restricts results" $
get "/items?order=id" get "/items?order=id"
+2 -3
View File
@@ -1,6 +1,5 @@
module Feature.Query.QuerySpec where module Feature.Query.QuerySpec where
import Network.Wai (Application)
import Network.Wai.Test (SResponse (simpleHeaders)) import Network.Wai.Test (SResponse (simpleHeaders))
import Network.HTTP.Types import Network.HTTP.Types
@@ -11,8 +10,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = do spec withConfig = withConfig baseCfg $ do
describe "Querying a table with a column called count" $ describe "Querying a table with a column called count" $
it "should not confuse count column with pg_catalog.count aggregate" $ it "should not confuse count column with pg_catalog.count aggregate" $
+2 -3
View File
@@ -1,6 +1,5 @@
module Feature.Query.RangeSpec where module Feature.Query.RangeSpec where
import Network.Wai (Application)
import Network.Wai.Test (SResponse (simpleHeaders, simpleStatus)) import Network.Wai.Test (SResponse (simpleHeaders, simpleStatus))
import Network.HTTP.Types import Network.HTTP.Types
@@ -11,8 +10,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = do spec withConfig = withConfig baseCfg $ do
describe "GET /rpc/getitemrange" $ do describe "GET /rpc/getitemrange" $ do
context "without range headers" $ do context "without range headers" $ do
context "with response under server size limit" $ context "with response under server size limit" $
@@ -1,17 +1,15 @@
module Feature.Query.RawOutputTypesSpec where module Feature.Query.RawOutputTypesSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import Protolude import Protolude
import SpecHelper (acceptHdrs) import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "When raw-media-types config variable is missing or left empty" $ do spec withConfig = withConfig baseCfg $ describe "When raw-media-types config variable is missing or left empty" $ do
let firefoxAcceptHdrs = acceptHdrs "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" let firefoxAcceptHdrs = acceptHdrs "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
chromeAcceptHdrs = acceptHdrs "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3" chromeAcceptHdrs = acceptHdrs "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3"
it "responds json to a GET request with Firefox Accept headers" $ it "responds json to a GET request with Firefox Accept headers" $
@@ -1,7 +1,5 @@
module Feature.Query.RelatedQueriesSpec where module Feature.Query.RelatedQueriesSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -10,8 +8,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = describe "related queries" $ do spec withConfig = withConfig baseCfg $ describe "related queries" $ do
context "related orders" $ do context "related orders" $ do
it "works on a many-to-one relationship" $ do it "works on a many-to-one relationship" $ do
get "/projects?select=id,clients(name)&order=clients(name).nullsfirst" `shouldRespondWith` get "/projects?select=id,clients(name)&order=clients(name).nullsfirst" `shouldRespondWith`
+2 -3
View File
@@ -2,7 +2,6 @@ module Feature.Query.RpcSpec where
import qualified Data.ByteString.Lazy as BL (empty) import qualified Data.ByteString.Lazy as BL (empty)
import Network.Wai (Application)
import Network.Wai.Test (SResponse (simpleBody, simpleHeaders, simpleStatus)) import Network.Wai.Test (SResponse (simpleBody, simpleHeaders, simpleStatus))
import Network.HTTP.Types import Network.HTTP.Types
@@ -16,8 +15,8 @@ import PostgREST.Config.PgVersion (PgVersion, pgVersion180)
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: PgVersion -> SpecWith ((), Application) spec :: PgVersion -> SpecWithConfig
spec actualPgVersion = spec actualPgVersion withConfig = withConfig baseCfg $
describe "remote procedure call" $ do describe "remote procedure call" $ do
context "a proc that returns a set" $ do context "a proc that returns a set" $ do
context "returns paginated results" $ do context "returns paginated results" $ do
+4 -4
View File
@@ -1,17 +1,17 @@
module Feature.Query.ServerTimingSpec where module Feature.Query.ServerTimingSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig (baseCfg { configDbPlanEnabled = True }) $
describe "Show Duration on Server-Timing header" $ do describe "Show Duration on Server-Timing header" $ do
context "responds with Server-Timing header" $ do context "responds with Server-Timing header" $ do
+2 -3
View File
@@ -1,6 +1,5 @@
module Feature.Query.SingularSpec where module Feature.Query.SingularSpec where
import Network.Wai (Application)
import Network.Wai.Test (SResponse (..)) import Network.Wai.Test (SResponse (..))
import Network.HTTP.Types import Network.HTTP.Types
@@ -11,8 +10,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "Requesting singular json object" $ do describe "Requesting singular json object" $ do
let singular = ("Accept", "application/vnd.pgrst.object+json") let singular = ("Accept", "application/vnd.pgrst.object+json")
+2 -4
View File
@@ -1,7 +1,5 @@
module Feature.Query.SpreadQueriesSpec where module Feature.Query.SpreadQueriesSpec where
import Network.Wai (Application)
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
@@ -9,8 +7,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "spread embeds" $ do describe "spread embeds" $ do
it "works on a many-to-one relationship" $ do it "works on a many-to-one relationship" $ do
get "/projects?select=id,...clients(client_name:name)" `shouldRespondWith` get "/projects?select=id,...clients(client_name:name)" `shouldRespondWith`
+5 -4
View File
@@ -1,17 +1,18 @@
module Feature.Query.UnicodeSpec where module Feature.Query.UnicodeSpec where
import Network.Wai (Application) import Data.List.NonEmpty (fromList)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig (baseCfg { configDbSchemas = fromList ["تست"] }) $
describe "Reading and writing to unicode schema and table names" $ describe "Reading and writing to unicode schema and table names" $
it "Can read and write values" $ do it "Can read and write values" $ do
get "/%D9%85%D9%88%D8%A7%D8%B1%D8%AF" get "/%D9%85%D9%88%D8%A7%D8%B1%D8%AF"
+2 -3
View File
@@ -1,6 +1,5 @@
module Feature.Query.UpdateSpec where module Feature.Query.UpdateSpec where
import Network.Wai (Application)
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import Network.HTTP.Types import Network.HTTP.Types
@@ -10,8 +9,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = do spec withConfig = withConfig baseCfg $ do
describe "Patching record" $ do describe "Patching record" $ do
context "to unknown uri" $ context "to unknown uri" $
it "indicates no table found by returning 404" $ it "indicates no table found by returning 404" $
+2 -4
View File
@@ -3,8 +3,6 @@
-- - Upsert/IgnoreDuplicates.hs -- - Upsert/IgnoreDuplicates.hs
module Feature.Query.UpsertSpec where module Feature.Query.UpsertSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
@@ -13,8 +11,8 @@ import Test.Hspec.Wai.JSON
import Protolude hiding (get, put) import Protolude hiding (get, put)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig baseCfg $
describe "UPSERT" $ do describe "UPSERT" $ do
context "with POST" $ do context "with POST" $ do
context "when Prefer: resolution=merge-duplicates is specified" $ do context "when Prefer: resolution=merge-duplicates is specified" $ do
+18 -8
View File
@@ -1,12 +1,12 @@
module Feature.RollbackSpec where module Feature.RollbackSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import Protolude hiding (get) import Protolude hiding (get)
import SpecHelper import SpecHelper
@@ -211,8 +211,8 @@ shouldNotPersistMutations reqHeaders respHeaders = do
`shouldRespondWith` `shouldRespondWith`
[json|[{"id":1}]|] [json|[{"id":1}]|]
allowed :: SpecWith ((), Application) allowed :: SpecWithConfig
allowed = describe "tx-allow-override = true" $ do allowed withConfig = withConfig baseCfg $ describe "tx-allow-override = true" $ do
describe "without Prefer tx" $ do describe "without Prefer tx" $ do
preferDefault `shouldRespondToReads` withoutPreferenceApplied preferDefault `shouldRespondToReads` withoutPreferenceApplied
preferDefault `shouldNotPersistMutations` withoutPreferenceApplied preferDefault `shouldNotPersistMutations` withoutPreferenceApplied
@@ -232,8 +232,13 @@ allowed = describe "tx-allow-override = true" $ do
-- because they return before the end of the transaction. -- because they return before the end of the transaction.
preferRollback `shouldRaiseExceptions` withoutPreferenceApplied preferRollback `shouldRaiseExceptions` withoutPreferenceApplied
disallowed :: SpecWith ((), Application) disallowed :: SpecWithConfig
disallowed = describe "tx-rollback-all = false, tx-allow-override = false" $ do disallowed withConfig = withConfig (
baseCfg {
configDbTxAllowOverride = False
, configDbTxRollbackAll = False
}
) $ describe "tx-rollback-all = false, tx-allow-override = false" $ do
describe "without Prefer tx" $ do describe "without Prefer tx" $ do
preferDefault `shouldRespondToReads` withoutPreferenceApplied preferDefault `shouldRespondToReads` withoutPreferenceApplied
preferDefault `shouldPersistMutations` withoutPreferenceApplied preferDefault `shouldPersistMutations` withoutPreferenceApplied
@@ -250,8 +255,13 @@ disallowed = describe "tx-rollback-all = false, tx-allow-override = false" $ do
preferRollback `shouldRaiseExceptions` withoutPreferenceApplied preferRollback `shouldRaiseExceptions` withoutPreferenceApplied
forced :: SpecWith ((), Application) forced :: SpecWithConfig
forced = describe "tx-rollback-all = true, tx-allow-override = false" $ do forced withConfig = withConfig (
baseCfg {
configDbTxAllowOverride = False
, configDbTxRollbackAll = True
}
) $ describe "tx-rollback-all = true, tx-allow-override = false" $ do
describe "without Prefer tx" $ do describe "without Prefer tx" $ do
preferDefault `shouldRespondToReads` withoutPreferenceApplied preferDefault `shouldRespondToReads` withoutPreferenceApplied
preferDefault `shouldNotPersistMutations` withoutPreferenceApplied preferDefault `shouldNotPersistMutations` withoutPreferenceApplied
+5 -4
View File
@@ -1,17 +1,18 @@
module Feature.RpcPreRequestGucsSpec where module Feature.RpcPreRequestGucsSpec where
import Network.Wai (Application)
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec hiding (pendingWith) import Test.Hspec hiding (pendingWith)
import Test.Hspec.Wai import Test.Hspec.Wai
import Test.Hspec.Wai.JSON import Test.Hspec.Wai.JSON
import PostgREST.Config (AppConfig (..))
import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..))
import Protolude hiding (get, put) import Protolude hiding (get, put)
import SpecHelper import SpecHelper
spec :: SpecWith ((), Application) spec :: SpecWithConfig
spec = spec withConfig = withConfig (baseCfg { configDbPreRequest = Just $ QualifiedIdentifier mempty "custom_headers" }) $
describe "GUC headers on all methods via pre-request" $ do describe "GUC headers on all methods via pre-request" $ do
it "succeeds setting the headers on POST" $ it "succeeds setting the headers on POST" $
post "/items" post "/items"
+34 -130
View File
@@ -79,15 +79,15 @@ main = do
, P.acquisitionTimeout 10 , P.acquisitionTimeout 10
, P.agingTimeout 60 , P.agingTimeout 60
, P.idlenessTimeout 60 , P.idlenessTimeout 60
, P.staticConnectionSettings $ toConnectionSettings identity testCfg , P.staticConnectionSettings $ toConnectionSettings identity baseCfg
] ]
actualPgVersion <- either (panic . show) id <$> P.use pool queryPgVersion actualPgVersion <- either (panic . show) id <$> P.use pool queryPgVersion
-- cached schema cache so most tests run fast -- cached schema cache so most tests run fast
baseSchemaCache <- loadSCache pool testCfg baseSchemaCache <- loadSCache pool baseCfg
loggerState <- Logger.init loggerState <- Logger.init
metricsState <- Metrics.init (configDbPoolSize testCfg) metricsState <- Metrics.init (configDbPoolSize baseCfg)
let let
initApp sCache config = do initApp sCache config = do
@@ -104,42 +104,29 @@ main = do
customSchemaCache <- loadSCache pool config customSchemaCache <- loadSCache pool config
initApp customSchemaCache config initApp customSchemaCache config
let withApp = app testCfg withConfig config = before (app config)
maxRowsApp = app testMaxRowsCfg withConfigDbs config = before (appDbs config)
disabledOpenApi = app testDisabledOpenApiCfg describeWithConfig label spec = describe label $ spec withConfig
securityOpenApi = app testSecurityOpenApiCfg
proxyApp = app testProxyCfg
noAnonApp = app testCfgNoAnon
noJwtSecretApp = app testCfgNoJwtSecret
binaryJwtApp = app testCfgBinaryJWT
audJwtApp = app testCfgAudienceJWT
asymJwkApp = app testCfgAsymJWK
asymJwkSetApp = app testCfgAsymJWKSet
rootSpecApp = app testCfgRootSpec
responseHeadersApp = app testCfgResponseHeaders
disallowRollbackApp = app testCfgDisallowRollback
forceRollbackApp = app testCfgForceRollback
planEnabledApp = app testPlanEnabledCfg
pgSafeUpdateApp = app testPgSafeUpdateEnabledCfg
obsApp = app testObservabilityCfg
serverTiming = app testCfgServerTiming
aggregatesEnabled = app testCfgAggregatesEnabled
extraSearchPathApp = appDbs testCfgExtraSearchPath let specs = uncurry describeWithConfig <$> [
unicodeApp = appDbs testUnicodeCfg ("Feature.Auth.AsymmetricJwtSpec" , Feature.Auth.AsymmetricJwtSpec.spec)
multipleSchemaApp = appDbs testMultipleSchemaCfg , ("Feature.Auth.AudienceJwtSecretSpec" , Feature.Auth.AudienceJwtSecretSpec.disabledSpec)
ignorePrivOpenApi = appDbs testIgnorePrivOpenApiCfg , ("Feature.Auth.AudienceJwtSecretSpec" , Feature.Auth.AudienceJwtSecretSpec.spec)
timezoneDisabled = appDbs testCfgTimezoneDisabled
let specs = uncurry describe <$> [
("Feature.Auth.AudienceJwtSecretSpec" , Feature.Auth.AudienceJwtSecretSpec.disabledSpec)
, ("Feature.Auth.AuthSpec" , Feature.Auth.AuthSpec.spec) , ("Feature.Auth.AuthSpec" , Feature.Auth.AuthSpec.spec)
, ("Feature.Auth.BinaryJwtSecretSpec" , Feature.Auth.BinaryJwtSecretSpec.spec)
, ("Feature.Auth.NoAnonSpec" , Feature.Auth.NoAnonSpec.spec)
, ("Feature.Auth.NoJwtSecretSpec" , Feature.Auth.NoJwtSecretSpec.spec)
, ("Feature.ConcurrentSpec" , Feature.ConcurrentSpec.spec) , ("Feature.ConcurrentSpec" , Feature.ConcurrentSpec.spec)
, ("Feature.CorsSpec" , Feature.CorsSpec.spec) , ("Feature.CorsSpec" , Feature.CorsSpec.spec)
, ("Feature.NoSuperuserSpec" , Feature.NoSuperuserSpec.spec) , ("Feature.NoSuperuserSpec" , Feature.NoSuperuserSpec.spec)
, ("Feature.ObservabilitySpec" , Feature.ObservabilitySpec.spec)
, ("Feature.OpenApi.DisabledOpenApiSpec" , Feature.OpenApi.DisabledOpenApiSpec.spec)
, ("Feature.OpenApi.OpenApiSpec" , Feature.OpenApi.OpenApiSpec.spec) , ("Feature.OpenApi.OpenApiSpec" , Feature.OpenApi.OpenApiSpec.spec)
, ("Feature.OpenApi.ProxySpec" , Feature.OpenApi.ProxySpec.spec)
, ("Feature.OpenApi.RootSpec" , Feature.OpenApi.RootSpec.spec)
, ("Feature.OpenApi.SecurityOpenApiSpec" , Feature.OpenApi.SecurityOpenApiSpec.spec)
, ("Feature.OptionsSpec" , Feature.OptionsSpec.spec) , ("Feature.OptionsSpec" , Feature.OptionsSpec.spec)
, ("Feature.Query.AggregateFunctionsSpec.allowed" , Feature.Query.AggregateFunctionsSpec.allowed)
, ("Feature.Query.AggregateFunctionsSpec.disallowed" , Feature.Query.AggregateFunctionsSpec.disallowed) , ("Feature.Query.AggregateFunctionsSpec.disallowed" , Feature.Query.AggregateFunctionsSpec.disallowed)
, ("Feature.Query.AndOrParamsSpec" , Feature.Query.AndOrParamsSpec.spec) , ("Feature.Query.AndOrParamsSpec" , Feature.Query.AndOrParamsSpec.spec)
, ("Feature.Query.ComputedRelsSpec" , Feature.Query.ComputedRelsSpec.spec) , ("Feature.Query.ComputedRelsSpec" , Feature.Query.ComputedRelsSpec.spec)
@@ -153,126 +140,43 @@ main = do
, ("Feature.Query.NullsStripSpec" , Feature.Query.NullsStripSpec.spec) , ("Feature.Query.NullsStripSpec" , Feature.Query.NullsStripSpec.spec)
, ("Feature.Query.PgSafeUpdateSpec.disabledSpec" , Feature.Query.PgSafeUpdateSpec.disabledSpec) , ("Feature.Query.PgSafeUpdateSpec.disabledSpec" , Feature.Query.PgSafeUpdateSpec.disabledSpec)
, ("Feature.Query.PlanSpec.disabledSpec" , Feature.Query.PlanSpec.disabledSpec) , ("Feature.Query.PlanSpec.disabledSpec" , Feature.Query.PlanSpec.disabledSpec)
, ("Feature.Query.PlanSpec.spec" , Feature.Query.PlanSpec.spec)
, ("Feature.Query.Preferences.HandlingSpec" , Feature.Query.Preferences.HandlingSpec.spec) , ("Feature.Query.Preferences.HandlingSpec" , Feature.Query.Preferences.HandlingSpec.spec)
, ("Feature.Query.Preferences.MaxAffectedSpec" , Feature.Query.Preferences.MaxAffectedSpec.spec) , ("Feature.Query.Preferences.MaxAffectedSpec" , Feature.Query.Preferences.MaxAffectedSpec.spec)
, ("Feature.Query.Preferences.TimezoneSpec.enabledSpec", Feature.Query.Preferences.TimezoneSpec.enabledSpec) , ("Feature.Query.Preferences.TimezoneSpec.enabledSpec", Feature.Query.Preferences.TimezoneSpec.enabledSpec)
, ("Feature.Query.QueryLimitedSpec" , Feature.Query.QueryLimitedSpec.spec)
, ("Feature.Query.QuerySpec" , Feature.Query.QuerySpec.spec) , ("Feature.Query.QuerySpec" , Feature.Query.QuerySpec.spec)
, ("Feature.Query.RangeSpec" , Feature.Query.RangeSpec.spec) , ("Feature.Query.RangeSpec" , Feature.Query.RangeSpec.spec)
, ("Feature.Query.RawOutputTypesSpec" , Feature.Query.RawOutputTypesSpec.spec) , ("Feature.Query.RawOutputTypesSpec" , Feature.Query.RawOutputTypesSpec.spec)
, ("Feature.Query.RelatedQueriesSpec" , Feature.Query.RelatedQueriesSpec.spec) , ("Feature.Query.RelatedQueriesSpec" , Feature.Query.RelatedQueriesSpec.spec)
, ("Feature.Query.RpcSpec" , Feature.Query.RpcSpec.spec actualPgVersion) , ("Feature.Query.RpcSpec" , Feature.Query.RpcSpec.spec actualPgVersion)
, ("Feature.Query.ServerTimingSpec" , Feature.Query.ServerTimingSpec.spec)
, ("Feature.Query.SingularSpec" , Feature.Query.SingularSpec.spec) , ("Feature.Query.SingularSpec" , Feature.Query.SingularSpec.spec)
, ("Feature.Query.SpreadQueriesSpec" , Feature.Query.SpreadQueriesSpec.spec) , ("Feature.Query.SpreadQueriesSpec" , Feature.Query.SpreadQueriesSpec.spec)
, ("Feature.Query.UpdateSpec" , Feature.Query.UpdateSpec.spec) , ("Feature.Query.UpdateSpec" , Feature.Query.UpdateSpec.spec)
, ("Feature.Query.UpsertSpec" , Feature.Query.UpsertSpec.spec) , ("Feature.Query.UpsertSpec" , Feature.Query.UpsertSpec.spec)
, ("Feature.RpcPreRequestGucsSpec" , Feature.RpcPreRequestGucsSpec.spec)
] ]
hspec $ do hspec $ do
mapM_ (parallel . before withApp) specs mapM_ parallel specs
-- this test runs with a different server flag
parallel $ before maxRowsApp $
describe "Feature.Query.QueryLimitedSpec" Feature.Query.QueryLimitedSpec.spec
-- this test runs with a different schema
parallel $ before unicodeApp $
describe "Feature.Query.UnicodeSpec" Feature.Query.UnicodeSpec.spec
-- this test runs with openapi-mode set to disabled
parallel $ before disabledOpenApi $
describe "Feature.DisabledOpenApiSpec" Feature.OpenApi.DisabledOpenApiSpec.spec
-- this test runs with openapi-mode set to ignore-acl
parallel $ before ignorePrivOpenApi $
describe "Feature.OpenApi.IgnorePrivOpenApiSpec" Feature.OpenApi.IgnorePrivOpenApiSpec.spec
-- this test runs with a proxy
parallel $ before proxyApp $
describe "Feature.OpenApi.ProxySpec" Feature.OpenApi.ProxySpec.spec
-- this test runs with openapi-security-active set to true
parallel $ before securityOpenApi $
describe "Feature.OpenApi.SecurityOpenApiSpec" Feature.OpenApi.SecurityOpenApiSpec.spec
-- this test runs without an anonymous role
parallel $ before noAnonApp $
describe "Feature.Auth.NoAnonSpec" Feature.Auth.NoAnonSpec.spec
-- this test runs without a JWT secret
parallel $ before noJwtSecretApp $
describe "Feature.Auth.NoJwtSecretSpec" Feature.Auth.NoJwtSecretSpec.spec
-- this test runs with a binary JWT secret
parallel $ before binaryJwtApp $
describe "Feature.Auth.BinaryJwtSecretSpec" Feature.Auth.BinaryJwtSecretSpec.spec
-- this test runs with a binary JWT secret and an audience claim
parallel $ before audJwtApp $
describe "Feature.Auth.AudienceJwtSecretSpec" Feature.Auth.AudienceJwtSecretSpec.spec
-- this test runs with asymmetric JWK
parallel $ before asymJwkApp $
describe "Feature.Auth.AsymmetricJwtSpec" Feature.Auth.AsymmetricJwtSpec.spec
-- this test runs with asymmetric JWKSet
parallel $ before asymJwkSetApp $
describe "Feature.Auth.AsymmetricJwtSpec" Feature.Auth.AsymmetricJwtSpec.spec
-- this test runs with an extra search path
parallel $ before extraSearchPathApp $ do
describe "Feature.ExtraSearchPathSpec" Feature.ExtraSearchPathSpec.spec
describe "Feature.Query.PostGISSpec" Feature.Query.PostGISSpec.spec
-- this test runs with a root spec function override
parallel $ before rootSpecApp $
describe "Feature.OpenApi.RootSpec" Feature.OpenApi.RootSpec.spec
-- this test runs with a pre request function override
parallel $ before responseHeadersApp $
describe "Feature.RpcPreRequestGucsSpec" Feature.RpcPreRequestGucsSpec.spec
-- this test runs with multiple schemas
parallel $ before multipleSchemaApp $
describe "Feature.Query.MultipleSchemaSpec" Feature.Query.MultipleSchemaSpec.spec
-- this test runs with db-plan-enabled = true
parallel $ before planEnabledApp $
describe "Feature.Query.PlanSpec.spec" Feature.Query.PlanSpec.spec
-- this test runs with server-trace-header set
parallel $ before obsApp $
describe "Feature.ObservabilitySpec.spec" Feature.ObservabilitySpec.spec
parallel $ before serverTiming $
describe "Feature.Query.ServerTimingSpec.spec" Feature.Query.ServerTimingSpec.spec
parallel $ before aggregatesEnabled $
describe "Feature.Query.AggregateFunctionsSpec" Feature.Query.AggregateFunctionsSpec.allowed
-- this test runs with db-timezone-enabled = false
parallel $ before timezoneDisabled $
describe "Feature.Query.Preferences.TimezoneSpec.disabledSpec" Feature.Query.Preferences.TimezoneSpec.disabledSpec
parallel $ describe "Feature.Query.UnicodeSpec" $ Feature.Query.UnicodeSpec.spec withConfigDbs
parallel $ describe "Feature.OpenApi.IgnorePrivOpenApiSpec" $ Feature.OpenApi.IgnorePrivOpenApiSpec.spec withConfigDbs
parallel $ describe "Feature.ExtraSearchPathSpec" $ Feature.ExtraSearchPathSpec.spec withConfigDbs
parallel $ describe "Feature.Query.PostGISSpec" $ Feature.Query.PostGISSpec.spec withConfigDbs
parallel $ describe "Feature.Query.MultipleSchemaSpec" $ Feature.Query.MultipleSchemaSpec.spec withConfigDbs
parallel $ describe "Feature.Query.Preferences.TimezoneSpec.disabledSpec" $ Feature.Query.Preferences.TimezoneSpec.disabledSpec withConfigDbs
-- Note: the rollback tests can not run in parallel, because they test persistence and -- Note: the rollback tests can not run in parallel, because they test persistence and
-- this results in race conditions -- this results in race conditions
describe "Feature.RollbackAllowedSpec" $ Feature.RollbackSpec.allowed withConfig
-- this test runs with tx-rollback-all = true and tx-allow-override = true describe "Feature.RollbackDisallowedSpec" $ Feature.RollbackSpec.disallowed withConfig
before withApp $ describe "Feature.RollbackForcedSpec" $ Feature.RollbackSpec.forced withConfig
describe "Feature.RollbackAllowedSpec" Feature.RollbackSpec.allowed
-- this test runs with tx-rollback-all = false and tx-allow-override = false
before disallowRollbackApp $
describe "Feature.RollbackDisallowedSpec" Feature.RollbackSpec.disallowed
-- this test runs with tx-rollback-all = true and tx-allow-override = false
before forceRollbackApp $
describe "Feature.RollbackForcedSpec" Feature.RollbackSpec.forced
-- This test runs with a pre request to enable the pg-safeupdate library per-session. -- This test runs with a pre request to enable the pg-safeupdate library per-session.
-- This needs to run last, because once pg safe update is loaded, it can't be unloaded again. -- This needs to run last, because once pg safe update is loaded, it can't be unloaded again.
before pgSafeUpdateApp $ describe "Feature.Query.PgSafeUpdateSpec.spec" $ Feature.Query.PgSafeUpdateSpec.spec withConfig
describe "Feature.Query.PgSafeUpdateSpec.spec" Feature.Query.PgSafeUpdateSpec.spec
where where
loadSCache pool conf = loadSCache pool conf =
+3 -96
View File
@@ -14,9 +14,10 @@ import qualified Jose.Jws as JWT
import qualified Jose.Jwt as JWT import qualified Jose.Jwt as JWT
import Data.Aeson ((.=)) import Data.Aeson ((.=))
import Data.CaseInsensitive (CI (..), mk, original) import Data.CaseInsensitive (CI (..), original)
import Data.List (lookup) import Data.List (lookup)
import Data.List.NonEmpty (fromList) import Data.List.NonEmpty (fromList)
import Network.Wai (Application)
import Network.Wai.Test (SResponse (simpleBody, simpleHeaders, simpleStatus)) import Network.Wai.Test (SResponse (simpleBody, simpleHeaders, simpleStatus))
import System.IO.Unsafe (unsafePerformIO) import System.IO.Unsafe (unsafePerformIO)
import Text.Regex.TDFA ((=~)) import Text.Regex.TDFA ((=~))
@@ -25,7 +26,6 @@ import Text.Regex.TDFA ((=~))
import Network.HTTP.Types import Network.HTTP.Types
import Test.Hspec import Test.Hspec
import Test.Hspec.Wai import Test.Hspec.Wai
import Text.Heredoc
import Data.String (String) import Data.String (String)
import PostgREST.Config (AppConfig (..), import PostgREST.Config (AppConfig (..),
@@ -106,6 +106,7 @@ validateOpenApiResponse headers = do
, matchHeaders = [] , matchHeaders = []
} }
type SpecWithConfig = (AppConfig -> SpecWith ((), Application) -> Spec) -> Spec
baseCfg :: AppConfig baseCfg :: AppConfig
baseCfg = let secret = encodeUtf8 "reallyreallyreallyreallyverysafe" in baseCfg = let secret = encodeUtf8 "reallyreallyreallyreallyverysafe" in
@@ -161,100 +162,6 @@ baseCfg = let secret = encodeUtf8 "reallyreallyreallyreallyverysafe" in
, configServerTimingEnabled = True , configServerTimingEnabled = True
} }
testCfg :: AppConfig
testCfg = baseCfg
testCfgDisallowRollback :: AppConfig
testCfgDisallowRollback = baseCfg { configDbTxAllowOverride = False, configDbTxRollbackAll = False }
testCfgForceRollback :: AppConfig
testCfgForceRollback = baseCfg { configDbTxAllowOverride = False, configDbTxRollbackAll = True }
testCfgNoAnon :: AppConfig
testCfgNoAnon = baseCfg { configDbAnonRole = Nothing }
testCfgNoJwtSecret :: AppConfig
testCfgNoJwtSecret = baseCfg { configJwtSecret = Nothing, configJWKS = Nothing }
testUnicodeCfg :: AppConfig
testUnicodeCfg = baseCfg { configDbSchemas = fromList ["تست"] }
testMaxRowsCfg :: AppConfig
testMaxRowsCfg = baseCfg { configDbMaxRows = Just 2 }
testDisabledOpenApiCfg :: AppConfig
testDisabledOpenApiCfg = baseCfg { configOpenApiMode = OADisabled }
testIgnorePrivOpenApiCfg :: AppConfig
testIgnorePrivOpenApiCfg = baseCfg { configOpenApiMode = OAIgnorePriv, configDbSchemas = fromList ["test", "v1"] }
testProxyCfg :: AppConfig
testProxyCfg = baseCfg { configOpenApiServerProxyUri = Just "https://postgrest.com/openapi.json" }
testSecurityOpenApiCfg :: AppConfig
testSecurityOpenApiCfg = baseCfg { configOpenApiSecurityActive = True }
testPlanEnabledCfg :: AppConfig
testPlanEnabledCfg = baseCfg { configDbPlanEnabled = True }
testCfgBinaryJWT :: AppConfig
testCfgBinaryJWT =
baseCfg {
configJwtSecret = Just generateSecret
, configJWKS = rightToMaybe $ parseSecret generateSecret
}
testCfgAudienceJWT :: AppConfig
testCfgAudienceJWT =
baseCfg {
configJwtSecret = Just generateSecret
, configJwtAudience = Just "youraudience"
, configJWKS = rightToMaybe $ parseSecret generateSecret
}
testCfgAsymJWK :: AppConfig
testCfgAsymJWK =
let secret = encodeUtf8 [str|{"alg":"RS256","e":"AQAB","key_ops":["verify"],"kty":"RSA","n":"0etQ2Tg187jb04MWfpuogYGV75IFrQQBxQaGH75eq_FpbkyoLcEpRUEWSbECP2eeFya2yZ9vIO5ScD-lPmovePk4Aa4SzZ8jdjhmAbNykleRPCxMg0481kz6PQhnHRUv3nF5WP479CnObJKqTVdEagVL66oxnX9VhZG9IZA7k0Th5PfKQwrKGyUeTGczpOjaPqbxlunP73j9AfnAt4XCS8epa-n3WGz1j-wfpr_ys57Aq-zBCfqP67UYzNpeI1AoXsJhD9xSDOzvJgFRvc3vm2wjAW4LEMwi48rCplamOpZToIHEPIaPzpveYQwDnB1HFTR1ove9bpKJsHmi-e2uzQ","use":"sig"}|]
in baseCfg {
configJwtSecret = Just secret
, configJWKS = rightToMaybe $ parseSecret secret
}
testCfgAsymJWKSet :: AppConfig
testCfgAsymJWKSet =
let secret = encodeUtf8 [str|{"keys": [{"alg":"RS256","e":"AQAB","key_ops":["verify"],"kty":"RSA","n":"0etQ2Tg187jb04MWfpuogYGV75IFrQQBxQaGH75eq_FpbkyoLcEpRUEWSbECP2eeFya2yZ9vIO5ScD-lPmovePk4Aa4SzZ8jdjhmAbNykleRPCxMg0481kz6PQhnHRUv3nF5WP479CnObJKqTVdEagVL66oxnX9VhZG9IZA7k0Th5PfKQwrKGyUeTGczpOjaPqbxlunP73j9AfnAt4XCS8epa-n3WGz1j-wfpr_ys57Aq-zBCfqP67UYzNpeI1AoXsJhD9xSDOzvJgFRvc3vm2wjAW4LEMwi48rCplamOpZToIHEPIaPzpveYQwDnB1HFTR1ove9bpKJsHmi-e2uzQ","use":"sig"}]}|]
in baseCfg {
configJwtSecret = Just secret
, configJWKS = rightToMaybe $ parseSecret secret
}
testCfgExtraSearchPath :: AppConfig
testCfgExtraSearchPath = baseCfg { configDbExtraSearchPath = ["public", "extensions", "EXTRA \"@/\\#~_-"] }
testCfgRootSpec :: AppConfig
testCfgRootSpec = baseCfg { configDbRootSpec = Just $ QualifiedIdentifier mempty "root"}
testCfgResponseHeaders :: AppConfig
testCfgResponseHeaders = baseCfg { configDbPreRequest = Just $ QualifiedIdentifier mempty "custom_headers" }
testMultipleSchemaCfg :: AppConfig
testMultipleSchemaCfg = baseCfg { configDbSchemas = fromList ["v1", "v2", "SPECIAL \"@/\\#~_-"] }
testPgSafeUpdateEnabledCfg :: AppConfig
testPgSafeUpdateEnabledCfg = baseCfg { configDbPreRequest = Just $ QualifiedIdentifier "test" "load_safeupdate" }
testObservabilityCfg :: AppConfig
testObservabilityCfg = baseCfg { configServerTraceHeader = Just $ mk "X-Request-Id" }
testCfgServerTiming :: AppConfig
testCfgServerTiming = baseCfg { configDbPlanEnabled = True }
testCfgAggregatesEnabled :: AppConfig
testCfgAggregatesEnabled = baseCfg { configDbAggregates = True }
testCfgTimezoneDisabled :: AppConfig
testCfgTimezoneDisabled = baseCfg { configDbTimezoneEnabled = False }
rangeHdrs :: ByteRange -> [Header] rangeHdrs :: ByteRange -> [Header]
rangeHdrs r = [rangeUnit, (hRange, renderByteRange r)] rangeHdrs r = [rangeUnit, (hRange, renderByteRange r)]