class TestVideoHTTPServer(unittest.TestCase): """ Class for testing HTTP-based video server. Mainly HTTP range queries. """ def setUp(self): """ unittest test setup code """ self.port = 6789 self.serv = VideoHTTPServer(self.port) self.serv.background_serve() self.serv.register(self.videoservthread_error_callback,self.videoservthread_set_status_callback) self.sourcefn = os.path.join("API","file.wmv") # 82KB or 82948 bytes self.sourcesize = os.path.getsize(self.sourcefn) def tearDown(self): """ unittest test tear down code """ print >>sys.stderr,time.asctime(),'-', "test: Tear down, sleeping 10 s" time.sleep(10) def videoservthread_error_callback(self,e,url): """ Called by HTTP serving thread """ print >>sys.stderr,time.asctime(),'-', "test: ERROR",e,url self.assert_(False) def videoservthread_set_status_callback(self,status): """ Called by HTTP serving thread """ print >>sys.stderr,time.asctime(),'-', "test: STATUS",status # # Tests # def test_ranges(self): # Run single test, VideoHTTPServer is singleton at the moment and # doesn't like recreate. self.range_test(115,214,self.sourcesize) self.range_test(self.sourcesize-100,None,self.sourcesize) self.range_test(None,100,self.sourcesize) self.range_test(115,214,self.sourcesize,setset=True) # # Internal # def register_file_stream(self): stream = open(self.sourcefn,"rb") streaminfo = { 'mimetype': 'video/x-ms-wmv', 'stream': stream, 'length': self.sourcesize } self.serv.set_inputstream(streaminfo,"/stream") def get_std_header(self): msg = "GET /stream HTTP/1.1\r\n" msg += "Host: 127.0.0.1:"+str(self.port)+"\r\n" return msg def create_range_str(self,firstbyte,lastbyte): head = "" if firstbyte is not None: head += str(firstbyte) head += "-" if lastbyte is not None: head += str(lastbyte) return head def range_test(self,firstbyte,lastbyte,sourcesize,setset=False): print >>sys.stderr,time.asctime(),'-', "test: range_test:",firstbyte,lastbyte,sourcesize,"setset",setset self.register_file_stream() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', self.port)) head = self.get_std_header() head += "Range: bytes=" head += self.create_range_str(firstbyte,lastbyte) if setset: # Make into set of byte ranges, VideoHTTPServer should refuse. head += ",0-99" head += "\r\n" head += "Connection: close\r\n" head += "\r\n" if firstbyte is not None and lastbyte is None: # 100- expfirstbyte = firstbyte explastbyte = self.sourcesize-1 elif firstbyte is None and lastbyte is not None: # -100 expfirstbyte = self.sourcesize-lastbyte explastbyte = self.sourcesize-1 else: expfirstbyte = firstbyte explastbyte = lastbyte # the amount of bytes actually requested. (Content-length) expsize = explastbyte - expfirstbyte + 1 print >>sys.stderr,time.asctime(),'-', "test: Expecting first",expfirstbyte,"last",explastbyte,"size",sourcesize s.send(head) # Parse header s.settimeout(10.0) while True: line = self.readline(s) print >>sys.stderr,time.asctime(),'-', "test: Got line",`line` if len(line)==0: print >>sys.stderr,time.asctime(),'-', "test: server closed conn" self.assert_(False) return if line.startswith("HTTP"): if not setset: # Python returns "HTTP/1.0 206 Partial Content\r\n" HTTP 1.0??? self.assert_(line.startswith("HTTP/1.")) self.assert_(line.find("206") != -1) # Partial content else: self.assert_(line.startswith("HTTP/1.")) self.assert_(line.find("416") != -1) # Requested Range Not Satisfiable return elif line.startswith("Content-Range:"): expline = "Content-Range: bytes "+self.create_range_str(expfirstbyte,explastbyte)+"/"+str(sourcesize)+"\r\n" self.assertEqual(expline,line) elif line.startswith("Content-Type:"): self.assertEqual(line,"Content-Type: video/x-ms-wmv\r\n") elif line.startswith("Content-Length:"): self.assertEqual(line,"Content-Length: "+str(expsize)+"\r\n") elif line.endswith("\r\n") and len(line) == 2: # End of header break data = s.recv(expsize) if len(data) == 0: print >>sys.stderr,time.asctime(),'-', "test: server closed conn2" self.assert_(False) return else: f = open(self.sourcefn,"rb") if firstbyte is not None: f.seek(firstbyte) else: f.seek(lastbyte,os.SEEK_END) expdata = f.read(expsize) f.close() self.assert_(data,expdata) try: # Readed body, reading more should EOF (we disabled persist conn) data = s.recv(10240) self.assert_(len(data) == 0) except socket.timeout: print >> sys.stderr,time.asctime(),'-', "test: Timeout, video server didn't respond with requested bytes, possibly bug in Python impl of HTTP" print_exc() def readline(self,s): line = '' while True: data = s.recv(1) if len(data) == 0: return line else: line = line+data if data == '\n' and len(line) >= 2 and line[-2:] == '\r\n': return line