graphql-engine/server/src-test/Hasura/RQL/WebhookTransformsSpec.hs
Tom Harding e0c0043e76 Upgrade Ormolu to 0.7.0.0
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/9284
GitOrigin-RevId: 2f2cf2ad01900a54e4bdb970205ac0ef313c7e00
2023-05-24 13:53:53 +00:00

170 lines
6.6 KiB
Haskell

module Hasura.RQL.WebhookTransformsSpec
( spec,
)
where
-------------------------------------------------------------------------------
import Data.Aeson (FromJSON, ToJSON, eitherDecode, encode, fromJSON, toJSON)
import Data.CaseInsensitive qualified as CI
import Data.List (nubBy)
import Data.Set qualified as S
import Hasura.Prelude
import Hasura.RQL.DDL.Webhook.Transform (RequestFields (..), RequestTransformFns, WithOptional (..), withOptional)
import Hasura.RQL.DDL.Webhook.Transform.Body (BodyTransformFn)
import Hasura.RQL.DDL.Webhook.Transform.Body qualified as Body
import Hasura.RQL.DDL.Webhook.Transform.Class (Template (..), TemplatingEngine (..), UnescapedTemplate (..))
import Hasura.RQL.DDL.Webhook.Transform.Headers (HeadersTransformFn, TransformFn (..))
import Hasura.RQL.DDL.Webhook.Transform.Headers qualified as Headers
import Hasura.RQL.DDL.Webhook.Transform.Method (Method (..), MethodTransformFn)
import Hasura.RQL.DDL.Webhook.Transform.Method qualified as Method
import Hasura.RQL.DDL.Webhook.Transform.QueryParams (QueryParamsTransformFn, TransformFn (..))
import Hasura.RQL.DDL.Webhook.Transform.QueryParams qualified as QueryParams
import Hasura.RQL.DDL.Webhook.Transform.Url (UrlTransformFn)
import Hasura.RQL.DDL.Webhook.Transform.Url qualified as Url
import Hedgehog (Gen, MonadTest, forAll, tripping, (===))
import Hedgehog.Gen qualified as Gen
import Hedgehog.Range qualified as Range
import Test.Hspec (Spec, describe, it)
import Test.Hspec.Hedgehog (hedgehog)
-------------------------------------------------------------------------------
spec :: Spec
spec = describe "WebhookTransform" do
it "Method RoundTrip"
. hedgehog
$ forAll genMethod
>>= trippingJSON
it "StringTemplateText RoundTrip"
. hedgehog
$ forAll genUnescapedTemplate
>>= trippingJSON
it "Url RoundTrip"
. hedgehog
$ forAll genUrl
>>= trippingJSON
it "Template RoundTrip"
. hedgehog
$ forAll genTemplate
>>= trippingJSON
it "TemplateEngine RoundTrip"
. hedgehog
$ forAll genTemplatingEngine
>>= trippingJSON
it "TransformHeaders" . hedgehog $ do
headers <- forAll genTransformHeaders
let sortH (Headers.AddReplaceOrRemoveFields {..}) =
Headers.AddReplaceOrRemoveFields (sort addOrReplaceHeaders) (sort removeHeaders)
let headersMaybe = eitherDecode $ encode headers
Right (sortH headers) === fmap sortH headersMaybe
it "MetadataRequestTransform RoundTrip" . hedgehog $ do
reqFields <- forAll genRequestTransformDefunc
let sortH (WithOptional Nothing) = WithOptional Nothing
sortH
(WithOptional (Just (HeadersTransformFn_ (Headers.AddReplaceOrRemove (Headers.AddReplaceOrRemoveFields {..}))))) =
WithOptional
. Just
. HeadersTransformFn_
. Headers.AddReplaceOrRemove
$ Headers.AddReplaceOrRemoveFields (sort addOrReplaceHeaders) (sort removeHeaders)
let sortQ (WithOptional Nothing) = WithOptional Nothing
sortQ
(WithOptional (Just (QueryParamsTransformFn_ (QueryParams.AddOrReplace qs)))) =
WithOptional
. Just
. QueryParamsTransformFn_
. QueryParams.AddOrReplace
$ sortOn fst qs
sortQ
(WithOptional (Just (QueryParamsTransformFn_ (QueryParams.ParamTemplate qs)))) =
WithOptional . Just . QueryParamsTransformFn_ . QueryParams.ParamTemplate $ qs
let sortRF rf@RequestFields {requestHeaders, queryParams} =
rf {requestHeaders = sortH requestHeaders, queryParams = sortQ queryParams}
let reqFieldsMaybe = eitherDecode $ encode reqFields
Right (sortRF reqFields) === fmap sortRF reqFieldsMaybe
-------------------------------------------------------------------------------
-- Generators
genMethod :: Gen Method
genMethod = (Method . CI.mk) <$> Gen.text (Range.constant 3 20) Gen.alphaNum
genTemplatingEngine :: Gen TemplatingEngine
genTemplatingEngine = Gen.enumBounded
-- NOTE: This generator is strictly useful for roundtrip aeson testing
-- and does not produce valid template snippets.
genTemplate :: Gen Template
genTemplate = Template . wrap <$> Gen.text (Range.constant 3 20) Gen.alphaNum
where
wrap txt = "\"" <> txt <> "\""
genUnescapedTemplate :: Gen UnescapedTemplate
genUnescapedTemplate = UnescapedTemplate <$> Gen.text (Range.constant 3 20) Gen.alphaNum
genTransformHeaders :: Gen Headers.AddReplaceOrRemoveFields
genTransformHeaders = do
numHeaders <- Gen.integral $ Range.constant 1 20
let genHeaderKey = CI.mk <$> Gen.text (Range.constant 1 20) Gen.alphaNum
genHeaderValue = genUnescapedTemplate
genKeys = S.toList <$> Gen.set (Range.singleton numHeaders) genHeaderKey
genValues = S.toList <$> Gen.set (Range.singleton numHeaders) genHeaderValue
removeHeaders <- Gen.list (Range.constant 1 10) genHeaderKey
addOrReplaceHeaders <- liftA2 zip genKeys genValues
pure $ Headers.AddReplaceOrRemoveFields {addOrReplaceHeaders, removeHeaders}
genQueryParams :: Gen [(UnescapedTemplate, Maybe UnescapedTemplate)]
genQueryParams = do
numParams <- Gen.integral $ Range.constant 1 20
let keyGen = genUnescapedTemplate
valueGen = Gen.maybe $ genUnescapedTemplate
keys <- Gen.list (Range.singleton numParams) keyGen
values <- Gen.list (Range.singleton numParams) valueGen
pure $ nubBy (\a b -> fst a == fst b) $ zip keys values
genUrl :: Gen UnescapedTemplate
genUrl = do
host <- Gen.text (Range.constant 3 20) Gen.alphaNum
pure $ UnescapedTemplate $ "http://www." <> host <> ".com"
genRequestTransformDefunc :: Gen RequestTransformFns
genRequestTransformDefunc = do
method <- Gen.maybe genMethod
-- NOTE: At the moment no need to generate valid urls or templates
-- but such instances maybe useful in the future.
url <- Gen.maybe genUrl
body <- Gen.maybe genTemplate
queryParams <- Gen.maybe genQueryParams
headers <- Gen.maybe genTransformHeaders
pure
RequestFields
{ method = withOptional @MethodTransformFn (fmap Method.Replace method),
url = withOptional @UrlTransformFn (fmap Url.Modify url),
body = withOptional @BodyTransformFn (fmap Body.ModifyAsJSON body),
queryParams = withOptional @QueryParamsTransformFn (fmap QueryParams.AddOrReplace queryParams),
requestHeaders = withOptional @HeadersTransformFn (fmap Headers.AddReplaceOrRemove headers)
}
-------------------------------------------------------------------------------
-- Helpers
-- | TODO: Move this out to a common module!
trippingJSON ::
forall a m.
(Show a, Eq a, ToJSON a, FromJSON a, MonadTest m) =>
a ->
m ()
trippingJSON val = tripping val toJSON fromJSON