[tor-commits] [onionoo/master] Use Gson to format JSON uptime documents.

karsten at torproject.org karsten at torproject.org
Fri May 9 06:35:54 UTC 2014


commit 7b05cc2bc7e94424ffdbccceaa6d2102c0e2aeae
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Sun Apr 20 14:51:44 2014 +0200

    Use Gson to format JSON uptime documents.
---
 src/org/torproject/onionoo/GraphHistory.java       |   56 +++++
 src/org/torproject/onionoo/ResponseBuilder.java    |    4 +-
 src/org/torproject/onionoo/UptimeDocument.java     |   14 ++
 .../torproject/onionoo/UptimeDocumentWriter.java   |   67 +++---
 .../onionoo/UptimeDocumentWriterTest.java          |  253 ++++++++++++++++++++
 5 files changed, 355 insertions(+), 39 deletions(-)

diff --git a/src/org/torproject/onionoo/GraphHistory.java b/src/org/torproject/onionoo/GraphHistory.java
new file mode 100644
index 0000000..f03be58
--- /dev/null
+++ b/src/org/torproject/onionoo/GraphHistory.java
@@ -0,0 +1,56 @@
+/* Copyright 2014 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.onionoo;
+
+import java.util.List;
+
+public class GraphHistory {
+
+  private String first;
+  public void setFirst(String first) {
+    this.first = first;
+  }
+  public String getFirst() {
+    return this.first;
+  }
+
+  private String last;
+  public void setLast(String last) {
+    this.last = last;
+  }
+  public String getLast() {
+    return this.last;
+  }
+
+  private Integer interval;
+  public void setInterval(Integer interval) {
+    this.interval = interval;
+  }
+  public Integer getInterval() {
+    return this.interval;
+  }
+
+  private Double factor;
+  public void setFactor(Double factor) {
+    this.factor = factor;
+  }
+  public Double getFactor() {
+    return this.factor;
+  }
+
+  private Integer count;
+  public void setCount(Integer count) {
+    this.count = count;
+  }
+  public Integer getCount() {
+    return this.count;
+  }
+
+  private List<Integer> values;
+  public void setValues(List<Integer> values) {
+    this.values = values;
+  }
+  public List<Integer> getValues() {
+    return this.values;
+  }
+}
diff --git a/src/org/torproject/onionoo/ResponseBuilder.java b/src/org/torproject/onionoo/ResponseBuilder.java
index c4f3f07..dbd8cc7 100644
--- a/src/org/torproject/onionoo/ResponseBuilder.java
+++ b/src/org/torproject/onionoo/ResponseBuilder.java
@@ -236,9 +236,7 @@ public class ResponseBuilder {
         UptimeDocument.class, false, fingerprint);
     if (uptimeDocument != null &&
         uptimeDocument.getDocumentString() != null) {
-      String uptimeLines = uptimeDocument.getDocumentString();
-      uptimeLines = uptimeLines.substring(0, uptimeLines.length() - 1);
-      return uptimeLines;
+      return uptimeDocument.getDocumentString();
     } else {
       return "{\"fingerprint\":\"" + fingerprint.toUpperCase() + "\"}";
     }
diff --git a/src/org/torproject/onionoo/UptimeDocument.java b/src/org/torproject/onionoo/UptimeDocument.java
index f71cb87..b2df03b 100644
--- a/src/org/torproject/onionoo/UptimeDocument.java
+++ b/src/org/torproject/onionoo/UptimeDocument.java
@@ -2,7 +2,21 @@
  * See LICENSE for licensing information */
 package org.torproject.onionoo;
 
+import java.util.Map;
+
 class UptimeDocument extends Document {
 
+  private String fingerprint;
+  public void setFingerprint(String fingerprint) {
+    this.fingerprint = fingerprint;
+  }
+
+  private Map<String, GraphHistory> uptime;
+  public void setUptime(Map<String, GraphHistory> uptime) {
+    this.uptime = uptime;
+  }
+  public Map<String, GraphHistory> getUptime() {
+    return this.uptime;
+  }
 }
 
diff --git a/src/org/torproject/onionoo/UptimeDocumentWriter.java b/src/org/torproject/onionoo/UptimeDocumentWriter.java
index 14c800d..8293f77 100644
--- a/src/org/torproject/onionoo/UptimeDocumentWriter.java
+++ b/src/org/torproject/onionoo/UptimeDocumentWriter.java
@@ -3,8 +3,9 @@
 package org.torproject.onionoo;
 
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Locale;
+import java.util.Map;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
@@ -70,9 +71,8 @@ public class UptimeDocumentWriter implements FingerprintListener,
       SortedSet<UptimeHistory> history = relay
           ? uptimeStatus.getRelayHistory()
           : uptimeStatus.getBridgeHistory();
-      UptimeDocument uptimeDocument = new UptimeDocument();
-      uptimeDocument.setDocumentString(this.formatHistoryString(relay,
-          fingerprint, history, knownStatuses));
+      UptimeDocument uptimeDocument = this.compileUptimeDocument(relay,
+          fingerprint, history, knownStatuses);
       this.documentStore.store(uptimeDocument, fingerprint);
       this.writtenDocuments++;
     }
@@ -99,31 +99,29 @@ public class UptimeDocumentWriter implements FingerprintListener,
       DateTimeHelper.TWO_DAYS,
       DateTimeHelper.TEN_DAYS };
 
-  private String formatHistoryString(boolean relay, String fingerprint,
-      SortedSet<UptimeHistory> history,
+  private UptimeDocument compileUptimeDocument(boolean relay,
+      String fingerprint, SortedSet<UptimeHistory> history,
       SortedSet<UptimeHistory> knownStatuses) {
-    StringBuilder sb = new StringBuilder();
-    sb.append("{\"fingerprint\":\"" + fingerprint + "\"");
-    sb.append(",\n\"uptime\":{");
-    int graphIntervalsWritten = 0;
+    UptimeDocument uptimeDocument = new UptimeDocument();
+    uptimeDocument.setFingerprint(fingerprint);
+    Map<String, GraphHistory> uptime =
+        new LinkedHashMap<String, GraphHistory>();
     for (int graphIntervalIndex = 0; graphIntervalIndex <
         this.graphIntervals.length; graphIntervalIndex++) {
-      String timeline = this.formatTimeline(graphIntervalIndex, relay,
-          history, knownStatuses);
-      if (timeline != null) {
-        sb.append((graphIntervalsWritten++ > 0 ? "," : "") + "\n"
-            + timeline);
+      String graphName = this.graphNames[graphIntervalIndex];
+      GraphHistory graphHistory = this.compileUptimeHistory(
+          graphIntervalIndex, relay, history, knownStatuses);
+      if (graphHistory != null) {
+        uptime.put(graphName, graphHistory);
       }
     }
-    sb.append("}");
-    sb.append("\n}\n");
-    return sb.toString();
+    uptimeDocument.setUptime(uptime);
+    return uptimeDocument;
   }
 
-  private String formatTimeline(int graphIntervalIndex, boolean relay,
-      SortedSet<UptimeHistory> history,
+  private GraphHistory compileUptimeHistory(int graphIntervalIndex,
+      boolean relay, SortedSet<UptimeHistory> history,
       SortedSet<UptimeHistory> knownStatuses) {
-    String graphName = this.graphNames[graphIntervalIndex];
     long graphInterval = this.graphIntervals[graphIntervalIndex];
     long dataPointInterval =
         this.dataPointIntervals[graphIntervalIndex];
@@ -253,18 +251,17 @@ public class UptimeDocumentWriter implements FingerprintListener,
     }
     long lastDataPointMillis = firstDataPointMillis
         + (lastNonNullIndex - firstNonNullIndex) * dataPointInterval;
-    double factor = 1.0 / 999.0;
     int count = lastNonNullIndex - firstNonNullIndex + 1;
-    StringBuilder sb = new StringBuilder();
-    sb.append("\"" + graphName + "\":{"
-        + "\"first\":\"" + DateTimeHelper.format(firstDataPointMillis)
-        + "\",\"last\":\"" + DateTimeHelper.format(lastDataPointMillis)
-        + "\",\"interval\":" + String.valueOf(dataPointInterval
-        / DateTimeHelper.ONE_SECOND)
-        + ",\"factor\":" + String.format(Locale.US, "%.9f", factor)
-        + ",\"count\":" + String.valueOf(count) + ",\"values\":[");
-    int dataPointsWritten = 0, previousNonNullIndex = -2;
+    GraphHistory graphHistory = new GraphHistory();
+    graphHistory.setFirst(DateTimeHelper.format(firstDataPointMillis));
+    graphHistory.setLast(DateTimeHelper.format(lastDataPointMillis));
+    graphHistory.setInterval((int) (dataPointInterval
+        / DateTimeHelper.ONE_SECOND));
+    graphHistory.setFactor(1.0 / 999.0);
+    graphHistory.setCount(count);
+    int previousNonNullIndex = -2;
     boolean foundTwoAdjacentDataPoints = false;
+    List<Integer> values = new ArrayList<Integer>();
     for (int dataPointIndex = firstNonNullIndex; dataPointIndex <=
         lastNonNullIndex; dataPointIndex++) {
       double dataPoint = dataPoints.get(dataPointIndex);
@@ -274,13 +271,11 @@ public class UptimeDocumentWriter implements FingerprintListener,
         }
         previousNonNullIndex = dataPointIndex;
       }
-      sb.append((dataPointsWritten++ > 0 ? "," : "")
-          + (dataPoint < -0.5 ? "null" :
-          String.valueOf((long) (dataPoint * 999.0))));
+      values.add(dataPoint < -0.5 ? null : ((int) (dataPoint * 999.0)));
     }
-    sb.append("]}");
+    graphHistory.setValues(values);
     if (foundTwoAdjacentDataPoints) {
-      return sb.toString();
+      return graphHistory;
     } else {
       return null;
     }
diff --git a/test/org/torproject/onionoo/UptimeDocumentWriterTest.java b/test/org/torproject/onionoo/UptimeDocumentWriterTest.java
new file mode 100644
index 0000000..5065e4d
--- /dev/null
+++ b/test/org/torproject/onionoo/UptimeDocumentWriterTest.java
@@ -0,0 +1,253 @@
+/* Copyright 2014 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.onionoo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class UptimeDocumentWriterTest {
+
+  private static final long TEST_TIME = DateTimeHelper.parse(
+      "2014-03-23 12:00:00");
+
+  private DummyTime dummyTime;
+
+  @Before
+  public void createDummyTime() {
+    this.dummyTime = new DummyTime(TEST_TIME);
+    ApplicationFactory.setTime(this.dummyTime);
+  }
+
+  private DummyDescriptorSource descriptorSource;
+
+  @Before
+  public void createDummyDescriptorSource() {
+    this.descriptorSource = new DummyDescriptorSource();
+    ApplicationFactory.setDescriptorSource(this.descriptorSource);
+  }
+
+  private DummyDocumentStore documentStore;
+
+  @Before
+  public void createDummyDocumentStore() {
+    this.documentStore = new DummyDocumentStore();
+    ApplicationFactory.setDocumentStore(this.documentStore);
+  }
+
+  @Test
+  public void testNoStatuses() {
+    UptimeDocumentWriter writer = new UptimeDocumentWriter();
+    writer.writeDocuments();
+    assertEquals("Without providing any data, nothing should be written "
+        + "to disk.", 0,
+        this.documentStore.getPerformedStoreOperations());
+  }
+
+  private static final String ALL_RELAYS_FINGERPRINT = null;
+
+  private static final String GABELMOO_FINGERPRINT =
+      "F2044413DAC2E02E3D6BCF4735A19BCA1DE97281";
+
+  private void addStatusOneWeekSample(String allRelaysUptime,
+      String gabelmooUptime) {
+    UptimeStatus status = new UptimeStatus();
+    status.fromDocumentString(allRelaysUptime);
+    this.documentStore.addDocument(status, ALL_RELAYS_FINGERPRINT);
+    status = new UptimeStatus();
+    status.fromDocumentString(gabelmooUptime);
+    this.documentStore.addDocument(status, GABELMOO_FINGERPRINT);
+    this.descriptorSource.addFingerprint(DescriptorType.RELAY_CONSENSUSES,
+        GABELMOO_FINGERPRINT);
+  }
+
+  private void assertOneWeekGraph(UptimeDocument document, int graphs,
+      String first, String last, int count, List<Integer> values) {
+    this.assertGraph(document, graphs, "1_week", first, last,
+        (int) (DateTimeHelper.ONE_HOUR / DateTimeHelper.ONE_SECOND),
+        count, values);
+  }
+
+  private void assertOneMonthGraph(UptimeDocument document, int graphs,
+      String first, String last, int count, List<Integer> values) {
+    this.assertGraph(document, graphs, "1_month", first, last,
+        (int) (DateTimeHelper.FOUR_HOURS / DateTimeHelper.ONE_SECOND),
+        count, values);
+  }
+
+  private void assertGraph(UptimeDocument document, int graphs,
+      String graphName, String first, String last, int interval,
+      int count, List<Integer> values) {
+    assertEquals("Should contain exactly " + graphs + " graphs.", graphs,
+        document.getUptime().size());
+    assertTrue("Should contain a graph for " + graphName + ".",
+        document.getUptime().containsKey(graphName));
+    GraphHistory history = document.getUptime().get(graphName);
+    assertEquals("First data point should be " + first + ".", first,
+        history.getFirst());
+    assertEquals("Last data point should be " + last + ".", last,
+        history.getLast());
+    assertEquals("Interval should be " + interval + " seconds.", interval,
+        (int) history.getInterval());
+    assertEquals("Factor should be 1.0 / 999.0.", 1.0 / 999.0,
+        (double) history.getFactor(), 0.01);
+    assertEquals("There should be one data point per hour.", count,
+        (int) history.getCount());
+    assertEquals("Count should be the same as the number of values.",
+        count, history.getValues().size());
+    if (values == null) {
+      for (int value : history.getValues()) {
+        assertEquals("All values should be 999.", 999, value);
+      }
+    } else {
+      assertEquals("Values are not as expected.", values,
+          history.getValues());
+    }
+  }
+
+  @Test
+  public void testOneHourUptime() {
+    this.addStatusOneWeekSample("r 2014-03-23-11 1\n",
+        "r 2014-03-23-11 1\n");
+    UptimeDocumentWriter writer = new UptimeDocumentWriter();
+    ApplicationFactory.getDescriptorSource().readDescriptors();
+    writer.writeDocuments();
+    assertEquals("Should write exactly one document.", 1,
+        this.documentStore.getPerformedStoreOperations());
+    UptimeDocument document = this.documentStore.getDocument(
+        UptimeDocument.class, GABELMOO_FINGERPRINT);
+    assertEquals("Should not contain any graph.", 0,
+        document.getUptime().size());
+  }
+
+  @Test
+  public void testTwoHoursUptime() {
+    this.addStatusOneWeekSample("r 2014-03-23-10 2\n",
+        "r 2014-03-23-10 2\n");
+    UptimeDocumentWriter writer = new UptimeDocumentWriter();
+    ApplicationFactory.getDescriptorSource().readDescriptors();
+    writer.writeDocuments();
+    assertEquals("Should write exactly one document.", 1,
+        this.documentStore.getPerformedStoreOperations());
+    UptimeDocument document = this.documentStore.getDocument(
+        UptimeDocument.class, GABELMOO_FINGERPRINT);
+    this.assertOneWeekGraph(document, 1, "2014-03-23 10:30:00",
+        "2014-03-23 11:30:00", 2, null);
+  }
+
+  @Test
+  public void testTwoHoursUptimeSeparatedByNull() {
+    this.addStatusOneWeekSample("r 2014-03-23-09 1\nr 2014-03-23-11 1\n",
+        "r 2014-03-23-09 1\nr 2014-03-23-11 1\n");
+    UptimeDocumentWriter writer = new UptimeDocumentWriter();
+    ApplicationFactory.getDescriptorSource().readDescriptors();
+    writer.writeDocuments();
+    assertEquals("Should write exactly one document.", 1,
+        this.documentStore.getPerformedStoreOperations());
+    UptimeDocument document = this.documentStore.getDocument(
+        UptimeDocument.class, GABELMOO_FINGERPRINT);
+    assertEquals("Should not contain any graph.", 0,
+        document.getUptime().size());
+  }
+
+  @Test
+  public void testTwoHoursUptimeSeparatedByZero() {
+    this.addStatusOneWeekSample("r 2014-03-23-09 3\n",
+        "r 2014-03-23-09 1\nr 2014-03-23-11 1\n");
+    UptimeDocumentWriter writer = new UptimeDocumentWriter();
+    ApplicationFactory.getDescriptorSource().readDescriptors();
+    writer.writeDocuments();
+    assertEquals("Should write exactly one document.", 1,
+        this.documentStore.getPerformedStoreOperations());
+    UptimeDocument document = this.documentStore.getDocument(
+        UptimeDocument.class, GABELMOO_FINGERPRINT);
+    this.assertOneWeekGraph(document, 1, "2014-03-23 09:30:00",
+        "2014-03-23 11:30:00", 3,
+        Arrays.asList(new Integer[] { 999, 0, 999 }));
+  }
+
+  @Test
+  public void testTwoHoursUptimeThenDowntime() {
+    this.addStatusOneWeekSample("r 2014-03-23-09 3\n",
+        "r 2014-03-23-09 2\n");
+    UptimeDocumentWriter writer = new UptimeDocumentWriter();
+    ApplicationFactory.getDescriptorSource().readDescriptors();
+    writer.writeDocuments();
+    assertEquals("Should write exactly one document.", 1,
+        this.documentStore.getPerformedStoreOperations());
+    UptimeDocument document = this.documentStore.getDocument(
+        UptimeDocument.class, GABELMOO_FINGERPRINT);
+    this.assertOneWeekGraph(document, 1, "2014-03-23 09:30:00",
+        "2014-03-23 11:30:00", 3,
+        Arrays.asList(new Integer[] { 999, 999, 0 }));
+  }
+
+  @Test
+  public void testOneWeekUptime() {
+    this.addStatusOneWeekSample("r 2014-03-16-12 168\n",
+        "r 2014-03-16-12 168\n");
+    UptimeDocumentWriter writer = new UptimeDocumentWriter();
+    ApplicationFactory.getDescriptorSource().readDescriptors();
+    writer.writeDocuments();
+    assertEquals("Should write exactly one document.", 1,
+        this.documentStore.getPerformedStoreOperations());
+    UptimeDocument document = this.documentStore.getDocument(
+        UptimeDocument.class, GABELMOO_FINGERPRINT);
+    this.assertOneWeekGraph(document, 1, "2014-03-16 12:30:00",
+        "2014-03-23 11:30:00", 168, null);
+  }
+
+  @Test
+  public void testOneWeekOneHourUptime() {
+    this.addStatusOneWeekSample("r 2014-03-16-11 169\n",
+        "r 2014-03-16-11 169\n");
+    UptimeDocumentWriter writer = new UptimeDocumentWriter();
+    ApplicationFactory.getDescriptorSource().readDescriptors();
+    writer.writeDocuments();
+    assertEquals("Should write exactly one document.", 1,
+        this.documentStore.getPerformedStoreOperations());
+    UptimeDocument document = this.documentStore.getDocument(
+        UptimeDocument.class, GABELMOO_FINGERPRINT);
+    this.assertOneWeekGraph(document, 2, "2014-03-16 12:30:00",
+        "2014-03-23 11:30:00", 168, null);
+    this.assertOneMonthGraph(document, 2, "2014-03-16 10:00:00",
+        "2014-03-23 10:00:00", 43, null);
+  }
+
+  @Test
+  public void testOneMonthPartialIntervalOnline() {
+    this.addStatusOneWeekSample("r 2014-03-16-08 8\n",
+        "r 2014-03-16-11 5\n");
+    UptimeDocumentWriter writer = new UptimeDocumentWriter();
+    ApplicationFactory.getDescriptorSource().readDescriptors();
+    writer.writeDocuments();
+    assertEquals("Should write exactly one document.", 1,
+        this.documentStore.getPerformedStoreOperations());
+    UptimeDocument document = this.documentStore.getDocument(
+        UptimeDocument.class, GABELMOO_FINGERPRINT);
+    this.assertOneMonthGraph(document, 2, "2014-03-16 10:00:00",
+        "2014-03-16 14:00:00", 2, null);
+  }
+
+  @Test
+  public void testOneMonthPartialIntervalOnOff() {
+    this.addStatusOneWeekSample("r 2014-03-16-08 8\n",
+        "r 2014-03-16-10 1\nr 2014-03-16-12 1\n");
+    UptimeDocumentWriter writer = new UptimeDocumentWriter();
+    ApplicationFactory.getDescriptorSource().readDescriptors();
+    writer.writeDocuments();
+    assertEquals("Should write exactly one document.", 1,
+        this.documentStore.getPerformedStoreOperations());
+    UptimeDocument document = this.documentStore.getDocument(
+        UptimeDocument.class, GABELMOO_FINGERPRINT);
+    this.assertOneMonthGraph(document, 2, "2014-03-16 10:00:00",
+        "2014-03-16 14:00:00", 2,
+        Arrays.asList(new Integer[] { 499, 249 }));
+  }
+}
+





More information about the tor-commits mailing list