diff options
Diffstat (limited to 'bittorrent/tests/Config.hs')
-rw-r--r-- | bittorrent/tests/Config.hs | 183 |
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 #-} | ||
3 | module 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 | |||
24 | import Control.Monad | ||
25 | import Network | ||
26 | import Data.Default | ||
27 | import Data.IORef | ||
28 | import Data.List as L | ||
29 | import Data.Maybe | ||
30 | import Options.Applicative | ||
31 | import System.Exit | ||
32 | import System.Environment | ||
33 | import System.IO.Unsafe | ||
34 | import Test.Hspec | ||
35 | |||
36 | import Data.Torrent | ||
37 | import Network.BitTorrent.Address (IP, PeerAddr (PeerAddr), genPeerId) | ||
38 | |||
39 | |||
40 | type ClientName = String | ||
41 | |||
42 | |||
43 | #if !MIN_VERSION_network(2,6,3) | ||
44 | instance Read PortNumber where | ||
45 | readsPrec = error "readsPrec" | ||
46 | #endif | ||
47 | |||
48 | data ClientOpts = ClientOpts | ||
49 | { peerPort :: PortNumber -- tcp port | ||
50 | , nodePort :: PortNumber -- udp port | ||
51 | } | ||
52 | |||
53 | instance Default ClientOpts where | ||
54 | def = ClientOpts | ||
55 | { peerPort = 6881 | ||
56 | , nodePort = 6881 | ||
57 | } | ||
58 | |||
59 | defRemoteOpts :: ClientOpts | ||
60 | defRemoteOpts = def | ||
61 | |||
62 | defThisOpts :: ClientOpts | ||
63 | defThisOpts = def | ||
64 | { peerPort = 6882 | ||
65 | , nodePort = 6882 | ||
66 | } | ||
67 | |||
68 | clientOptsParser :: Parser ClientOpts | ||
69 | clientOptsParser = 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 | |||
83 | data EnvOpts = EnvOpts | ||
84 | { testClient :: Maybe ClientName | ||
85 | , testTorrents :: [FilePath] | ||
86 | , remoteOpts :: ClientOpts | ||
87 | , thisOpts :: ClientOpts | ||
88 | } | ||
89 | |||
90 | instance Default EnvOpts where | ||
91 | def = EnvOpts | ||
92 | { testClient = Just "rtorrent" | ||
93 | , testTorrents = ["testfile.torrent"] | ||
94 | , remoteOpts = defRemoteOpts | ||
95 | , thisOpts = defThisOpts | ||
96 | } | ||
97 | |||
98 | findConflicts :: EnvOpts -> [String] | ||
99 | findConflicts 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 | |||
106 | envOptsParser :: Parser EnvOpts | ||
107 | envOptsParser = 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 | |||
117 | envOptsInfo :: ParserInfo EnvOpts | ||
118 | envOptsInfo = 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 | ||
126 | envOptsRef :: IORef EnvOpts | ||
127 | envOptsRef = unsafePerformIO (newIORef def) | ||
128 | |||
129 | -- | Should be used from spec items. | ||
130 | getEnvOpts :: IO EnvOpts | ||
131 | getEnvOpts = readIORef envOptsRef | ||
132 | |||
133 | getThisOpts :: IO ClientOpts | ||
134 | getThisOpts = thisOpts <$> getEnvOpts | ||
135 | |||
136 | -- | Return 'Nothing' if remote client is not running. | ||
137 | getRemoteOpts :: IO (Maybe ClientOpts) | ||
138 | getRemoteOpts = do | ||
139 | EnvOpts {..} <- getEnvOpts | ||
140 | return $ const remoteOpts <$> testClient | ||
141 | |||
142 | withRemote :: (ClientOpts -> Expectation) -> Expectation | ||
143 | withRemote action = do | ||
144 | mopts <- getRemoteOpts | ||
145 | case mopts of | ||
146 | Nothing -> pendingWith "Remote client isn't running" | ||
147 | Just opts -> action opts | ||
148 | |||
149 | withRemoteAddr :: (PeerAddr IP -> Expectation) -> Expectation | ||
150 | withRemoteAddr action = do | ||
151 | withRemote $ \ ClientOpts {..} -> | ||
152 | action (PeerAddr Nothing "0.0.0.0" peerPort) | ||
153 | |||
154 | getMyAddr :: IO (PeerAddr (Maybe IP)) | ||
155 | getMyAddr = do | ||
156 | ClientOpts {..} <- getThisOpts | ||
157 | pid <- genPeerId | ||
158 | return $ PeerAddr (Just pid) Nothing peerPort | ||
159 | |||
160 | getTestTorrent :: IO Torrent | ||
161 | getTestTorrent = 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. | ||
170 | getOpts :: IO (EnvOpts, [String]) | ||
171 | getOpts = 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) | ||