def setUpDB(self): try: self.richMetadata_db = self.session.open_dbhandler( NTFY_RICH_METADATA) #add some metadata self.mdto = MetadataDTO(self.anotherpermid, self.testInfohash) subtitle1 = SubtitleInfo("nld", self.sub1) subtitle1.computeChecksum() subtitle2 = SubtitleInfo("eng", os.path.join(RES_DIR, "fake0.srt")) subtitle2.computeChecksum() self.mdto.addSubtitle(subtitle1) self.mdto.addSubtitle(subtitle2) self.mdto.sign(self.another_keypair) self.richMetadata_db.insertMetadata(self.mdto) #hisoermid has the nld subtitle but doesn't have the english one self.richMetadata_db.updateSubtitlePath(self.mdto.channel, self.mdto.infohash, "eng", None) except: print_exc()
def getSomeMetadata(self, channel_id, infohash): s1 = SubtitleInfo("eng", None) s2 = SubtitleInfo("rus", None) self.content1 = u"Subtitle Content 1" self.content2 = u"Subtitle Content 2" hasher = sha() hasher.update(self.content1) s1.checksum = hasher.digest() hasher = sha() hasher.update(self.content2) s2.checksum = hasher.digest() metadata = MetadataDTO(channel_id, infohash, time.time(), "", {"eng":s1, "rus":s2}) if self.nextKeypair is None: metadata.signature = "fake" else: metadata.sign(self.nextKeypair) return metadata
def getSomeMetadata(self, channel_id, infohash): s1 = SubtitleInfo("eng", None) s2 = SubtitleInfo("rus", None) self.content1 = u"Subtitle Content 1" self.content2 = u"Subtitle Content 2" hasher = sha() hasher.update(self.content1) s1.checksum = hasher.digest() hasher = sha() hasher.update(self.content2) s2.checksum = hasher.digest() metadata = MetadataDTO(channel_id, infohash, time.time(), "", { "eng": s1, "rus": s2 }) if self.nextKeypair is None: metadata.signature = "fake" else: metadata.sign(self.nextKeypair) return metadata
def testDesrialize(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) dto.description = u"Sample Description" dto.sign(test_keypair) serialized = dto.serialize() newDto = MDUtil.deserialize(serialized) self.assertEquals(dto, newDto)
def testSerialize(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) dto.description = u"Sample Description" dto.sign(test_keypair) serialized = dto.serialize() self.assertEquals(7, len(serialized)) signature = serialized[6] self.assertEquals(dto.signature, signature)
def getMetadata(self, channel, infohash): """ Returns a MetadataDTO instance for channel/infohash if available in DB Given a channel/infhash couple returns a MetadataDTO instance, built with the values retrieved from the Metadata and Subtitles DB. If no result returns None @param channel: the permid of the channel's owner (binary) @param infohash: the infohash of the item the metadata refers to (binary) @return: a MetadataDTO instance comprehensive of subtitles if any metadata is found in the DB. None otherwise. """ query = QUERIES["SELECT METADATA"] infohash = bin2str(infohash) channel = bin2str(channel) res = self._db.fetchall(query, (infohash, channel)) if len(res) == 0: return None if len(res) > 1: raise MetadataDBException("Metadata DB Constraint violated") metaTuple = res[0] subsDictionary = self._getAllSubtitlesByKey(metaTuple[0]) publisher = str2bin(metaTuple[1]) infohash = str2bin(metaTuple[2]) timestamp = int(metaTuple[4]) description = unicode(metaTuple[3]) signature = str2bin(metaTuple[5]) toReturn = MetadataDTO(publisher, infohash, timestamp, description, None, signature) for sub in subsDictionary.itervalues(): toReturn.addSubtitle(sub) return toReturn
def testSignature(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) dto.sign(test_keypair) self.assertTrue(dto.verifySignature()) dto.timestamp = 2 ok = dto.verifySignature() self.assertFalse(ok)
def testMetadataDTOInit(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) self.assertFalse(dto is None) self.assertEqual(test_perm_id, dto.channel) self.assertEquals(badInfohash, dto.infohash) current = time.time() self.assertTrue(current - 1 <= int(dto.timestamp) <= current) self.assertEquals("", dto.description) self.assertEquals({}, dto._subtitles) self.assertTrue(dto.signature is None)
def setupDB(self, nickname): TestChannels.setupDB(self, nickname) try: self.richMetadata_db = self.session.open_dbhandler( NTFY_RICH_METADATA) #add some metadata for torrents (they are defined in TestChannels.setupDB() self.mdto = MetadataDTO(self.hispermid, self.infohash1) subtitle1 = SubtitleInfo("nld", os.path.join(RES_DIR, "fake.srt")) subtitle1.computeChecksum() subtitle2 = SubtitleInfo("eng", os.path.join(RES_DIR, "fake0.srt")) subtitle2.computeChecksum() self.mdto.addSubtitle(subtitle1) self.mdto.addSubtitle(subtitle2) self.mdto.sign(self.his_keypair) self.richMetadata_db.insertMetadata(self.mdto) except: print_exc()
def test_packData(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) dto.description = u"Sample Description\u041f" bla = dto._packData() decoded = bdecode(bla) self.assertTrue(len(decoded) == 6) decodedChannelId = decoded[0] decodedInfohash = decoded[1] decodedDescription = decoded[2].decode("utf-8") decodedTimestamp = decoded[3] bin_decodedBitmask = decoded[4] decodedBitmask, = unpack("!L", bin_decodedBitmask) self.assertEquals(dto.channel, decodedChannelId) self.assertEquals(dto.infohash, decodedInfohash) self.assertEquals(dto.description, decodedDescription) self.assertAlmostEquals(dto.timestamp, decodedTimestamp) self.assertEquals(0, decodedBitmask) self.assertEquals(0, len(decoded[5]))
def testSignatureOnChecksums(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) subtitles = [ SubtitleInfo(lang, path) for lang, path in self._srtSubs.iteritems() ] for sub in subtitles: sub.computeChecksum() dto.addSubtitle(sub) dto.sign(test_keypair) self.assertTrue(dto.verifySignature()) dto.getSubtitle("rus").checksum = "ABCDEFGHILMOPQRS" self.assertFalse(dto.verifySignature())
def test_packDataWithSubs(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) subtitles = [SubtitleInfo(lang,path) for lang,path in self._srtSubs.iteritems()] for sub in subtitles : sub.computeChecksum() dto.addSubtitle(sub) packed = dto._packData() decoded = bdecode(packed) self.assertTrue(len(decoded) == 6) decodedChannelId = decoded[0] decodedInfohash = decoded[1] decodedDescription = decoded[2] decodedTimestamp = decoded[3] decodedBitmask = decoded[4] checksums = decoded[5] expectedMask = \ LanguagesProvider.getLanguagesInstance().langCodesToMask(self._srtSubs.keys()) binaryExpexted = pack("!L", expectedMask) self.assertEquals(dto.channel, decodedChannelId) self.assertEquals(dto.infohash, decodedInfohash) self.assertEquals(dto.description,decodedDescription) self.assertAlmostEquals(dto.timestamp,decodedTimestamp) self.assertEquals(binaryExpexted,decodedBitmask) self.assertEquals(3,len(checksums)) subs = dto.getAllSubtitles() i=0 for key in sorted(subs.iterkeys()): self.assertEquals(subs[key].checksum, checksums[i]) i += 1
def testSignatureOnChecksums(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) subtitles = [SubtitleInfo(lang, path) for lang, path in self._srtSubs.iteritems()] for sub in subtitles: sub.computeChecksum() dto.addSubtitle(sub) dto.sign(test_keypair) self.assertTrue(dto.verifySignature()) dto.getSubtitle("rus").checksum = "ABCDEFGHILMOPQRS" self.assertFalse(dto.verifySignature())
def testDeserializeWithSubs(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) subtitles = [ SubtitleInfo(lang, path) for lang, path in self._srtSubs.iteritems() ] for sub in subtitles: sub.computeChecksum() dto.addSubtitle(sub) dto.sign(test_keypair) serial = dto.serialize() newDto = MDUtil.deserialize(serial) self.assertEquals(dto, newDto)
def setupDB(self,nickname): TestChannels.setupDB(self,nickname) try: self.richMetadata_db = self.session.open_dbhandler(NTFY_RICH_METADATA) #add some metadata for torrents (they are defined in TestChannels.setupDB() self.mdto = MetadataDTO(self.hispermid, self.infohash1) subtitle1 = SubtitleInfo("nld", os.path.join(RES_DIR,"fake.srt")) subtitle1.computeChecksum() subtitle2 = SubtitleInfo("eng", os.path.join(RES_DIR, "fake0.srt")) subtitle2.computeChecksum() self.mdto.addSubtitle(subtitle1) self.mdto.addSubtitle(subtitle2) self.mdto.sign(self.his_keypair) self.richMetadata_db.insertMetadata(self.mdto) except: print_exc()
def testDeserializeWithSubs(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) subtitles = [SubtitleInfo(lang, path) for lang, path in self._srtSubs.iteritems()] for sub in subtitles: sub.computeChecksum() dto.addSubtitle(sub) dto.sign(test_keypair) serial = dto.serialize() newDto = MDUtil.deserialize(serial) self.assertEquals(dto, newDto)
def testSerializeWithSubs(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) subtitles = [ SubtitleInfo(lang, path) for lang, path in self._srtSubs.iteritems() ] for sub in subtitles: sub.computeChecksum() dto.addSubtitle(sub) dto.sign(test_keypair) serial = dto.serialize() decoded = serial self.assertEquals(7, len(decoded)) signature = decoded[6] self.assertEquals(dto.signature, signature)
def testSerializeWithSubs(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) subtitles = [SubtitleInfo(lang, path) for lang, path in self._srtSubs.iteritems()] for sub in subtitles: sub.computeChecksum() dto.addSubtitle(sub) dto.sign(test_keypair) serial = dto.serialize() decoded = serial self.assertEquals(7, len(decoded)) signature = decoded[6] self.assertEquals(dto.signature, signature)
def setUpDB(self): try: self.richMetadata_db = self.session.open_dbhandler(NTFY_RICH_METADATA) #add some metadata self.mdto = MetadataDTO(self.anotherpermid, self.testInfohash) subtitle1 = SubtitleInfo("nld", self.sub1) subtitle1.computeChecksum() subtitle2 = SubtitleInfo("eng", os.path.join(RES_DIR, "fake0.srt")) subtitle2.computeChecksum() self.mdto.addSubtitle(subtitle1) self.mdto.addSubtitle(subtitle2) self.mdto.sign(self.another_keypair) self.richMetadata_db.insertMetadata(self.mdto) #hisoermid has the nld subtitle but doesn't have the english one self.richMetadata_db.updateSubtitlePath(self.mdto.channel,self.mdto.infohash,"eng",None) except: print_exc()
def test_packDataWithSubs(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) subtitles = [ SubtitleInfo(lang, path) for lang, path in self._srtSubs.iteritems() ] for sub in subtitles: sub.computeChecksum() dto.addSubtitle(sub) packed = dto._packData() decoded = bdecode(packed) self.assertTrue(len(decoded) == 6) decodedChannelId = decoded[0] decodedInfohash = decoded[1] decodedDescription = decoded[2] decodedTimestamp = decoded[3] decodedBitmask = decoded[4] checksums = decoded[5] expectedMask = \ LanguagesProvider.getLanguagesInstance().langCodesToMask(self._srtSubs.keys()) binaryExpexted = pack("!L", expectedMask) self.assertEquals(dto.channel, decodedChannelId) self.assertEquals(dto.infohash, decodedInfohash) self.assertEquals(dto.description, decodedDescription) self.assertAlmostEquals(dto.timestamp, decodedTimestamp) self.assertEquals(binaryExpexted, decodedBitmask) self.assertEquals(3, len(checksums)) subs = dto.getAllSubtitles() i = 0 for key in sorted(subs.iterkeys()): self.assertEquals(subs[key].checksum, checksums[i]) i += 1
class TestSubtitleMessages(TestAsServer): def setUpPreSession(self): """ override TestAsServer """ TestAsServer.setUpPreSession(self) self.config.set_buddycast(True) BuddyCastCore.TESTASSERVER = True ChannelCastCore.TESTASSERVER = True VoteCastCore.TESTASSERVER = True self.config.set_start_recommender(True) self.config.set_bartercast(True) self.config.set_remote_query(True) self.config.set_crawler(False) self.config.set_torrent_collecting_dir(os.path.join(self.config_path, "tmp_torrent_collecting")) self.collecting_dir = os.path.join(self.config_path, "temp_subtitles_collecting") os.makedirs(self.collecting_dir) self.config.set_subtitles_collecting(True) self.config.set_subtitles_collecting_dir(self.collecting_dir) # # Write superpeers.txt and DB schema self.install_path = tempfile.mkdtemp() spdir = os.path.join(self.install_path, LIBRARYNAME, 'Core') os.makedirs(spdir) statsdir = os.path.join(self.install_path, LIBRARYNAME, 'Core', 'Statistics') os.makedirs(statsdir) superpeerfilename = os.path.join(spdir, 'superpeer.txt') print >> sys.stderr,"test: writing empty superpeers to",superpeerfilename f = open(superpeerfilename, "w") f.write('# Leeg') f.close() self.config.set_install_dir(self.install_path) srcfiles = [] srcfiles.append(os.path.join(LIBRARYNAME,"schema_sdb_v5.sql")) for srcfile in srcfiles: sfn = os.path.join('..','..',srcfile) dfn = os.path.join(self.install_path,srcfile) print >>sys.stderr,"test: copying",sfn,dfn shutil.copyfile(sfn,dfn) #copy subtitles files in the appropriate subtitles folder self.src1 = os.path.join(RES_DIR,'fake.srt') self.src2 = os.path.join(RES_DIR,'fake0.srt') def setUpPostSession(self): """ override TestAsServer """ TestAsServer.setUpPostSession(self) self.mypermid = str(self.my_keypair.pub().get_der()) self.hispermid = str(self.his_keypair.pub().get_der()) self.another_keypair = generate_keypair() self.anotherpermid = str(self.another_keypair.pub().get_der()) self.testInfohash = hashlib.sha1("yoman!").digest() #copy subtitles in the collecting dir nldName = SubUtils.getSubtitleFileRelativeName(self.anotherpermid, self.testInfohash, "nld") engName = SubUtils.getSubtitleFileRelativeName(self.anotherpermid, self.testInfohash, "eng") self.sub1 = os.path.join(self.collecting_dir, nldName) self.sub2 = os.path.join(self.collecting_dir, engName) shutil.copyfile(self.src1, self.sub1) # Let's say that the receiving peer has only the nld subtitle # avialable locally # shutil.copyfile(self.src2, self.sub2) def setUpDB(self): try: self.richMetadata_db = self.session.open_dbhandler(NTFY_RICH_METADATA) #add some metadata self.mdto = MetadataDTO(self.anotherpermid, self.testInfohash) subtitle1 = SubtitleInfo("nld", self.sub1) subtitle1.computeChecksum() subtitle2 = SubtitleInfo("eng", os.path.join(RES_DIR, "fake0.srt")) subtitle2.computeChecksum() self.mdto.addSubtitle(subtitle1) self.mdto.addSubtitle(subtitle2) self.mdto.sign(self.another_keypair) self.richMetadata_db.insertMetadata(self.mdto) #hisoermid has the nld subtitle but doesn't have the english one self.richMetadata_db.updateSubtitlePath(self.mdto.channel,self.mdto.infohash,"eng",None) except: print_exc() def tearDown(self): TestAsServer.tearDown(self) self.session.close_dbhandler(self.richMetadata_db) def subtest_receptionOfSUBS(self): ''' Asking for the single available subtitle. The response should be a valid SUBS message containing its contents ''' print >> sys.stderr, "test: test_subtitles_msgs_1_1 -----------------------" ol_conn = OLConnection(self.my_keypair,'localhost',self.hisport) bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask(['nld']) binmask = utilities.uintToBinaryString(bitmask, length=4) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, binmask )) subshandler = SubtitlesHandler() subshandler.register(ol_conn, self.richMetadata_db, self.session) ol_conn.send(request) subs_data = ol_conn.recv() print >> sys.stderr, "test: subtitles_messages : received SUBS response: len",len(subs_data) self.assertEquals(SUBS, subs_data[0]) data = bdecode(subs_data[1:]) print >> sys.stderr, "test: subtitles_messages : received SUBS response: ", data #check on the format of the response self.assertTrue(isinstance(data,list)) self.assertEquals(4, len(data)) # for fields self.assertEquals(self.mdto.channel,data[0]) self.assertEquals(self.mdto.infohash, data[1]) self.assertEquals(binmask, data[2]) self.assertTrue(isinstance(data[3],list)) self.assertEquals(1, len(data[3])) with codecs.open(self.sub1, "rb", "utf-8") as sub: expectedContents = sub.read() self.assertEquals(expectedContents, data[3][0]) ol_conn.close() print >> sys.stderr, "test: subtitles_messages: received content is valid." print >> sys.stderr, "End of test_subtitles_msgs_1_1 test --------------------" def subtest_receptionOfSUBSTwoRequestsOneAvailable(self): """ Asking for two subtitles while the recipent of the request has only one. The response should contain only the one available subtitle content, plus a bitmask that reflects the contents of the response. """ print >> sys.stderr, "test: test_subtitles_msgs_2_1 -----------------------" ol_conn = OLConnection(self.my_keypair,'localhost',self.hisport) bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask(['nld','eng']) binmask = utilities.uintToBinaryString(bitmask, length=4) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, binmask )) subshandler = SubtitlesHandler() subshandler.register(ol_conn, self.richMetadata_db, self.session) ol_conn.send(request) subs_data = ol_conn.recv() self.assertEquals(SUBS, subs_data[0]) data = bdecode(subs_data[1:]) print >> sys.stderr, "test: subtitles_messages : received SUBS repsonse: ", data #check on the format of the response self.assertTrue(isinstance(data,list)) self.assertEquals(4, len(data)) # for fields self.assertEquals(self.mdto.channel,data[0]) self.assertEquals(self.mdto.infohash, data[1]) #the receiver had only one of the two requested subtitles # so I expect a different bitmask bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask(['nld']) expectedBinarymask = utilities.uintToBinaryString(bitmask, length=4) self.assertEquals(expectedBinarymask, data[2]) self.assertTrue(isinstance(data[3],list)) self.assertEquals(1, len(data[3])) with codecs.open(self.sub1, "rb", "utf-8") as sub: expectedContents = sub.read() self.assertEquals(expectedContents, data[3][0]) ol_conn.close() print >> sys.stderr, "test: subtitles_messages: received content is valid." print >> sys.stderr, "End of test_subtitles_msgs_2_1 test --------------------" def subtest_invalidRequest1(self): """ Trying to send an empty message. The connection should be closed by the receiver """ print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_1 ------------------" ol_conn = OLConnection(self.my_keypair,'localhost',self.hisport) request = GET_SUBS + \ bencode({}) ol_conn.send(request) self.assertEquals(0, len(ol_conn.recv())) print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_1: connection closed as expected" ol_conn.close() print >> sys.stderr, "End of test_subtitles_msgs_invalid_request_1 ------------------" def subtest_invalidRequest2(self): """ Trying to send an invalid message (an integer instead of a 4 bytes binary string) The connection should be closed by the receiver """ print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_2 ------------------" ol_conn = OLConnection(self.my_keypair,'localhost',self.hisport) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, 42 )) ol_conn.send(request) self.assertEquals(0, len(ol_conn.recv())) print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_2: connection closed as expected" ol_conn.close() print >> sys.stderr, "End of test_subtitles_msgs_invalid_request_2 ------------------" def subtest_invalidRequest3(self): """ Trying to send an invalid message (valid for everythin except that there is one field more) The connection should be closed by the receiver """ print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_3 ------------------" ol_conn = OLConnection(self.my_keypair,'localhost',self.hisport) bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask(['nld','eng']) binmask = utilities.uintToBinaryString(bitmask, length=4) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, binmask, 42 )) ol_conn.send(request) self.assertEquals(0, len(ol_conn.recv())) print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_3: connection closed as expected" ol_conn.close() print >> sys.stderr, "End of test_subtitles_msgs_invalid_request_3 ------------------" def singtest_subs_messages(self): self.setUpDB() self.subtest_receptionOfSUBS() self.subtest_receptionOfSUBSTwoRequestsOneAvailable() self.subtest_invalidRequest1() self.subtest_invalidRequest2() self.subtest_invalidRequest3()
class TestChannelsPlusSubtitles(TestChannels): """ Testing the rich metadata extension of channelcast. The test suite defined in this module executes all the old channelcast tests, plus a test to validate that the rich metadata (currently subtitles) extension works properly """ def setupDB(self, nickname): TestChannels.setupDB(self, nickname) try: self.richMetadata_db = self.session.open_dbhandler( NTFY_RICH_METADATA) #add some metadata for torrents (they are defined in TestChannels.setupDB() self.mdto = MetadataDTO(self.hispermid, self.infohash1) subtitle1 = SubtitleInfo("nld", os.path.join(RES_DIR, "fake.srt")) subtitle1.computeChecksum() subtitle2 = SubtitleInfo("eng", os.path.join(RES_DIR, "fake0.srt")) subtitle2.computeChecksum() self.mdto.addSubtitle(subtitle1) self.mdto.addSubtitle(subtitle2) self.mdto.sign(self.his_keypair) self.richMetadata_db.insertMetadata(self.mdto) except: print_exc() def tearDown(self): TestChannels.tearDown(self) self.session.close_dbhandler(self.richMetadata_db) def _test_all(self, nickname): """ I want to start a Tribler client once and then connect to it many times. So there must be only one test method to prevent setUp() from creating a new client every time. The code is constructed so unittest will show the name of the (sub)test where the error occured in the traceback it prints. """ TestChannels._test_all(self, nickname) self.subtest_channelcastPlusMetadata() def subtest_channelcastPlusMetadata(self): ''' Extends channelcast test to channelcast messages enriched with metadata (subtitles) informations ''' print >> sys.stderr, "test: channelcast_subtitles ---------------------------" s = OLConnection(self.my_keypair, 'localhost', self.hisport) chcast = ChannelCastCore(None, s, self.session, None, log='', dnsindb=None) #test send standard channelcast chdata = {} print >> sys.stderr, "Test Good ChannelCast Plus Subtitles", ` chdata ` msg = CHANNELCAST + bencode(chdata) s.send(msg) resp = s.recv() if len(resp) > 0: print >> sys.stderr, "test: channelcast_subtitles: got", getMessageName( resp[0]) self.assert_(resp[0] == CHANNELCAST) print >> sys.stderr, "test: channelcast_subtitles: got msg", ` bdecode( resp[1:]) ` chdata_rcvd = bdecode(resp[1:]) self.assertTrue(validChannelCastMsg(chdata_rcvd)) for entry in chdata_rcvd.itervalues(): if entry[ 'infohash'] == self.infohash1: #the torrent for which two subtitles exist self.assertTrue('rich_metadata' in entry.keys()) richMetadata = entry['rich_metadata'] print >> sys.stderr, "test: channelcast_subtitles: richMetadata entry is ", richMetadata self.assertEquals(6, len(richMetadata)) self.assertEquals(self.mdto.description, richMetadata[0]) self.assertEquals(4, len( richMetadata[2])) #the subtitles mask 4 bytes self.assertTrue(isinstance(richMetadata[3], list)) #the subtitles checsums for checksum in richMetadata[3]: self.assertEquals(20, len(checksum)) #160 bit sha1 checksum self.assertEquals(self.mdto.signature, richMetadata[4]) self.assertEquals(4, len( richMetadata[5])) #the subtitles have mask 32 bit #also must (in this case) be equal to the subtitles mask self.assertEquals(richMetadata[2], richMetadata[5]) print >> sys.stderr, "test: channelcast_subtitles; richMetadata entry is valid and correct" else: self.assertFalse('rich_metadata' in entry.keys()) s.close() #Now, send a bad ChannelCast message. # The other side should close the connection # Create bad message by manipulating a good one #bad bitmask chdata = deepcopy(chdata_rcvd) for k, v in chdata.items(): if 'rich_metadata' in v: v['rich_metadata'][ 2] = 44 #an integer instead of a 4bytes bitmask self.subtest_bad_channelcast(chdata) #Bad message format chdata = deepcopy(chdata_rcvd) for k, v in chdata.items(): if 'rich_metadata' in v: v['rich_metadata'].insert(0, u"asdfafa22") self.subtest_bad_channelcast(chdata) #Bad print >> sys.stderr, "End of channelcast_subtitles test ---------------------------"
class TestSubtitleMessages(TestAsServer): def setUpPreSession(self): """ override TestAsServer """ TestAsServer.setUpPreSession(self) self.config.set_buddycast(True) BuddyCastCore.TESTASSERVER = True ChannelCastCore.TESTASSERVER = True VoteCastCore.TESTASSERVER = True self.config.set_start_recommender(True) self.config.set_bartercast(True) self.config.set_remote_query(True) self.config.set_crawler(False) self.config.set_torrent_collecting_dir( os.path.join(self.config_path, "tmp_torrent_collecting")) self.collecting_dir = os.path.join(self.config_path, "temp_subtitles_collecting") os.makedirs(self.collecting_dir) self.config.set_subtitles_collecting(True) self.config.set_subtitles_collecting_dir(self.collecting_dir) # # Write superpeers.txt and DB schema self.install_path = tempfile.mkdtemp() spdir = os.path.join(self.install_path, LIBRARYNAME, 'Core') os.makedirs(spdir) statsdir = os.path.join(self.install_path, LIBRARYNAME, 'Core', 'Statistics') os.makedirs(statsdir) superpeerfilename = os.path.join(spdir, 'superpeer.txt') print >> sys.stderr, "test: writing empty superpeers to", superpeerfilename f = open(superpeerfilename, "w") f.write('# Leeg') f.close() self.config.set_install_dir(self.install_path) srcfiles = [] srcfiles.append(os.path.join(LIBRARYNAME, "schema_sdb_v5.sql")) for srcfile in srcfiles: sfn = os.path.join('..', '..', srcfile) dfn = os.path.join(self.install_path, srcfile) print >> sys.stderr, "test: copying", sfn, dfn shutil.copyfile(sfn, dfn) #copy subtitles files in the appropriate subtitles folder self.src1 = os.path.join(RES_DIR, 'fake.srt') self.src2 = os.path.join(RES_DIR, 'fake0.srt') def setUpPostSession(self): """ override TestAsServer """ TestAsServer.setUpPostSession(self) self.mypermid = str(self.my_keypair.pub().get_der()) self.hispermid = str(self.his_keypair.pub().get_der()) self.another_keypair = generate_keypair() self.anotherpermid = str(self.another_keypair.pub().get_der()) self.testInfohash = hashlib.sha1("yoman!").digest() #copy subtitles in the collecting dir nldName = SubUtils.getSubtitleFileRelativeName(self.anotherpermid, self.testInfohash, "nld") engName = SubUtils.getSubtitleFileRelativeName(self.anotherpermid, self.testInfohash, "eng") self.sub1 = os.path.join(self.collecting_dir, nldName) self.sub2 = os.path.join(self.collecting_dir, engName) shutil.copyfile(self.src1, self.sub1) # Let's say that the receiving peer has only the nld subtitle # avialable locally # shutil.copyfile(self.src2, self.sub2) def setUpDB(self): try: self.richMetadata_db = self.session.open_dbhandler( NTFY_RICH_METADATA) #add some metadata self.mdto = MetadataDTO(self.anotherpermid, self.testInfohash) subtitle1 = SubtitleInfo("nld", self.sub1) subtitle1.computeChecksum() subtitle2 = SubtitleInfo("eng", os.path.join(RES_DIR, "fake0.srt")) subtitle2.computeChecksum() self.mdto.addSubtitle(subtitle1) self.mdto.addSubtitle(subtitle2) self.mdto.sign(self.another_keypair) self.richMetadata_db.insertMetadata(self.mdto) #hisoermid has the nld subtitle but doesn't have the english one self.richMetadata_db.updateSubtitlePath(self.mdto.channel, self.mdto.infohash, "eng", None) except: print_exc() def tearDown(self): TestAsServer.tearDown(self) self.session.close_dbhandler(self.richMetadata_db) def subtest_receptionOfSUBS(self): ''' Asking for the single available subtitle. The response should be a valid SUBS message containing its contents ''' print >> sys.stderr, "test: test_subtitles_msgs_1_1 -----------------------" ol_conn = OLConnection(self.my_keypair, 'localhost', self.hisport) bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask( ['nld']) binmask = utilities.uintToBinaryString(bitmask, length=4) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, binmask )) subshandler = SubtitlesHandler() subshandler.register(ol_conn, self.richMetadata_db, self.session) ol_conn.send(request) subs_data = ol_conn.recv() print >> sys.stderr, "test: subtitles_messages : received SUBS response: len", len( subs_data) self.assertEquals(SUBS, subs_data[0]) data = bdecode(subs_data[1:]) print >> sys.stderr, "test: subtitles_messages : received SUBS response: ", data #check on the format of the response self.assertTrue(isinstance(data, list)) self.assertEquals(4, len(data)) # for fields self.assertEquals(self.mdto.channel, data[0]) self.assertEquals(self.mdto.infohash, data[1]) self.assertEquals(binmask, data[2]) self.assertTrue(isinstance(data[3], list)) self.assertEquals(1, len(data[3])) with codecs.open(self.sub1, "rb", "utf-8") as sub: expectedContents = sub.read() self.assertEquals(expectedContents, data[3][0]) ol_conn.close() print >> sys.stderr, "test: subtitles_messages: received content is valid." print >> sys.stderr, "End of test_subtitles_msgs_1_1 test --------------------" def subtest_receptionOfSUBSTwoRequestsOneAvailable(self): """ Asking for two subtitles while the recipent of the request has only one. The response should contain only the one available subtitle content, plus a bitmask that reflects the contents of the response. """ print >> sys.stderr, "test: test_subtitles_msgs_2_1 -----------------------" ol_conn = OLConnection(self.my_keypair, 'localhost', self.hisport) bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask( ['nld', 'eng']) binmask = utilities.uintToBinaryString(bitmask, length=4) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, binmask )) subshandler = SubtitlesHandler() subshandler.register(ol_conn, self.richMetadata_db, self.session) ol_conn.send(request) subs_data = ol_conn.recv() self.assertEquals(SUBS, subs_data[0]) data = bdecode(subs_data[1:]) print >> sys.stderr, "test: subtitles_messages : received SUBS repsonse: ", data #check on the format of the response self.assertTrue(isinstance(data, list)) self.assertEquals(4, len(data)) # for fields self.assertEquals(self.mdto.channel, data[0]) self.assertEquals(self.mdto.infohash, data[1]) #the receiver had only one of the two requested subtitles # so I expect a different bitmask bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask( ['nld']) expectedBinarymask = utilities.uintToBinaryString(bitmask, length=4) self.assertEquals(expectedBinarymask, data[2]) self.assertTrue(isinstance(data[3], list)) self.assertEquals(1, len(data[3])) with codecs.open(self.sub1, "rb", "utf-8") as sub: expectedContents = sub.read() self.assertEquals(expectedContents, data[3][0]) ol_conn.close() print >> sys.stderr, "test: subtitles_messages: received content is valid." print >> sys.stderr, "End of test_subtitles_msgs_2_1 test --------------------" def subtest_invalidRequest1(self): """ Trying to send an empty message. The connection should be closed by the receiver """ print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_1 ------------------" ol_conn = OLConnection(self.my_keypair, 'localhost', self.hisport) request = GET_SUBS + \ bencode({}) ol_conn.send(request) self.assertEquals(0, len(ol_conn.recv())) print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_1: connection closed as expected" ol_conn.close() print >> sys.stderr, "End of test_subtitles_msgs_invalid_request_1 ------------------" def subtest_invalidRequest2(self): """ Trying to send an invalid message (an integer instead of a 4 bytes binary string) The connection should be closed by the receiver """ print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_2 ------------------" ol_conn = OLConnection(self.my_keypair, 'localhost', self.hisport) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, 42 )) ol_conn.send(request) self.assertEquals(0, len(ol_conn.recv())) print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_2: connection closed as expected" ol_conn.close() print >> sys.stderr, "End of test_subtitles_msgs_invalid_request_2 ------------------" def subtest_invalidRequest3(self): """ Trying to send an invalid message (valid for everythin except that there is one field more) The connection should be closed by the receiver """ print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_3 ------------------" ol_conn = OLConnection(self.my_keypair, 'localhost', self.hisport) bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask( ['nld', 'eng']) binmask = utilities.uintToBinaryString(bitmask, length=4) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, binmask, 42 )) ol_conn.send(request) self.assertEquals(0, len(ol_conn.recv())) print >> sys.stderr, "test: test_subtitles_msgs_invalid_request_3: connection closed as expected" ol_conn.close() print >> sys.stderr, "End of test_subtitles_msgs_invalid_request_3 ------------------" def singtest_subs_messages(self): self.setUpDB() self.subtest_receptionOfSUBS() self.subtest_receptionOfSUBSTwoRequestsOneAvailable() self.subtest_invalidRequest1() self.subtest_invalidRequest2() self.subtest_invalidRequest3()
class SubtitlesSupport(object): ''' Subtitle dissemination system facade. Acts as the only faced between the subtitle dissemination system and the GUI (or whoever needs to subtitles). Provides methods to query the subtitles database. Allows publishers to add their own subtitles, and if necessary permits to retrieve the subtitle remotely if not available. ''' __single = None _singletonLock = threading.RLock() def __init__(self): #singleton pattern not really enforced if someone just calls # the normal constructor. But this way I can test the instance easier try: SubtitlesSupport._singletonLock.acquire() SubtitlesSupport.__single = self finally: SubtitlesSupport._singletonLock.release() self.richMetadata_db = None self.subtitlesHandler = None self.channelcast_db = None self.langUtility = LanguagesProvider.getLanguagesInstance() self._registered = False @staticmethod def getInstance(*args, **kw): try: SubtitlesSupport._singletonLock.acquire() if SubtitlesSupport.__single == None: SubtitlesSupport(*args, **kw) finally: SubtitlesSupport._singletonLock.release() return SubtitlesSupport.__single def _register(self, richMetadataDBHandler, subtitlesHandler, channelcast_db, my_permid, my_keypair, peersHaveManger, ol_bridge): assert richMetadataDBHandler is not None assert subtitlesHandler is not None assert channelcast_db is not None assert peersHaveManger is not None assert ol_bridge is not None assert isValidPermid(my_permid) self.richMetadata_db = richMetadataDBHandler self.subtitlesHandler = subtitlesHandler self.channelcast_db = channelcast_db self.my_permid = my_permid self.my_keypair = my_keypair self._peersHaveManager = peersHaveManger #used to decouple calls to SubtitleHandler self._ol_bridge = ol_bridge self._registered = True def getSubtileInfosForInfohash(self, infohash): ''' Retrieve available information about subtitles for the given infohash. Given the infohash of a .torrent, retrieves every information about subtitles published for that .torrent that is currently available in the DB. @param infohash: a .torrent infohash (binary) @return: a dictionary. The dictionary looks like this:: { channel_id1 : {langCode : L{SubtitleInfo}, ...} , channel_id2 : {langCode : L{SubtitleInfo}, ... }, ... } Each entry in the dictionary has the following semantics: - channel_id is the permid identifiying the channel (binary). - langCode is an ISO 693-2 three characters language code ''' assert utilities.isValidInfohash(infohash) assert self._registered, "Instance is not registered" returnDictionary = dict() #a metadataDTO corresponds to all metadata for a pair channel, infohash metadataDTOs = self.richMetadata_db.getAllMetadataForInfohash(infohash) for metadataDTO in metadataDTOs: channel = metadataDTO.channel subtitles = metadataDTO.getAllSubtitles() if len(subtitles) > 0: returnDictionary[channel] = subtitles return returnDictionary def getSubtitleInfos(self, channel, infohash): ''' Retrieve subtitles information for the given channel-infohash pair. Searches in the local database for information about subtitles that are currently available. @param channel: the channel_id (perm_id) of a channel (binary) @param infohash: a .torrent infohash (binary) @return: a dictionary of SubtitleInfo instances. The keys are the language codes of the subtitles ''' assert self._registered, "Instance is not registered" metadataDTO = self.richMetadata_db.getMetadata(channel, infohash) if metadataDTO: return metadataDTO.getAllSubtitles() return {} def publishSubtitle(self, infohash, lang, pathToSrtSubtitle): ''' Allows an user to publish an srt subtitle file in his channel. Called by a channel owner this method inserts a new subtitle for a torrent published in his channel. The method assumes that the torrent identified by the infohash parameter is already in the channel, and that the parameter pathToSrtSubtitle points to an existing srt file on the local filesystem. If a subtitle for the same language was already associated to the specified infohash and channel, it will be overwritten. After calling this method the newly inserted subtitle will be disseminated via Channelcast. @param infohash: the infohash of the torrent to associate the subtitle with, binary @param lang: a 3 characters code for the language of the subtitle as specified in ISO 639-2. Currently just 32 language codes will be supported. @param pathToSrtSubtitle: a path in the local filesystem to a subtitle in srt format. @raise RichMetadataException: if something "general" goes wrong while adding new metadata @raise IOError: if disk related problems occur ''' assert utilities.isValidInfohash(infohash), "Invalid Infohash" assert lang is not None and self.langUtility.isLangCodeSupported(lang) assert self._registered, "Instance is not registered" channelid = bin2str(self.my_permid) base64infohash = bin2str(infohash) # consisnstency check: I want to assure that this method is called # for an item that is actually in my channel consinstent = self.channelcast_db.isItemInChannel( channelid, base64infohash) if not consinstent: msg = "Infohash %s not found in my channel. Rejecting subtitle" % base64infohash if DEBUG: print >> sys.stderr, msg raise RichMetadataException(msg) try: filepath = self.subtitlesHandler.copyToSubtitlesFolder( pathToSrtSubtitle, self.my_permid, infohash, lang) except Exception, e: if DEBUG: print >> sys.stderr, "Failed to read and copy subtitle to appropriate folder: %s" % str( e) # retrieve existing metadata from my channel, infohash metadataDTO = self.richMetadata_db.getMetadata(self.my_permid, infohash) # can be none if no metadata was available if metadataDTO is None: metadataDTO = MetadataDTO(self.my_permid, infohash) else: #update the timestamp metadataDTO.resetTimestamp() newSubtitle = SubtitleInfo(lang, filepath) # this check should be redundant, since i should be sure that subtitle # exists at this point if newSubtitle.subtitleExists(): newSubtitle.computeChecksum() else: msg = "Inconsistency found. The subtitle was not published" if DEBUG: print >> sys.stderr, msg raise RichMetadataException(msg) metadataDTO.addSubtitle(newSubtitle) metadataDTO.sign(self.my_keypair) self.richMetadata_db.insertMetadata(metadataDTO)
class TestChannelsPlusSubtitles(TestChannels): """ Testing the rich metadata extension of channelcast. The test suite defined in this module executes all the old channelcast tests, plus a test to validate that the rich metadata (currently subtitles) extension works properly """ def setupDB(self,nickname): TestChannels.setupDB(self,nickname) try: self.richMetadata_db = self.session.open_dbhandler(NTFY_RICH_METADATA) #add some metadata for torrents (they are defined in TestChannels.setupDB() self.mdto = MetadataDTO(self.hispermid, self.infohash1) subtitle1 = SubtitleInfo("nld", os.path.join(RES_DIR,"fake.srt")) subtitle1.computeChecksum() subtitle2 = SubtitleInfo("eng", os.path.join(RES_DIR, "fake0.srt")) subtitle2.computeChecksum() self.mdto.addSubtitle(subtitle1) self.mdto.addSubtitle(subtitle2) self.mdto.sign(self.his_keypair) self.richMetadata_db.insertMetadata(self.mdto) except: print_exc() def tearDown(self): TestChannels.tearDown(self) self.session.close_dbhandler(self.richMetadata_db) def _test_all(self,nickname): """ I want to start a Tribler client once and then connect to it many times. So there must be only one test method to prevent setUp() from creating a new client every time. The code is constructed so unittest will show the name of the (sub)test where the error occured in the traceback it prints. """ TestChannels._test_all(self,nickname) self.subtest_channelcastPlusMetadata() def subtest_channelcastPlusMetadata(self): ''' Extends channelcast test to channelcast messages enriched with metadata (subtitles) informations ''' print >>sys.stderr,"test: channelcast_subtitles ---------------------------" s = OLConnection(self.my_keypair,'localhost',self.hisport) chcast = ChannelCastCore(None, s, self.session, None, log = '', dnsindb = None) #test send standard channelcast chdata = {} print >> sys.stderr, "Test Good ChannelCast Plus Subtitles", `chdata` msg = CHANNELCAST+bencode(chdata) s.send(msg) resp = s.recv() if len(resp) > 0: print >>sys.stderr,"test: channelcast_subtitles: got",getMessageName(resp[0]) self.assert_(resp[0]==CHANNELCAST) print >>sys.stderr, "test: channelcast_subtitles: got msg", `bdecode(resp[1:])` chdata_rcvd = bdecode(resp[1:]) self.assertTrue(validChannelCastMsg(chdata_rcvd)) for entry in chdata_rcvd.itervalues(): if entry['infohash'] == self.infohash1: #the torrent for which two subtitles exist self.assertTrue('rich_metadata' in entry.keys()) richMetadata = entry['rich_metadata'] print >> sys.stderr, "test: channelcast_subtitles: richMetadata entry is ", richMetadata self.assertEquals(6, len(richMetadata)) self.assertEquals(self.mdto.description, richMetadata[0]) self.assertEquals(4, len(richMetadata[2])) #the subtitles mask 4 bytes self.assertTrue(isinstance(richMetadata[3],list)) #the subtitles checsums for checksum in richMetadata[3]: self.assertEquals(20,len(checksum)) #160 bit sha1 checksum self.assertEquals(self.mdto.signature, richMetadata[4]) self.assertEquals(4,len(richMetadata[5])) #the subtitles have mask 32 bit #also must (in this case) be equal to the subtitles mask self.assertEquals(richMetadata[2], richMetadata[5]) print >> sys.stderr, "test: channelcast_subtitles; richMetadata entry is valid and correct" else: self.assertFalse('rich_metadata' in entry.keys()) s.close() #Now, send a bad ChannelCast message. # The other side should close the connection # Create bad message by manipulating a good one #bad bitmask chdata = deepcopy(chdata_rcvd) for k,v in chdata.items(): if 'rich_metadata' in v: v['rich_metadata'][2] = 44 #an integer instead of a 4bytes bitmask self.subtest_bad_channelcast(chdata) #Bad message format chdata = deepcopy(chdata_rcvd) for k,v in chdata.items(): if 'rich_metadata' in v: v['rich_metadata'].insert(0, u"asdfafa22") self.subtest_bad_channelcast(chdata) #Bad print>>sys.stderr, "End of channelcast_subtitles test ---------------------------"