1 # Written by Arno Bakker
2 # see LICENSE.txt for license information
10 from traceback import print_exc
11 from types import DictType,StringType,IntType
13 from BaseLib.Test.test_as_server import TestAsServer
14 from olconn import OLConnection
15 from btconn import BTConnection
16 from BaseLib.Core.TorrentDef import TorrentDef
17 from BaseLib.Core.DownloadConfig import DownloadStartupConfig
18 from BaseLib.Core.BitTornado.bencode import bencode,bdecode
19 from BaseLib.Core.BitTornado.BT1.MessageID import *
20 from BaseLib.Core.DownloadConfig import *
25 class TestG2G(TestAsServer):
27 Testing EXTEND G2G message V2:
29 See BitTornado/BT1/Connecter.py
33 """ override TestAsServer """
34 TestAsServer.setUp(self)
35 print >>sys.stderr,"test: Giving MyLaunchMany time to startup"
37 print >>sys.stderr,"test: MyLaunchMany should have started up"
39 def setUpPostSession(self):
40 """ override TestAsServer """
41 TestAsServer.setUpPostSession(self)
43 # Let Tribler start downloading an non-functioning torrent, so
44 # we can talk to a normal download engine.
46 self.torrentfn = os.path.join('extend_hs_dir','dummydata.merkle.torrent')
47 tdef = TorrentDef.load(self.torrentfn)
49 dscfg = DownloadStartupConfig()
50 dscfg.set_dest_dir(self.config_path)
51 dscfg.set_video_event_callback(self.vod_ready_callback)
53 self.d = self.session.start_download(tdef,dscfg)
55 # This is the infohash of the torrent in test/extend_hs_dir
56 self.infohash = '\xccg\x07\xe2\x9e!]\x16\xae{\xb8\x10?\xf9\xa5\xf9\x07\xfdBk'
57 self.mylistenport = 4810
59 def vod_ready_callback(self,d,event,params):
64 I want to start a Tribler client once and then connect to
65 it many times. So there must be only one test method
66 to prevent setUp() from creating a new client every time.
68 The code is constructed so unittest will show the name of the
69 (sub)test where the error occured in the traceback it prints.
71 self.subtest_good_tribler_g2g_v2()
72 self.subtest_bad_g2g_v2()
77 def subtest_good_tribler_g2g_v2(self):
78 self._test_good(self.create_good_tribler_extend_hs_v2,infohash=self.infohash)
80 # We've said we're a Tribler peer, and we initiated the connection, so
81 # now *we* should now try to establish an overlay-swarm connection.
82 s = OLConnection(self.my_keypair,'localhost',self.hisport,mylistenport=self.mylistenport)
83 # the connection should be intact, so this should not throw an
89 def _test_good(self,msg_gen_func,options=None,infohash=None,g2g_id=G2G_ID):
90 if options is None and infohash is None:
91 s = BTConnection('localhost',self.hisport)
93 s = BTConnection('localhost',self.hisport,user_infohash=infohash)
94 elif infohash is None:
95 s = BTConnection('localhost',self.hisport,user_option_pattern=options)
97 s = BTConnection('localhost',self.hisport,user_option_pattern=options,user_infohash=infohash)
100 print "test: Creating test HS message",msg_gen_func,"g2g_id",g2g_id
101 msg = msg_gen_func(g2g_id=g2g_id)
103 s.read_handshake_medium_rare()
105 # Send our g2g_v2 message to Tribler
106 msg = self.create_good_g2g_v2(g2g_id=g2g_id)
111 # Tribler should send an EXTEND HS message back
115 self.assert_(len(resp) > 0)
116 self.assert_(resp[0] == EXTEND)
117 self.check_tribler_extend_hs_v2(resp[1:])
118 except socket.timeout:
119 print >> sys.stderr,"test: Timeout, bad, peer didn't reply with EXTEND HS message"
122 # Tribler should send an g2g_v2 message after a while
123 print "test: Setting 60 second timeout to see if Tribler sends periodic g2g_v2"
126 connlist = self.d.sd.dow.connecter.connections.values()[:]
127 piece = '\xab' * (2 ** 14)
128 for conn in connlist:
129 conn.queue_g2g_piece_xfer(0,0,piece)
135 self.assert_(len(resp) > 0)
136 print "test: Tribler returns",getMessageName(resp[0])
137 if resp[0] == EXTEND:
138 self.check_g2g_v2(resp[1:],g2g_id=g2g_id)
141 except socket.timeout:
142 print >> sys.stderr,"test: Timeout, bad, peer didn't reply with EXTEND g2g_v2 message"
146 def create_good_tribler_extend_hs_v2(self,g2g_id=G2G_ID):
148 d['m'] = {'Tr_OVERLAYSWARM':253,'Tr_G2G_v2':g2g_id}
149 d['p'] = self.mylistenport
150 d['v'] = 'Tribler 4.2.0'
153 return EXTEND+chr(0)+bd
155 def check_tribler_extend_hs_v2(self,data):
156 self.assert_(data[0] == chr(0))
157 d = bdecode(data[1:])
158 self.assert_(type(d) == DictType)
159 self.assert_('m' in d.keys())
161 self.assert_(type(m) == DictType)
162 self.assert_('Tr_OVERLAYSWARM' in m.keys())
163 val = m['Tr_OVERLAYSWARM']
164 self.assert_(type(val) == IntType)
165 self.assert_(val == 253)
166 self.assert_('Tr_G2G_v2' in m.keys())
168 self.assert_(type(val) == IntType)
169 self.assert_(val == G2G_ID)
171 def create_good_g2g_v2(self,g2g_id=G2G_ID):
172 d = {'0':'d','1':'b'}
174 return EXTEND+chr(g2g_id)+bd
176 def check_g2g_v2(self,data,g2g_id):
177 self.assert_(data[0] == chr(g2g_id))
178 d = bdecode(data[1:])
180 print >>sys.stderr,"test: l is",`d`
182 self.assert_(type(d) == DictType)
183 for k,v in d.iteritems():
184 self.assert_(type(k) == StringType)
185 self.assert_(type(v) == StringType)
186 self.assert_(ord(k) > 0)
187 self.assert_(ord(v) <= 100)
190 # Bad EXTEND handshake message
192 def subtest_bad_g2g_v2(self):
193 methods = [self.create_empty,
194 self.create_ext_id_not_byte,
195 self.create_not_bdecodable,
196 self.create_not_dict1,
197 self.create_not_dict2,
198 self.create_key_not_int,
199 self.create_val_not_str,
200 self.create_val_too_big]
206 # Main test code for bad EXTEND g2g_v2 messages
208 def _test_bad(self,gen_drequest_func):
209 options = '\x00\x00\x00\x00\x00\x10\x00\x00'
210 s = BTConnection('localhost',self.hisport,user_option_pattern=options,user_infohash=self.infohash)
211 print >> sys.stderr,"\ntest: ",gen_drequest_func
213 hsmsg = self.create_good_tribler_extend_hs_v2()
216 msg = gen_drequest_func()
220 # the other side should not like this and close the connection
223 s.read_handshake_medium_rare(close_ok = True)
227 print >>sys.stderr,"test: Got",getMessageName(resp[0]),"from peer"
228 self.assert_(resp[0] == EXTEND or resp[0]==UNCHOKE)
230 self.assert_(len(resp)==0)
233 except socket.timeout:
234 print >> sys.stderr,"test: Timeout, bad, peer didn't close connection"
238 # Bad message creators
240 def create_empty(self):
241 return EXTEND+chr(G2G_ID)
243 def create_ext_id_not_byte(self):
244 return EXTEND+'Hallo kijkbuiskinderen'
246 def create_not_bdecodable(self):
247 return EXTEND+chr(G2G_ID)+"bla"
249 def create_not_dict1(self):
252 return EXTEND+chr(G2G_ID)+bd
254 def create_not_dict2(self):
257 return EXTEND+chr(G2G_ID)+bd
259 def create_key_not_int(self):
262 return EXTEND+chr(G2G_ID)+bd
264 def create_val_not_str(self):
267 return EXTEND+chr(G2G_ID)+bd
269 def create_val_too_big(self):
272 return EXTEND+chr(G2G_ID)+bd
276 suite = unittest.TestSuite()
277 suite.addTest(unittest.makeSuite(TestG2G))
281 if __name__ == "__main__":