@@ -36,7 +36,7 @@ testData :: String
36testData = "Test data 1234567891012131415!@#$%^&*()`~ABCD"
36testData = "Test data 1234567891012131415!@#$%^&*()`~ABCD"
38testDataSource :: String
38testDataSource :: String
39−testDataSource = (concat $ replicate 1000 testData)
39+testDataSource = concat $ replicate 1000 testData
41------------------------------------------------------------------------------
41------------------------------------------------------------------------------
42-- Read and Write data on a socket
42-- Read and Write data on a socket
@@ -50,15 +50,28 @@ handlerRW sk =
50------------------------------------------------------------------------------
50------------------------------------------------------------------------------
51-- Accept connections and handle connected sockets
51-- Accept connections and handle connected sockets
52------------------------------------------------------------------------------
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.
63+basePort :: PortNumber
54 :: Unfold.Unfold IO PortNumber Socket
67 :: Unfold.Unfold IO PortNumber Socket
55 -> PortNumber
68 -> PortNumber
56 -> MVar ()
69 -> MVar ()
57 -> (Socket -> IO ())
70 -> (Socket -> IO ())
59−server addr port sem handler = do
72+server listener port sem handler = do
60 putMVar sem ()
73 putMVar sem ()
61− (Stream.serially $ Stream.unfold addr port)
74+ Stream.serially (Stream.unfold listener port)
62 & (Stream.asyncly . Stream.mapM (Socket.handleWithM handler))
75 & (Stream.asyncly . Stream.mapM (Socket.handleWithM handler))
63 & Stream.drain
76 & Stream.drain
@@ -69,8 +82,8 @@ sender :: PortNumber -> MVar () -> SerialT IO Char
69sender port sem = do
82sender port sem = do
70 _ <- liftIO $ takeMVar sem
83 _ <- liftIO $ takeMVar sem
71 liftIO $ threadDelay 1000000 -- wait for server
84 liftIO $ threadDelay 1000000 -- wait for server
72− Stream.replicate 1000 testData -- SerialT IO String
85+ Stream.replicate 1000 testData -- SerialT IO String
73− & Stream.concatMap Stream.fromList -- SerialT IO Char
86+ & Stream.concatMap Stream.fromList -- SerialT IO Char
74 & Unicode.encodeLatin1 -- SerialT IO Word8
87 & Unicode.encodeLatin1 -- SerialT IO Word8
75 & TCP.transformBytesWith remoteAddr port -- SerialT IO Word8
88 & TCP.transformBytesWith remoteAddr port -- SerialT IO Word8
76 & Unicode.decodeLatin1 -- SerialT IO Char
89 & Unicode.decodeLatin1 -- SerialT IO Char
@@ -81,18 +94,19 @@ execute
82 -> (Socket -> IO ())
95 -> (Socket -> IO ())
83 -> IO (SerialT IO Char)
96 -> IO (SerialT IO Char)
84−execute addr port size handler = do
97+execute listener port size handler = do
85 sem <- newEmptyMVar
98 sem <- newEmptyMVar
86− tid <- forkIO $ server addr port sem handler
99+ tid <- forkIO $ server listener port sem handler
87 let lst = sender port sem
100 let lst = sender port sem
88 & Stream.take size
101 & Stream.take size
89 & Stream.finally (killThread tid)
102 & Stream.finally (killThread tid)
90− return $ lst
103+ return lst
92validateOnPort :: Property
105validateOnPort :: Property
93validateOnPort = monadicIO $ do
106validateOnPort = monadicIO $ do
94 res <- run $ do
107 res <- run $ do
95− ls2 <- execute TCP.acceptOnPort 8007 Array.defaultChunkSize handlerRW
109+ execute TCP.acceptOnPort basePort Array.defaultChunkSize handlerRW
96 let dataChunk = take Array.defaultChunkSize testDataSource
110 let dataChunk = take Array.defaultChunkSize testDataSource
97 Stream.eqBy (==) (Stream.fromList dataChunk) ls2
111 Stream.eqBy (==) (Stream.fromList dataChunk) ls2
98 assert res
112 assert res
@@ -102,10 +116,10 @@ validateOnPortLocal = monadicIO $ do
102 res <- run $ do
116 res <- run $ do
105− TCP.acceptOnPortLocal
119+ TCP.acceptOnPortLocal
106− 8008
120+ (basePort + 1)
107− Array.defaultChunkSize
121+ Array.defaultChunkSize
108− handlerRW
122+ handlerRW
109 let dataChunk = take Array.defaultChunkSize testDataSource
123 let dataChunk = take Array.defaultChunkSize testDataSource
110 Stream.eqBy (==) (Stream.fromList dataChunk) ls2
124 Stream.eqBy (==) (Stream.fromList dataChunk) ls2
111 assert res
125 assert res
@@ -113,7 +127,7 @@ validateOnPortLocal = monadicIO $ do
113main :: IO ()
127main :: IO ()
114main = hspec $ do
128main = hspec $ do
115 modifyMaxSuccess (const 1) $ do
129 modifyMaxSuccess (const 1) $ do
116− describe "TCP Tests: " $ do
130+ describe "Accept Connections" $ do
117 prop "acceptOnPort" validateOnPort
131 prop "acceptOnPort" validateOnPort
118 prop "acceptOnPortLocal" validateOnPortLocal
132 prop "acceptOnPortLocal" validateOnPortLocal
119 -- prop "acceptOnAddr/connect" Tested as part of above test cases
133 -- prop "acceptOnAddr/connect" Tested as part of above test cases