summaryrefslogtreecommitdiff
path: root/bittorrent/tests/Config.hs
diff options
context:
space:
mode:
Diffstat (limited to 'bittorrent/tests/Config.hs')
-rw-r--r--bittorrent/tests/Config.hs183
1 files changed, 183 insertions, 0 deletions
diff --git a/bittorrent/tests/Config.hs b/bittorrent/tests/Config.hs
new file mode 100644
index 00000000..55e30867
--- /dev/null
+++ b/bittorrent/tests/Config.hs
@@ -0,0 +1,183 @@
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE RecordWildCards #-}
3module Config
4 ( -- * Types
5 ClientName
6 , ClientOpts (..)
7 , EnvOpts (..)
8
9 -- * For test suite driver
10 , getOpts
11
12 -- * For item specs
13 , getEnvOpts
14 , getThisOpts
15 , getMyAddr
16
17 , getRemoteOpts
18 , withRemote
19 , withRemoteAddr
20
21 , getTestTorrent
22 ) where
23
24import Control.Monad
25import Network
26import Data.Default
27import Data.IORef
28import Data.List as L
29import Data.Maybe
30import Options.Applicative
31import System.Exit
32import System.Environment
33import System.IO.Unsafe
34import Test.Hspec
35
36import Data.Torrent
37import Network.BitTorrent.Address (IP, PeerAddr (PeerAddr), genPeerId)
38
39
40type ClientName = String
41
42
43#if !MIN_VERSION_network(2,6,3)
44instance Read PortNumber where
45 readsPrec = error "readsPrec"
46#endif
47
48data ClientOpts = ClientOpts
49 { peerPort :: PortNumber -- tcp port
50 , nodePort :: PortNumber -- udp port
51 }
52
53instance Default ClientOpts where
54 def = ClientOpts
55 { peerPort = 6881
56 , nodePort = 6881
57 }
58
59defRemoteOpts :: ClientOpts
60defRemoteOpts = def
61
62defThisOpts :: ClientOpts
63defThisOpts = def
64 { peerPort = 6882
65 , nodePort = 6882
66 }
67
68clientOptsParser :: Parser ClientOpts
69clientOptsParser = ClientOpts
70 <$> option auto
71 ( long "peer-port" <> short 'p'
72 <> value 6881 <> showDefault
73 <> metavar "NUM"
74 <> help "port to bind the specified bittorrent client"
75 )
76 <*> option auto
77 ( long "node-port" <> short 'n'
78 <> value 6881 <> showDefault
79 <> metavar "NUM"
80 <> help "port to bind node of the specified client"
81 )
82
83data EnvOpts = EnvOpts
84 { testClient :: Maybe ClientName
85 , testTorrents :: [FilePath]
86 , remoteOpts :: ClientOpts
87 , thisOpts :: ClientOpts
88 }
89
90instance Default EnvOpts where
91 def = EnvOpts
92 { testClient = Just "rtorrent"
93 , testTorrents = ["testfile.torrent"]
94 , remoteOpts = defRemoteOpts
95 , thisOpts = defThisOpts
96 }
97
98findConflicts :: EnvOpts -> [String]
99findConflicts EnvOpts {..}
100 | isNothing testClient = []
101 | peerPort remoteOpts == peerPort thisOpts = ["Peer port the same"]
102 | nodePort remoteOpts == nodePort thisOpts = ["Node port the same"]
103 | otherwise = []
104
105
106envOptsParser :: Parser EnvOpts
107envOptsParser = EnvOpts
108 <$> optional (strOption
109 ( long "bittorrent-client"
110 <> metavar "CLIENT"
111 <> help "torrent client to run"
112 ))
113 <*> pure []
114 <*> clientOptsParser
115 <*> clientOptsParser
116
117envOptsInfo :: ParserInfo EnvOpts
118envOptsInfo = info (helper <*> envOptsParser)
119 ( fullDesc
120 <> progDesc "The bittorrent library testsuite"
121 <> header ""
122 )
123
124-- do not modify this while test suite is running because spec items
125-- can run in parallel
126envOptsRef :: IORef EnvOpts
127envOptsRef = unsafePerformIO (newIORef def)
128
129-- | Should be used from spec items.
130getEnvOpts :: IO EnvOpts
131getEnvOpts = readIORef envOptsRef
132
133getThisOpts :: IO ClientOpts
134getThisOpts = thisOpts <$> getEnvOpts
135
136-- | Return 'Nothing' if remote client is not running.
137getRemoteOpts :: IO (Maybe ClientOpts)
138getRemoteOpts = do
139 EnvOpts {..} <- getEnvOpts
140 return $ const remoteOpts <$> testClient
141
142withRemote :: (ClientOpts -> Expectation) -> Expectation
143withRemote action = do
144 mopts <- getRemoteOpts
145 case mopts of
146 Nothing -> pendingWith "Remote client isn't running"
147 Just opts -> action opts
148
149withRemoteAddr :: (PeerAddr IP -> Expectation) -> Expectation
150withRemoteAddr action = do
151 withRemote $ \ ClientOpts {..} ->
152 action (PeerAddr Nothing "0.0.0.0" peerPort)
153
154getMyAddr :: IO (PeerAddr (Maybe IP))
155getMyAddr = do
156 ClientOpts {..} <- getThisOpts
157 pid <- genPeerId
158 return $ PeerAddr (Just pid) Nothing peerPort
159
160getTestTorrent :: IO Torrent
161getTestTorrent = do
162 EnvOpts {..} <- getEnvOpts
163 if L.null testTorrents
164 then error "getTestTorrent"
165 else fromFile ("res/" ++ L.head testTorrents)
166
167-- TODO fix EnvOpts parsing
168
169-- | Should be used by test suite driver.
170getOpts :: IO (EnvOpts, [String])
171getOpts = do
172 args <- getArgs
173-- case runParser SkipOpts envOptsParser args) (prefs idm) of
174 case (Right (def, args), ()) of
175 (Left err , _ctx) -> exitFailure
176 (Right (envOpts, hspecOpts), _ctx) -> do
177 let conflicts = findConflicts envOpts
178 unless (L.null conflicts) $ do
179 forM_ conflicts putStrLn
180 exitFailure
181
182 writeIORef envOptsRef envOpts
183 return (envOpts, hspecOpts)