instrumentation: add next-share/
[cs-p2p-next.git] / instrumentation / next-share / BaseLib / Test / test_buddycast_msg8plus.py
1 # Written by Nicolas Neubauer, Arno Bakker\r
2 # see LICENSE.txt for license information\r
3 #\r
4 # Test case for BuddyCast overlay version 12 (and 8). To be integrated into\r
5 # test_buddycast_msg.py\r
6 #\r
7 # Very sensitive to the order in which things are put into DB,\r
8 # so not a robust test\r
9 \r
10 \r
11 import unittest\r
12 import os\r
13 import sys\r
14 import time\r
15 import tempfile\r
16 import shutil\r
17 from sha import sha\r
18 from random import randint,shuffle\r
19 from traceback import print_exc\r
20 from types import StringType, ListType, DictType\r
21 from threading import Thread\r
22 from time import sleep\r
23 from M2Crypto import Rand,EC\r
24 \r
25 \r
26 from BaseLib.Test.test_as_server import TestAsServer\r
27 from olconn import OLConnection\r
28 from BaseLib.__init__ import LIBRARYNAME\r
29 from BaseLib.Core.BitTornado.bencode import bencode,bdecode\r
30 from BaseLib.Core.BitTornado.BT1.MessageID import *\r
31 \r
32 from BaseLib.Core.CacheDB.CacheDBHandler import BarterCastDBHandler\r
33 \r
34 from BaseLib.Core.BuddyCast.buddycast import BuddyCastFactory, BuddyCastCore\r
35 \r
36 from BaseLib.Core.Overlay.SecureOverlay import OLPROTO_VER_FIRST, OLPROTO_VER_SECOND, OLPROTO_VER_THIRD, OLPROTO_VER_FOURTH, OLPROTO_VER_FIFTH, OLPROTO_VER_SIXTH, OLPROTO_VER_SEVENTH, OLPROTO_VER_EIGHTH, OLPROTO_VER_ELEVENTH, OLPROTO_VER_CURRENT, OLPROTO_VER_LOWEST\r
37 from BaseLib.Core.simpledefs import *\r
38 \r
39 from BaseLib.Core.CacheDB.SqliteCacheDBHandler import *\r
40 from BaseLib.Core.CacheDB.sqlitecachedb import CURRENT_MAIN_DB_VERSION\r
41 \r
42 DEBUG=True\r
43 \r
44     \r
45 \r
46 class TestBuddyCastMsg8Plus(TestAsServer):\r
47     """ \r
48     Testing BuddyCast 5 / overlay protocol v12+v8 interactions:\r
49     swarm size info exchange.\r
50     """\r
51     \r
52     def setUp(self):\r
53         """ override TestAsServer """\r
54         TestAsServer.setUp(self)\r
55         Rand.load_file('randpool.dat', -1)\r
56 \r
57     def setUpPreSession(self):\r
58         """ override TestAsServer """\r
59         TestAsServer.setUpPreSession(self)\r
60         # Enable buddycast\r
61         self.config.set_buddycast(True)\r
62         BuddyCastCore.TESTASSERVER = True\r
63         self.config.set_start_recommender(True)\r
64         self.config.set_bartercast(True)\r
65         \r
66         # Arno, 2010-02-02: Install empty superpeers.txt so no interference from \r
67         # real BuddyCast.\r
68         self.config.set_crawler(False)\r
69         \r
70         # Write superpeers.txt\r
71         self.install_path = tempfile.mkdtemp()\r
72         spdir = os.path.join(self.install_path, LIBRARYNAME, 'Core')\r
73         os.makedirs(spdir)\r
74 \r
75         statsdir = os.path.join(self.install_path, LIBRARYNAME, 'Core', 'Statistics')\r
76         os.makedirs(statsdir)\r
77         \r
78         superpeerfilename = os.path.join(spdir, 'superpeer.txt')\r
79         print >> sys.stderr,"test: writing empty superpeers to",superpeerfilename\r
80         f = open(superpeerfilename, "w")\r
81         f.write('# Leeg')\r
82         f.close()\r
83 \r
84         self.config.set_install_dir(self.install_path)\r
85         \r
86         srcfiles = []\r
87         srcfiles.append(os.path.join(LIBRARYNAME,"schema_sdb_v"+str(CURRENT_MAIN_DB_VERSION)+".sql"))\r
88         for srcfile in srcfiles:\r
89             sfn = os.path.join('..','..',srcfile)\r
90             dfn = os.path.join(self.install_path,srcfile)\r
91             print >>sys.stderr,"test: copying",sfn,dfn\r
92             shutil.copyfile(sfn,dfn)\r
93 \r
94         \r
95 \r
96     def setUpPostSession(self):\r
97         """ override TestAsServer """\r
98         TestAsServer.setUpPostSession(self)\r
99 \r
100         self.mypermid = str(self.my_keypair.pub().get_der())\r
101         self.hispermid = str(self.his_keypair.pub().get_der())        \r
102         self.myhash = sha(self.mypermid).digest()\r
103         \r
104         self.buddycast = BuddyCastFactory.getInstance(superpeer=True)\r
105         self.buddycast.olthread_register(True)\r
106         \r
107 #        arg0 = sys.argv[0].lower()\r
108 #        if arg0.endswith('.exe'):\r
109 #            installdir = os.path.abspath(os.path.dirname(sys.argv[0]))\r
110 #        else:\r
111 #           installdir = os.getcwd()          \r
112 #       self.utility = Utility(installdir)        \r
113 \r
114         \r
115         # wait for buddycast to have completed on run cycle,\r
116         # seems to create problems otherwise\r
117         while not self.buddycast.ranonce:\r
118             pass\r
119             \r
120     def tearDown(self):\r
121         """ override TestAsServer """\r
122         TestAsServer.tearDown(self)\r
123         try:\r
124             os.remove('randpool.dat')\r
125         except:\r
126             pass\r
127 \r
128 \r
129     def singtest_all_olproto_ver_current(self):\r
130         self._test_all(OLPROTO_VER_CURRENT)\r
131 \r
132     def singtest_all_olproto_ver_11(self):\r
133         self._test_all(11)\r
134 \r
135     def singtest_all_olproto_ver_8(self):\r
136         self._test_all(8)\r
137 \r
138     def _test_all(self,myoversion):\r
139         """ \r
140             I want to start a Tribler client once and then connect to\r
141             it many times. So there must be only one test method\r
142             to prevent setUp() from creating a new client every time.\r
143 \r
144             The code is constructed so unittest will show the name of the\r
145             (sub)test where the error occured in the traceback it prints.\r
146         """\r
147         # Arno, 2010-02-03: clicklog 1,2,3 must be run consecutively\r
148         # create_mypref() must be called after clicklog 1,2,3\r
149         self.subtest_good_buddycast_clicklog(1,myoversion)\r
150         self.subtest_good_buddycast_clicklog(2,myoversion)\r
151         self.subtest_good_buddycast_clicklog(3,myoversion)\r
152         self.subtest_terms(myoversion)\r
153         self.subtest_create_mypref()\r
154         self.subtest_create_bc(myoversion)\r
155 \r
156     \r
157     def get_good_clicklog_msg(self,n,myoversion=8):\r
158         if n==1:\r
159             # OLv8:\r
160             # infohash\r
161             # search terms\r
162             # click position\r
163             # reranking strategy\r
164             # OLv11:\r
165             # number of seeders\r
166             # number of leechers\r
167             # age of checking\r
168             # number of sources seen'\r
169             prec = ["hash1hash1hash1hash1", ["linux","ubuntu"], 1, 2]\r
170             if myoversion >= 11:\r
171                 prec += [400, 500, 1000, 50]\r
172             preferences = [prec]\r
173             if myoversion >= 11:\r
174                 prec = ['hash0hash0hash0hash0', 300, 800, 5000, 30]\r
175                 collected_torrents = [prec]\r
176             else:\r
177                 collected_torrents = ['hash0hash0hash0hash0'] \r
178 \r
179         elif n==2:\r
180             prec = ["hash2hash2hash2hash2", ["linux", "ubuntu"], 2, 2]\r
181             if myoversion >= 11:\r
182                 prec += [600, 700,20000,60]\r
183             preferences = [prec]\r
184             if myoversion >= 11:\r
185                 prec = ['hash2hash2hash2hash2', 500, 200, 70000, 8000]\r
186                 collected_torrents = [prec]\r
187             else:\r
188                 collected_torrents = ["hash2hash2hash2hash2"]            \r
189         elif n==3:\r
190             prec = ["hash3hash3hash3hash3", ["linux","redhat"], 5 ,2 ]\r
191             if myoversion >= 11:\r
192                 prec += [800, 900, 30000, 70]\r
193             preferences = [prec]\r
194             if myoversion >= 11:\r
195                 prec = ['hash3hash3hash3hash3', 700, 200, 45000, 75]\r
196                 collected_torrents = [prec]\r
197             else:\r
198                 collected_torrents = ['hash3hash3hash3hash3'] \r
199 \r
200             \r
201         return {\r
202                 'preferences': preferences, \r
203                 'ndls': 1, \r
204                 'permid': self.mypermid,\r
205                 'ip': '127.0.0.1', #'130.149.146.117', \r
206                 'taste buddies': [], \r
207                 'name': 'nic', \r
208                 'random peers': [], \r
209                 'collected torrents': collected_torrents, \r
210                 'nfiles': 0, \r
211                 'npeers': 0, \r
212                 'port': self.hisport, \r
213                 'connectable': 1}\r
214             \r
215 \r
216             \r
217             \r
218     def subtest_good_buddycast_clicklog(self, i, myoversion):\r
219         """sends two buddy cast messages containing clicklog data,\r
220            then checks in the DB to find out whether the correct\r
221            data was stored.\r
222            \r
223            This in fact checks quite a lot of things.\r
224            For example, the messages always contain terms [1,2]\r
225         """\r
226            \r
227         print >>sys.stderr,"\ntest: subtest_good_buddycast_clicklog",i,"selversion",myoversion    \r
228            \r
229         s = OLConnection(self.my_keypair,'localhost',self.hisport,myoversion=myoversion)\r
230         \r
231         prefmsg = self.get_good_clicklog_msg(i,myoversion)\r
232         \r
233         print >>sys.stderr,myoversion,`prefmsg`\r
234         \r
235         msg = self.create_payload(prefmsg)\r
236         s.send(msg)\r
237         resp = s.recv()\r
238         if len(resp)>0:\r
239             print >>sys.stderr,"test: reply message %s:%s" % (getMessageName(resp[0]), resp[1:])\r
240         else:\r
241             print >>sys.stderr,"no reply message"\r
242         self.assert_(len(resp) > 0)\r
243             \r
244         #if we have survived this, check if the content of the remote database is correct\r
245         search_db = self.session.open_dbhandler(NTFY_SEARCH)\r
246         term_db = self.session.open_dbhandler(NTFY_TERM)\r
247         pref_db = self.session.open_dbhandler(NTFY_PREFERENCES)\r
248         torrent_db = self.session.open_dbhandler(NTFY_TORRENTS)\r
249 \r
250         torrent_id = None\r
251         while not torrent_id:\r
252             hash = prefmsg['preferences'][0][0]\r
253             print >> sys.stderr, "hash: %s, bin2str: %s" % (hash, bin2str(hash))\r
254             torrent_data =  torrent_db.getTorrentID(hash)\r
255             print >> sys.stderr, "Torrent data for torrent %s: %s" % (prefmsg['preferences'][0][0], torrent_data)\r
256             torrent_id = torrent_data\r
257             if not torrent_id:\r
258                 print >> sys.stderr, "torrent not yet saved, waiting..."\r
259                 sleep(1)\r
260         \r
261 \r
262         # self.getAll("rowid, peer_id, torrent_id, click_position,reranking_strategy", order_by="peer_id, torrent_id")\r
263         real_prefs = pref_db.getAllEntries()\r
264         print >>sys.stderr,"test: getAllEntries returned",real_prefs\r
265         \r
266         my_peer_id = real_prefs[0][1] \r
267         real_terms = term_db.getAllEntries()\r
268         real_search = search_db.getAllEntries()\r
269         \r
270 \r
271         if i==1:\r
272             wanted_prefs = [[1,my_peer_id,1,1,2]]\r
273             wanted_terms = [[1,u'linux'], [2,u'ubuntu']]\r
274             wanted_search = [[1,my_peer_id,'?',1,0],\r
275                              [2,my_peer_id,'?',2,1]]\r
276         elif i==2:\r
277             # Arno, 2010-02-04: Nicolas assumed the collected torrent for i=1\r
278             # wouldn't be stored in DB?\r
279             wanted_prefs = [[1,my_peer_id,'?',1,2],[2,my_peer_id,torrent_id,2,2]]\r
280             wanted_terms = [[1,u'linux'], [2,u'ubuntu']]\r
281             wanted_search = [[1,my_peer_id,'?',1,0],\r
282                              [2,my_peer_id,'?',2,1],\r
283                              [3,my_peer_id,'?',1,0],\r
284                              [4,my_peer_id,'?',2,1]]\r
285             \r
286         elif i==3:\r
287             wanted_prefs = [[1,my_peer_id,'?',1,2],[2,my_peer_id,'?',2,2],[3,my_peer_id,torrent_id,5,2]]\r
288             wanted_terms = [[1,u'linux'], [2,u'ubuntu'], [3, u'redhat']]\r
289             wanted_search = [[1,my_peer_id,'?',1,0],\r
290                              [2,my_peer_id,'?',2,1],\r
291                              [3,my_peer_id,'?',1,0],\r
292                              [4,my_peer_id,'?',2,1],\r
293                              [5,my_peer_id,'?',1,0],\r
294                              [6,my_peer_id,'?',3,1]]\r
295             \r
296                 \r
297         \r
298         print >> sys.stderr, "real_prefs: %s" % real_prefs\r
299         print >> sys.stderr, "real_terms: %s" % real_terms\r
300         print >> sys.stderr, "real_search: %s " % real_search\r
301 \r
302         print >> sys.stderr, "wanted_prefs: %s" % wanted_prefs\r
303         print >> sys.stderr, "wanted_terms: %s" % wanted_terms\r
304         print >> sys.stderr, "wanted_search: %s " % wanted_search\r
305 \r
306         self.assert_(self.lol_equals(real_search, wanted_search, "good buddycast %d: search" % i))\r
307         self.assert_(self.lol_equals(real_terms, wanted_terms, "good buddycast %d: terms" % i))\r
308         self.assert_(self.lol_equals(real_prefs, wanted_prefs, "good buddycast %d: prefs" % i))\r
309         \r
310     def subtest_terms(self,myoversion):\r
311         """assumes clicklog message 1 and 2 have been sent and digested"""\r
312         \r
313         print >>sys.stderr,"\ntest: subtest_terms"\r
314         \r
315         term_db = self.session.open_dbhandler(NTFY_TERM)\r
316         \r
317         s = OLConnection(self.my_keypair,'localhost',self.hisport,myoversion=myoversion)        \r
318         msg = self.get_good_clicklog_msg(3,myoversion)\r
319         msg = self.create_payload(msg)\r
320         s.send(msg)\r
321         resp = s.recv()\r
322         self.assert_(len(resp) > 0)\r
323         \r
324         termid = term_db.getTermID(u"linux")\r
325         print >>sys.stderr, "TermID for Linux: %s" % termid\r
326         #self.assert_(termid == 1)\r
327         \r
328         #self.assert_(term_db.getTerm(1)==bin2str(str(u"linux")))\r
329         \r
330         completedTerms = term_db.getTermsStartingWith("li")\r
331         print >> sys.stderr, "terms starting with l: %s" % completedTerms  \r
332         self.assert_(len(completedTerms)==1)\r
333         self.assert_(u'linux' in completedTerms)\r
334         \r
335         term_db.insertTerm("asd#")\r
336         completedTerms = term_db.getTermsStartingWith("asd")\r
337         print >> sys.stderr, "terms starting with asd: %s" % completedTerms  \r
338         self.assert_(len(completedTerms)==1)\r
339         # Arno, 2010-02-03: Nicolas had 'asd' here, but I don't see any place\r
340         # where the # should have been stripped.\r
341         #\r
342         self.assert_(u'asd#' in completedTerms)\r
343         \r
344 \r
345 \r
346 \r
347     def subtest_create_mypref(self):\r
348         print >>sys.stderr,"\ntest: creating test MyPreference data"\r
349         \r
350         torrent_db = self.session.open_dbhandler(NTFY_TORRENTS)\r
351         torrent_db.addInfohash('mhashmhashmhashmhash')\r
352         torrent_id = torrent_db.getTorrentID('mhashmhashmhashmhash')\r
353         mypref_db = self.session.open_dbhandler(NTFY_MYPREFERENCES)\r
354         search_db = self.session.open_dbhandler(NTFY_SEARCH)\r
355         \r
356         mypref_db.addMyPreference('mhashmhashmhashmhash', {'destination_path':''}, commit=True)\r
357         clicklog_data = {\r
358                             'click_position': 1,\r
359                             'reranking_strategy': 2,\r
360                             'keywords': ['linux', 'fedora']\r
361                         }\r
362         mypref_db.addClicklogToMyPreference('mhashmhashmhashmhash', clicklog_data, commit=True)\r
363         \r
364         # self.getAll("torrent_id, click_position, reranking_strategy", order_by="torrent_id")\r
365         allEntries = mypref_db.getAllEntries()\r
366         print >> sys.stderr, "all mypref entries: %s" % allEntries\r
367         self.assert_(len(allEntries)==1)\r
368         # (torrent_id, click_pos, rerank_strategy)\r
369         mypref_wanted = [['?',1,2]]\r
370         self.assert_(self.lol_equals(allEntries, mypref_wanted, "create mypref all"))\r
371         \r
372         # self.getAll("rowid, peer_id, torrent_id, term_id, term_order ", order_by="rowid")\r
373         real_search = search_db.getAllOwnEntries()\r
374         wanted_search = [[7,0,torrent_id,1,0],\r
375                          [8,0,torrent_id,5,1]] # is now 5 for some reason\r
376         self.assert_(self.lol_equals(real_search, wanted_search, "create mypref allown"))        \r
377         \r
378         \r
379     def subtest_create_bc(self,myoversion):\r
380         print >>sys.stderr,"\ntest: creating test create_bc"\r
381         \r
382         torrent_db = self.session.open_dbhandler(NTFY_TORRENTS)\r
383         torrent_db._db.update("Torrent", status_id=1)\r
384         pref_db = self.session.open_dbhandler(NTFY_MYPREFERENCES)\r
385         pref_db.loadData()\r
386         msg = self.buddycast.buddycast_core.createBuddyCastMessage(0, myoversion, target_ip="127.0.0.1", target_port=80)\r
387         print >> sys.stderr, "created bc pref: %s" % msg\r
388         \r
389         wantpref = ['mhashmhashmhashmhash',['linux','fedora'],1,2]\r
390         if myoversion >= OLPROTO_VER_ELEVENTH:\r
391             wantpref += [-1,-1,-1,-1]  \r
392         wantprefs = [wantpref]\r
393                 \r
394         self.assert_(msg['preferences']==wantprefs)\r
395         \r
396 \r
397                 \r
398     def lol_equals(self, lol1, lol2, msg):\r
399         ok = True\r
400         for (l1, l2) in zip(lol1, lol2):\r
401             for (e1, e2) in zip(l1, l2):\r
402                 if e1=='?' or e2=='?':\r
403                     continue\r
404                 if not e1==e2:\r
405                     print >> sys.stderr, "%s != %s!" % (e1, e2)\r
406                     ok = False\r
407                     break\r
408         if not ok:\r
409             print >> sys.stderr, "%s: lol != lol:\nreal   %s\nwanted %s" % (msg, lol1, lol2)\r
410         return ok\r
411         \r
412 \r
413     def create_payload(self,r):\r
414         return BUDDYCAST+bencode(r)\r
415 \r
416 \r
417 def test_suite():\r
418     suite = unittest.TestSuite()\r
419     # We should run the tests in a separate Python interpreter to prevent \r
420     # problems with our singleton classes, e.g. PeerDB, etc.\r
421     if len(sys.argv) != 2:\r
422         print "Usage: python test_buddycast_msg8plus.py <method name>"\r
423     else:\r
424         suite.addTest(TestBuddyCastMsg8Plus(sys.argv[1]))\r
425     \r
426     return suite\r
427 \r
428 def main():\r
429     unittest.main(defaultTest='test_suite',argv=[sys.argv[0]])\r
430 \r
431 if __name__ == "__main__":\r
432     main()\r