[tor-commits] [onionoo/master] Add UptimeStatusTest and improve test dummies.

karsten at torproject.org karsten at torproject.org
Mon Apr 14 13:29:25 UTC 2014


commit 9748e432b8d750112f52c82bbf788dd3f130c9a7
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Sat Apr 12 18:32:11 2014 +0200

    Add UptimeStatusTest and improve test dummies.
---
 src/org/torproject/onionoo/DateTimeHelper.java     |    2 +-
 src/org/torproject/onionoo/UptimeStatus.java       |    4 +-
 .../org/torproject/onionoo/DummyDocumentStore.java |   85 ++++---
 .../torproject/onionoo/ResourceServletTest.java    |   68 +++---
 test/org/torproject/onionoo/UptimeStatusTest.java  |  238 ++++++++++++++++++++
 5 files changed, 335 insertions(+), 62 deletions(-)

diff --git a/src/org/torproject/onionoo/DateTimeHelper.java b/src/org/torproject/onionoo/DateTimeHelper.java
index fb0c00d..ff61423 100644
--- a/src/org/torproject/onionoo/DateTimeHelper.java
+++ b/src/org/torproject/onionoo/DateTimeHelper.java
@@ -40,7 +40,7 @@ public class DateTimeHelper {
 
   public static final String ISO_YEARMONTH_FORMAT = "yyyy-MM";
 
-  public static final String YEARHOUR_NOSPACE_FORMAT = "yyyy-MM-dd-HH";
+  public static final String DATEHOUR_NOSPACE_FORMAT = "yyyy-MM-dd-HH";
 
   private static Map<String, DateFormat> dateFormats =
       new HashMap<String, DateFormat>();
diff --git a/src/org/torproject/onionoo/UptimeStatus.java b/src/org/torproject/onionoo/UptimeStatus.java
index 1a222b0..02b83ee 100644
--- a/src/org/torproject/onionoo/UptimeStatus.java
+++ b/src/org/torproject/onionoo/UptimeStatus.java
@@ -43,7 +43,7 @@ class UptimeHistory
       return null;
     }
     long startMillis = DateTimeHelper.parse(parts[1],
-          DateTimeHelper.YEARHOUR_NOSPACE_FORMAT);
+          DateTimeHelper.DATEHOUR_NOSPACE_FORMAT);
     if (startMillis < 0L) {
       return null;
     }
@@ -60,7 +60,7 @@ class UptimeHistory
     StringBuilder sb = new StringBuilder();
     sb.append(this.relay ? "r" : "b");
     sb.append(" " + DateTimeHelper.format(this.startMillis,
-        DateTimeHelper.YEARHOUR_NOSPACE_FORMAT));
+        DateTimeHelper.DATEHOUR_NOSPACE_FORMAT));
     sb.append(" " + String.format("%d", this.uptimeHours));
     return sb.toString();
   }
diff --git a/test/org/torproject/onionoo/DummyDocumentStore.java b/test/org/torproject/onionoo/DummyDocumentStore.java
index c7ca7ff..05723d0 100644
--- a/test/org/torproject/onionoo/DummyDocumentStore.java
+++ b/test/org/torproject/onionoo/DummyDocumentStore.java
@@ -1,5 +1,7 @@
 package org.torproject.onionoo;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.SortedMap;
 import java.util.SortedSet;
 import java.util.TreeMap;
@@ -7,69 +9,96 @@ import java.util.TreeSet;
 
 public class DummyDocumentStore extends DocumentStore {
 
-  private long lastModified;
+  private Map<Class<? extends Document>, SortedMap<String, Document>>
+      storedDocuments = new HashMap<Class<? extends Document>,
+      SortedMap<String, Document>>();
 
-  public DummyDocumentStore(long lastModified) {
-    this.lastModified = lastModified;
+  private static final String FINGERPRINT_NULL = "";
+
+  private <T extends Document> SortedMap<String, Document>
+      getStoredDocumentsByClass(Class<T> documentType) {
+    if (!this.storedDocuments.containsKey(documentType)) {
+      this.storedDocuments.put(documentType,
+          new TreeMap<String, Document>());
+    }
+    return this.storedDocuments.get(documentType);
   }
 
-  private SortedMap<String, NodeStatus> nodeStatuses =
-      new TreeMap<String, NodeStatus>();
-  void addNodeStatus(String nodeStatusString) {
-    NodeStatus nodeStatus = NodeStatus.fromString(nodeStatusString);
-    this.nodeStatuses.put(nodeStatus.getFingerprint(), nodeStatus);
+  public <T extends Document> void addDocument(T document,
+      String fingerprint) {
+    this.getStoredDocumentsByClass(document.getClass()).put(
+        fingerprint == null ? FINGERPRINT_NULL : fingerprint, document);
   }
 
   public void flushDocumentCache() {
-    throw new RuntimeException("Not implemented.");
+    /* Nothing to do. */
   }
 
   public String getStatsString() {
-    throw new RuntimeException("Not implemented.");
+    /* No statistics to return. */
+    return null;
+  }
+
+  private int performedListOperations = 0;
+  public int getPerformedListOperations() {
+    return this.performedListOperations;
   }
 
   public <T extends Document> SortedSet<String> list(
       Class<T> documentType, boolean includeArchive) {
-    if (documentType.equals(NodeStatus.class)) {
-      return new TreeSet<String>(this.nodeStatuses.keySet());
-    }
-    throw new RuntimeException("Not implemented.");
+    this.performedListOperations++;
+    return new TreeSet<String>(this.getStoredDocumentsByClass(
+        documentType).keySet());
+  }
+
+  private int performedRemoveOperations = 0;
+  public int getPerformedRemoveOperations() {
+    return this.performedRemoveOperations;
   }
 
   public <T extends Document> boolean remove(Class<T> documentType) {
-    throw new RuntimeException("Not implemented.");
+    return this.remove(documentType, null);
   }
 
   public <T extends Document> boolean remove(Class<T> documentType,
       String fingerprint) {
-    throw new RuntimeException("Not implemented.");
+    this.performedRemoveOperations++;
+    return this.getStoredDocumentsByClass(documentType).remove(
+        fingerprint) != null;
+  }
+
+  private int performedRetrieveOperations = 0;
+  public int getPerformedRetrieveOperations() {
+    return this.performedRetrieveOperations;
   }
 
   public <T extends Document> T retrieve(Class<T> documentType,
       boolean parse) {
-    if (documentType.equals(UpdateStatus.class)) {
-      UpdateStatus updateStatus = new UpdateStatus();
-      updateStatus.setDocumentString(String.valueOf(this.lastModified));
-      return documentType.cast(updateStatus);
-    }
-    throw new RuntimeException("Not implemented.");
+    return this.retrieve(documentType, parse, null);
   }
 
   public <T extends Document> T retrieve(Class<T> documentType,
       boolean parse, String fingerprint) {
-    if (documentType.equals(NodeStatus.class)) {
-      return documentType.cast(this.nodeStatuses.get(fingerprint));
-    }
-    throw new RuntimeException("Not implemented.");
+    this.performedRetrieveOperations++;
+    return documentType.cast(this.getStoredDocumentsByClass(documentType).
+        get(fingerprint == null ? FINGERPRINT_NULL : fingerprint));
+  }
+
+  private int performedStoreOperations = 0;
+  public int getPerformedStoreOperations() {
+    return this.performedStoreOperations;
   }
 
   public <T extends Document> boolean store(T document) {
-    throw new RuntimeException("Not implemented.");
+    return this.store(document, null);
   }
 
   public <T extends Document> boolean store(T document,
       String fingerprint) {
-    throw new RuntimeException("Not implemented.");
+    this.performedStoreOperations++;
+    this.getStoredDocumentsByClass(document.getClass()).put(
+        fingerprint == null ? FINGERPRINT_NULL : fingerprint, document);
+    return true;
   }
 }
 
diff --git a/test/org/torproject/onionoo/ResourceServletTest.java b/test/org/torproject/onionoo/ResourceServletTest.java
index e2a6a7e..cbe787c 100644
--- a/test/org/torproject/onionoo/ResourceServletTest.java
+++ b/test/org/torproject/onionoo/ResourceServletTest.java
@@ -104,42 +104,44 @@ public class ResourceServletTest {
   @Before
   public void createSampleRelaysAndBridges() {
     this.relays = new TreeMap<String, String>();
-    this.relays.put("000C5F55", "r\tTorkaZ\t"
-        + "000C5F55BD4814B917CC474BD537F1A3B33CCE2A\t"
+    this.relays.put("000C5F55BD4814B917CC474BD537F1A3B33CCE2A",
+        "r\tTorkaZ\t000C5F55BD4814B917CC474BD537F1A3B33CCE2A\t"
         + "62.216.201.221;;62.216.201.222+62.216.201.223\t"
         + "2013-04-19\t05:00:00\t9001\t0\tRunning,Valid\t20\tde\tnull\t"
         + "-1\treject\t1-65535\t2013-04-18\t05:00:00\t"
         + "2013-04-19\t05:00:00\tAS8767\ttorkaz <klaus dot zufall at "
         + "gmx dot de> <fb-token:np5_g_83jmf=>");
-    this.relays.put("001C13B3", "r\tFerrari458\t"
-        + "001C13B3A55A71B977CA65EC85539D79C653A3FC\t"
+    this.relays.put("001C13B3A55A71B977CA65EC85539D79C653A3FC",
+        "r\tFerrari458\t001C13B3A55A71B977CA65EC85539D79C653A3FC\t"
         + "68.38.171.200;[2001:4f8:3:2e::51]:9001;\t"
         + "2013-04-24\t12:00:00\t9001\t9030\t"
         + "Fast,Named,Running,V2Dir,Valid\t1140\tus\t"
         + "c-68-38-171-200.hsd1.pa.comcast.net\t1366805763009\treject\t"
         + "1-65535\t2013-02-12\t16:00:00\t2013-02-26\t18:00:00\t"
         + "AS7922\t");
-    this.relays.put("0025C136", "r\tTimMayTribute\t"
-        + "0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B\t89.69.68.246;;\t"
-        + "2013-04-22\t20:00:00\t9001\t9030\t"
+    this.relays.put("0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B",
+        "r\tTimMayTribute\t0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B\t"
+        + "89.69.68.246;;\t2013-04-22\t20:00:00\t9001\t9030\t"
         + "Fast,Running,Unnamed,V2Dir,Valid\t63\ta1\tnull\t-1\treject\t"
         + "1-65535\t2013-04-16\t18:00:00\t2013-04-16\t18:00:00\t"
         + "AS6830\t1024D/51E2A1C7 steven j. murdoch "
         + "<tor+steven.murdoch at cl.cam.ac.uk> <fb-token:5sr_k_zs2wm=>");
     this.bridges = new TreeMap<String, String>();
-    this.bridges.put("0000831B", "b\tec2bridgercc7f31fe\t"
+    this.bridges.put("0000831B236DFF73D409AD17B40E2A728A53994F",
+        "b\tec2bridgercc7f31fe\t"
         + "0000831B236DFF73D409AD17B40E2A728A53994F\t10.199.7.176;;\t"
         + "2013-04-21\t18:07:03\t443\t0\tValid\t-1\t??\tnull\t-1\t"
         + "null\tnull\t2013-04-20\t15:37:04\tnull\tnull\tnull\tnull");
-    this.bridges.put("0002D9BD", "b\tUnnamed\t"
-        + "0002D9BDBBC230BD9C78FF502A16E0033EF87E0C\t10.0.52.84;;\t"
-        + "2013-04-20\t17:37:04\t443\t0\tValid\t-1\t??\tnull\t-1\t"
-        + "null\tnull\t2013-04-14\t07:07:05\tnull\tnull\tnull\tnull");
-    this.bridges.put("0010D49C", "b\tgummy\t"
-        + "1FEDE50ED8DBA1DD9F9165F78C8131E4A44AB756\t10.63.169.98;;\t"
-        + "2013-04-24\t01:07:04\t9001\t0\tRunning,Valid\t-1\t??\tnull\t"
-        + "-1\tnull\tnull\t2013-01-16\t21:07:04\tnull\tnull\tnull\t"
+    this.bridges.put("0002D9BDBBC230BD9C78FF502A16E0033EF87E0C",
+        "b\tUnnamed\t0002D9BDBBC230BD9C78FF502A16E0033EF87E0C\t"
+        + "10.0.52.84;;\t2013-04-20\t17:37:04\t443\t0\tValid\t-1\t??\t"
+        + "null\t-1\tnull\tnull\t2013-04-14\t07:07:05\tnull\tnull\tnull\t"
         + "null");
+    this.bridges.put("1FEDE50ED8DBA1DD9F9165F78C8131E4A44AB756",
+        "b\tgummy\t1FEDE50ED8DBA1DD9F9165F78C8131E4A44AB756\t"
+        + "10.63.169.98;;\t2013-04-24\t01:07:04\t9001\t0\tRunning,Valid\t"
+        + "-1\t??\tnull\t-1\tnull\tnull\t2013-01-16\t21:07:04\tnull\t"
+        + "null\tnull\tnull");
   }
 
   private void runTest(String requestURI,
@@ -164,13 +166,17 @@ public class ResourceServletTest {
      * ResponseBuilder to read state from the newly created DocumentStore.
      * Otherwise, ResponseBuilder would use data from the previous test
      * run.  This is bad design and should be fixed. */
-    DummyDocumentStore documentStore = new DummyDocumentStore(
-        lastModified++);
-    for (String relay : relays.values()) {
-      documentStore.addNodeStatus(relay);
+    DummyDocumentStore documentStore = new DummyDocumentStore();
+    UpdateStatus updateStatus = new UpdateStatus();
+    updateStatus.setDocumentString(String.valueOf(lastModified++));
+    documentStore.addDocument(updateStatus, null);
+    for (Map.Entry<String, String> e : relays.entrySet()) {
+      documentStore.addDocument(NodeStatus.fromString(e.getValue()),
+          e.getKey());
     }
-    for (String bridge : bridges.values()) {
-      documentStore.addNodeStatus(bridge);
+    for (Map.Entry<String, String> e : bridges.entrySet()) {
+      documentStore.addDocument(NodeStatus.fromString(e.getValue()),
+          e.getKey());
     }
     ApplicationFactory.setDocumentStore(documentStore);
   }
@@ -278,11 +284,11 @@ public class ResourceServletTest {
   @Test()
   public void testValidSummaryRelay() throws IOException {
     this.relays.clear();
-    this.relays.put("000C5F55", "r TorkaZ "
-        + "000C5F55BD4814B917CC474BD537F1A3B33CCE2A 62.216.201.221;; "
-        + "2013-04-19 05:00:00 9001 0 Running,Valid 20 de null -1 "
-        + "reject 1-65535 2013-04-18 05:00:00 2013-04-19 05:00:00 "
-        + "AS8767");
+    this.relays.put("000C5F55BD4814B917CC474BD537F1A3B33CCE2A",
+        "r TorkaZ 000C5F55BD4814B917CC474BD537F1A3B33CCE2A "
+        + "62.216.201.221;; 2013-04-19 05:00:00 9001 0 Running,Valid 20 "
+        + "de null -1 reject 1-65535 2013-04-18 05:00:00 2013-04-19 "
+        + "05:00:00 AS8767");
     this.runTest("/summary", null);
     assertEquals("2013-04-19 05:00:00",
         this.summaryDocument.relays_published);
@@ -298,10 +304,10 @@ public class ResourceServletTest {
   @Test()
   public void testValidSummaryBridge() {
     this.bridges.clear();
-    this.bridges.put("0000831", "b ec2bridgercc7f31fe "
-        + "0000831B236DFF73D409AD17B40E2A728A53994F 10.199.7.176;; "
-        + "2013-04-21 18:07:03 443 0 Valid -1 ?? null -1 null null "
-        + "2013-04-20 15:37:04 null null null");
+    this.bridges.put("0000831B236DFF73D409AD17B40E2A728A53994F",
+        "b ec2bridgercc7f31fe 0000831B236DFF73D409AD17B40E2A728A53994F "
+        + "10.199.7.176;; 2013-04-21 18:07:03 443 0 Valid -1 ?? null -1 "
+        + "null null 2013-04-20 15:37:04 null null null");
     this.runTest("/summary", null);
     assertEquals("2013-04-21 18:07:03",
         this.summaryDocument.bridges_published);
diff --git a/test/org/torproject/onionoo/UptimeStatusTest.java b/test/org/torproject/onionoo/UptimeStatusTest.java
new file mode 100644
index 0000000..fab48e6
--- /dev/null
+++ b/test/org/torproject/onionoo/UptimeStatusTest.java
@@ -0,0 +1,238 @@
+/* Copyright 2014 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.onionoo;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.TreeSet;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class UptimeStatusTest {
+
+  private DummyDocumentStore documentStore;
+
+  @Before
+  public void createDummyDocumentStore() {
+    this.documentStore = new DummyDocumentStore();
+    ApplicationFactory.setDocumentStore(this.documentStore);
+  }
+
+  private static final String MORIA1_FINGERPRINT =
+      "9695DFC35FFEB861329B9F1AB04C46397020CE31";
+
+  @Test()
+  public void testEmptyStatusNoWriteToDisk() {
+    UptimeStatus uptimeStatus = UptimeStatus.loadOrCreate(
+        MORIA1_FINGERPRINT);
+    uptimeStatus.storeIfChanged();
+    assertEquals("Should make one retrieve attempt.", 1,
+        this.documentStore.getPerformedRetrieveOperations());
+    assertEquals("Newly created uptime status with empty history should "
+        + "not be written to disk.", 0,
+        this.documentStore.getPerformedStoreOperations());
+  }
+
+  @Test()
+  public void testSingleHourWriteToDisk() {
+    UptimeStatus uptimeStatus = UptimeStatus.loadOrCreate(
+        MORIA1_FINGERPRINT);
+    uptimeStatus.addToHistory(true, new TreeSet<Long>(Arrays.asList(
+        new Long[] { DateTimeHelper.parse("2013-12-20 00:00:00") })));
+    uptimeStatus.storeIfChanged();
+    assertEquals("History must contain single entry.", 1,
+        uptimeStatus.getHistory().size());
+    UptimeHistory newUptimeHistory = uptimeStatus.getHistory().first();
+    assertEquals("History not for relay.", true,
+        newUptimeHistory.isRelay());
+    assertEquals("History start millis not same as provided.",
+        DateTimeHelper.parse("2013-12-20 00:00:00"),
+        newUptimeHistory.getStartMillis());
+    assertEquals("History uptime hours not 1.", 1,
+        newUptimeHistory.getUptimeHours());
+    assertEquals("Newly created uptime status with non-empty history "
+        + "must be written to disk.", 1,
+        this.documentStore.getPerformedStoreOperations());
+  }
+
+  @Test()
+  public void testTwoConsecutiveHours() {
+    UptimeStatus uptimeStatus = UptimeStatus.loadOrCreate(
+        MORIA1_FINGERPRINT);
+    uptimeStatus.addToHistory(true, new TreeSet<Long>(Arrays.asList(
+        new Long[] { DateTimeHelper.parse("2013-12-20 00:00:00"),
+        DateTimeHelper.parse("2013-12-20 01:00:00") })));
+    uptimeStatus.storeIfChanged();
+    assertEquals("History must contain single entry.", 1,
+        uptimeStatus.getHistory().size());
+    UptimeHistory newUptimeHistory = uptimeStatus.getHistory().first();
+    assertEquals("History not for relay.", true,
+        newUptimeHistory.isRelay());
+    assertEquals("History start millis not same as provided.",
+        DateTimeHelper.parse("2013-12-20 00:00:00"),
+        newUptimeHistory.getStartMillis());
+    assertEquals("History uptime hours not 2.", 2,
+        newUptimeHistory.getUptimeHours());
+  }
+
+  private static final String GABELMOO_FINGERPRINT =
+      "F2044413DAC2E02E3D6BCF4735A19BCA1DE97281";
+
+  private static final String GABELMOO_UPTIME_SAMPLE =
+      "r 2013-07-22-17 1161\n" /* ends 2013-09-09 02:00:00 */
+      + "r 2013-09-09-03 2445\n" /* ends 2013-12-20 00:00:00 */
+      + "r 2013-12-20-01 2203\n"; /* ends 2014-03-21 20:00:00 */
+
+  private void addGabelmooUptimeSample() {
+    UptimeStatus uptimeStatus = new UptimeStatus();
+    uptimeStatus.fromDocumentString(GABELMOO_UPTIME_SAMPLE);
+    this.documentStore.addDocument(uptimeStatus, GABELMOO_FINGERPRINT);
+  }
+
+  @Test()
+  public void testGabelmooFillInGaps() {
+    this.addGabelmooUptimeSample();
+    UptimeStatus uptimeStatus = UptimeStatus.loadOrCreate(
+        GABELMOO_FINGERPRINT);
+    uptimeStatus.addToHistory(true, new TreeSet<Long>(Arrays.asList(
+        new Long[] { DateTimeHelper.parse("2013-09-09 02:00:00"),
+        DateTimeHelper.parse("2013-12-20 00:00:00") })));
+    assertEquals("Uncompressed history must contain five entries.", 5,
+        uptimeStatus.getHistory().size());
+    uptimeStatus.storeIfChanged();
+    assertEquals("Compressed history must contain one entry.", 1,
+        uptimeStatus.getHistory().size());
+    UptimeHistory newUptimeHistory = uptimeStatus.getHistory().first();
+    assertEquals("History not for relay.", true,
+        newUptimeHistory.isRelay());
+    assertEquals("History start millis not as expected.",
+        DateTimeHelper.parse("2013-07-22 17:00:00"),
+        newUptimeHistory.getStartMillis());
+    assertEquals("History uptime hours not 1161+1+2445+1+2203=5811.",
+        5811, newUptimeHistory.getUptimeHours());
+  }
+
+  @Test()
+  public void testAddExistingHourToIntervalStart() {
+    this.addGabelmooUptimeSample();
+    UptimeStatus uptimeStatus = UptimeStatus.loadOrCreate(
+        GABELMOO_FINGERPRINT);
+    uptimeStatus.addToHistory(true, new TreeSet<Long>(Arrays.asList(
+        new Long[] { DateTimeHelper.parse("2013-07-22 17:00:00") })));
+    uptimeStatus.storeIfChanged();
+    assertEquals("Unchanged history should not be written to disk.", 0,
+        this.documentStore.getPerformedStoreOperations());
+  }
+
+  @Test()
+  public void testAddExistingHourToIntervalEnd() {
+    this.addGabelmooUptimeSample();
+    UptimeStatus uptimeStatus = UptimeStatus.loadOrCreate(
+        GABELMOO_FINGERPRINT);
+    uptimeStatus.addToHistory(true, new TreeSet<Long>(Arrays.asList(
+        new Long[] { DateTimeHelper.parse("2013-09-09 01:00:00") })));
+    uptimeStatus.storeIfChanged();
+    assertEquals("Unchanged history should not be written to disk.", 0,
+        this.documentStore.getPerformedStoreOperations());
+  }
+
+  @Test()
+  public void testTwoHoursOverlappingWithIntervalStart() {
+    this.addGabelmooUptimeSample();
+    UptimeStatus uptimeStatus = UptimeStatus.loadOrCreate(
+        GABELMOO_FINGERPRINT);
+    uptimeStatus.addToHistory(true, new TreeSet<Long>(Arrays.asList(
+        new Long[] { DateTimeHelper.parse("2013-07-22 16:00:00"),
+        DateTimeHelper.parse("2013-07-22 17:00:00")})));
+    uptimeStatus.storeIfChanged();
+    assertEquals("Compressed history must still contain three entries.",
+        3, uptimeStatus.getHistory().size());
+    UptimeHistory newUptimeHistory = uptimeStatus.getHistory().first();
+    assertEquals("History not for relay.", true,
+        newUptimeHistory.isRelay());
+    assertEquals("History start millis not as expected.",
+        DateTimeHelper.parse("2013-07-22 16:00:00"),
+        newUptimeHistory.getStartMillis());
+    assertEquals("History uptime hours not 1+1161=1162.", 1162,
+        newUptimeHistory.getUptimeHours());
+  }
+
+  @Test()
+  public void testTwoHoursOverlappingWithIntervalEnd() {
+    this.addGabelmooUptimeSample();
+    UptimeStatus uptimeStatus = UptimeStatus.loadOrCreate(
+        GABELMOO_FINGERPRINT);
+    uptimeStatus.addToHistory(true, new TreeSet<Long>(Arrays.asList(
+        new Long[] { DateTimeHelper.parse("2013-09-09 01:00:00"),
+        DateTimeHelper.parse("2013-09-09 02:00:00")})));
+    uptimeStatus.storeIfChanged();
+    assertEquals("Compressed history must now contain two entries.",
+        2, uptimeStatus.getHistory().size());
+    UptimeHistory newUptimeHistory = uptimeStatus.getHistory().first();
+    assertEquals("History not for relay.", true,
+        newUptimeHistory.isRelay());
+    assertEquals("History start millis not as expected.",
+        DateTimeHelper.parse("2013-07-22 17:00:00"),
+        newUptimeHistory.getStartMillis());
+    assertEquals("History uptime hours not 1161+1+2445=3607.", 3607,
+        newUptimeHistory.getUptimeHours());
+  }
+
+  private static final String ALL_RELAYS_AND_BRIDGES_FINGERPRINT = null;
+
+  private static final String ALL_RELAYS_AND_BRIDGES_UPTIME_SAMPLE =
+      "r 2013-07-22-17 5811\n" /* ends 2014-03-21 20:00:00 */
+      + "b 2013-07-22-17 5811\n"; /* ends 2014-03-21 20:00:00 */
+
+  private void addAllRelaysAndBridgesUptimeSample() {
+    UptimeStatus uptimeStatus = new UptimeStatus();
+    uptimeStatus.fromDocumentString(ALL_RELAYS_AND_BRIDGES_UPTIME_SAMPLE);
+    this.documentStore.addDocument(uptimeStatus,
+        ALL_RELAYS_AND_BRIDGES_FINGERPRINT);
+  }
+
+  @Test()
+  public void testAddRelayUptimeHours() {
+    this.addAllRelaysAndBridgesUptimeSample();
+    UptimeStatus uptimeStatus = UptimeStatus.loadOrCreate(
+        ALL_RELAYS_AND_BRIDGES_FINGERPRINT);
+    uptimeStatus.addToHistory(true, new TreeSet<Long>(Arrays.asList(
+        new Long[] { DateTimeHelper.parse("2013-07-22 16:00:00"),
+        DateTimeHelper.parse("2014-03-21 20:00:00")})));
+    uptimeStatus.storeIfChanged();
+    assertEquals("Compressed history must still contain two entries.",
+        2, uptimeStatus.getHistory().size());
+    UptimeHistory newUptimeHistory = uptimeStatus.getHistory().first();
+    assertEquals("History not for relay.", true,
+        newUptimeHistory.isRelay());
+    assertEquals("History start millis not as expected.",
+        DateTimeHelper.parse("2013-07-22 16:00:00"),
+        newUptimeHistory.getStartMillis());
+    assertEquals("History uptime hours not 1+5811+1=5813.", 5813,
+        newUptimeHistory.getUptimeHours());
+  }
+
+  @Test()
+  public void testAddBridgeUptimeHours() {
+    this.addAllRelaysAndBridgesUptimeSample();
+    UptimeStatus uptimeStatus = UptimeStatus.loadOrCreate(
+        ALL_RELAYS_AND_BRIDGES_FINGERPRINT);
+    uptimeStatus.addToHistory(false, new TreeSet<Long>(Arrays.asList(
+        new Long[] { DateTimeHelper.parse("2013-07-22 16:00:00"),
+        DateTimeHelper.parse("2014-03-21 20:00:00")})));
+    uptimeStatus.storeIfChanged();
+    assertEquals("Compressed history must still contain two entries.",
+        2, uptimeStatus.getHistory().size());
+    UptimeHistory newUptimeHistory = uptimeStatus.getHistory().last();
+    assertEquals("History not for bridge.", false,
+        newUptimeHistory.isRelay());
+    assertEquals("History start millis not as expected.",
+        DateTimeHelper.parse("2013-07-22 16:00:00"),
+        newUptimeHistory.getStartMillis());
+    assertEquals("History uptime hours not 1+5811+1=5813.", 5813,
+        newUptimeHistory.getUptimeHours());
+  }
+}
+





More information about the tor-commits mailing list