commit 7ad85bd18b82973a6a323fe776a0dd657a7f8a15 Author: Karsten Loesing karsten.loesing@gmx.net Date: Sun Mar 23 17:09:38 2014 +0100
Add tests for UpdateStatusUpdater. --- .../torproject/onionoo/ClientsStatusUpdater.java | 1 - src/org/torproject/onionoo/DescriptorSource.java | 49 +++--- src/org/torproject/onionoo/Main.java | 19 +-- .../torproject/onionoo/UptimeStatusUpdater.java | 1 - test/org/torproject/onionoo/DummyBridgeStatus.java | 43 +++++ test/org/torproject/onionoo/DummyConsensus.java | 114 +++++++++++++ .../torproject/onionoo/DummyDescriptorSource.java | 133 +++++++++++++++ .../org/torproject/onionoo/DummyDocumentStore.java | 6 + test/org/torproject/onionoo/DummyStatusEntry.java | 92 ++++++++++ .../onionoo/UptimeStatusUpdaterTest.java | 176 ++++++++++++++++++++ 10 files changed, 594 insertions(+), 40 deletions(-)
diff --git a/src/org/torproject/onionoo/ClientsStatusUpdater.java b/src/org/torproject/onionoo/ClientsStatusUpdater.java index ed4390e..4fe2b2d 100644 --- a/src/org/torproject/onionoo/ClientsStatusUpdater.java +++ b/src/org/torproject/onionoo/ClientsStatusUpdater.java @@ -149,7 +149,6 @@ public class ClientsStatusUpdater implements DescriptorListener, this.compressHistory(clientsStatus); this.documentStore.store(clientsStatus, hashedFingerprint); } - Logger.printStatusTime("Updated clients status files"); }
private void addToHistory(ClientsStatus clientsStatus, diff --git a/src/org/torproject/onionoo/DescriptorSource.java b/src/org/torproject/onionoo/DescriptorSource.java index f5adf56..f4ff2fc 100644 --- a/src/org/torproject/onionoo/DescriptorSource.java +++ b/src/org/torproject/onionoo/DescriptorSource.java @@ -318,42 +318,21 @@ public class DescriptorSource { this.fingerprintListeners.get(descriptorType).add(listener); }
- public void readRelayNetworkConsensuses() { + public void readDescriptors() { this.readDescriptors(DescriptorType.RELAY_CONSENSUSES, DescriptorHistory.RELAY_CONSENSUS_HISTORY, true); - } - - public void readRelayServerDescriptors() { this.readDescriptors(DescriptorType.RELAY_SERVER_DESCRIPTORS, DescriptorHistory.RELAY_SERVER_HISTORY, true); - } - - public void readRelayExtraInfos() { this.readDescriptors(DescriptorType.RELAY_EXTRA_INFOS, DescriptorHistory.RELAY_EXTRAINFO_HISTORY, true); - } - - public void readExitLists() { this.readDescriptors(DescriptorType.EXIT_LISTS, DescriptorHistory.EXIT_LIST_HISTORY, true); - } - - public void readBridgeNetworkStatuses() { this.readDescriptors(DescriptorType.BRIDGE_STATUSES, DescriptorHistory.BRIDGE_STATUS_HISTORY, false); - } - - public void readBridgeServerDescriptors() { this.readDescriptors(DescriptorType.BRIDGE_SERVER_DESCRIPTORS, DescriptorHistory.BRIDGE_SERVER_HISTORY, false); - } - - public void readBridgeExtraInfos() { this.readDescriptors(DescriptorType.BRIDGE_EXTRA_INFOS, DescriptorHistory.BRIDGE_EXTRAINFO_HISTORY, false); - } - - public void readBridgePoolAssignments() { this.readDescriptors(DescriptorType.BRIDGE_POOL_ASSIGNMENTS, DescriptorHistory.BRIDGE_POOLASSIGN_HISTORY, false); } @@ -419,6 +398,32 @@ public class DescriptorSource { fingerprintListener.processFingerprints(fingerprints, relay); } } + switch (descriptorType) { + case RELAY_CONSENSUSES: + Logger.printStatusTime("Read relay network consensuses"); + break; + case RELAY_SERVER_DESCRIPTORS: + Logger.printStatusTime("Read relay server descriptors"); + break; + case RELAY_EXTRA_INFOS: + Logger.printStatusTime("Read relay extra-info descriptors"); + break; + case EXIT_LISTS: + Logger.printStatusTime("Read exit lists"); + break; + case BRIDGE_STATUSES: + Logger.printStatusTime("Read bridge network statuses"); + break; + case BRIDGE_SERVER_DESCRIPTORS: + Logger.printStatusTime("Read bridge server descriptors"); + break; + case BRIDGE_EXTRA_INFOS: + Logger.printStatusTime("Read bridge extra-info descriptors"); + break; + case BRIDGE_POOL_ASSIGNMENTS: + Logger.printStatusTime("Read bridge-pool assignments"); + break; + } }
public void writeHistoryFiles() { diff --git a/src/org/torproject/onionoo/Main.java b/src/org/torproject/onionoo/Main.java index 141e44b..cceef92 100644 --- a/src/org/torproject/onionoo/Main.java +++ b/src/org/torproject/onionoo/Main.java @@ -59,26 +59,13 @@ public class Main { udw };
Logger.printStatus("Reading descriptors."); - dso.readRelayNetworkConsensuses(); - Logger.printStatusTime("Read relay network consensuses"); - dso.readRelayServerDescriptors(); - Logger.printStatusTime("Read relay server descriptors"); - dso.readRelayExtraInfos(); - Logger.printStatusTime("Read relay extra-info descriptors"); - dso.readExitLists(); - Logger.printStatusTime("Read exit lists"); - dso.readBridgeNetworkStatuses(); - Logger.printStatusTime("Read bridge network statuses"); - dso.readBridgeServerDescriptors(); - Logger.printStatusTime("Read bridge server descriptors"); - dso.readBridgeExtraInfos(); - Logger.printStatusTime("Read bridge extra-info descriptors"); - dso.readBridgePoolAssignments(); - Logger.printStatusTime("Read bridge-pool assignments"); + dso.readDescriptors();
Logger.printStatus("Updating internal status files."); for (StatusUpdater su : sus) { su.updateStatuses(); + Logger.printStatusTime(su.getClass().getSimpleName() + + " updated status files"); }
Logger.printStatus("Updating document files."); diff --git a/src/org/torproject/onionoo/UptimeStatusUpdater.java b/src/org/torproject/onionoo/UptimeStatusUpdater.java index 6dc0b94..eccc2f2 100644 --- a/src/org/torproject/onionoo/UptimeStatusUpdater.java +++ b/src/org/torproject/onionoo/UptimeStatusUpdater.java @@ -100,7 +100,6 @@ public class UptimeStatusUpdater implements DescriptorListener, this.updateStatus(false, e.getKey(), e.getValue()); } this.updateStatus(false, null, this.newBridgeStatuses); - Logger.printStatusTime("Updated uptime status files"); }
private void updateStatus(boolean relay, String fingerprint, diff --git a/test/org/torproject/onionoo/DummyBridgeStatus.java b/test/org/torproject/onionoo/DummyBridgeStatus.java new file mode 100644 index 0000000..35a9036 --- /dev/null +++ b/test/org/torproject/onionoo/DummyBridgeStatus.java @@ -0,0 +1,43 @@ +/* Copyright 2014 The Tor Project + * See LICENSE for licensing information */ +package org.torproject.onionoo; + +import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.torproject.descriptor.BridgeNetworkStatus; +import org.torproject.descriptor.NetworkStatusEntry; + +public class DummyBridgeStatus implements BridgeNetworkStatus { + + public byte[] getRawDescriptorBytes() { + return null; + } + + public List<String> getAnnotations() { + return null; + } + + public List<String> getUnrecognizedLines() { + return null; + } + + private long publishedMillis; + public void setPublishedMillis(long publishedMillis) { + this.publishedMillis = publishedMillis; + } + public long getPublishedMillis() { + return this.publishedMillis; + } + + private SortedMap<String, NetworkStatusEntry> statusEntries = + new TreeMap<String, NetworkStatusEntry>(); + public void addStatusEntry(NetworkStatusEntry statusEntry) { + this.statusEntries.put(statusEntry.getFingerprint(), statusEntry); + } + public SortedMap<String, NetworkStatusEntry> getStatusEntries() { + return this.statusEntries; + } +} + diff --git a/test/org/torproject/onionoo/DummyConsensus.java b/test/org/torproject/onionoo/DummyConsensus.java new file mode 100644 index 0000000..3fa0fdd --- /dev/null +++ b/test/org/torproject/onionoo/DummyConsensus.java @@ -0,0 +1,114 @@ +/* Copyright 2014 The Tor Project + * See LICENSE for licensing information */ +package org.torproject.onionoo; + +import java.util.List; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; + +import org.torproject.descriptor.DirSourceEntry; +import org.torproject.descriptor.DirectorySignature; +import org.torproject.descriptor.NetworkStatusEntry; +import org.torproject.descriptor.RelayNetworkStatusConsensus; + +public class DummyConsensus implements RelayNetworkStatusConsensus { + + public byte[] getRawDescriptorBytes() { + return null; + } + + public List<String> getAnnotations() { + return null; + } + + public List<String> getUnrecognizedLines() { + return null; + } + + public int getNetworkStatusVersion() { + return 0; + } + + public String getConsensusFlavor() { + return null; + } + + public int getConsensusMethod() { + return 0; + } + + private long validAfterMillis; + public void setValidAfterMillis(long validAfterMillis) { + this.validAfterMillis = validAfterMillis; + } + public long getValidAfterMillis() { + return this.validAfterMillis; + } + + public long getFreshUntilMillis() { + return 0; + } + + public long getValidUntilMillis() { + return 0; + } + + public long getVoteSeconds() { + return 0; + } + + public long getDistSeconds() { + return 0; + } + + public List<String> getRecommendedServerVersions() { + return null; + } + + public List<String> getRecommendedClientVersions() { + return null; + } + + public SortedSet<String> getKnownFlags() { + return null; + } + + public SortedMap<String, Integer> getConsensusParams() { + return null; + } + + public SortedMap<String, DirSourceEntry> getDirSourceEntries() { + return null; + } + + private SortedMap<String, NetworkStatusEntry> statusEntries = + new TreeMap<String, NetworkStatusEntry>(); + public void addStatusEntry(NetworkStatusEntry statusEntry) { + this.statusEntries.put(statusEntry.getFingerprint(), statusEntry); + } + public SortedMap<String, NetworkStatusEntry> getStatusEntries() { + return this.statusEntries; + } + + public boolean containsStatusEntry(String fingerprint) { + return false; + } + + public NetworkStatusEntry getStatusEntry(String fingerprint) { + return null; + } + + public SortedMap<String, DirectorySignature> getDirectorySignatures() { + return null; + } + + public SortedMap<String, Integer> getBandwidthWeights() { + return null; + } + + public String getConsensusDigest() { + return null; + } +} + diff --git a/test/org/torproject/onionoo/DummyDescriptorSource.java b/test/org/torproject/onionoo/DummyDescriptorSource.java new file mode 100644 index 0000000..06ec499 --- /dev/null +++ b/test/org/torproject/onionoo/DummyDescriptorSource.java @@ -0,0 +1,133 @@ +package org.torproject.onionoo; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.torproject.descriptor.Descriptor; + +public class DummyDescriptorSource extends DescriptorSource { + + private Map<DescriptorType, Set<Descriptor>> descriptors = + new HashMap<DescriptorType, Set<Descriptor>>(); + + public void provideDescriptors(DescriptorType descriptorType, + Collection<Descriptor> descriptors) { + for (Descriptor descriptor : descriptors) { + this.addDescriptor(descriptorType, descriptor); + } + } + + public void addDescriptor(DescriptorType descriptorType, + Descriptor descriptor) { + this.getDescriptorsByType(descriptorType).add(descriptor); + } + + private Set<Descriptor> getDescriptorsByType( + DescriptorType descriptorType) { + if (!this.descriptors.containsKey(descriptorType)) { + this.descriptors.put(descriptorType, new HashSet<Descriptor>()); + } + return this.descriptors.get(descriptorType); + } + + private Map<DescriptorType, SortedSet<String>> fingerprints = + new HashMap<DescriptorType, SortedSet<String>>(); + + public void addFingerprints(DescriptorType descriptorType, + Collection<String> fingerprints) { + this.getFingerprintsByType(descriptorType).addAll(fingerprints); + } + + public void addFingerprint(DescriptorType descriptorType, + String fingerprint) { + this.getFingerprintsByType(descriptorType).add(fingerprint); + } + + private SortedSet<String> getFingerprintsByType( + DescriptorType descriptorType) { + if (!this.fingerprints.containsKey(descriptorType)) { + this.fingerprints.put(descriptorType, new TreeSet<String>()); + } + return this.fingerprints.get(descriptorType); + } + + private Map<DescriptorType, Set<DescriptorListener>> + descriptorListeners = new HashMap<DescriptorType, + Set<DescriptorListener>>(); + + public void registerDescriptorListener(DescriptorListener listener, + DescriptorType descriptorType) { + if (!this.descriptorListeners.containsKey(descriptorType)) { + this.descriptorListeners.put(descriptorType, + new HashSet<DescriptorListener>()); + } + this.descriptorListeners.get(descriptorType).add(listener); + } + + private Map<DescriptorType, Set<FingerprintListener>> + fingerprintListeners = new HashMap<DescriptorType, + Set<FingerprintListener>>(); + + public void registerFingerprintListener(FingerprintListener listener, + DescriptorType descriptorType) { + if (!this.fingerprintListeners.containsKey(descriptorType)) { + this.fingerprintListeners.put(descriptorType, + new HashSet<FingerprintListener>()); + } + this.fingerprintListeners.get(descriptorType).add(listener); + } + + public void readDescriptors() { + Set<DescriptorType> descriptorTypes = new HashSet<DescriptorType>(); + descriptorTypes.addAll(this.descriptorListeners.keySet()); + descriptorTypes.addAll(this.fingerprintListeners.keySet()); + for (DescriptorType descriptorType : descriptorTypes) { + boolean relay; + switch (descriptorType) { + case RELAY_CONSENSUSES: + case RELAY_SERVER_DESCRIPTORS: + case RELAY_EXTRA_INFOS: + case EXIT_LISTS: + relay = true; + break; + case BRIDGE_STATUSES: + case BRIDGE_SERVER_DESCRIPTORS: + case BRIDGE_EXTRA_INFOS: + case BRIDGE_POOL_ASSIGNMENTS: + default: + relay = false; + break; + } + if (this.descriptors.containsKey(descriptorType) && + this.descriptorListeners.containsKey(descriptorType)) { + Set<DescriptorListener> listeners = + this.descriptorListeners.get(descriptorType); + for (Descriptor descriptor : + this.getDescriptorsByType(descriptorType)) { + for (DescriptorListener listener : listeners) { + listener.processDescriptor(descriptor, relay); + } + } + } + if (this.fingerprints.containsKey(descriptorType) && + this.fingerprintListeners.containsKey(descriptorType)) { + Set<FingerprintListener> listeners = + this.fingerprintListeners.get(descriptorType); + for (FingerprintListener listener : listeners) { + listener.processFingerprints(this.getFingerprintsByType( + descriptorType), relay); + } + } + } + } + + public void writeHistoryFiles() { + /* Nothing to do here. */ + } +} + diff --git a/test/org/torproject/onionoo/DummyDocumentStore.java b/test/org/torproject/onionoo/DummyDocumentStore.java index 05723d0..6969b8f 100644 --- a/test/org/torproject/onionoo/DummyDocumentStore.java +++ b/test/org/torproject/onionoo/DummyDocumentStore.java @@ -30,6 +30,12 @@ public class DummyDocumentStore extends DocumentStore { fingerprint == null ? FINGERPRINT_NULL : fingerprint, document); }
+ public <T extends Document> T getDocument(Class<T> documentType, + String fingerprint) { + return documentType.cast(this.getStoredDocumentsByClass(documentType). + get(fingerprint == null ? FINGERPRINT_NULL : fingerprint)); + } + public void flushDocumentCache() { /* Nothing to do. */ } diff --git a/test/org/torproject/onionoo/DummyStatusEntry.java b/test/org/torproject/onionoo/DummyStatusEntry.java new file mode 100644 index 0000000..8fdc5cd --- /dev/null +++ b/test/org/torproject/onionoo/DummyStatusEntry.java @@ -0,0 +1,92 @@ +/* Copyright 2014 The Tor Project + * See LICENSE for licensing information */ +package org.torproject.onionoo; + +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.torproject.descriptor.NetworkStatusEntry; + +public class DummyStatusEntry implements NetworkStatusEntry { + + public DummyStatusEntry(String fingerprint) { + this.fingerprint = fingerprint; + } + + public byte[] getStatusEntryBytes() { + return null; + } + + @Override + public String getNickname() { + return null; + } + + private String fingerprint; + public String getFingerprint() { + return this.fingerprint; + } + + public String getDescriptor() { + return null; + } + + public long getPublishedMillis() { + return 0; + } + + public String getAddress() { + return null; + } + + public int getOrPort() { + return 0; + } + + public int getDirPort() { + return 0; + } + + public Set<String> getMicrodescriptorDigests() { + return null; + } + + public List<String> getOrAddresses() { + return null; + } + + private SortedSet<String> flags = new TreeSet<String>(); + public void addFlag(String flag) { + this.flags.add(flag); + } + public SortedSet<String> getFlags() { + return this.flags; + } + + public String getVersion() { + return null; + } + + public long getBandwidth() { + return 0; + } + + public long getMeasured() { + return 0; + } + + public boolean getUnmeasured() { + return false; + } + + public String getDefaultPolicy() { + return null; + } + + public String getPortList() { + return null; + } +} + diff --git a/test/org/torproject/onionoo/UptimeStatusUpdaterTest.java b/test/org/torproject/onionoo/UptimeStatusUpdaterTest.java new file mode 100644 index 0000000..4ca2245 --- /dev/null +++ b/test/org/torproject/onionoo/UptimeStatusUpdaterTest.java @@ -0,0 +1,176 @@ +/* Copyright 2014 The Tor Project + * See LICENSE for licensing information */ +package org.torproject.onionoo; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +public class UptimeStatusUpdaterTest { + + 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 testNoDescriptorsNoStatusFiles() { + UptimeStatusUpdater updater = new UptimeStatusUpdater(); + ApplicationFactory.getDescriptorSource().readDescriptors(); + updater.updateStatuses(); + assertEquals("Without providing any data, nothing should be written " + + "to disk.", 0, + this.documentStore.getPerformedStoreOperations()); + } + + private static final long VALID_AFTER_SAMPLE = + DateTimeHelper.parse("2014-03-21 20:00:00"); + + private static final String GABELMOO_FINGERPRINT = + "F2044413DAC2E02E3D6BCF4735A19BCA1DE97281"; + + private void addConsensusSample() { + DummyStatusEntry statusEntry = new DummyStatusEntry( + GABELMOO_FINGERPRINT); + statusEntry.addFlag("Running"); + DummyConsensus consensus = new DummyConsensus(); + consensus.setValidAfterMillis(VALID_AFTER_SAMPLE); + consensus.addStatusEntry(statusEntry); + this.descriptorSource.addDescriptor(DescriptorType.RELAY_CONSENSUSES, + consensus); + } + + @Test + public void testOneConsensusNoStatusFiles() { + this.addConsensusSample(); + UptimeStatusUpdater updater = new UptimeStatusUpdater(); + ApplicationFactory.getDescriptorSource().readDescriptors(); + updater.updateStatuses(); + assertEquals("Two status files should have been written to disk.", + 2, this.documentStore.getPerformedStoreOperations()); + for (String fingerprint : new String[] { GABELMOO_FINGERPRINT, + null }) { + UptimeStatus status = this.documentStore.getDocument( + UptimeStatus.class, fingerprint); + UptimeHistory history = status.getHistory().first(); + assertEquals("History must contain one entry.", 1, + status.getHistory().size()); + assertEquals("History not for relay.", true, history.isRelay()); + assertEquals("History start millis not as expected.", + VALID_AFTER_SAMPLE, history.getStartMillis()); + assertEquals("History uptime hours must be 1.", 1, + history.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 testOneConsensusOneStatusFiles() { + this.addAllRelaysAndBridgesUptimeSample(); + this.addConsensusSample(); + UptimeStatusUpdater updater = new UptimeStatusUpdater(); + ApplicationFactory.getDescriptorSource().readDescriptors(); + updater.updateStatuses(); + assertEquals("Two status files should have been written to disk.", + 2, this.documentStore.getPerformedStoreOperations()); + UptimeStatus status = this.documentStore.getDocument( + UptimeStatus.class, ALL_RELAYS_AND_BRIDGES_FINGERPRINT); + assertEquals("History must contain two entries.", 2, + status.getHistory().size()); + UptimeHistory history = status.getHistory().first(); + assertEquals("History not for relay.", true, history.isRelay()); + assertEquals("History start millis not as expected.", + DateTimeHelper.parse("2013-07-22 17:00:00"), + history.getStartMillis()); + assertEquals("History uptime hours must be 5812.", 5812, + history.getUptimeHours()); + } + + private static final long PUBLISHED_SAMPLE = + DateTimeHelper.parse("2014-03-21 20:37:03"); + + private static final String NDNOP2_FINGERPRINT = + "DE6397A047ABE5F78B4C87AF725047831B221AAB"; + + private void addBridgeStatusSample() { + DummyStatusEntry statusEntry = new DummyStatusEntry( + NDNOP2_FINGERPRINT); + statusEntry.addFlag("Running"); + DummyBridgeStatus bridgeStatus = new DummyBridgeStatus(); + bridgeStatus.setPublishedMillis(PUBLISHED_SAMPLE); + bridgeStatus.addStatusEntry(statusEntry); + this.descriptorSource.addDescriptor(DescriptorType.BRIDGE_STATUSES, + bridgeStatus); + } + + @Test + public void testOneBridgeStatusNoStatusFiles() { + this.addBridgeStatusSample(); + UptimeStatusUpdater updater = new UptimeStatusUpdater(); + ApplicationFactory.getDescriptorSource().readDescriptors(); + updater.updateStatuses(); + assertEquals("Two status files should have been written to disk.", + 2, this.documentStore.getPerformedStoreOperations()); + for (String fingerprint : new String[] { NDNOP2_FINGERPRINT, + null }) { + UptimeStatus status = this.documentStore.getDocument( + UptimeStatus.class, fingerprint); + UptimeHistory history = status.getHistory().first(); + assertEquals("History must contain one entry.", 1, + status.getHistory().size()); + assertEquals("History not for bridge.", false, history.isRelay()); + assertEquals("History start millis not as expected.", + DateTimeHelper.parse("2014-03-21 20:00:00"), + history.getStartMillis()); + assertEquals("History uptime hours must be 1.", 1, + history.getUptimeHours()); + } + } + + @Test + public void testOneBridgeStatusOneStatusFiles() { + this.addAllRelaysAndBridgesUptimeSample(); + this.addBridgeStatusSample(); + UptimeStatusUpdater updater = new UptimeStatusUpdater(); + ApplicationFactory.getDescriptorSource().readDescriptors(); + updater.updateStatuses(); + assertEquals("Two status files should have been written to disk.", + 2, this.documentStore.getPerformedStoreOperations()); + UptimeStatus status = this.documentStore.getDocument( + UptimeStatus.class, ALL_RELAYS_AND_BRIDGES_FINGERPRINT); + assertEquals("History must contain two entries.", 2, + status.getHistory().size()); + UptimeHistory history = status.getHistory().last(); + assertEquals("History not for relay.", false, history.isRelay()); + assertEquals("History start millis not as expected.", + DateTimeHelper.parse("2013-07-22 17:00:00"), + history.getStartMillis()); + assertEquals("History uptime hours must be 5812.", 5812, + history.getUptimeHours()); + } +} +