packages feed

hans-2.4.0.0: tests/Tcp/Window.hs

module Tcp.Window where

import Tcp.Packet

import Hans.Layer.Tcp.Window
    (emptyLocalWindow,addInSegment,stepWindow,InSegment(..)
    ,localWindowSackBlocks)
import Hans.Message.Tcp (TcpHeader(..))

import Control.Arrow ((&&&))
import Test.Framework (Test,testGroup)
import Test.QuickCheck (forAll)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import qualified Data.ByteString as S
import qualified Data.Foldable as F
import qualified Data.Sequence as Seq


tcpWindowTests :: Test
tcpWindowTests  = testGroup "tcp window"
  [ testProperty "prop_localOrdered" prop_localOrdered
  , testProperty "prop_localRandom"  prop_localRandom
  , testProperty "prop_sackOrdered"  prop_sackOrdered
  ]


-- Local Window ----------------------------------------------------------------

fromInSegment :: InSegment -> (TcpHeader,S.ByteString)
fromInSegment  = inHeader &&& inBody

-- | Check that if a stream of packets goes into the @LocalWindow@ in order,
-- that they will come out in the same order.
prop_localOrdered = forAll packetStream $ \ segs ->
  let (hdr,_)         = Seq.index segs 0
      win             = emptyLocalWindow (tcpSeqNum hdr) 14600 0
      step w (h,body) = addInSegment h body w
      win'            = F.foldl step win segs
      (segs',_)       = stepWindow win'
   in segs == fmap fromInSegment segs'

-- | Check that if a stream of initially ordered packets goes into the
-- @LocalWindow@ in a random order, that they come out ordered again.  In this
-- case, we just reverse the stream, as that should be the degenrate case for
-- incoming packets.
prop_localRandom = forAll packetStream $ \ segs ->
  let (hdr,_)         = Seq.index segs 0
      win             = emptyLocalWindow (tcpSeqNum hdr) 14600 0
      step (h,body) w = addInSegment h body w
      win'            = F.foldr step win segs
      (segs',_)       = stepWindow win'
   in segs == fmap fromInSegment segs'

-- | Generating a sequence of sack blocks from a window constructed of in-order
-- packets should generate a single sack block.
prop_sackOrdered = forAll packetStream $ \ segs ->
  let (hdr,_)         = Seq.index segs 0
      win             = emptyLocalWindow (tcpSeqNum hdr) 14600 0
      step w (h,body) = addInSegment h body w
      win'            = F.foldl step win segs
   in Seq.length (localWindowSackBlocks win') == 1