diff options
Diffstat (limited to 'test-server.hs')
-rw-r--r-- | test-server.hs | 541 |
1 files changed, 541 insertions, 0 deletions
diff --git a/test-server.hs b/test-server.hs new file mode 100644 index 00000000..795a8190 --- /dev/null +++ b/test-server.hs | |||
@@ -0,0 +1,541 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | ||
2 | module Main where | ||
3 | |||
4 | import Debug.Trace | ||
5 | import Control.Exception (evaluate) -- ,handle,SomeException(..),bracketOnError) | ||
6 | import Control.Exception ({-evaluate,-}handle,SomeException(..),bracketOnError,ErrorCall(..)) | ||
7 | import System.IO.Error (ioeGetErrorType) | ||
8 | import Server | ||
9 | import Control.Monad | ||
10 | import Control.Monad.Trans.Resource | ||
11 | import Control.Monad.IO.Class | ||
12 | import Control.Monad.STM | ||
13 | import Control.Monad.Fix | ||
14 | import Control.Concurrent (threadDelay,forkOS,forkIO) | ||
15 | import Control.Concurrent.STM.TMVar | ||
16 | import Control.Concurrent.STM.TChan | ||
17 | import Network.Socket | ||
18 | import System.Process.Internals | ||
19 | import System.Process | ||
20 | import Data.Char | ||
21 | import System.IO hiding (isEOF) | ||
22 | import System.Posix.Signals hiding (Ignore) | ||
23 | |||
24 | |||
25 | makeGots sv = do | ||
26 | let chan = serverEvent sv | ||
27 | gotchan <- atomically $ dupTChan chan | ||
28 | forkIO $ do | ||
29 | fix $ \loop -> do | ||
30 | (k,e) <- atomically $ readTChan chan | ||
31 | case e of | ||
32 | Connection pingflag read write -> todo | ||
33 | EOF -> todo | ||
34 | loop | ||
35 | return gotchan | ||
36 | |||
37 | isConnection (_,Connection {}) = True | ||
38 | isConnection _ = False | ||
39 | isPending want (_,HalfConnection got) | got/=want = True | ||
40 | isPending _ _ = False | ||
41 | isRead str (_,Got r) | r==str = True | ||
42 | isRead _ _ = False | ||
43 | isEOF (_,EOF) = True | ||
44 | isEOF _ = False | ||
45 | |||
46 | -- localhost port = SockAddrInet port 127 | ||
47 | localhost port = SockAddrInet6 port 0 (0,0,0,1) 0 | ||
48 | |||
49 | withServer f = runResourceT $ do | ||
50 | sv <- server | ||
51 | result <- liftIO $ f sv | ||
52 | release (serverReleaseKey sv) | ||
53 | return result | ||
54 | |||
55 | writeToPort port str = do | ||
56 | s <- readProcess "/usr/bin/socat" ["-","TCP6:localhost:"++show port] str | ||
57 | reverse s `seq` return () | ||
58 | |||
59 | connectToPort port = do | ||
60 | (inp,outp,err,p) <- | ||
61 | runInteractiveProcess "/usr/bin/socat" | ||
62 | ["-","TCP6:localhost:"++show port] | ||
63 | Nothing | ||
64 | Nothing | ||
65 | hSetBuffering inp NoBuffering | ||
66 | hSetBuffering outp NoBuffering | ||
67 | hSetBuffering err NoBuffering | ||
68 | forkOS $ do putStrLn $ "SOCAT-ConnectToPort:"++show (port,(inp,outp,err)) | ||
69 | hGetContents err >>= putStrLn | ||
70 | return (inp,outp,err,p) | ||
71 | |||
72 | listenOnPort port = do | ||
73 | putStrLn $ "socat - TCP6-LISTEN:"++show port++",fork" | ||
74 | (inp,outp,err,p) <- | ||
75 | runInteractiveProcess "/usr/bin/socat" | ||
76 | ["-","TCP6-LISTEN:"++show port++",fork"] | ||
77 | Nothing | ||
78 | Nothing | ||
79 | hSetBuffering inp NoBuffering | ||
80 | hSetBuffering outp NoBuffering | ||
81 | hSetBuffering err NoBuffering | ||
82 | forkOS $ do { putStrLn "SOCAT-listenOnPort:"; hGetContents err >>= putStrLn } | ||
83 | -- forkOS $ do { putStrLn "SOCAT-listenOnPort:"; hGetContents outp >>= putStrLn } | ||
84 | return (inp,outp,err,p) | ||
85 | |||
86 | stopListening (inp,outp,err,p) = do | ||
87 | {- | ||
88 | forkOS $ do | ||
89 | o <- hGetContents outp | ||
90 | void $ evaluate (length o) | ||
91 | forkOS $ do | ||
92 | e <- hGetContents err | ||
93 | void $ evaluate (length e) | ||
94 | threadDelay 1000000 | ||
95 | hClose inp | ||
96 | threadDelay 1000000 | ||
97 | forkOS $ do | ||
98 | threadDelay 100000 | ||
99 | mapM_ hClose [outp,err] | ||
100 | -} | ||
101 | withProcessHandle p $ \p -> do | ||
102 | case p of | ||
103 | OpenHandle pid -> trace ("interrupting: "++show pid) | ||
104 | $ signalProcess sigINT pid | ||
105 | _ -> return () | ||
106 | return (p,()) | ||
107 | {- | ||
108 | threadDelay 500000 | ||
109 | terminateProcess p | ||
110 | -} | ||
111 | e <- waitForProcess p | ||
112 | putStrLn $ "SOCAT-LISTEN exit: "++show e | ||
113 | |||
114 | |||
115 | |||
116 | chanContents ch = do | ||
117 | x <- atomically $ do | ||
118 | bempty <- isEmptyTChan ch | ||
119 | if bempty | ||
120 | then return Nothing | ||
121 | else fmap Just $ readTChan ch | ||
122 | maybe (return []) | ||
123 | (\x -> do | ||
124 | xs <- chanContents ch | ||
125 | return (x:xs)) | ||
126 | x | ||
127 | |||
128 | control sv = atomically . putTMVar (serverCommand sv) | ||
129 | |||
130 | testListen = do | ||
131 | let send con str = do hPutStr con str | ||
132 | hFlush con | ||
133 | threadDelay 100000 | ||
134 | events <- withServer $ \sv -> do | ||
135 | let _ = sv :: Server SockAddr | ||
136 | events = serverEvent sv | ||
137 | params :: ConnectionParameters SockAddr | ||
138 | params = connectionDefaults (return . snd) | ||
139 | control sv (Listen 39242 params) | ||
140 | h1@(con1,con2,_,_)<- connectToPort 39242 | ||
141 | send con1 "Joe was here" | ||
142 | control sv (Ignore 39242) | ||
143 | threadDelay 500000 | ||
144 | stopListening h1 | ||
145 | threadDelay 500000 | ||
146 | return events | ||
147 | e <- chanContents events | ||
148 | putStrLn $ "testListen: "++ show e | ||
149 | return $ | ||
150 | and [ length e == 3 | ||
151 | , isConnection $ e !! 0 | ||
152 | , isRead "Joe was here" $ e !! 1 | ||
153 | , isEOF $ e !! 2 | ||
154 | ] | ||
155 | |||
156 | |||
157 | testReplace = do | ||
158 | let send con str = do hPutStrLn con str | ||
159 | hFlush con | ||
160 | threadDelay 100000 | ||
161 | events <- withServer $ \sv -> do | ||
162 | let _ = sv :: Server () | ||
163 | events = serverEvent sv | ||
164 | params = connectionDefaults (const $ return ()) | ||
165 | control sv (Listen 39242 params) | ||
166 | h1@(con1,_,_,_)<- connectToPort 39242 | ||
167 | send con1 "Joe was here" | ||
168 | h2@(con2,_,_,_) <- connectToPort 39242 | ||
169 | send con2 "Jim also" | ||
170 | send con1 "What?" | ||
171 | threadDelay 500000 | ||
172 | stopListening h1 -- misnomer | ||
173 | stopListening h2 -- misnomer | ||
174 | threadDelay 500000 | ||
175 | return events | ||
176 | e <- chanContents events | ||
177 | -- [([::ffff:127.0.0.1]:43722,Connection) | ||
178 | -- ,([::ffff:127.0.0.1]:43722,Got "Joe was here\n") | ||
179 | -- ,([::ffff:127.0.0.1]:43723,Connection) | ||
180 | -- ,([::ffff:127.0.0.1]:43723,Got "Jim also\n") | ||
181 | -- ,([::ffff:127.0.0.1]:43722,Got "What?\n") | ||
182 | -- ,([::ffff:127.0.0.1,EOF)]:43722 | ||
183 | -- ,([::ffff:127.0.0.1,EOF)]:43723] | ||
184 | -- putStrLn $ show e | ||
185 | putStrLn $ "testReplace: "++ show e | ||
186 | return $ case e of | ||
187 | [(_,Connection {}) | ||
188 | ,(_,Got "Joe was here\n") | ||
189 | ,(_,EOF) | ||
190 | ,(_,Connection {}) | ||
191 | ,(_,Got "Jim also\n") | ||
192 | ,(_,EOF)] | ||
193 | -> True | ||
194 | _ -> False | ||
195 | |||
196 | testPendingOut = do | ||
197 | let send con str = do hPutStr con str | ||
198 | hFlush con | ||
199 | threadDelay 100000 | ||
200 | events <- withServer $ \sv -> do | ||
201 | let _ = sv :: Server SockAddr | ||
202 | events = serverEvent sv | ||
203 | params :: ConnectionParameters SockAddr | ||
204 | params = (connectionDefaults (return . snd)) | ||
205 | { duplex = False } | ||
206 | control sv (Listen 39249 params) | ||
207 | h1@(con1,con2,_,_)<- connectToPort 39249 | ||
208 | send con1 "Joe was here" | ||
209 | stopListening h1 | ||
210 | threadDelay 500000 | ||
211 | return events | ||
212 | |||
213 | e <- chanContents events | ||
214 | putStrLn $ "testPendingOut: "++ show e | ||
215 | return $ | ||
216 | and [ length e == 3 | ||
217 | , isPending Out $ e !! 0 | ||
218 | , isRead "Joe was here" $ e !! 1 | ||
219 | , isEOF $ e !! 2 | ||
220 | ] | ||
221 | |||
222 | testReplacePendingOut = do | ||
223 | let send con str = do hPutStrLn con str | ||
224 | hFlush con | ||
225 | threadDelay 100000 | ||
226 | events <- withServer $ \sv -> do | ||
227 | let _ = sv :: Server () | ||
228 | events = serverEvent sv | ||
229 | params = (connectionDefaults (const $ return ())) | ||
230 | { duplex = False } | ||
231 | control sv (Ignore 39242) | ||
232 | control sv (Listen 39242 params) | ||
233 | threadDelay 500000 | ||
234 | h1@(con1,_,_,_) <- connectToPort 39242 | ||
235 | send con1 "Joe was here" | ||
236 | h2@(con2,_,_,_) <- connectToPort 39242 | ||
237 | send con2 "Jim also" | ||
238 | send con1 "What?" | ||
239 | threadDelay 500000 | ||
240 | control sv (Ignore 39242) | ||
241 | threadDelay 500000 | ||
242 | stopListening h1 -- misnomer | ||
243 | stopListening h2 -- misnomer | ||
244 | threadDelay 500000 | ||
245 | return events | ||
246 | e <- chanContents events | ||
247 | putStrLn $ "testReplacePendingOut: "++ show e | ||
248 | return $ case e of | ||
249 | [ (_,HalfConnection In) | ||
250 | ,(_,Got "Joe was here\n") | ||
251 | ,(_,EOF) | ||
252 | ,(_,HalfConnection In) | ||
253 | ,(_,Got "Jim also\n") | ||
254 | ,(_,EOF)] | ||
255 | -> True | ||
256 | _ -> False | ||
257 | |||
258 | testReplacePendingIn = do | ||
259 | let send con str = do hPutStrLn con str | ||
260 | hFlush con | ||
261 | threadDelay 100000 | ||
262 | (events,socat) <- withServer $ \sv -> do | ||
263 | let _ = sv :: Server () | ||
264 | events = serverEvent sv | ||
265 | params = (connectionDefaults (const $ return ())) | ||
266 | { duplex = False } | ||
267 | threadDelay 500000 | ||
268 | socat <- listenOnPort 39242 | ||
269 | threadDelay 500000 | ||
270 | control sv (Connect (localhost 39242) params) | ||
271 | control sv (Connect (localhost 39242) params) | ||
272 | return (events,socat) | ||
273 | threadDelay 500000 | ||
274 | stopListening socat | ||
275 | threadDelay 500000 | ||
276 | e <- chanContents events | ||
277 | putStrLn $ "testReplacePendingIn: "++ show e | ||
278 | return $ e==[((),HalfConnection Out) | ||
279 | ,((),EOF) | ||
280 | ,((),HalfConnection Out) | ||
281 | ,((),EOF)] | ||
282 | |||
283 | testPromotePendingOut = do | ||
284 | putStrLn "----------- testPromotePendingOut" | ||
285 | hFlush stdout | ||
286 | let send con str = do hPutStr con str | ||
287 | hFlush con | ||
288 | threadDelay 100000 | ||
289 | (events,s,socat) <- withServer $ \sv -> do | ||
290 | let _ = sv :: Server () | ||
291 | events = serverEvent sv | ||
292 | params = (connectionDefaults (const $ return ())) | ||
293 | { duplex = False } | ||
294 | control sv (Ignore 39244) | ||
295 | threadDelay 500000 | ||
296 | control sv (Listen 39244 params) | ||
297 | socat <- listenOnPort 39243 | ||
298 | h@(con1,con2,_,_) <- connectToPort 39244 | ||
299 | putStrLn $ "connected to 39244, Sending Joe was here" | ||
300 | send con1 "Joe was here" | ||
301 | threadDelay 500000 | ||
302 | putStrLn $ "Connecting to 39243" | ||
303 | control sv (Connect (localhost 39243) params) | ||
304 | threadDelay 500000 | ||
305 | putStrLn $ "probably connected to 39243" | ||
306 | control sv (Send () "and jim") | ||
307 | putStrLn $ "connected to 39244, Sending Joe was here twice" | ||
308 | hFlush stdout | ||
309 | send con1 "Joe was here twice" | ||
310 | threadDelay 500000 | ||
311 | s <- fmap (take 7) $ hGetContents ((\(_,x,_,_)->x) socat) | ||
312 | last s `seq` threadDelay 500000 | ||
313 | stopListening h -- misnomer | ||
314 | threadDelay 50000 | ||
315 | return (events,s,socat) | ||
316 | stopListening socat | ||
317 | threadDelay 500000 | ||
318 | e <- chanContents events | ||
319 | putStrLn $ "testPromotePendingOut: "++ show (s,e) | ||
320 | -- testPromotePendingOut: ("and jim",[HalfConnection () In,((),Got "Joe was here"),((),Read () "Joe was here twice",((),EOF)]),Connection) | ||
321 | -- | ||
322 | return . and $ | ||
323 | [ s== "and jim" | ||
324 | , e== [ ((),HalfConnection In) | ||
325 | , ((),Got "Joe was here") | ||
326 | , ((),Connection {}) | ||
327 | , ((),Got "Joe was here twice") | ||
328 | , ((),EOF) ] | ||
329 | ] | ||
330 | |||
331 | testPromotePendingIn = do | ||
332 | putStrLn "----------- testPromotePendingIn" | ||
333 | hFlush stdout | ||
334 | let send con str = do handle (\e -> putStrLn . show $ ioeGetErrorType e) $ do | ||
335 | hPutStrLn con str | ||
336 | hFlush con | ||
337 | threadDelay 500000 | ||
338 | (events,socat,s) <- withServer $ \sv -> do | ||
339 | let _ = sv :: Server () | ||
340 | events = serverEvent sv | ||
341 | params = (connectionDefaults (const $ return ())) | ||
342 | { duplex = False } | ||
343 | |||
344 | -- Outgoing connection | ||
345 | socat <- listenOnPort 39248 | ||
346 | threadDelay 500000 | ||
347 | putStrLn $ "Connecting to 39248..." | ||
348 | control sv (Connect (localhost 39248) params) | ||
349 | threadDelay 1000000 | ||
350 | putStrLn $ "...probably connected to 39248" | ||
351 | control sv (Send () "and jim") | ||
352 | threadDelay 1000000 | ||
353 | |||
354 | s <- fmap (take 7) $ hGetContents ((\(_,x,_,_)->x) socat) | ||
355 | length s `seq` threadDelay 500000 | ||
356 | |||
357 | control sv (Listen 39247 params) | ||
358 | threadDelay 500000 | ||
359 | h@(con1,con2,_,_) <- connectToPort 39247 | ||
360 | send con1 "howdy!" | ||
361 | h2@(con1',con2',_,_) <- connectToPort 39247 | ||
362 | threadDelay 500000 | ||
363 | send con1' "what?" | ||
364 | threadDelay 1000000 | ||
365 | hClose con1 | ||
366 | hClose con1' | ||
367 | threadDelay 1000000 | ||
368 | stopListening socat | ||
369 | threadDelay 1000000 | ||
370 | |||
371 | return (events,socat,s) | ||
372 | e <- chanContents events | ||
373 | putStrLn $ "testPromotePendingIn: "++ show (s,e) | ||
374 | -- testPromotePendingIn: ("and jim",[HalfConnection () Out,((),((),Got "howdy!\n"),((),EOF (),HalfConnection () In,Read () "what?\n",EOF (),EOF)]),Connection) | ||
375 | -- ("and jim",[HalfConnection () Out,((),((),Got "howdy!\n"),((),HalfConnection () In,Read () "what?\n",EOF (),EOF)]),Connection) | ||
376 | return . and $ | ||
377 | [ s == "and jim" | ||
378 | , e == [ ((),HalfConnection Out) | ||
379 | ,((),Connection {}) | ||
380 | ,((),Got "howdy!\n") | ||
381 | ,((),EOF) | ||
382 | ,((),HalfConnection In) | ||
383 | ,((),Got "what?\n") | ||
384 | ,((),EOF)] | ||
385 | ] | ||
386 | |||
387 | testPing = do | ||
388 | putStrLn "----------- testPing" | ||
389 | let send con str = do handle (\e -> putStrLn . show $ ioeGetErrorType e) $ do | ||
390 | hPutStrLn con str | ||
391 | hFlush con | ||
392 | threadDelay 500000 | ||
393 | events <- withServer $ \sv -> do | ||
394 | let _ = sv :: Server () | ||
395 | events = serverEvent sv | ||
396 | params = (connectionDefaults (const $ return ())) | ||
397 | { pingInterval = 2000 | ||
398 | , timeout = 1000 } | ||
399 | control sv (Listen 32957 params) | ||
400 | threadDelay 500000 | ||
401 | socat@(h,_,_,_) <- connectToPort 32957 | ||
402 | |||
403 | -- putStrLn $ "sending hey you!" | ||
404 | send h "hey you!" | ||
405 | -- putStrLn $ "delay" | ||
406 | threadDelay 3500000 -- ping timeout | ||
407 | -- putStrLn $ "sending what?" | ||
408 | send h "what?" -- lost due to timeout | ||
409 | -- putStrLn $ "delay-2" | ||
410 | threadDelay 500000 | ||
411 | -- putStrLn $ "close h" | ||
412 | hClose h | ||
413 | |||
414 | threadDelay 500000 | ||
415 | socat@(h,_,_,_) <- connectToPort 32957 | ||
416 | send h "try 2: hey you!" | ||
417 | threadDelay 2500000 -- ping warning | ||
418 | send h "try 2: what?" | ||
419 | threadDelay 1000000 -- no warning or timeout | ||
420 | send h "try 2: yes." | ||
421 | stopListening socat | ||
422 | threadDelay 1000000 | ||
423 | return events | ||
424 | |||
425 | e <- chanContents events | ||
426 | putStrLn $ "testPing: "++show e | ||
427 | -- testPing: [((),Connection <STM action> <IO action> <function>) | ||
428 | {- | ||
429 | ,((),Got "hey you!\n") | ||
430 | ,((),RequiresPing) | ||
431 | ,((),RequiresPing) | ||
432 | ,((),Got "what?\n") | ||
433 | ,((),EOF) | ||
434 | ,((),Connection <STM action> <IO action> <function>) | ||
435 | ,((),Got "try 2: hey you!\n") | ||
436 | ,((),RequiresPing) | ||
437 | ,((),Got "try 2: what?\n") | ||
438 | ,((),Got "try 2: yes.\n") | ||
439 | ,((),EOF)] | ||
440 | testPing: [((),Connection <STM action> <IO action> <function>) | ||
441 | ,((),Got "hey you!\n") | ||
442 | ,((),RequiresPing) | ||
443 | ,((),Got "what?\n") | ||
444 | ,((),RequiresPing) | ||
445 | ,((),EOF) | ||
446 | ,((),Connection <STM action> <IO action> <function>) | ||
447 | ,((),Got "try 2: hey you!\n") | ||
448 | ,((),RequiresPing) | ||
449 | ,((),Got "try 2: what?\n") | ||
450 | ,((),RequiresPing)] | ||
451 | testPing: [((),Connection <STM action> <IO action> <function>) | ||
452 | ,((),Got "hey you!\n") | ||
453 | ,((),RequiresPing) | ||
454 | ,((),Got "what?\n") | ||
455 | ,((),RequiresPing) | ||
456 | ,((),EOF) | ||
457 | ,((),Connection <STM action> <IO action> <function>) | ||
458 | ,((),Got "try 2: hey you!\n") | ||
459 | ,((),RequiresPing) | ||
460 | ,((),Got "try 2: what?\n") | ||
461 | ,((),Got "try 2: yes.\n") | ||
462 | ,((),EOF)] | ||
463 | |||
464 | -} | ||
465 | |||
466 | return $ e == [((),Connection {}) | ||
467 | ,((),Got "hey you!\n") | ||
468 | ,((),RequiresPing) | ||
469 | ,((),EOF) | ||
470 | ,((),Connection {}) | ||
471 | ,((),Got "try 2: hey you!\n") | ||
472 | ,((),RequiresPing) | ||
473 | ,((),Got "try 2: what?\n") | ||
474 | ,((),Got "try 2: yes.\n") | ||
475 | ,((),EOF)] | ||
476 | |||
477 | testDisabledPing = do | ||
478 | let send con str = do hPutStrLn con str | ||
479 | hFlush con | ||
480 | threadDelay 500000 | ||
481 | events <- withServer $ \sv -> do | ||
482 | let _ = sv :: Server () | ||
483 | events = serverEvent sv | ||
484 | params = (connectionDefaults (const $ return ())) | ||
485 | { pingInterval = 0 | ||
486 | , timeout = 0 } | ||
487 | control sv (Listen 32958 params) | ||
488 | threadDelay 500000 | ||
489 | socat@(h,_,_,_) <- connectToPort 32958 | ||
490 | |||
491 | send h "hey you!" | ||
492 | threadDelay 3500000 -- ping timeout | ||
493 | send h "what?" -- lost due to timeout | ||
494 | threadDelay 500000 | ||
495 | hClose h | ||
496 | |||
497 | threadDelay 500000 | ||
498 | socat@(h,_,_,_) <- connectToPort 32958 | ||
499 | send h "try 2: hey you!" | ||
500 | threadDelay 2500000 -- ping warning | ||
501 | send h "try 2: what?" | ||
502 | threadDelay 1000000 -- no warning or timeout | ||
503 | send h "try 2: yes." | ||
504 | stopListening socat | ||
505 | threadDelay 5000000 | ||
506 | return events | ||
507 | |||
508 | e <- chanContents events | ||
509 | putStrLn $ "testDisabledPing: "++show e | ||
510 | return $ e == [((),Connection {}) | ||
511 | ,((),Got "hey you!\n") | ||
512 | ,((),Got "what?\n") | ||
513 | ,((),EOF) | ||
514 | ,((),Connection {}) | ||
515 | ,((),Got "try 2: hey you!\n") | ||
516 | ,((),Got "try 2: what?\n") | ||
517 | ,((),Got "try 2: yes.\n") | ||
518 | ,((),EOF)] | ||
519 | main = do | ||
520 | result1 <- testListen | ||
521 | result2 <- testReplace | ||
522 | result3 <- testPendingOut | ||
523 | result4 <- testReplacePendingOut | ||
524 | threadDelay 100000 | ||
525 | result5 <- testReplacePendingIn | ||
526 | result6 <- testPromotePendingOut | ||
527 | result7 <- testPromotePendingIn | ||
528 | result8 <- testPing | ||
529 | result9 <- testDisabledPing | ||
530 | let passOrFail str True = putStrLn $ str ++ ": passed" | ||
531 | passOrFail str False = putStrLn $ str ++ ": failed" | ||
532 | passOrFail "testListen" result1 | ||
533 | passOrFail "testReplace" result2 | ||
534 | passOrFail "testPendingOut" result3 | ||
535 | passOrFail "testReplacePendingOut" result4 | ||
536 | passOrFail "testReplacePendingIn" result5 | ||
537 | passOrFail "testPromotePendingOut" result6 | ||
538 | passOrFail "testPromotePendingIn" result7 | ||
539 | passOrFail "testPing" result8 | ||
540 | passOrFail "testDisabledPing" result9 | ||
541 | return () | ||