From dc1afc81bbfe95de9f5f962453a52b13e0b993b5 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@lothar.com>
Date: Mon, 9 Aug 2010 15:03:42 -0700
Subject: [PATCH] web download-status: tolerate DYHBs that haven't retired yet.
 Fixes #1160.

Also add a better unit test for it.
---
 src/allmydata/test/test_web.py | 40 ++++++++++++++++++++++++++++++++--
 src/allmydata/web/status.py    |  7 ++++--
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py
index e2bd9850..dfaaabda 100644
--- a/src/allmydata/test/test_web.py
+++ b/src/allmydata/test/test_web.py
@@ -1,5 +1,5 @@
 
-import os.path, re, urllib
+import os.path, re, urllib, time
 import simplejson
 from StringIO import StringIO
 from twisted.application import service
@@ -74,9 +74,40 @@ class FakeUploader(service.Service):
     def get_helper_info(self):
         return (None, False)
 
+def build_one_ds():
+    ds = DownloadStatus("storage_index", 1234)
+    now = time.time()
+
+    ds.add_segment_request(0, now)
+    # segnum, when, start,len, decodetime
+    ds.add_segment_delivery(0, now+1, 0, 100, 0.5)
+    ds.add_segment_request(1, now+2)
+    ds.add_segment_error(1, now+3)
+
+    e = ds.add_dyhb_sent("serverid_a", now)
+    e.finished([1,2], now+1)
+    e = ds.add_dyhb_sent("serverid_b", now+2) # left unfinished
+
+    e = ds.add_read_event(0, 120, now)
+    e.update(60, 0.5, 0.1) # bytes, decrypttime, pausetime
+    e.finished(now+1)
+    e = ds.add_read_event(120, 30, now+2) # left unfinished
+
+    e = ds.add_request_sent("serverid_a", 1, 100, 20, now)
+    e.finished(20, now+1)
+    e = ds.add_request_sent("serverid_a", 1, 120, 30, now+1) # left unfinished
+
+    # make sure that add_read_event() can come first too
+    ds1 = DownloadStatus("storage_index", 1234)
+    e = ds1.add_read_event(0, 120, now)
+    e.update(60, 0.5, 0.1) # bytes, decrypttime, pausetime
+    e.finished(now+1)
+
+    return ds
+
 class FakeHistory:
     _all_upload_status = [upload.UploadStatus()]
-    _all_download_status = [DownloadStatus("storage_index", 1234)]
+    _all_download_status = [build_one_ds()]
     _all_mapupdate_statuses = [servermap.UpdateStatus()]
     _all_publish_statuses = [publish.PublishStatus()]
     _all_retrieve_statuses = [retrieve.RetrieveStatus()]
@@ -516,6 +547,11 @@ class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi
         def _check_dl(res):
             self.failUnless("File Download Status" in res, res)
         d.addCallback(_check_dl)
+        d.addCallback(lambda res: self.GET("/status/down-%d?t=json" % dl_num))
+        def _check_dl_json(res):
+            data = simplejson.loads(res)
+            self.failUnless(isinstance(data, dict))
+        d.addCallback(_check_dl_json)
         d.addCallback(lambda res: self.GET("/status/up-%d" % ul_num))
         def _check_ul(res):
             self.failUnless("File Upload Status" in res, res)
diff --git a/src/allmydata/web/status.py b/src/allmydata/web/status.py
index 636a2db9..8af453c6 100644
--- a/src/allmydata/web/status.py
+++ b/src/allmydata/web/status.py
@@ -413,7 +413,11 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page):
         for d_ev in dyhb_events:
             (serverid, sent, shnums, received) = d_ev
             serverid_s = idlib.shortnodeid_b2a(serverid)
-            rtt = received - sent
+            rtt = None
+            if received is not None:
+                rtt = received - sent
+            if not shnums:
+                shnums = []
             t[T.tr(style="background: %s" % self.color(serverid))[
                 [T.td[serverid_s], T.td[srt(sent)], T.td[srt(received)],
                  T.td[",".join([str(shnum) for shnum in shnums])],
@@ -427,7 +431,6 @@ class DownloadStatusPage(DownloadResultsRendererMixin, rend.Page):
                T.td["speed"]]]
         for r_ev in self.download_status.read_events:
             (start, length, requesttime, finishtime, bytes, decrypt, paused) = r_ev
-            #print r_ev
             if finishtime is not None:
                 rtt = finishtime - requesttime - paused
                 speed = self.render_rate(None, 1.0 * bytes / rtt)
-- 
2.45.2