commit 569bb83ff5e50843079ebd1150801a8bd8efa747 Author: Karsten Loesing karsten.loesing@gmx.net Date: Wed Aug 14 08:51:29 2019 +0200
Archive snowflake statistics.
Implements #29461. --- CHANGELOG.md | 2 + build.xml | 2 +- .../org/torproject/metrics/collector/Main.java | 3 + .../metrics/collector/conf/Annotation.java | 3 +- .../metrics/collector/conf/Configuration.java | 1 + .../org/torproject/metrics/collector/conf/Key.java | 8 +- .../persist/SnowflakeStatsPersistence.java | 37 ++++ .../snowflake/SnowflakeStatsDownloader.java | 191 +++++++++++++++++++++ .../metrics/collector/sync/SyncPersistence.java | 5 + src/main/resources/collector.properties | 20 +++ src/main/resources/create-tarballs.sh | 7 + src/main/resources/docs/PROTOCOL | 33 +++- .../metrics/collector/conf/ConfigurationTest.java | 2 +- .../metrics/collector/cron/CollecTorMainTest.java | 1 + .../metrics/collector/cron/SchedulerTest.java | 9 +- 15 files changed, 317 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fd0401..c537d22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ versions resolved by Ivy are the same as in Debian stretch with few exceptions. - Remove Cobertura from the build process. + - Archive snowflake statistics. + - Update to metrics-lib 2.7.0.
# Changes in version 1.9.1 - 2019-05-29 diff --git a/build.xml b/build.xml index 39180c7..d1d5b70 100644 --- a/build.xml +++ b/build.xml @@ -12,7 +12,7 @@ <property name="release.version" value="1.9.1-dev" /> <property name="project-main-class" value="org.torproject.metrics.collector.Main" /> <property name="name" value="collector"/> - <property name="metricslibversion" value="2.6.2" /> + <property name="metricslibversion" value="2.7.0" /> <property name="jarincludes" value="collector.properties logback.xml" />
<patternset id="runtime" > diff --git a/src/main/java/org/torproject/metrics/collector/Main.java b/src/main/java/org/torproject/metrics/collector/Main.java index 46e93af..6907e93 100644 --- a/src/main/java/org/torproject/metrics/collector/Main.java +++ b/src/main/java/org/torproject/metrics/collector/Main.java @@ -14,6 +14,7 @@ import org.torproject.metrics.collector.exitlists.ExitListDownloader; import org.torproject.metrics.collector.indexer.CreateIndexJson; import org.torproject.metrics.collector.onionperf.OnionPerfDownloader; import org.torproject.metrics.collector.relaydescs.ArchiveWriter; +import org.torproject.metrics.collector.snowflake.SnowflakeStatsDownloader; import org.torproject.metrics.collector.webstats.SanitizeWeblogs;
import org.slf4j.Logger; @@ -53,6 +54,8 @@ public class Main { collecTorMains.put(Key.RelaydescsActivated, ArchiveWriter.class); collecTorMains.put(Key.OnionPerfActivated, OnionPerfDownloader.class); collecTorMains.put(Key.WebstatsActivated, SanitizeWeblogs.class); + collecTorMains.put(Key.SnowflakeStatsActivated, + SnowflakeStatsDownloader.class); }
private static Configuration conf = new Configuration(); diff --git a/src/main/java/org/torproject/metrics/collector/conf/Annotation.java b/src/main/java/org/torproject/metrics/collector/conf/Annotation.java index 2e47df0..8cd3324 100644 --- a/src/main/java/org/torproject/metrics/collector/conf/Annotation.java +++ b/src/main/java/org/torproject/metrics/collector/conf/Annotation.java @@ -18,7 +18,8 @@ public enum Annotation { Server("@type server-descriptor 1.0\n"), Status("@type bridge-network-status 1.2\n"), OnionPerf("@type torperf 1.1\n"), - Vote("@type network-status-vote-3 1.0\n"); + Vote("@type network-status-vote-3 1.0\n"), + SnowflakeStats("@type snowflake-stats 1.0\n");
private final String annotation; private final byte[] bytes; diff --git a/src/main/java/org/torproject/metrics/collector/conf/Configuration.java b/src/main/java/org/torproject/metrics/collector/conf/Configuration.java index 69d3bcd..27f5125 100644 --- a/src/main/java/org/torproject/metrics/collector/conf/Configuration.java +++ b/src/main/java/org/torproject/metrics/collector/conf/Configuration.java @@ -91,6 +91,7 @@ public class Configuration extends Observable implements Cloneable { || this.getBool(Key.ExitlistsActivated) || this.getBool(Key.UpdateindexActivated) || this.getBool(Key.OnionPerfActivated) + || this.getBool(Key.SnowflakeStatsActivated) || this.getBool(Key.WebstatsActivated))) { throw new ConfigurationException("Nothing is activated!\n" + "Please edit collector.properties. Exiting."); diff --git a/src/main/java/org/torproject/metrics/collector/conf/Key.java b/src/main/java/org/torproject/metrics/collector/conf/Key.java index ba4bcd9..e683fe2 100644 --- a/src/main/java/org/torproject/metrics/collector/conf/Key.java +++ b/src/main/java/org/torproject/metrics/collector/conf/Key.java @@ -66,7 +66,13 @@ public enum Key { WebstatsActivated(Boolean.class), WebstatsLimits(Boolean.class), WebstatsOffsetMinutes(Integer.class), - WebstatsPeriodMinutes(Integer.class); + WebstatsPeriodMinutes(Integer.class), + SnowflakeStatsActivated(Boolean.class), + SnowflakeStatsOffsetMinutes(Integer.class), + SnowflakeStatsPeriodMinutes(Integer.class), + SnowflakeStatsUrl(URL.class), + SnowflakeStatsSources(SourceType[].class), + SnowflakeStatsSyncOrigins(URL[].class);
private Class clazz; private static Set<String> keys; diff --git a/src/main/java/org/torproject/metrics/collector/persist/SnowflakeStatsPersistence.java b/src/main/java/org/torproject/metrics/collector/persist/SnowflakeStatsPersistence.java new file mode 100644 index 0000000..ee6e029 --- /dev/null +++ b/src/main/java/org/torproject/metrics/collector/persist/SnowflakeStatsPersistence.java @@ -0,0 +1,37 @@ +/* Copyright 2019 The Tor Project + * See LICENSE for licensing information */ + +package org.torproject.metrics.collector.persist; + +import org.torproject.descriptor.SnowflakeStats; +import org.torproject.metrics.collector.conf.Annotation; + +import java.nio.file.Paths; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; + +public class SnowflakeStatsPersistence + extends DescriptorPersistence<SnowflakeStats> { + + private static final String SNOWFLAKES = "snowflakes"; + + public SnowflakeStatsPersistence(SnowflakeStats desc) { + super(desc, Annotation.SnowflakeStats.bytes()); + calculatePaths(); + } + + private void calculatePaths() { + DateTimeFormatter directoriesFormatter = DateTimeFormatter + .ofPattern("uuuu/MM/dd").withZone(ZoneOffset.UTC); + String[] directories = this.desc.snowflakeStatsEnd() + .format(directoriesFormatter).split("/"); + DateTimeFormatter fileFormatter = DateTimeFormatter + .ofPattern("uuuu-MM-dd-HH-mm-ss").withZone(ZoneOffset.UTC); + String fileOut = this.desc.snowflakeStatsEnd().format(fileFormatter) + + "-snowflake-stats"; + this.recentPath = Paths.get(SNOWFLAKES, fileOut).toString(); + this.storagePath = Paths.get(SNOWFLAKES, directories[0], directories[1], + directories[2], fileOut).toString(); + } +} + diff --git a/src/main/java/org/torproject/metrics/collector/snowflake/SnowflakeStatsDownloader.java b/src/main/java/org/torproject/metrics/collector/snowflake/SnowflakeStatsDownloader.java new file mode 100644 index 0000000..4f7994e --- /dev/null +++ b/src/main/java/org/torproject/metrics/collector/snowflake/SnowflakeStatsDownloader.java @@ -0,0 +1,191 @@ +/* Copyright 2019 The Tor Project + * See LICENSE for licensing information */ + +package org.torproject.metrics.collector.snowflake; + +import org.torproject.descriptor.Descriptor; +import org.torproject.descriptor.DescriptorParser; +import org.torproject.descriptor.DescriptorSourceFactory; +import org.torproject.descriptor.SnowflakeStats; +import org.torproject.metrics.collector.conf.Annotation; +import org.torproject.metrics.collector.conf.Configuration; +import org.torproject.metrics.collector.conf.ConfigurationException; +import org.torproject.metrics.collector.conf.Key; +import org.torproject.metrics.collector.cron.CollecTorMain; +import org.torproject.metrics.collector.persist.SnowflakeStatsPersistence; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.SortedSet; +import java.util.Stack; +import java.util.TreeSet; + +public class SnowflakeStatsDownloader extends CollecTorMain { + + private static final Logger logger = LoggerFactory.getLogger( + SnowflakeStatsDownloader.class); + + private String recentPathName; + + /** Instantiate the snowflake-stats module using the given configuration. */ + public SnowflakeStatsDownloader(Configuration config) { + super(config); + this.mapPathDescriptors.put("recent/snowflakes", SnowflakeStats.class); + } + + @Override + public String module() { + return "SnowflakeStats"; + } + + @Override + protected String syncMarker() { + return "SnowflakeStats"; + } + + @Override + protected void startProcessing() throws ConfigurationException { + + this.recentPathName = config.getPath(Key.RecentPath).toString(); + logger.debug("Downloading snowflake stats..."); + URL url = config.getUrl(Key.SnowflakeStatsUrl); + ByteArrayOutputStream downloadedSnowflakeStats + = this.downloadFromHttpServer(url); + if (null == downloadedSnowflakeStats) { + return; + } + logger.debug("Finished downloading {}.", url); + + DescriptorParser descriptorParser = + DescriptorSourceFactory.createDescriptorParser(); + SortedSet<LocalDateTime> snowflakeStatsEnds = new TreeSet<>(); + String outputPathName = config.getPath(Key.OutputPath).toString(); + for (Descriptor descriptor : descriptorParser.parseDescriptors( + downloadedSnowflakeStats.toByteArray(), null, null)) { + if (descriptor instanceof SnowflakeStats) { + SnowflakeStats snowflakeStats = (SnowflakeStats) descriptor; + LocalDateTime snowflakeStatsEnd = snowflakeStats.snowflakeStatsEnd(); + snowflakeStatsEnds.add(snowflakeStatsEnd); + SnowflakeStatsPersistence persistence + = new SnowflakeStatsPersistence(snowflakeStats); + File tarballFile = new File(outputPathName + "/" + + persistence.getStoragePath()); + if (tarballFile.exists()) { + continue; + } + File rsyncFile = new File(this.recentPathName + "/" + + persistence.getRecentPath()); + File[] outputFiles = new File[] { tarballFile, rsyncFile }; + for (File outputFile : outputFiles) { + this.writeToFile(outputFile, Annotation.SnowflakeStats.bytes(), + snowflakeStats.getRawDescriptorBytes()); + } + } + } + if (snowflakeStatsEnds.isEmpty()) { + logger.warn("Could not parse downloaded snowflake stats."); + return; + } else if (snowflakeStatsEnds.last().isBefore(LocalDateTime.now() + .minusHours(48L))) { + logger.warn("The latest snowflake stats are older than 48 hours: {}.", + snowflakeStatsEnds.last()); + } + + this.cleanUpRsyncDirectory(); + } + + /** + * Download the given URL from an HTTP server and return a stream with + * downloaded bytes. + * + * <p>If anything goes wrong while downloading, log a warning and return + * {@code null}.</p> + * + * @param url URL to download. + * @return Stream with downloaded bytes, or {@code null} if an error has + * occurred. + */ + private ByteArrayOutputStream downloadFromHttpServer(URL url) { + ByteArrayOutputStream downloadedBytes = new ByteArrayOutputStream(); + try { + HttpURLConnection huc = (HttpURLConnection) url.openConnection(); + huc.setRequestMethod("GET"); + huc.setReadTimeout(5000); + huc.connect(); + int response = huc.getResponseCode(); + if (response != 200) { + logger.warn("Could not download {}. Response code {}", url, response); + return null; + } + try (BufferedInputStream in = new BufferedInputStream( + huc.getInputStream())) { + int len; + byte[] data = new byte[1024]; + while ((len = in.read(data, 0, 1024)) >= 0) { + downloadedBytes.write(data, 0, len); + } + } + } catch (IOException e) { + logger.warn("Failed downloading {}.", url, e); + return null; + } + return downloadedBytes; + } + + /** + * Write the given byte array(s) to the given file. + * + * <p>If the file already exists, it is overwritten. If the parent directory + * (or any of its parent directories) does not exist, it is created. If + * anything goes wrong, log a warning and return.</p> + * + * @param outputFile File to write to. + * @param bytes One or more byte arrays. + */ + private void writeToFile(File outputFile, byte[] ... bytes) { + try { + if (!outputFile.getParentFile().exists() + && !outputFile.getParentFile().mkdirs()) { + logger.warn("Could not create parent directories of {}.", outputFile); + return; + } + OutputStream os = new FileOutputStream(outputFile); + for (byte[] b : bytes) { + os.write(b); + } + os.close(); + } catch (IOException e) { + logger.warn("Could not write downloaded snowflake stats to {}", + outputFile.getAbsolutePath(), e); + } + } + + /** Delete all files from the rsync directory that have not been modified + * in the last three days. */ + public void cleanUpRsyncDirectory() { + long cutOffMillis = System.currentTimeMillis() + - 3L * 24L * 60L * 60L * 1000L; + Stack<File> allFiles = new Stack<>(); + allFiles.add(new File(recentPathName)); + while (!allFiles.isEmpty()) { + File file = allFiles.pop(); + if (file.isDirectory()) { + allFiles.addAll(Arrays.asList(file.listFiles())); + } else if (file.lastModified() < cutOffMillis) { + file.delete(); + } + } + } +} + diff --git a/src/main/java/org/torproject/metrics/collector/sync/SyncPersistence.java b/src/main/java/org/torproject/metrics/collector/sync/SyncPersistence.java index 0d344bf..4b3b7bc 100644 --- a/src/main/java/org/torproject/metrics/collector/sync/SyncPersistence.java +++ b/src/main/java/org/torproject/metrics/collector/sync/SyncPersistence.java @@ -13,6 +13,7 @@ import org.torproject.descriptor.RelayExtraInfoDescriptor; import org.torproject.descriptor.RelayNetworkStatusConsensus; import org.torproject.descriptor.RelayNetworkStatusVote; import org.torproject.descriptor.RelayServerDescriptor; +import org.torproject.descriptor.SnowflakeStats; import org.torproject.descriptor.TorperfResult; import org.torproject.descriptor.WebServerAccessLog; import org.torproject.metrics.collector.conf.Configuration; @@ -29,6 +30,7 @@ import org.torproject.metrics.collector.persist.MicroConsensusPersistence; import org.torproject.metrics.collector.persist.OnionPerfPersistence; import org.torproject.metrics.collector.persist.PersistenceUtils; import org.torproject.metrics.collector.persist.ServerDescriptorPersistence; +import org.torproject.metrics.collector.persist.SnowflakeStatsPersistence; import org.torproject.metrics.collector.persist.StatusPersistence; import org.torproject.metrics.collector.persist.VotePersistence; import org.torproject.metrics.collector.persist.WebServerAccessLogPersistence; @@ -143,6 +145,9 @@ public class SyncPersistence { case "BandwidthFile": descPersist = new BandwidthFilePersistence((BandwidthFile) desc); break; + case "SnowflakeStats": + descPersist = new SnowflakeStatsPersistence((SnowflakeStats) desc); + break; default: log.trace("Invalid descriptor type {} for sync-merge.", clazz.getName()); diff --git a/src/main/resources/collector.properties b/src/main/resources/collector.properties index 292e876..a4eed7a 100644 --- a/src/main/resources/collector.properties +++ b/src/main/resources/collector.properties @@ -47,6 +47,13 @@ WebstatsActivated = false WebstatsPeriodMinutes = 360 # offset in minutes since the epoch and WebstatsOffsetMinutes = 31 +# the following defines, if this module is activated +SnowflakeStatsActivated = false +# period in minutes +SnowflakeStatsPeriodMinutes = 480 +# offset in minutes since the epoch and +SnowflakeStatsOffsetMinutes = 100 + ########################################## ## All below can be changed at runtime. ##### @@ -178,3 +185,16 @@ WebstatsLocalOrigins = in/webstats # Default 'true' behaves as stated in section 4 of # https://metrics.torproject.org/web-server-logs.html WebstatsLimits = true +# +# +######## Snowflake statistics ######## +# +## Define descriptor sources +# possible values: Sync, Remote +SnowflakeStatsSources = Remote +## Retrieve files from the following instances. +## List of URLs separated by comma. +SnowflakeStatsSyncOrigins = https://collector.torproject.org +## Where to download snowflake statistics from. +SnowflakeStatsUrl = https://snowflake-broker.torproject.net/metrics +# diff --git a/src/main/resources/create-tarballs.sh b/src/main/resources/create-tarballs.sh index 7e4668a..50b7fdb 100755 --- a/src/main/resources/create-tarballs.sh +++ b/src/main/resources/create-tarballs.sh @@ -59,6 +59,8 @@ TARBALLS=( bridge-server-descriptors-$YEARTWO-$MONTHTWO bridge-extra-infos-$YEARONE-$MONTHONE bridge-extra-infos-$YEARTWO-$MONTHTWO + snowflakes-$YEARONE-$MONTHONE + snowflakes-$YEARTWO-$MONTHTWO ) TARBALLS=($(printf "%s\n" "${TARBALLS[@]}" | uniq))
@@ -86,6 +88,8 @@ DIRECTORIES=( $OUTDIR/bridge-descriptors/$YEARTWO/$MONTHTWO/server-descriptors/ $OUTDIR/bridge-descriptors/$YEARONE/$MONTHONE/extra-infos/ $OUTDIR/bridge-descriptors/$YEARTWO/$MONTHTWO/extra-infos/ + $OUTDIR/snowflakes/$YEARONE/$MONTHONE/ + $OUTDIR/snowflakes/$YEARTWO/$MONTHTWO/ ) DIRECTORIES=($(printf "%s\n" "${DIRECTORIES[@]}" | uniq))
@@ -169,4 +173,7 @@ ln -f -s -t $ARCHIVEDIR/torperf/ $TARBALLTARGETDIR/torperf-20??-??.tar.xz mkdir -p $ARCHIVEDIR/webstats/ ln -f -s -t $ARCHIVEDIR/webstats/ $TARBALLTARGETDIR/webstats-20??-??.tar
+mkdir -p $ARCHIVEDIR/snowflakes/ +ln -f -s -t $ARCHIVEDIR/snowflakes/ $TARBALLTARGETDIR/snowflakes-20??-??.tar.xz + echo `date` "Finished." diff --git a/src/main/resources/docs/PROTOCOL b/src/main/resources/docs/PROTOCOL index 58ed4dc..478f168 100644 --- a/src/main/resources/docs/PROTOCOL +++ b/src/main/resources/docs/PROTOCOL @@ -45,6 +45,7 @@ * exit-lists * relay-descriptors * torperf + * snowflakes
The substructure of these folders differs depending on their content.
@@ -116,6 +117,13 @@ * for bandwidths, from the file_created value if available, otherwise the timestamp.
+2.5 'snowflakes' below 'archive' + + 'snowflakes' contains compressed tarballs with snowflake statistics, + named in the following way: + + 'snowflakes' DASH year DASH month DOT TAR DOT compression-type + 3.0 Index Files
The index.json file and its compressed versions of various types are @@ -132,6 +140,7 @@ * exit-lists * relay-descriptors * torperf + * snowflakes
4.1 'exit-lists' and 'torperf' below 'recent'
@@ -254,6 +263,16 @@ 'webstats' contains compressed log files named according to the 'Tor web server logs' specification, section 4.3 [0].
+4.5 'snowflakes' below 'recent' + + 'snowflakes' contains files named + + year DASH month DASH day DASH hour DASH minute DASH second + DASH SNOWFLAKESTATS + + Where SNOWFLAKESTATS is the string "snowflake-stats" and all time related + values are derived from the snowflake statistics interval end. + 5.0 The Tar-ball's Directory Structure and the Internal Structure
The 'out' directory is the internal storage that is used for @@ -266,8 +285,9 @@ * exit-lists * relay-descriptors * torperf + * snowflakes
- (There has been a fifth subdirectory 'bridge-pool-assignments' which has been + (There has been another subdirectory 'bridge-pool-assignments' which has been removed when CollecTor stopped collecting those descriptors. However, it's structure can still be found in the tarballs.)
@@ -416,6 +436,17 @@ 'webstats' contains compressed log files structured and named according to the 'Tor web server logs' specification, section 4.3 [0].
+5.5 'snowflakes' below 'out' + + 'snowflakes' contains the subdirectory structure + + year SEP month SEP day + + Where the time related values are taken from the snowflake statistics + interval end. + + The files are named according to the structure in 4.5. + 6.0 The 'contrib' Folder
The 'contrib' folder contains third-party contributions. diff --git a/src/test/java/org/torproject/metrics/collector/conf/ConfigurationTest.java b/src/test/java/org/torproject/metrics/collector/conf/ConfigurationTest.java index 4ac623e..3a69c0c 100644 --- a/src/test/java/org/torproject/metrics/collector/conf/ConfigurationTest.java +++ b/src/test/java/org/torproject/metrics/collector/conf/ConfigurationTest.java @@ -38,7 +38,7 @@ public class ConfigurationTest { public void testKeyCount() { assertEquals("The number of properties keys in enum Key changed." + "\n This test class should be adapted.", - 53, Key.values().length); + 59, Key.values().length); }
@Test() diff --git a/src/test/java/org/torproject/metrics/collector/cron/CollecTorMainTest.java b/src/test/java/org/torproject/metrics/collector/cron/CollecTorMainTest.java index 78b6ac7..d0fe173 100644 --- a/src/test/java/org/torproject/metrics/collector/cron/CollecTorMainTest.java +++ b/src/test/java/org/torproject/metrics/collector/cron/CollecTorMainTest.java @@ -72,6 +72,7 @@ public class CollecTorMainTest { case "Exitlist": case "OnionPerf": case "Webstats": + case "SnowflakeStats": assertNotNull("Property '" + key + "' not specified in " + Main.CONF_FILE + ".", props.getProperty(key)); diff --git a/src/test/java/org/torproject/metrics/collector/cron/SchedulerTest.java b/src/test/java/org/torproject/metrics/collector/cron/SchedulerTest.java index e0496fb..3f20646 100644 --- a/src/test/java/org/torproject/metrics/collector/cron/SchedulerTest.java +++ b/src/test/java/org/torproject/metrics/collector/cron/SchedulerTest.java @@ -31,7 +31,9 @@ public class SchedulerTest { + "UpdateindexActivated=true\nUpdateindexPeriodMinutes=1\n" + "UpdateindexOffsetMinutes=0\n" + "BridgedescsActivated=true\nBridgedescsPeriodMinutes=1\n" - + "BridgedescsOffsetMinutes=0\n"; + + "BridgedescsOffsetMinutes=0\n" + + "SnowflakeStatsActivated=true\nSnowflakeStatsPeriodMinutes=1\n" + + "SnowflakeStatsOffsetMinutes=0\n";
@Test() public void testSimpleSchedule() throws Exception { @@ -42,6 +44,7 @@ public class SchedulerTest { ctms.put(Key.BridgedescsActivated, Dummy.class); ctms.put(Key.RelaydescsActivated, Dummy.class); ctms.put(Key.ExitlistsActivated, Dummy.class); + ctms.put(Key.SnowflakeStatsActivated, Dummy.class); ctms.put(Key.UpdateindexActivated, Dummy.class); Field schedulerField = Scheduler.class.getDeclaredField("scheduler"); schedulerField.setAccessible(true); @@ -74,6 +77,7 @@ public class SchedulerTest { ctms.put(Key.BridgedescsActivated, Counter.class); ctms.put(Key.RelaydescsActivated, Counter.class); ctms.put(Key.ExitlistsActivated, Counter.class); + ctms.put(Key.SnowflakeStatsActivated, Counter.class); ctms.put(Key.UpdateindexActivated, Counter.class); conf.setProperty(Key.BridgeSources.name(), "Local"); conf.setProperty(Key.RelaySources.name(), "Remote"); @@ -84,7 +88,7 @@ public class SchedulerTest { schedulerField.get(Scheduler.getInstance()); Scheduler.getInstance().scheduleModuleRuns(ctms, conf); Scheduler.getInstance().shutdownScheduler(); - assertEquals(5, Counter.count.get()); + assertEquals(6, Counter.count.get()); }
@Ignore("This test takes 180 seconds, which is too long.") @@ -97,6 +101,7 @@ public class SchedulerTest { ctms.put(Key.BridgedescsActivated, Broken.class); ctms.put(Key.RelaydescsActivated, Broken.class); ctms.put(Key.ExitlistsActivated, Broken.class); + ctms.put(Key.SnowflakeStatsActivated, Broken.class); ctms.put(Key.UpdateindexActivated, Broken.class); Field schedulerField = Scheduler.class.getDeclaredField("scheduler"); schedulerField.setAccessible(true);
tor-commits@lists.torproject.org