Introduced raw-media-types config option (#1349)
* extracted rawOutputTypes to config variable raw-output-media-types * removed CTTextHtml from Types.hs
This commit is contained in:
committed by
Steve Chávez
parent
afb7266f17
commit
f5cef205f1
@@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- #1349, Add user defined raw output media types via `raw-media-types` config option
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
## [6.0.0] - 2019-06-21
|
## [6.0.0] - 2019-06-21
|
||||||
@@ -24,6 +26,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- #790, Allow override of OpenAPI spec through `root-spec` config option - @steve-chavez
|
- #790, Allow override of OpenAPI spec through `root-spec` config option - @steve-chavez
|
||||||
- #1308, Accept `text/plain` and `text/html` for raw output - @steve-chavez
|
- #1308, Accept `text/plain` and `text/html` for raw output - @steve-chavez
|
||||||
|
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- #1223, Fix incorrect OpenAPI externalDocs url - @steve-chavez
|
- #1223, Fix incorrect OpenAPI externalDocs url - @steve-chavez
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ test-suite spec
|
|||||||
Feature.StructureSpec
|
Feature.StructureSpec
|
||||||
Feature.UnicodeSpec
|
Feature.UnicodeSpec
|
||||||
Feature.UpsertSpec
|
Feature.UpsertSpec
|
||||||
|
Feature.RawOutputTypesSpec
|
||||||
|
Feature.HtmlRawOutputSpec
|
||||||
SpecHelper
|
SpecHelper
|
||||||
TestTypes
|
TestTypes
|
||||||
hs-source-dirs: test
|
hs-source-dirs: test
|
||||||
|
|||||||
+16
-11
@@ -8,6 +8,7 @@ module PostgREST.App (
|
|||||||
|
|
||||||
import qualified Data.ByteString.Char8 as BS
|
import qualified Data.ByteString.Char8 as BS
|
||||||
import qualified Data.HashMap.Strict as M
|
import qualified Data.HashMap.Strict as M
|
||||||
|
import qualified Data.List as L (union)
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import qualified Hasql.Pool as P
|
import qualified Hasql.Pool as P
|
||||||
import qualified Hasql.Transaction as H
|
import qualified Hasql.Transaction as H
|
||||||
@@ -56,7 +57,6 @@ postgrest :: AppConfig -> IORef (Maybe DbStructure) -> P.Pool -> IO UTCTime -> I
|
|||||||
postgrest conf refDbStructure pool getTime worker =
|
postgrest conf refDbStructure pool getTime worker =
|
||||||
let middle = (if configQuiet conf then id else logStdout) . defaultMiddle
|
let middle = (if configQuiet conf then id else logStdout) . defaultMiddle
|
||||||
jwtSecret = parseSecret <$> configJwtSecret conf in
|
jwtSecret = parseSecret <$> configJwtSecret conf in
|
||||||
|
|
||||||
middle $ \ req respond -> do
|
middle $ \ req respond -> do
|
||||||
time <- getTime
|
time <- getTime
|
||||||
body <- strictRequestBody req
|
body <- strictRequestBody req
|
||||||
@@ -103,14 +103,14 @@ transactionMode proc action =
|
|||||||
|
|
||||||
app :: DbStructure -> Maybe ProcDescription -> S.Set FieldName -> AppConfig -> ApiRequest -> H.Transaction Response
|
app :: DbStructure -> Maybe ProcDescription -> S.Set FieldName -> AppConfig -> ApiRequest -> H.Transaction Response
|
||||||
app dbStructure proc cols conf apiRequest =
|
app dbStructure proc cols conf apiRequest =
|
||||||
case responseContentTypeOrError (iAccepts apiRequest) (iAction apiRequest) (iTarget apiRequest) of
|
case responseContentTypeOrError (iAccepts apiRequest) rawContentTypes (iAction apiRequest) (iTarget apiRequest) of
|
||||||
Left errorResponse -> return errorResponse
|
Left errorResponse -> return errorResponse
|
||||||
Right contentType ->
|
Right contentType ->
|
||||||
case (iAction apiRequest, iTarget apiRequest, iPayload apiRequest) of
|
case (iAction apiRequest, iTarget apiRequest, iPayload apiRequest) of
|
||||||
|
|
||||||
(ActionRead, TargetIdent qi, Nothing) ->
|
(ActionRead, TargetIdent qi, Nothing) ->
|
||||||
let partsField = (,) <$> readSqlParts
|
let partsField = (,) <$> readSqlParts
|
||||||
<*> (binaryField contentType =<< fldNames) in
|
<*> (binaryField contentType rawContentTypes =<< fldNames) in
|
||||||
case partsField of
|
case partsField of
|
||||||
Left errorResponse -> return errorResponse
|
Left errorResponse -> return errorResponse
|
||||||
Right ((q, cq), bField) -> do
|
Right ((q, cq), bField) -> do
|
||||||
@@ -265,7 +265,7 @@ app dbStructure proc cols conf apiRequest =
|
|||||||
_ -> False
|
_ -> False
|
||||||
rpcBinaryField = if returnsScalar
|
rpcBinaryField = if returnsScalar
|
||||||
then Right Nothing
|
then Right Nothing
|
||||||
else binaryField contentType =<< fldNames
|
else binaryField contentType rawContentTypes =<< fldNames
|
||||||
parts = (,) <$> readSqlParts <*> rpcBinaryField in
|
parts = (,) <$> readSqlParts <*> rpcBinaryField in
|
||||||
case parts of
|
case parts of
|
||||||
Left errorResponse -> return errorResponse
|
Left errorResponse -> return errorResponse
|
||||||
@@ -329,17 +329,22 @@ app dbStructure proc cols conf apiRequest =
|
|||||||
mutateSqlParts s t =
|
mutateSqlParts s t =
|
||||||
(,) <$> selectQuery
|
(,) <$> selectQuery
|
||||||
<*> (requestToQuery schema False . DbMutate <$> mutationDbRequest s t)
|
<*> (requestToQuery schema False . DbMutate <$> mutationDbRequest s t)
|
||||||
|
rawContentTypes =
|
||||||
|
(decodeContentType <$> configRawMediaTypes conf) `L.union`
|
||||||
|
[ CTOctetStream, CTTextPlain ]
|
||||||
|
|
||||||
responseContentTypeOrError :: [ContentType] -> Action -> Target -> Either Response ContentType
|
responseContentTypeOrError :: [ContentType] -> [ContentType] -> Action -> Target -> Either Response ContentType
|
||||||
responseContentTypeOrError accepts action target = serves contentTypesForRequest accepts
|
responseContentTypeOrError accepts rawContentTypes action target = serves contentTypesForRequest accepts
|
||||||
where
|
where
|
||||||
contentTypesForRequest = case action of
|
contentTypesForRequest = case action of
|
||||||
ActionRead -> [CTApplicationJSON, CTSingularJSON, CTTextCSV] ++ rawContentTypes
|
ActionRead -> [CTApplicationJSON, CTSingularJSON, CTTextCSV]
|
||||||
|
++ rawContentTypes
|
||||||
ActionCreate -> [CTApplicationJSON, CTSingularJSON, CTTextCSV]
|
ActionCreate -> [CTApplicationJSON, CTSingularJSON, CTTextCSV]
|
||||||
ActionUpdate -> [CTApplicationJSON, CTSingularJSON, CTTextCSV]
|
ActionUpdate -> [CTApplicationJSON, CTSingularJSON, CTTextCSV]
|
||||||
ActionDelete -> [CTApplicationJSON, CTSingularJSON, CTTextCSV]
|
ActionDelete -> [CTApplicationJSON, CTSingularJSON, CTTextCSV]
|
||||||
ActionInvoke _ -> [CTApplicationJSON, CTSingularJSON, CTTextCSV] ++ rawContentTypes ++
|
ActionInvoke _ -> [CTApplicationJSON, CTSingularJSON, CTTextCSV]
|
||||||
[CTOpenAPI | tpIsRootSpec target]
|
++ rawContentTypes
|
||||||
|
++ [CTOpenAPI | tpIsRootSpec target]
|
||||||
ActionInspect -> [CTOpenAPI, CTApplicationJSON]
|
ActionInspect -> [CTOpenAPI, CTApplicationJSON]
|
||||||
ActionInfo -> [CTTextCSV]
|
ActionInfo -> [CTTextCSV]
|
||||||
ActionSingleUpsert -> [CTApplicationJSON, CTSingularJSON, CTTextCSV]
|
ActionSingleUpsert -> [CTApplicationJSON, CTSingularJSON, CTTextCSV]
|
||||||
@@ -352,8 +357,8 @@ responseContentTypeOrError accepts action target = serves contentTypesForRequest
|
|||||||
| If raw(binary) output is requested, check that ContentType is one of the admitted rawContentTypes and that
|
| If raw(binary) output is requested, check that ContentType is one of the admitted rawContentTypes and that
|
||||||
| `?select=...` contains only one field other than `*`
|
| `?select=...` contains only one field other than `*`
|
||||||
-}
|
-}
|
||||||
binaryField :: ContentType -> [FieldName] -> Either Response (Maybe FieldName)
|
binaryField :: ContentType -> [ContentType]-> [FieldName] -> Either Response (Maybe FieldName)
|
||||||
binaryField ct fldNames
|
binaryField ct rawContentTypes fldNames
|
||||||
| ct `elem` rawContentTypes =
|
| ct `elem` rawContentTypes =
|
||||||
let fieldName = headMay fldNames in
|
let fieldName = headMay fldNames in
|
||||||
if length fldNames == 1 && fieldName /= Just "*"
|
if length fldNames == 1 && fieldName /= Just "*"
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ data AppConfig = AppConfig {
|
|||||||
, configExtraSearchPath :: [Text]
|
, configExtraSearchPath :: [Text]
|
||||||
|
|
||||||
, configRootSpec :: Maybe QualifiedIdentifier
|
, configRootSpec :: Maybe QualifiedIdentifier
|
||||||
|
, configRawMediaTypes :: [B.ByteString]
|
||||||
}
|
}
|
||||||
|
|
||||||
configPoolTimeout' :: (Fractional a) => AppConfig -> a
|
configPoolTimeout' :: (Fractional a) => AppConfig -> a
|
||||||
@@ -168,6 +169,7 @@ readOptions = do
|
|||||||
<*> (maybe (Right [JSPKey "role"]) parseRoleClaimKey <$> optValue "role-claim-key")
|
<*> (maybe (Right [JSPKey "role"]) parseRoleClaimKey <$> optValue "role-claim-key")
|
||||||
<*> (maybe ["public"] splitExtraSearchPath <$> optValue "db-extra-search-path")
|
<*> (maybe ["public"] splitExtraSearchPath <$> optValue "db-extra-search-path")
|
||||||
<*> ((\x y -> QualifiedIdentifier x <$> y) <$> dbSchema <*> optString "root-spec")
|
<*> ((\x y -> QualifiedIdentifier x <$> y) <$> dbSchema <*> optString "root-spec")
|
||||||
|
<*> (fmap encodeUtf8 <$> optionalListOfText "raw-media-types")
|
||||||
|
|
||||||
parseJwtAudience :: C.Key -> C.Parser C.Config (Maybe StringOrURI)
|
parseJwtAudience :: C.Key -> C.Parser C.Config (Maybe StringOrURI)
|
||||||
parseJwtAudience k =
|
parseJwtAudience k =
|
||||||
@@ -178,6 +180,12 @@ readOptions = do
|
|||||||
(Just "") -> pure Nothing
|
(Just "") -> pure Nothing
|
||||||
aud' -> pure aud'
|
aud' -> pure aud'
|
||||||
|
|
||||||
|
optionalListOfText :: C.Key -> C.Parser C.Config [Text]
|
||||||
|
optionalListOfText k =
|
||||||
|
C.optional k (C.list C.string) >>= \case
|
||||||
|
Nothing -> pure []
|
||||||
|
Just types -> pure types
|
||||||
|
|
||||||
reqString :: C.Key -> C.Parser C.Config Text
|
reqString :: C.Key -> C.Parser C.Config Text
|
||||||
reqString k = C.required k C.string
|
reqString k = C.required k C.string
|
||||||
|
|
||||||
@@ -273,6 +281,9 @@ readOptions = do
|
|||||||
|## stored proc that overrides the root "/" spec
|
|## stored proc that overrides the root "/" spec
|
||||||
|## it must be inside the db-schema
|
|## it must be inside the db-schema
|
||||||
|# root-spec = "stored_proc_name"
|
|# root-spec = "stored_proc_name"
|
||||||
|
|
|
||||||
|
|## content types to produce raw output
|
||||||
|
|# raw-media-types=["image/png","image/jpg"]
|
||||||
|]
|
|]
|
||||||
|
|
||||||
pathParser :: Parser FilePath
|
pathParser :: Parser FilePath
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import Protolude
|
|||||||
|
|
||||||
-- | Enumeration of currently supported response content types
|
-- | Enumeration of currently supported response content types
|
||||||
data ContentType = CTApplicationJSON | CTSingularJSON
|
data ContentType = CTApplicationJSON | CTSingularJSON
|
||||||
| CTTextCSV | CTTextPlain | CTTextHtml
|
| CTTextCSV | CTTextPlain
|
||||||
| CTOpenAPI | CTOctetStream
|
| CTOpenAPI | CTOctetStream
|
||||||
| CTAny | CTOther ByteString deriving (Show, Eq)
|
| CTAny | CTOther ByteString deriving (Show, Eq)
|
||||||
|
|
||||||
@@ -37,7 +37,6 @@ toMime :: ContentType -> ByteString
|
|||||||
toMime CTApplicationJSON = "application/json"
|
toMime CTApplicationJSON = "application/json"
|
||||||
toMime CTTextCSV = "text/csv"
|
toMime CTTextCSV = "text/csv"
|
||||||
toMime CTTextPlain = "text/plain"
|
toMime CTTextPlain = "text/plain"
|
||||||
toMime CTTextHtml = "text/html"
|
|
||||||
toMime CTOpenAPI = "application/openapi+json"
|
toMime CTOpenAPI = "application/openapi+json"
|
||||||
toMime CTSingularJSON = "application/vnd.pgrst.object+json"
|
toMime CTSingularJSON = "application/vnd.pgrst.object+json"
|
||||||
toMime CTOctetStream = "application/octet-stream"
|
toMime CTOctetStream = "application/octet-stream"
|
||||||
@@ -50,7 +49,6 @@ decodeContentType ct = case BS.takeWhile (/= BS.c2w ';') ct of
|
|||||||
"application/json" -> CTApplicationJSON
|
"application/json" -> CTApplicationJSON
|
||||||
"text/csv" -> CTTextCSV
|
"text/csv" -> CTTextCSV
|
||||||
"text/plain" -> CTTextPlain
|
"text/plain" -> CTTextPlain
|
||||||
"text/html" -> CTTextHtml
|
|
||||||
"application/openapi+json" -> CTOpenAPI
|
"application/openapi+json" -> CTOpenAPI
|
||||||
"application/vnd.pgrst.object+json" -> CTSingularJSON
|
"application/vnd.pgrst.object+json" -> CTSingularJSON
|
||||||
"application/vnd.pgrst.object" -> CTSingularJSON
|
"application/vnd.pgrst.object" -> CTSingularJSON
|
||||||
@@ -58,10 +56,6 @@ decodeContentType ct = case BS.takeWhile (/= BS.c2w ';') ct of
|
|||||||
"*/*" -> CTAny
|
"*/*" -> CTAny
|
||||||
ct' -> CTOther ct'
|
ct' -> CTOther ct'
|
||||||
|
|
||||||
-- | ContentTypes that can get a raw/unwrapped response
|
|
||||||
rawContentTypes :: [ContentType]
|
|
||||||
rawContentTypes = [CTOctetStream, CTTextPlain, CTTextHtml]
|
|
||||||
|
|
||||||
data PreferResolution = MergeDuplicates | IgnoreDuplicates deriving Eq
|
data PreferResolution = MergeDuplicates | IgnoreDuplicates deriving Eq
|
||||||
instance Show PreferResolution where
|
instance Show PreferResolution where
|
||||||
show MergeDuplicates = "resolution=merge-duplicates"
|
show MergeDuplicates = "resolution=merge-duplicates"
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
module Feature.HtmlRawOutputSpec where
|
||||||
|
|
||||||
|
import Network.Wai (Application)
|
||||||
|
|
||||||
|
import Network.HTTP.Types
|
||||||
|
import Test.Hspec hiding (pendingWith)
|
||||||
|
import Test.Hspec.Wai
|
||||||
|
import Text.Heredoc
|
||||||
|
|
||||||
|
import Protolude hiding (get)
|
||||||
|
import SpecHelper (acceptHdrs)
|
||||||
|
|
||||||
|
spec :: SpecWith Application
|
||||||
|
spec = describe "When raw-media-types is set to \"text/html\"" $
|
||||||
|
it "can get raw output with Accept: text/html" $
|
||||||
|
request methodGet "/rpc/welcome.html" (acceptHdrs "text/html") ""
|
||||||
|
`shouldRespondWith`
|
||||||
|
[str|
|
||||||
|
|<html>
|
||||||
|
| <head>
|
||||||
|
| <title>PostgREST</title>
|
||||||
|
| </head>
|
||||||
|
| <body>
|
||||||
|
| <h1>Welcome to PostgREST</h1>
|
||||||
|
| </body>
|
||||||
|
|</html>
|
||||||
|
|]
|
||||||
|
{ matchStatus = 200
|
||||||
|
, matchHeaders = ["Content-Type" <:> "text/html; charset=utf-8"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
module Feature.RawOutputTypesSpec where
|
||||||
|
|
||||||
|
import Network.Wai (Application)
|
||||||
|
|
||||||
|
import Network.HTTP.Types
|
||||||
|
import Test.Hspec
|
||||||
|
import Test.Hspec.Wai
|
||||||
|
import Test.Hspec.Wai.JSON
|
||||||
|
|
||||||
|
import Protolude
|
||||||
|
import SpecHelper (acceptHdrs)
|
||||||
|
|
||||||
|
spec :: SpecWith Application
|
||||||
|
spec = 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"
|
||||||
|
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" $
|
||||||
|
request methodGet "/items?id=eq.1" firefoxAcceptHdrs ""
|
||||||
|
`shouldRespondWith` [json| [{"id":1}] |]
|
||||||
|
{ matchHeaders= ["Content-Type" <:> "application/json; charset=utf-8"] }
|
||||||
|
it "responds json to a GET request with Chrome Accept headers" $
|
||||||
|
request methodGet "/items?id=eq.1" chromeAcceptHdrs ""
|
||||||
|
`shouldRespondWith` [json| [{"id":1}] |]
|
||||||
|
{ matchHeaders= ["Content-Type" <:> "application/json; charset=utf-8"] }
|
||||||
|
|
||||||
|
it "responds json to a GET request to RPC with Firefox Accept headers" $
|
||||||
|
request methodGet "/rpc/get_projects_below?id=3" chromeAcceptHdrs ""
|
||||||
|
`shouldRespondWith` [json|[{"id":1,"name":"Windows 7","client_id":1}, {"id":2,"name":"Windows 10","client_id":1}]|]
|
||||||
|
{ matchHeaders= ["Content-Type" <:> "application/json; charset=utf-8"] }
|
||||||
|
it "responds json to a GET request to RPC with Chrome Accept headers" $
|
||||||
|
request methodGet "/rpc/get_projects_below?id=3" chromeAcceptHdrs ""
|
||||||
|
`shouldRespondWith` [json|[{"id":1,"name":"Windows 7","client_id":1}, {"id":2,"name":"Windows 10","client_id":1}]|]
|
||||||
|
{ matchHeaders= ["Content-Type" <:> "application/json; charset=utf-8"] }
|
||||||
@@ -464,23 +464,6 @@ spec actualPgVersion =
|
|||||||
, matchHeaders = ["Content-Type" <:> "application/octet-stream; charset=utf-8"]
|
, matchHeaders = ["Content-Type" <:> "application/octet-stream; charset=utf-8"]
|
||||||
}
|
}
|
||||||
|
|
||||||
it "can get raw output with Accept: text/html" $
|
|
||||||
request methodGet "/rpc/welcome.html" (acceptHdrs "text/html") ""
|
|
||||||
`shouldRespondWith`
|
|
||||||
[str|
|
|
||||||
|<html>
|
|
||||||
| <head>
|
|
||||||
| <title>PostgREST</title>
|
|
||||||
| </head>
|
|
||||||
| <body>
|
|
||||||
| <h1>Welcome to PostgREST</h1>
|
|
||||||
| </body>
|
|
||||||
|</html>
|
|
||||||
|]
|
|
||||||
{ matchStatus = 200
|
|
||||||
, matchHeaders = ["Content-Type" <:> "text/html; charset=utf-8"]
|
|
||||||
}
|
|
||||||
|
|
||||||
it "can get raw output with Accept: text/plain" $
|
it "can get raw output with Accept: text/plain" $
|
||||||
request methodGet "/rpc/welcome" (acceptHdrs "text/plain") ""
|
request methodGet "/rpc/welcome" (acceptHdrs "text/plain") ""
|
||||||
`shouldRespondWith` "Welcome to PostgREST"
|
`shouldRespondWith` "Welcome to PostgREST"
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import qualified Feature.ConcurrentSpec
|
|||||||
import qualified Feature.CorsSpec
|
import qualified Feature.CorsSpec
|
||||||
import qualified Feature.DeleteSpec
|
import qualified Feature.DeleteSpec
|
||||||
import qualified Feature.ExtraSearchPathSpec
|
import qualified Feature.ExtraSearchPathSpec
|
||||||
|
import qualified Feature.HtmlRawOutputSpec
|
||||||
import qualified Feature.InsertSpec
|
import qualified Feature.InsertSpec
|
||||||
import qualified Feature.JsonOperatorSpec
|
import qualified Feature.JsonOperatorSpec
|
||||||
import qualified Feature.NoJwtSpec
|
import qualified Feature.NoJwtSpec
|
||||||
@@ -37,6 +38,7 @@ import qualified Feature.ProxySpec
|
|||||||
import qualified Feature.QueryLimitedSpec
|
import qualified Feature.QueryLimitedSpec
|
||||||
import qualified Feature.QuerySpec
|
import qualified Feature.QuerySpec
|
||||||
import qualified Feature.RangeSpec
|
import qualified Feature.RangeSpec
|
||||||
|
import qualified Feature.RawOutputTypesSpec
|
||||||
import qualified Feature.RootSpec
|
import qualified Feature.RootSpec
|
||||||
import qualified Feature.RpcSpec
|
import qualified Feature.RpcSpec
|
||||||
import qualified Feature.SingularSpec
|
import qualified Feature.SingularSpec
|
||||||
@@ -74,6 +76,7 @@ main = do
|
|||||||
nonexistentSchemaApp = return $ postgrest (testNonexistentSchemaCfg testDbConn) refDbStructure pool getTime $ pure ()
|
nonexistentSchemaApp = return $ postgrest (testNonexistentSchemaCfg testDbConn) refDbStructure pool getTime $ pure ()
|
||||||
extraSearchPathApp = return $ postgrest (testCfgExtraSearchPath testDbConn) refDbStructure pool getTime $ pure ()
|
extraSearchPathApp = return $ postgrest (testCfgExtraSearchPath testDbConn) refDbStructure pool getTime $ pure ()
|
||||||
rootSpecApp = return $ postgrest (testCfgRootSpec testDbConn) refDbStructure pool getTime $ pure ()
|
rootSpecApp = return $ postgrest (testCfgRootSpec testDbConn) refDbStructure pool getTime $ pure ()
|
||||||
|
htmlRawOutputApp = return $ postgrest (testCfgHtmlRawOutput testDbConn) refDbStructure pool getTime $ pure ()
|
||||||
|
|
||||||
let reset :: IO ()
|
let reset :: IO ()
|
||||||
reset = resetDb testDbConn
|
reset = resetDb testDbConn
|
||||||
@@ -86,6 +89,7 @@ main = do
|
|||||||
|
|
||||||
specs = uncurry describe <$> [
|
specs = uncurry describe <$> [
|
||||||
("Feature.AuthSpec" , Feature.AuthSpec.spec actualPgVersion)
|
("Feature.AuthSpec" , Feature.AuthSpec.spec actualPgVersion)
|
||||||
|
, ("Feature.RawOutputTypesSpec" , Feature.RawOutputTypesSpec.spec)
|
||||||
, ("Feature.ConcurrentSpec" , Feature.ConcurrentSpec.spec)
|
, ("Feature.ConcurrentSpec" , Feature.ConcurrentSpec.spec)
|
||||||
, ("Feature.CorsSpec" , Feature.CorsSpec.spec)
|
, ("Feature.CorsSpec" , Feature.CorsSpec.spec)
|
||||||
, ("Feature.DeleteSpec" , Feature.DeleteSpec.spec)
|
, ("Feature.DeleteSpec" , Feature.DeleteSpec.spec)
|
||||||
@@ -102,6 +106,10 @@ main = do
|
|||||||
hspec $ do
|
hspec $ do
|
||||||
mapM_ (beforeAll_ reset . before withApp) specs
|
mapM_ (beforeAll_ reset . before withApp) specs
|
||||||
|
|
||||||
|
-- this test runs with a raw-output-media-types set to text/html
|
||||||
|
beforeAll_ reset . before htmlRawOutputApp $
|
||||||
|
describe "Feature.HtmlRawOutputSpec" Feature.HtmlRawOutputSpec.spec
|
||||||
|
|
||||||
-- this test runs with a different server flag
|
-- this test runs with a different server flag
|
||||||
beforeAll_ reset . before ltdApp $
|
beforeAll_ reset . before ltdApp $
|
||||||
describe "Feature.QueryLimitedSpec" Feature.QueryLimitedSpec.spec
|
describe "Feature.QueryLimitedSpec" Feature.QueryLimitedSpec.spec
|
||||||
|
|||||||
@@ -81,6 +81,8 @@ _baseCfg = -- Connection Settings
|
|||||||
[]
|
[]
|
||||||
-- No root spec override
|
-- No root spec override
|
||||||
Nothing
|
Nothing
|
||||||
|
-- Raw output media types
|
||||||
|
[]
|
||||||
|
|
||||||
testCfg :: Text -> AppConfig
|
testCfg :: Text -> AppConfig
|
||||||
testCfg testDbConn = _baseCfg { configDatabase = testDbConn }
|
testCfg testDbConn = _baseCfg { configDatabase = testDbConn }
|
||||||
@@ -131,6 +133,9 @@ testCfgExtraSearchPath testDbConn = (testCfg testDbConn) { configExtraSearchPath
|
|||||||
testCfgRootSpec :: Text -> AppConfig
|
testCfgRootSpec :: Text -> AppConfig
|
||||||
testCfgRootSpec testDbConn = (testCfg testDbConn) { configRootSpec = Just $ QualifiedIdentifier "test" "root"}
|
testCfgRootSpec testDbConn = (testCfg testDbConn) { configRootSpec = Just $ QualifiedIdentifier "test" "root"}
|
||||||
|
|
||||||
|
testCfgHtmlRawOutput :: Text -> AppConfig
|
||||||
|
testCfgHtmlRawOutput testDbConn = (testCfg testDbConn) { configRawMediaTypes = ["text/html"] }
|
||||||
|
|
||||||
setupDb :: Text -> IO ()
|
setupDb :: Text -> IO ()
|
||||||
setupDb dbConn = do
|
setupDb dbConn = do
|
||||||
loadFixture dbConn "database"
|
loadFixture dbConn "database"
|
||||||
|
|||||||
Reference in New Issue
Block a user