packages feed

amazonka-core-2.0: test/Test/Amazonka/Sign/V4/Chunked.hs

-- |
-- Module      : Test.Amazonka.Sign.V$
-- Copyright   : (c) 2013-2023 Brendan Hay
-- License     : Mozilla Public License, v. 2.0.
-- Maintainer  : Brendan Hay <brendan.g.hay+amazonka@gmail.com>
-- Stability   : provisional
-- Portability : non-portable (GHC extensions)
module Test.Amazonka.Sign.V4.Chunked (tests) where

import Amazonka.Core hiding (length)
import Amazonka.Prelude hiding (elem)
import Amazonka.Sign.V4
import qualified Data.ByteString.Char8 as BS8
import qualified Data.Conduit.List as Conduit
import qualified Data.Foldable as Fold
import qualified Network.HTTP.Conduit as Client
import Numeric (showHex)
import Test.Amazonka.Arbitrary ()
import qualified Test.QuickCheck as QC
import Test.QuickCheck.Property ()
import Test.Tasty
import Test.Tasty.QuickCheck

tests :: TestTree
tests =
  testGroup
    "headers"
    [ testProperty "empty body" testEmptyBody,
      testProperty "1 chunk body" testOneChunkBody,
      testProperty "2 chunks body" testTwoChunksBody
    ]

testEmptyBody :: Property
testEmptyBody =
  QC.forAll (mkSigned []) $ \Signed {..} ->
    let elem = (`Fold.elem` Client.requestHeaders signedRequest)
     in elem ("X-Amz-Decoded-Content-Length", "0")
          && elem ("Content-Length", "86")

testOneChunkBody :: Property
testOneChunkBody =
  let n = 123
      str = BS8.pack . show
      inp = BS8.replicate n 'a'
   in QC.forAll (mkSigned [inp]) $ \Signed {..} ->
        let elem = (`Fold.elem` Client.requestHeaders signedRequest)
         in elem ("X-Amz-Decoded-Content-Length", str n)
              && elem ("Content-Length", str (87 + n + 86))

testTwoChunksBody :: Property
testTwoChunksBody =
  let size = fromIntegral defaultChunkSize
      sizeLen = length (showHex size "")
      n = 123
      str = BS8.pack . show
      full = BS8.replicate size 'a' -- full-sized chunk
      final = BS8.replicate n 'b' -- final non-empty chunk
   in QC.forAll (mkSigned [full, final]) $ \Signed {..} ->
        let elem = (`Fold.elem` Client.requestHeaders signedRequest)
         in elem ("X-Amz-Decoded-Content-Length", str (size + n))
              && elem ("Content-Length", str (sizeLen + 85 + size + 87 + n + 86))

mkSigned :: [BS8.ByteString] -> Gen (Signed ())
mkSigned bs = do
  aReq <- arbitrary :: Gen (Request ())
  aService <- arbitrary

  let svc = aService {signer = v4}

      req =
        aReq
          { body = Chunked (mkBody bs),
            service = svc
          }

  requestSign req <$> arbitrary <*> arbitrary <*> arbitrary

mkBody :: [BS8.ByteString] -> ChunkedBody
mkBody bs =
  ChunkedBody
    defaultChunkSize
    (fromIntegral . sum $ fmap BS8.length bs)
    (Conduit.sourceList bs)