2-- Module : Streamly.Test.Network.Socket
3-- Copyright : (c) 2020 Composewell technologies
4-- License : BSD-3-Clause
5-- Maintainer : streamly@composewell.com
6-- Stability : experimental
9module Main (main) where
11import Control.Concurrent (threadDelay, killThread, forkIO)
12import Control.Concurrent.MVar (MVar, newEmptyMVar, takeMVar, putMVar)
13import Control.Monad.IO.Class (liftIO)
14import Data.Function ((&))
15import Data.Word (Word8)
16import Network.Socket (Socket, PortNumber)
17import Streamly.Internal.Control.Monad (discard)
18import Streamly.Prelude (SerialT)
19import Test.QuickCheck (Property)
20import Test.QuickCheck.Monadic (monadicIO, assert, run)
22import qualified Streamly.Internal.Data.Array.Foreign.Type as Array
23import qualified Streamly.Internal.Data.Unfold as Unfold
24import qualified Streamly.Internal.Network.Inet.TCP as TCP
25import qualified Streamly.Internal.Network.Socket as Socket
26import qualified Streamly.Internal.Unicode.Stream as Unicode
27import qualified Streamly.Prelude as Stream
30import Test.Hspec.QuickCheck
32------------------------------------------------------------------------------
34------------------------------------------------------------------------------
36testData = "Test data 1234567891012131415!@#$%^&*()`~ABCD"
38testDataSource :: String
39testDataSource = concat $ replicate 1000 testData
41------------------------------------------------------------------------------
42-- Read and Write data on a socket
43------------------------------------------------------------------------------
44handlerRW :: Socket -> IO ()
46 Stream.unfold Socket.read sk
47 & Stream.fold (Socket.write sk)
50------------------------------------------------------------------------------
51-- Accept connections and handle connected sockets
52------------------------------------------------------------------------------
54-- Ideally we should choose an available port automatically. However, to test
55-- the APIs that do not allow choosing a port automatically we still need to
56-- use a hardcoded port or search an available port on the system.
58-- This is unreliable and the test may fail on systems where this port is not
59-- available. We choose a higher port number so that the likelihood of it being
62-- Also, we cannot run the test after running it once until the timeout.
67 :: Unfold.Unfold IO PortNumber Socket
72server listener port sem handler = do
74 Stream.fromSerial (Stream.unfold listener port)
75 & (Stream.fromAsync . Stream.mapM (Socket.forSocketM handler))
78remoteAddr :: (Word8,Word8,Word8,Word8)
79remoteAddr = (127, 0, 0, 1)
81sender :: PortNumber -> MVar () -> SerialT IO Char
83 _ <- liftIO $ takeMVar sem
84 liftIO $ threadDelay 1000000 -- wait for server
85 Stream.replicate 1000 testData -- SerialT IO String
86 & Stream.concatMap Stream.fromList -- SerialT IO Char
87 & Unicode.encodeLatin1 -- SerialT IO Word8
88 & TCP.processBytes remoteAddr port -- SerialT IO Word8
89 & Unicode.decodeLatin1 -- SerialT IO Char
92 :: Unfold.Unfold IO PortNumber Socket
96 -> IO (SerialT IO Char)
97execute listener port size handler = do
99 tid <- forkIO $ server listener port sem handler
100 let lst = sender port sem
102 & Stream.finally (killThread tid)
105validateOnPort :: Property
106validateOnPort = monadicIO $ do
109 execute TCP.acceptOnPort basePort Array.defaultChunkSize handlerRW
110 let dataChunk = take Array.defaultChunkSize testDataSource
111 Stream.eqBy (==) (Stream.fromList dataChunk) ls2
114validateOnPortLocal :: Property
115validateOnPortLocal = monadicIO $ do
119 TCP.acceptOnPortLocal
121 Array.defaultChunkSize
123 let dataChunk = take Array.defaultChunkSize testDataSource
124 Stream.eqBy (==) (Stream.fromList dataChunk) ls2
128moduleName = "Network.Inet.TCP"
132 modifyMaxSuccess (const 1) $ do
133 describe moduleName $ do
134 describe "Accept Connections" $ do
135 prop "acceptOnPort" validateOnPort
136 prop "acceptOnPortLocal" validateOnPortLocal
137 -- 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