packages feed

xrefcheck-0.3.0: tests/Test/Xrefcheck/RedirectDefaultSpec.hs

{- SPDX-FileCopyrightText: 2022 Serokell <https://serokell.io>
 -
 - SPDX-License-Identifier: MPL-2.0
 -}

module Test.Xrefcheck.RedirectDefaultSpec where

import Universum

import Data.CaseInsensitive qualified as CI
import Data.Set qualified as S
import Network.HTTP.Types (Status, mkStatus)
import Network.HTTP.Types.Header (HeaderName, hLocation)
import Network.Wai qualified as Web
import Test.Tasty (TestName, TestTree, testGroup)
import Test.Tasty.HUnit (Assertion, testCase)
import Web.Scotty qualified as Web

import Test.Xrefcheck.UtilRequests
import Xrefcheck.Config
import Xrefcheck.Progress
import Xrefcheck.Verify

test_redirectRequests :: TestTree
test_redirectRequests = testGroup "Redirect response defaults"
  [ testGroup "Temporary" $ allowedRedirectTests <$> [302, 303, 307]
  , testGroup "Permanent" $ permanentRedirectTests <$> [301, 308]
  , testGroup "304 Not Modified" $ allowedRedirectTests <$> [304]
  ]
  where
    url :: Text
    url = "http://127.0.0.1:5000/redirect"

    location :: Maybe Text
    location = Just "http://127.0.0.1:5000/other"

    allowedRedirectTests :: Int -> TestTree
    allowedRedirectTests statusCode =
      redirectTests
        (show statusCode <> " passes by default")
        (mkStatus statusCode "Allowed redirect")
        (\case
          Nothing -> Just $ RedirectMissingLocation $ fromList [url]
          Just _ -> Nothing
        )

    permanentRedirectTests :: Int -> TestTree
    permanentRedirectTests statusCode =
      redirectTests
        (show statusCode <> " fails by default")
        (mkStatus statusCode "Permanent redirect")
        (\case
          Nothing -> Just $ RedirectMissingLocation $ fromList [url]
          Just loc -> Just $ RedirectRuleError (fromList [url, loc]) (Just RROPermanent)
        )

    redirectTests :: TestName -> Status -> (Maybe Text -> Maybe VerifyError) -> TestTree
    redirectTests name expectedStatus expectedError =
      testGroup name
        [
          testCase "With no location" $
            redirectAssertion expectedStatus Nothing (expectedError Nothing),
          testCase "With location" $
            redirectAssertion expectedStatus location (expectedError location)
        ]

    redirectAssertion :: Status -> Maybe Text -> Maybe VerifyError -> Assertion
    redirectAssertion expectedStatus expectedLocation expectedError = do
      setRef <- newIORef S.empty
      checkLinkAndProgressWithServerDefault
        setRef
        (5000, mockRedirect expectedLocation expectedStatus)
        url
        ( (if isNothing expectedError then reportSuccess else reportError) "" $
            initProgress 1
        )
        (VerifyResult $ maybeToList expectedError)

    mockRedirect :: Maybe Text -> Status -> IO Web.Application
    mockRedirect expectedLocation expectedStatus =
      Web.scottyApp $ Web.matchAny "/redirect" $ do
        whenJust expectedLocation (setHeader hLocation)
        Web.status expectedStatus

    setHeader :: HeaderName -> Text -> Web.ActionM ()
    setHeader hdr value = Web.setHeader (decodeUtf8 (CI.original hdr)) (fromStrict value)