packages feed

keter-2.3.2: test/Keter/RewriteSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Keter.RewriteSpec (tests) where

import Data.Aeson (eitherDecodeStrict)
import Data.ByteString.Char8 qualified as BS
import Test.Tasty
import Test.Tasty.HUnit
import Keter.Rewrite

tests :: TestTree
tests = testGroup "Keter.Rewrite"
  [ testGroup "ReverseProxyConfig parsing"
    [ testCase "preserve-host defaults to False when omitted" casePreserveHostDefault
    , testCase "preserve-host parses True" casePreserveHostTrue
    , testCase "preserve-host parses False explicitly" casePreserveHostFalse
    ]
  , testGroup "filterHeaders"
    [ testCase "strips Host header when preserveHost is False" caseFilterHeadersStripsHost
    , testCase "preserves Host header when preserveHost is True" caseFilterHeadersPreservesHost
    , testCase "always strips Transfer-Encoding" caseFilterHeadersStripsTransferEncoding
    , testCase "always strips Content-Length" caseFilterHeadersStripsContentLength
    , testCase "preserves other headers" caseFilterHeadersPreservesOthers
    ]
  ]

-- | Helper to parse ReverseProxyConfig from JSON/YAML bytes
parseReverseProxyConfig :: BS.ByteString -> Either String ReverseProxyConfig
parseReverseProxyConfig = eitherDecodeStrict

-- Config parsing tests

casePreserveHostDefault :: IO ()
casePreserveHostDefault = do
    let json = BS.unlines
          [ "{"
          , "  \"reversed-host\": \"localhost\","
          , "  \"reversed-port\": 3000,"
          , "  \"reversed-ssl\": false,"
          , "  \"reversing-host\": \"example.com\""
          , "}"
          ]
    case parseReverseProxyConfig json of
        Left err -> assertFailure ("Failed to parse: " <> err)
        Right cfg -> reversePreserveHost cfg @?= False

casePreserveHostTrue :: IO ()
casePreserveHostTrue = do
    let json = BS.unlines
          [ "{"
          , "  \"reversed-host\": \"localhost\","
          , "  \"reversed-port\": 3000,"
          , "  \"reversed-ssl\": false,"
          , "  \"reversing-host\": \"example.com\","
          , "  \"preserve-host\": true"
          , "}"
          ]
    case parseReverseProxyConfig json of
        Left err -> assertFailure ("Failed to parse: " <> err)
        Right cfg -> reversePreserveHost cfg @?= True

casePreserveHostFalse :: IO ()
casePreserveHostFalse = do
    let json = BS.unlines
          [ "{"
          , "  \"reversed-host\": \"localhost\","
          , "  \"reversed-port\": 3000,"
          , "  \"reversed-ssl\": false,"
          , "  \"reversing-host\": \"example.com\","
          , "  \"preserve-host\": false"
          , "}"
          ]
    case parseReverseProxyConfig json of
        Left err -> assertFailure ("Failed to parse: " <> err)
        Right cfg -> reversePreserveHost cfg @?= False

-- filterHeaders tests

caseFilterHeadersStripsHost :: IO ()
caseFilterHeadersStripsHost = do
    let headers = [("Host", "example.com"), ("Accept", "text/html")]
        result = filterHeaders False headers
    result @?= [("Accept", "text/html")]

caseFilterHeadersPreservesHost :: IO ()
caseFilterHeadersPreservesHost = do
    let headers = [("Host", "example.com"), ("Accept", "text/html")]
        result = filterHeaders True headers
    result @?= [("Host", "example.com"), ("Accept", "text/html")]

caseFilterHeadersStripsTransferEncoding :: IO ()
caseFilterHeadersStripsTransferEncoding = do
    let headers = [("Transfer-Encoding", "chunked"), ("Accept", "text/html")]
    -- Should be stripped regardless of preserveHost
    filterHeaders False headers @?= [("Accept", "text/html")]
    filterHeaders True headers @?= [("Accept", "text/html")]

caseFilterHeadersStripsContentLength :: IO ()
caseFilterHeadersStripsContentLength = do
    let headers = [("Content-Length", "123"), ("Accept", "text/html")]
    -- Should be stripped regardless of preserveHost
    filterHeaders False headers @?= [("Accept", "text/html")]
    filterHeaders True headers @?= [("Accept", "text/html")]

caseFilterHeadersPreservesOthers :: IO ()
caseFilterHeadersPreservesOthers = do
    let headers = [("Accept", "text/html"), ("User-Agent", "test"), ("X-Custom", "value")]
        result = filterHeaders False headers
    result @?= headers