commit 9748e432b8d750112f52c82bbf788dd3f130c9a7 Author: Karsten Loesing karsten.loesing@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@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()); + } +} +
tor-commits@lists.torproject.org