module Main where import qualified Hasql.Pool as P import qualified Hasql.Pool.Config as P import qualified Hasql.Transaction.Sessions as HT import Data.Function (id) import Data.IORef (newIORef, readIORef) import Test.Hspec import PostgREST.App (postgrest) import PostgREST.Config (AppConfig (..), toConnectionSettings) import PostgREST.Config.Database (queryPgVersion) import PostgREST.SchemaCache (querySchemaCache) import Protolude hiding (toList, toS) import SpecHelper import qualified PostgREST.AppState as AppState import qualified PostgREST.Logger as Logger import qualified PostgREST.Metrics as Metrics import qualified Feature.Auth.AsymmetricJwtSpec import qualified Feature.Auth.AudienceJwtSecretSpec import qualified Feature.Auth.AuthSpec import qualified Feature.Auth.BinaryJwtSecretSpec import qualified Feature.Auth.JwtCacheSpec import qualified Feature.Auth.NoAnonSpec import qualified Feature.Auth.NoJwtSecretSpec import qualified Feature.ConcurrentSpec import qualified Feature.CorsSpec import qualified Feature.ExtraSearchPathSpec import qualified Feature.HttpHeaderSpec import qualified Feature.NoSuperuserSpec import qualified Feature.ObservabilitySpec import qualified Feature.OpenApi.DisabledOpenApiSpec import qualified Feature.OpenApi.IgnorePrivOpenApiSpec import qualified Feature.OpenApi.OpenApiSpec import qualified Feature.OpenApi.ProxySpec import qualified Feature.OpenApi.RootSpec import qualified Feature.OpenApi.SecurityOpenApiSpec import qualified Feature.OptionsSpec import qualified Feature.Query.AggregateFunctionsSpec import qualified Feature.Query.AndOrParamsSpec import qualified Feature.Query.ComputedRelsSpec import qualified Feature.Query.CustomMediaSpec import qualified Feature.Query.DeleteSpec import qualified Feature.Query.EmbedDisambiguationSpec import qualified Feature.Query.EmbedInnerJoinSpec import qualified Feature.Query.ErrorSpec import qualified Feature.Query.InsertSpec import qualified Feature.Query.JsonOperatorSpec import qualified Feature.Query.MultipleSchemaSpec import qualified Feature.Query.NullsStripSpec import qualified Feature.Query.PgSafeUpdateSpec import qualified Feature.Query.PlanSpec import qualified Feature.Query.PostGISSpec import qualified Feature.Query.Preferences.HandlingSpec import qualified Feature.Query.Preferences.MaxAffectedSpec import qualified Feature.Query.Preferences.TimezoneSpec import qualified Feature.Query.PreparedStatementsSpec import qualified Feature.Query.QueryLimitedSpec import qualified Feature.Query.QuerySpec import qualified Feature.Query.RangeSpec import qualified Feature.Query.RawOutputTypesSpec import qualified Feature.Query.RelatedQueriesSpec import qualified Feature.Query.RpcSpec import qualified Feature.Query.ServerTimingSpec import qualified Feature.Query.SingularSpec import qualified Feature.Query.SpreadQueriesSpec import qualified Feature.Query.UnicodeSpec import qualified Feature.Query.UpdateSpec import qualified Feature.Query.UpsertSpec import qualified Feature.RollbackSpec import qualified Feature.RpcPreRequestGucsSpec main :: IO () main = do pool <- P.acquire $ P.settings [ P.size 3 , P.acquisitionTimeout 10 , P.agingTimeout 60 , P.idlenessTimeout 60 , P.staticConnectionSettings $ toConnectionSettings identity baseCfg ] actualPgVersion <- either (panic . show) id <$> P.use pool queryPgVersion -- cached schema cache so most tests run fast baseSchemaCache <- loadSCache pool actualPgVersion baseCfg metricsState <- Metrics.init (configDbPoolSize baseCfg) let initApp sCache config = do confRef <- newIORef config loggerState <- Logger.init (configLogLevel <$> readIORef confRef) appState <- AppState.initWithPool pool confRef loggerState metricsState (Metrics.observationMetrics metricsState) mempty AppState.putPgVersion appState actualPgVersion AppState.putSchemaCache appState (Just sCache) return ((), postgrest appState (pure ())) -- For tests that run with the same schema cache app = initApp baseSchemaCache -- For tests that run with a different SchemaCache (depends on configSchemas) appDbs config = do customSchemaCache <- loadSCache pool actualPgVersion config initApp customSchemaCache config withConfig config = before (app config) withConfigDbs config = before (appDbs config) describeWithConfig label spec = describe label $ spec withConfig let specs = uncurry describeWithConfig <$> [ ("Feature.Auth.AsymmetricJwtSpec" , Feature.Auth.AsymmetricJwtSpec.spec) , ("Feature.Auth.AudienceJwtSecretSpec" , Feature.Auth.AudienceJwtSecretSpec.disabledSpec) , ("Feature.Auth.AudienceJwtSecretSpec" , Feature.Auth.AudienceJwtSecretSpec.spec) , ("Feature.Auth.AuthSpec" , Feature.Auth.AuthSpec.spec) , ("Feature.Auth.BinaryJwtSecretSpec" , Feature.Auth.BinaryJwtSecretSpec.spec) , ("Feature.Auth.JwtCacheSpec" , Feature.Auth.JwtCacheSpec.spec) , ("Feature.Auth.NoAnonSpec" , Feature.Auth.NoAnonSpec.spec) , ("Feature.Auth.NoJwtSecretSpec" , Feature.Auth.NoJwtSecretSpec.spec) , ("Feature.ConcurrentSpec" , Feature.ConcurrentSpec.spec) , ("Feature.CorsSpec" , Feature.CorsSpec.spec) , ("Feature.HttpHeaderSpec" , Feature.HttpHeaderSpec.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.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.Query.AggregateFunctionsSpec.allowed" , Feature.Query.AggregateFunctionsSpec.allowed) , ("Feature.Query.AggregateFunctionsSpec.disallowed" , Feature.Query.AggregateFunctionsSpec.disallowed) , ("Feature.Query.AndOrParamsSpec" , Feature.Query.AndOrParamsSpec.spec) , ("Feature.Query.ComputedRelsSpec" , Feature.Query.ComputedRelsSpec.spec) , ("Feature.Query.CustomMediaSpec" , Feature.Query.CustomMediaSpec.spec) , ("Feature.Query.DeleteSpec" , Feature.Query.DeleteSpec.spec) , ("Feature.Query.EmbedDisambiguationSpec" , Feature.Query.EmbedDisambiguationSpec.spec) , ("Feature.Query.EmbedInnerJoinSpec" , Feature.Query.EmbedInnerJoinSpec.spec) , ("Feature.Query.ErrorSpec" , Feature.Query.ErrorSpec.spec) , ("Feature.Query.InsertSpec" , Feature.Query.InsertSpec.spec) , ("Feature.Query.JsonOperatorSpec" , Feature.Query.JsonOperatorSpec.spec actualPgVersion) , ("Feature.Query.NullsStripSpec" , Feature.Query.NullsStripSpec.spec) , ("Feature.Query.PgSafeUpdateSpec.disabledSpec" , Feature.Query.PgSafeUpdateSpec.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.MaxAffectedSpec" , Feature.Query.Preferences.MaxAffectedSpec.spec) , ("Feature.Query.Preferences.TimezoneSpec" , Feature.Query.Preferences.TimezoneSpec.spec) , ("Feature.Query.PreparedStatementsSpec.spec" , Feature.Query.PreparedStatementsSpec.spec) , ("Feature.Query.QueryLimitedSpec" , Feature.Query.QueryLimitedSpec.spec) , ("Feature.Query.QuerySpec" , Feature.Query.QuerySpec.spec actualPgVersion) , ("Feature.Query.QuerySpec.specLegacyTargetNames" , Feature.Query.QuerySpec.specLegacyTargetNames) , ("Feature.Query.RangeSpec" , Feature.Query.RangeSpec.spec) , ("Feature.Query.RawOutputTypesSpec" , Feature.Query.RawOutputTypesSpec.spec) , ("Feature.Query.RelatedQueriesSpec" , Feature.Query.RelatedQueriesSpec.spec) , ("Feature.Query.RpcSpec" , Feature.Query.RpcSpec.spec actualPgVersion) , ("Feature.Query.ServerTimingSpec" , Feature.Query.ServerTimingSpec.spec) , ("Feature.Query.SingularSpec" , Feature.Query.SingularSpec.spec) , ("Feature.Query.SpreadQueriesSpec" , Feature.Query.SpreadQueriesSpec.spec) , ("Feature.Query.UpdateSpec" , Feature.Query.UpdateSpec.spec) , ("Feature.Query.UpsertSpec" , Feature.Query.UpsertSpec.spec) , ("Feature.RpcPreRequestGucsSpec" , Feature.RpcPreRequestGucsSpec.spec) ] hspec $ do mapM_ parallel specs 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 -- Note: the rollback tests can not run in parallel, because they test persistence and -- this results in race conditions describe "Feature.RollbackAllowedSpec" $ Feature.RollbackSpec.allowed withConfig describe "Feature.RollbackDisallowedSpec" $ Feature.RollbackSpec.disallowed withConfig describe "Feature.RollbackForcedSpec" $ Feature.RollbackSpec.forced withConfig -- 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. describe "Feature.Query.PgSafeUpdateSpec.spec" $ Feature.Query.PgSafeUpdateSpec.spec withConfig where loadSCache pool pgVersion conf = either (panic.show) fst <$> P.use pool (HT.transaction HT.ReadCommitted HT.Read $ querySchemaCache pgVersion conf)