mirror of
https://github.com/i2p/i2p.i2p.git
synced 2026-06-08 21:41:42 +00:00
447 lines
12 KiB
Python
447 lines
12 KiB
Python
|
|
# -----------------------------------------------------
|
|
# test_samclasses.py: Unit tests for samclasses.py.
|
|
# -----------------------------------------------------
|
|
|
|
# Make sure we can import i2p
|
|
import sys; sys.path += ['../../']
|
|
|
|
import traceback, time, thread, threading, random
|
|
from i2p import eep, sam, samclasses
|
|
|
|
def test_passed(s, msg='OK'):
|
|
"""Notify user that the given unit test passed."""
|
|
print ' ' + (s + ':').ljust(50) + msg
|
|
|
|
def verify_html(s):
|
|
"""Raise an error if s does not end with </html>"""
|
|
assert s.strip().lower()[-7:] == '</html>'
|
|
|
|
def resolve_test(name='duck.i2p'):
|
|
"""Unit test for resolve."""
|
|
try:
|
|
rname = sam.resolve(name)
|
|
except:
|
|
print 'Unit test failed for sam.resolve'
|
|
traceback.print_exc(); sys.exit()
|
|
|
|
test_passed('sam.resolve', 'See below')
|
|
print ' Use hosts.txt to verify that ' + name + '=' + \
|
|
rname[:15] + '...'
|
|
|
|
def raw_test1():
|
|
"""Unit test for samclasses.RawSession."""
|
|
|
|
try:
|
|
C = samclasses.RawSession('Carol')
|
|
D = samclasses.RawSession('Dave')
|
|
|
|
C.send('Hello!', D.dest)
|
|
D.send('Hi C!', C.dest)
|
|
|
|
(packet, addr) = C.recv(1000)
|
|
assert packet == 'Hi C!'
|
|
(packet, addr) = D.recv(1000)
|
|
assert packet == 'Hello!'
|
|
C.close()
|
|
D.close()
|
|
except:
|
|
print 'Unit test failed for samclasses.RawSession'
|
|
traceback.print_exc(); sys.exit()
|
|
test_passed('samclasses.RawSession')
|
|
|
|
def datagram_test1():
|
|
"""Unit test for samclasses.DatagramSession."""
|
|
|
|
try:
|
|
C = samclasses.DatagramSession('Carol')
|
|
D = samclasses.DatagramSession('Dave')
|
|
|
|
C.send('Hello!', D.dest)
|
|
D.send('Hi C!', C.dest)
|
|
|
|
(packet, remotedest) = C.recv(1000)
|
|
assert str(packet) == 'Hi C!' and remotedest == D.dest
|
|
(packet, remotedest) = D.recv(1000)
|
|
assert str(packet) == 'Hello!' and remotedest == C.dest
|
|
C.close()
|
|
D.close()
|
|
except:
|
|
print 'Unit test failed for samclasses.DatagramSession'
|
|
traceback.print_exc(); sys.exit()
|
|
test_passed('samclasses.DatagramSession')
|
|
|
|
def stream_readline(S):
|
|
"""Read a line, with a \r\n newline, including trailing \r\n."""
|
|
ans = []
|
|
while True:
|
|
c = S.recv(1)
|
|
if c == '': break
|
|
if c == '\n': break
|
|
ans += [c]
|
|
return ''.join(ans)
|
|
|
|
def stream_http_get(S, dest):
|
|
"""Get contents of http://dest/ via HTTP/1.0 and
|
|
samclasses.StreamSession S."""
|
|
C = S.connect(dest)
|
|
|
|
C.send('GET / HTTP/1.0\r\n\r\n')
|
|
|
|
while True:
|
|
line = stream_readline(C).strip()
|
|
if line.find('Content-Length: ') == 0:
|
|
clen = int(line.split()[1])
|
|
if line == '': break
|
|
|
|
s = C.recv(clen, timeout=None)
|
|
time.sleep(2.0)
|
|
C.close()
|
|
return s
|
|
|
|
def stream_test1():
|
|
"""Unit test for samclasses.StreamSession.connect."""
|
|
|
|
try:
|
|
dest = sam.resolve('duck.i2p')
|
|
S = samclasses.StreamSession('Bob')
|
|
verify_html(stream_http_get(S, dest))
|
|
verify_html(stream_http_get(S, dest))
|
|
verify_html(stream_http_get(S, dest))
|
|
S.close()
|
|
|
|
except:
|
|
print 'Unit test failed for samclasses.StreamSession'
|
|
traceback.print_exc(); sys.exit()
|
|
test_passed('samclasses.StreamSession.connect')
|
|
|
|
def stream_test2():
|
|
"""Unit test for samclasses.StreamSession.accept."""
|
|
global __server_done, __client_done, __err
|
|
__server_done = False
|
|
__client_done = False
|
|
__err = None
|
|
|
|
S = samclasses.StreamSession('Bob')
|
|
S.listen(10)
|
|
msg = '<h1>Hello!</h1>'
|
|
|
|
def serve():
|
|
try:
|
|
# Serve 3 connections, then quit.
|
|
for i in range(3):
|
|
C = S.accept() # Get a connection.
|
|
req = stream_readline(C) # Read HTTP request.
|
|
|
|
s = msg # Message to send back
|
|
|
|
C.send('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n' +
|
|
'Content-Length: ' + str(int(len(s))) + '\r\n\r\n' + s)
|
|
|
|
if i % 2 == 0: C.close() # Close connection
|
|
S.close()
|
|
except Exception, e:
|
|
global __err
|
|
__err = e
|
|
global __server_done
|
|
__server_done = True
|
|
|
|
thread.start_new_thread(serve, ())
|
|
# Wait for accept to kick in (should work without).
|
|
time.sleep(2.0)
|
|
|
|
def client():
|
|
try:
|
|
S2 = samclasses.StreamSession('Carol')
|
|
# Get / on server three times.
|
|
assert stream_http_get(S2, S.dest) == msg
|
|
assert stream_http_get(S2, S.dest) == msg
|
|
assert stream_http_get(S2, S.dest) == msg
|
|
S2.close()
|
|
except Exception, e:
|
|
global __err
|
|
__err = e
|
|
global __client_done
|
|
__client_done = True
|
|
|
|
thread.start_new_thread(client, ())
|
|
|
|
while not (__client_done and __server_done): time.sleep(0.01)
|
|
|
|
if __err != None:
|
|
print 'Unit test failed for samclasses.StreamSession.accept'
|
|
raise __err
|
|
test_passed('samclasses.StreamSession.accept')
|
|
|
|
def multithread_packet_test(raw=True):
|
|
"""If raw: Multithreaded unit test for samclasses.RawSession.
|
|
Not raw: Multithreaded unit test for samclasses.DatagramSession.
|
|
"""
|
|
|
|
try:
|
|
multithread_wait_time = 200.0
|
|
may_need_increase = False
|
|
|
|
if raw:
|
|
C = samclasses.RawSession('Carol', in_depth=0, out_depth=0)
|
|
D = samclasses.RawSession('Dave', in_depth=0, out_depth=0)
|
|
else:
|
|
C = samclasses.DatagramSession('Carol',in_depth=0,out_depth=0)
|
|
D = samclasses.DatagramSession('Dave',in_depth=0,out_depth=0)
|
|
|
|
global C_recv, D_recv, C_got, D_got, __lock
|
|
C_recv = [] # Packets C *should* receive
|
|
D_recv = [] # Packets D *should* receive
|
|
C_got = [] # Packets C actually got
|
|
D_got = [] # Packets D actually got
|
|
|
|
n = 50 # Create n threads
|
|
m = 40 # Each thread sends m packets
|
|
|
|
global __done_count
|
|
__done_count = 0
|
|
__lock = threading.Lock()
|
|
|
|
# Use C and D to send and read in many different threads.
|
|
def f():
|
|
# This code is run in each separate thread
|
|
global C_recv, D_recv, C_got, D_got, __lock, __done_count
|
|
for i in range(m):
|
|
# Random binary string of length 2-80.
|
|
index_list = range(random.randrange(2, 80))
|
|
s = ''.join([chr(random.randrange(256)) for j in index_list])
|
|
if random.randrange(2) == 0:
|
|
# Send packet from C to D, and log it.
|
|
C.send(s, D.dest)
|
|
__lock.acquire()
|
|
D_recv += [s]
|
|
__lock.release()
|
|
else:
|
|
# Send packet from D to C, and log it.
|
|
D.send(s, C.dest)
|
|
__lock.acquire()
|
|
C_recv += [s]
|
|
__lock.release()
|
|
time.sleep(0.01*random.uniform(0.0,1.0))
|
|
# Read any available packets.
|
|
try: (p, fromaddr) = C.recv(timeout=0.0)
|
|
except sam.BlockError: p = None
|
|
if p != None and not raw: assert fromaddr == D.dest
|
|
|
|
__lock.acquire()
|
|
if p != None: C_got += [p]
|
|
__lock.release()
|
|
|
|
try: (p, fromaddr) = D.recv(timeout=0.0)
|
|
except sam.BlockError: p = None
|
|
if p != None and not raw: assert fromaddr == C.dest
|
|
|
|
__lock.acquire()
|
|
if p != None: D_got += [p]
|
|
__lock.release()
|
|
|
|
__lock.acquire()
|
|
__done_count += 1
|
|
__lock.release()
|
|
|
|
# Create n threads.
|
|
for i in range(n):
|
|
threading.Thread(target=f).start()
|
|
|
|
# Wait for them to finish.
|
|
while __done_count < n: time.sleep(0.01)
|
|
|
|
# Read any left-over received packets.
|
|
end_time = time.clock() + multithread_wait_time
|
|
while time.clock() < end_time:
|
|
# Read any available packets.
|
|
try: (p, fromaddr) = C.recv(timeout=0.0)
|
|
except sam.BlockError: p = None
|
|
if p != None and not raw: assert fromaddr == D.dest
|
|
|
|
if p != None: C_got += [p]
|
|
|
|
try: (p, fromaddr) = D.recv(timeout=0.0)
|
|
except sam.BlockError: p = None
|
|
if p != None and not raw: assert fromaddr == C.dest
|
|
|
|
if p != None: D_got += [p]
|
|
if len(C_got) == len(C_recv) and len(D_got) == len(D_recv):
|
|
break
|
|
|
|
if time.clock() >= end_time:
|
|
may_need_increase = True
|
|
|
|
C_got.sort()
|
|
D_got.sort()
|
|
C_recv.sort()
|
|
D_recv.sort()
|
|
assert C_got == C_recv
|
|
assert D_got == D_recv
|
|
|
|
C.close()
|
|
D.close()
|
|
except:
|
|
if raw:
|
|
print 'Unit test failed for samclasses.RawSession ' + \
|
|
'(multithreaded).'
|
|
print 'Raw packets are not reliable.'
|
|
else:
|
|
print 'Unit test failed for samclasses.DatagramSession ' + \
|
|
'(multithreaded).'
|
|
print 'Datagram packets are not reliable.'
|
|
|
|
if may_need_increase:
|
|
print 'Try increasing multithread_wait_time.'
|
|
|
|
traceback.print_exc(); sys.exit()
|
|
if raw:
|
|
test_passed('samclasses.RawSession (multithreaded)')
|
|
else:
|
|
test_passed('samclasses.DatagramSession (multithreaded)')
|
|
|
|
|
|
|
|
def multithread_stream_test():
|
|
"""Multithreaded unit test for samclasses.StreamSession."""
|
|
|
|
try:
|
|
multithread_wait_time = 200.0
|
|
may_need_increase = False
|
|
|
|
C = samclasses.StreamSession('Carol', in_depth=0, out_depth=0)
|
|
D = samclasses.StreamSession('Dave', in_depth=0, out_depth=0)
|
|
C.listen(10)
|
|
D.listen(10)
|
|
|
|
Cout = C.connect(D.dest)
|
|
Dout = D.connect(C.dest)
|
|
Cin = C.accept()
|
|
Din = D.accept()
|
|
|
|
global C_recv, D_recv, C_got, D_got, __lock
|
|
C_recv = [] # String data C *should* receive
|
|
D_recv = [] # String data D *should* receive
|
|
C_got = [] # String data C actually got
|
|
D_got = [] # String data D actually got
|
|
|
|
n = 50 # Create n threads
|
|
m = 40 # Each thread sends m strings
|
|
|
|
global __done_count
|
|
__done_count = 0
|
|
__lock = threading.Lock()
|
|
|
|
# Use C and D to send and read in many different threads.
|
|
def f():
|
|
# This code is run in each separate thread
|
|
global C_recv, D_recv, C_got, D_got, __lock, __done_count
|
|
for i in range(m):
|
|
# Random binary string of length 2-80.
|
|
index_list = range(random.randrange(2, 80))
|
|
s = ''.join([chr(random.randrange(256)) for j in index_list])
|
|
if random.randrange(2) == 0:
|
|
# Send packet from C to D, and log it.
|
|
__lock.acquire()
|
|
Cout.send(s)
|
|
D_recv += [s]
|
|
__lock.release()
|
|
else:
|
|
# Send packet from D to C, and log it.
|
|
__lock.acquire()
|
|
Dout.send(s)
|
|
C_recv += [s]
|
|
__lock.release()
|
|
time.sleep(0.01*random.uniform(0.0,1.0))
|
|
# Read any available string data, non-blocking.
|
|
|
|
__lock.acquire()
|
|
try: p = Cin.recv(100000, timeout=0.0)
|
|
except sam.BlockError: p = None
|
|
if p != None: C_got += [p]
|
|
__lock.release()
|
|
|
|
__lock.acquire()
|
|
try: p = Din.recv(100000, timeout=0.0)
|
|
except sam.BlockError: p = None
|
|
if p != None: D_got += [p]
|
|
__lock.release()
|
|
|
|
__lock.acquire()
|
|
__done_count += 1
|
|
__lock.release()
|
|
|
|
# Create n threads.
|
|
for i in range(n):
|
|
threading.Thread(target=f).start()
|
|
|
|
# Wait for them to finish.
|
|
while __done_count < n: time.sleep(0.01)
|
|
|
|
# Read any left-over received string data.
|
|
end_time = time.clock() + multithread_wait_time
|
|
while time.clock() < end_time:
|
|
# Read any available string data, non-blocking.
|
|
try: p = Cin.recv(100000, timeout=0.0)
|
|
except sam.BlockError: p = None
|
|
if p != None: C_got += [p]
|
|
|
|
try: p = Din.recv(100000, timeout=0.0)
|
|
except sam.BlockError: p = None
|
|
if p != None: D_got += [p]
|
|
|
|
if len(''.join(C_got)) == len(''.join(C_recv)) and \
|
|
len(''.join(D_got)) == len(''.join(D_recv)):
|
|
break
|
|
|
|
if time.clock() >= end_time:
|
|
may_need_increase = True
|
|
|
|
C_got = ''.join(C_got)
|
|
D_got = ''.join(D_got)
|
|
C_recv = ''.join(C_recv)
|
|
D_recv = ''.join(D_recv)
|
|
assert C_got == C_recv
|
|
assert D_got == D_recv
|
|
|
|
Cin.close()
|
|
Din.close()
|
|
Cout.close()
|
|
Dout.close()
|
|
C.close()
|
|
D.close()
|
|
except:
|
|
print 'Unit test failed for samclasses.StreamSession ' + \
|
|
'(multithreaded).'
|
|
|
|
if may_need_increase:
|
|
print 'Try increasing multithread_wait_time.'
|
|
|
|
traceback.print_exc(); sys.exit()
|
|
test_passed('samclasses.StreamSession (multithreaded)')
|
|
|
|
|
|
def test():
|
|
print 'Tests may take several minutes each.'
|
|
print 'If the network is unreliable, tests will fail.'
|
|
print 'A test only needs to pass once to be considered successful.'
|
|
print
|
|
print 'Testing:'
|
|
|
|
resolve_test()
|
|
raw_test1()
|
|
datagram_test1()
|
|
stream_test1()
|
|
stream_test2()
|
|
multithread_packet_test(raw=True)
|
|
multithread_stream_test()
|
|
|
|
# Note: The datagram unit test fails, but it's apparently I2P's
|
|
# fault (the code is the same as for raw packets, and the sam
|
|
# bridge is sent all the relevant data).
|
|
# Code: multithread_packet_test(raw=False)
|
|
|
|
if __name__ == '__main__':
|
|
test()
|
|
|