packages feed

http3-0.1.0: test/QPACK/QIFSpec.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

module QPACK.QIFSpec where

import Control.Monad
import Data.ByteString (ByteString)
import Data.Conduit.Attoparsec
import Data.IORef
import Data.Sequence (Seq, ViewR (..), viewr, (<|))
import qualified Data.Sequence as Seq
import Network.QUIC (StreamId)
import System.IO
import Test.Hspec

import Network.QPACK
import Network.QPACK.Internal

import QIF

spec :: Spec
spec = do
    describe "simple decoder" $ do
        it "decodes with dynamic table" $ do
            forM_ ["fb-req-hq", "fb-resp-hq", "netbsd-hq"] $ \svc ->
                forM_ ["f5", "ls-qpack", "nghttp3", "proxygen", "qthingey", "quinn"] $ \impl ->
                    forM_ [".0.0", ".0.1", ".100.0", ".100.1"] $ \suffix ->
                        forM_ [256, 512, 4096 :: Int] $ \size -> do
                            let inp =
                                    "qifs/encoded/qpack-05/" ++ impl ++ "/" ++ svc ++ ".out." ++ show size ++ suffix
                                out = "qifs/qifs/" ++ svc ++ ".qif"
                            putStrLn inp
                            test size inp out

        it "decodes only with static table" $ do
            forM_ ["fb-req-hq", "fb-resp-hq", "netbsd-hq"] $ \svc ->
                forM_ ["ls-qpack", "nghttp3", "qthingey", "quinn"] $ \impl ->
                    forM_ [".0.0", ".0.1", ".100.0", ".100.1"] $ \suffix -> do
                        let size = 0
                        let inp =
                                "qifs/encoded/qpack-05/" ++ impl ++ "/" ++ svc ++ ".out." ++ show size ++ suffix
                            out = "qifs/qifs/" ++ svc ++ ".qif"
                        putStrLn inp
                        test size inp out

----------------------------------------------------------------

test :: Int -> FilePath -> FilePath -> IO ()
test size efile qfile = do
    (dec, insthdr) <-
        newQDecoderS
            defaultQDecoderConfig{dcMaxTableCapacity = size}
            (\_ -> return ())
            False
    _ <- encodeEncoderInstructions [SetDynamicTableCapacity size] False >>= insthdr
    ref <- newIORef Seq.empty
    withFile qfile ReadMode $ \h -> do
        processBlock efile $ testSwitch dec insthdr ref h

testSwitch
    :: (StreamId -> ByteString -> IO (Maybe [Header]))
    -> EncoderInstructionHandlerS
    -> IORef (Seq Block)
    -> Handle
    -> (PositionRange, Block)
    -> IO ()
testSwitch dec insthdr ref h (_, blk@(Block n bs))
    | n == 0 = do
        _ <- insthdr bs
        fifo <- readIORef ref
        loop fifo
    -- to avoid blocking by "dec", ask decoding to the other thread
    | otherwise = do
        mhdr <- dec n bs
        case mhdr of
            Nothing -> modifyIORef' ref (blk <|)
            Just hdr -> compareHeaders hdr
  where
    loop fifo = do
        case viewr fifo of
            EmptyR -> writeIORef ref Seq.empty
            fifo' :> Block n1 bs1 -> do
                mhdr <- dec n1 bs1
                case mhdr of
                    Nothing -> writeIORef ref fifo
                    Just hdr -> do
                        compareHeaders hdr
                        loop fifo'
    compareHeaders hdr = do
        hdr' <- fromCaseSensitive <$> headerlist h
        fromCaseSensitive hdr `shouldBe` hdr'