1{-# OPTIONS_GHC -Wno-deprecations #-}
4-- Module : Streamly.Test.Network.Socket
5-- Copyright : (c) 2020 Composewell technologies
6-- License : BSD-3-Clause
7-- Maintainer : streamly@composewell.com
8-- Stability : experimental
11module Main (main) where
13import Control.Concurrent (threadDelay, killThread, forkIO)
14import Control.Concurrent.MVar (MVar, newEmptyMVar, takeMVar, putMVar)
15import Control.Monad.IO.Class (liftIO)
16import Data.Function ((&))
17import Data.Word (Word8)
18import Network.Socket (Socket, PortNumber)
19import Streamly.Internal.Control.Monad (discard)
20import Streamly.Internal.System.IO (defaultChunkSize)
21import Streamly.Internal.Data.Stream (Stream)
22import Test.QuickCheck (Property)
23import Test.QuickCheck.Monadic (monadicIO, assert, run)
25import qualified Streamly.Data.Fold as Fold
26import qualified Streamly.Data.Stream.Prelude as Stream
27import qualified Streamly.Internal.Data.Unfold as Unfold
28import qualified Streamly.Internal.Network.Inet.TCP as TCP
29import qualified Streamly.Internal.Network.Socket as Socket
30import qualified Streamly.Internal.Unicode.Stream as Unicode
33import Test.Hspec.QuickCheck
35------------------------------------------------------------------------------
37------------------------------------------------------------------------------
39testData = "Test data 1234567891012131415!@#$%^&*()`~ABCD"
41testDataSource :: String
42testDataSource = concat $ replicate 1000 testData
44------------------------------------------------------------------------------
45-- Read and Write data on a socket
46------------------------------------------------------------------------------
47handlerRW :: Socket -> IO ()
49 Stream.unfold Socket.reader sk
50 & Stream.fold (Socket.write sk)
53------------------------------------------------------------------------------
54-- Accept connections and handle connected sockets
55------------------------------------------------------------------------------
57-- Ideally we should choose an available port automatically. However, to test
58-- the APIs that do not allow choosing a port automatically we still need to
59-- use a hardcoded port or search an available port on the system.
61-- This is unreliable and the test may fail on systems where this port is not
62-- available. We choose a higher port number so that the likelihood of it being
65-- Also, we cannot run the test after running it once until the timeout.
70 :: Unfold.Unfold IO PortNumber Socket
75server listener port sem handler = do
77 Stream.unfold listener port
78 & Stream.mapM (Socket.forSocketM handler)
79 & Stream.fold Fold.drain
81remoteAddr :: (Word8,Word8,Word8,Word8)
82remoteAddr = (127, 0, 0, 1)
84sender :: PortNumber -> MVar () -> Stream IO Char
85sender port sem = Stream.before action stream
89 action = liftIO (takeMVar sem >> threadDelay 1000000) -- wait for server
92 Stream.replicate 1000 testData -- Stream IO String
93 & Stream.concatMap Stream.fromList -- Stream IO Char
94 & Unicode.encodeLatin1 -- Stream IO Word8
95 & TCP.pipeBytes remoteAddr port -- Stream IO Word8
96 & Unicode.decodeLatin1 -- Stream IO Char
99 :: Unfold.Unfold IO PortNumber Socket
103 -> IO (Stream IO Char)
104execute listener port size handler = do
106 tid <- forkIO $ server listener port sem handler
107 let lst = sender port sem
109 & Stream.finally (killThread tid)
112validateOnPort :: Property
113validateOnPort = monadicIO $ do
116 execute TCP.acceptorOnPort basePort defaultChunkSize handlerRW
117 let dataChunk = take defaultChunkSize testDataSource
118 Stream.eqBy (==) (Stream.fromList dataChunk) ls2
121validateOnPortLocal :: Property
122validateOnPortLocal = monadicIO $ do
126 TCP.acceptorOnPortLocal
130 let dataChunk = take defaultChunkSize testDataSource
131 Stream.eqBy (==) (Stream.fromList dataChunk) ls2
135moduleName = "Network.Inet.TCP"
139 modifyMaxSuccess (const 1) $ do
140 describe moduleName $ do
141 describe "Accept Connections" $ do
142 prop "acceptOnPort" validateOnPort
143 prop "acceptOnPortLocal" validateOnPortLocal
144 -- prop "acceptOnAddr/connect" Tested as part of above test cases
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list