aurora-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From wfar...@apache.org
Subject git commit: Add stat gauge coverage for AsyncModule and MemStorage.
Date Fri, 31 Oct 2014 21:00:52 GMT
Repository: incubator-aurora
Updated Branches:
  refs/heads/master 02a1c040e -> 765f2dd4e


Add stat gauge coverage for AsyncModule and MemStorage.

Bugs closed: AURORA-884

Reviewed at https://reviews.apache.org/r/27371/


Project: http://git-wip-us.apache.org/repos/asf/incubator-aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-aurora/commit/765f2dd4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-aurora/tree/765f2dd4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-aurora/diff/765f2dd4

Branch: refs/heads/master
Commit: 765f2dd4e4392bc8ce33bc823329b95a6f26924c
Parents: 02a1c04
Author: Bill Farner <wfarner@apache.org>
Authored: Fri Oct 31 14:00:39 2014 -0700
Committer: Bill Farner <wfarner@apache.org>
Committed: Fri Oct 31 14:00:39 2014 -0700

----------------------------------------------------------------------
 .../apache/aurora/CoverageReportCheck.groovy    |  17 ++-
 config/legacy_untested_classes.txt              |  14 ---
 .../aurora/scheduler/async/AsyncModule.java     |  99 +++++++++++----
 .../scheduler/storage/mem/MemStorage.java       |  49 ++++++--
 .../aurora/scheduler/async/AsyncModuleTest.java | 123 +++++++++++++++++++
 .../scheduler/storage/mem/MemStorageTest.java   |  14 ++-
 .../scheduler/testing/FakeStatsProvider.java    |  18 +++
 .../aurora/scheduler/updater/JobUpdaterIT.java  |   3 +
 8 files changed, 283 insertions(+), 54 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/765f2dd4/buildSrc/src/main/groovy/org/apache/aurora/CoverageReportCheck.groovy
----------------------------------------------------------------------
diff --git a/buildSrc/src/main/groovy/org/apache/aurora/CoverageReportCheck.groovy b/buildSrc/src/main/groovy/org/apache/aurora/CoverageReportCheck.groovy
index 06d25c0..1d98442 100644
--- a/buildSrc/src/main/groovy/org/apache/aurora/CoverageReportCheck.groovy
+++ b/buildSrc/src/main/groovy/org/apache/aurora/CoverageReportCheck.groovy
@@ -78,9 +78,22 @@ class CoverageReportCheck extends DefaultTask {
       // constructor for anonymous classes.  Anonymous classes are identified by their name,
       // which we expect to be of the form 'Something$1'.  Jacoco names default constructors
       // '<init>', so we filter based on that.
-      def methodFilter = cls.@name ==~ /.*\$\d+/ ? { m -> m.@name != '<init>' }
: { true }
+      def isAnonymous = { c -> c.@name ==~ /.*\$\d+/ }
+      def methodFilter = isAnonymous(cls) ? { m -> m.@name != '<init>' } : { true
}
+
+      def matchedMethods = cls.method.findAll(methodFilter)
+      if (isAnonymous(cls) && matchedMethods.isEmpty()) {
+        // Ignore anonymous classes that only have a constructor. This will avoid tripping
for
+        // things like TypeLiteral and Clazz.
+        if (cls.@name in legacyClassesWithoutCoverage) {
+          return 'Please remove ' + cls.@name + ' from the legacyClassesWithoutCoverage list'
\
+              + ', this check does not apply for constructor-only anonymous classes.'
+        } else {
+          return null
+        }
+      }
 
-      def covered = cls.method.findAll(methodFilter).collect { m ->
+      def covered = matchedMethods.collect { m ->
         m.counter.find({ c -> c.@type == 'INSTRUCTION' }).@covered.toInteger()}.sum(0)
 
       if (cls.@name in legacyClassesWithoutCoverage) {

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/765f2dd4/config/legacy_untested_classes.txt
----------------------------------------------------------------------
diff --git a/config/legacy_untested_classes.txt b/config/legacy_untested_classes.txt
index 542ac31..f1d1921 100644
--- a/config/legacy_untested_classes.txt
+++ b/config/legacy_untested_classes.txt
@@ -5,10 +5,6 @@ org/apache/aurora/auth/UnsecureAuthModule$UnsecureSessionValidator$1
 org/apache/aurora/Protobufs$1
 org/apache/aurora/scheduler/app/SchedulerMain$2
 org/apache/aurora/scheduler/app/SchedulerMain$3
-org/apache/aurora/scheduler/async/AsyncModule$1
-org/apache/aurora/scheduler/async/AsyncModule$10$1
-org/apache/aurora/scheduler/async/AsyncModule$3$1
-org/apache/aurora/scheduler/async/AsyncModule$4$1
 org/apache/aurora/scheduler/async/GcExecutorLauncher$1
 org/apache/aurora/scheduler/async/OfferQueue$OfferQueueImpl$2
 org/apache/aurora/scheduler/base/Conversions$1
@@ -18,7 +14,6 @@ org/apache/aurora/scheduler/base/Conversions$4
 org/apache/aurora/scheduler/cron/quartz/CronSchedulerImpl
 org/apache/aurora/scheduler/cron/quartz/CronSchedulerImpl$1
 org/apache/aurora/scheduler/http/JerseyTemplateServlet
-org/apache/aurora/scheduler/http/JettyServerModule$1
 org/apache/aurora/scheduler/http/Maintenance
 org/apache/aurora/scheduler/http/Maintenance$1
 org/apache/aurora/scheduler/http/Maintenance$2
@@ -55,22 +50,13 @@ org/apache/aurora/scheduler/http/Utilization$Display
 org/apache/aurora/scheduler/http/Utilization$DisplayMetric
 org/apache/aurora/scheduler/log/Log$Stream$InvalidPositionException
 org/apache/aurora/scheduler/log/mesos/MesosLogStreamModule
-org/apache/aurora/scheduler/log/mesos/MesosLogStreamModule$1
-org/apache/aurora/scheduler/log/mesos/MesosLogStreamModule$2
 org/apache/aurora/scheduler/log/mesos/MesosLogStreamModule$3
 org/apache/aurora/scheduler/log/mesos/MesosLogStreamModule$4
 org/apache/aurora/scheduler/log/mesos/MesosLogStreamModule$5
 org/apache/aurora/scheduler/state/MaintenanceController$MaintenanceControllerImpl$4
 org/apache/aurora/scheduler/state/MaintenanceController$MaintenanceControllerImpl$8
 org/apache/aurora/scheduler/stats/AsyncStatsModule$OfferAdapter$1
-org/apache/aurora/scheduler/storage/backup/BackupModule$1
-org/apache/aurora/scheduler/storage/backup/BackupModule$2
 org/apache/aurora/scheduler/storage/log/LogStorage$RecoveryFailedException
-org/apache/aurora/scheduler/storage/log/LogStorageModule$1
-org/apache/aurora/scheduler/storage/log/LogStorageModule$2
 org/apache/aurora/scheduler/storage/mem/Util
 org/apache/aurora/scheduler/storage/mem/Util$1
-org/apache/aurora/scheduler/thrift/aop/AopModule$2$1
-org/apache/aurora/scheduler/thrift/aop/AopModule$2$2
-org/apache/aurora/scheduler/thrift/auth/ThriftAuthModule$1
 org/apache/aurora/scheduler/updater/UpdateConfigurationException

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/765f2dd4/src/main/java/org/apache/aurora/scheduler/async/AsyncModule.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/async/AsyncModule.java b/src/main/java/org/apache/aurora/scheduler/async/AsyncModule.java
index 90b26e5..df7e56a 100644
--- a/src/main/java/org/apache/aurora/scheduler/async/AsyncModule.java
+++ b/src/main/java/org/apache/aurora/scheduler/async/AsyncModule.java
@@ -20,27 +20,27 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.logging.Logger;
 
+import javax.inject.Inject;
 import javax.inject.Qualifier;
 import javax.inject.Singleton;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
 import com.google.common.util.concurrent.RateLimiter;
 import com.google.inject.AbstractModule;
 import com.google.inject.Binder;
 import com.google.inject.Key;
 import com.google.inject.PrivateModule;
 import com.google.inject.TypeLiteral;
-
 import com.twitter.common.application.modules.LifecycleModule;
 import com.twitter.common.args.Arg;
 import com.twitter.common.args.CmdLine;
 import com.twitter.common.args.constraints.NotNegative;
 import com.twitter.common.args.constraints.Positive;
+import com.twitter.common.base.Command;
 import com.twitter.common.quantity.Amount;
 import com.twitter.common.quantity.Time;
-import com.twitter.common.stats.StatImpl;
-import com.twitter.common.stats.Stats;
 import com.twitter.common.stats.StatsProvider;
 import com.twitter.common.util.Random;
 import com.twitter.common.util.TruncatedBinaryBackoff;
@@ -61,6 +61,7 @@ import static java.lang.annotation.ElementType.FIELD;
 import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.util.Objects.requireNonNull;
 
 import static org.apache.aurora.scheduler.async.Preemptor.PreemptorImpl;
 import static org.apache.aurora.scheduler.async.Preemptor.PreemptorImpl.PreemptionDelay;
@@ -203,19 +204,34 @@ public class AsyncModule extends AbstractModule {
   @CmdLine(name = "gc_executor_path", help = "Path to the gc executor launch script.")
   private static final Arg<String> GC_EXECUTOR_PATH = Arg.create(null);
 
+  @Qualifier
+  @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
+  private @interface AsyncExecutor { }
+
+  private final boolean enablePreemptor;
+
+  @VisibleForTesting
+  AsyncModule(boolean enablePreemptor) {
+    this.enablePreemptor = enablePreemptor;
+  }
+
+  public AsyncModule() {
+    this(ENABLE_PREEMPTOR.get());
+  }
+
+  @VisibleForTesting
+  static final String TIMEOUT_QUEUE_GAUGE = "timeout_queue_size";
+
+  @VisibleForTesting
+  static final String ASYNC_TASKS_GAUGE = "async_tasks_completed";
+
   @Override
   protected void configure() {
     // Don't worry about clean shutdown, these can be daemon and cleanup-free.
     final ScheduledThreadPoolExecutor executor =
         AsyncUtil.loggingScheduledExecutor(ASYNC_WORKER_THREADS.get(), "AsyncProcessor-%d",
LOG);
-
-    Stats.exportSize("timeout_queue_size", executor.getQueue());
-    Stats.export(new StatImpl<Long>("async_tasks_completed") {
-      @Override
-      public Long read() {
-        return executor.getCompletedTaskCount();
-      }
-    });
+    bind(ScheduledThreadPoolExecutor.class).annotatedWith(AsyncExecutor.class).toInstance(executor);
+    LifecycleModule.bindStartupAction(binder(), RegisterGauges.class);
 
     // AsyncModule itself is not a subclass of PrivateModule because TaskEventModule internally
uses
     // a MultiBinder, which cannot span multiple injectors.
@@ -227,7 +243,6 @@ public class AsyncModule extends AbstractModule {
         bind(ScheduledExecutorService.class).toInstance(executor);
 
         bind(TaskTimeout.class).in(Singleton.class);
-        requireBinding(StatsProvider.class);
         expose(TaskTimeout.class);
       }
     });
@@ -251,7 +266,7 @@ public class AsyncModule extends AbstractModule {
 
         bind(RescheduleCalculator.class).to(RescheduleCalculatorImpl.class).in(Singleton.class);
         expose(RescheduleCalculator.class);
-        if (ENABLE_PREEMPTOR.get()) {
+        if (enablePreemptor) {
           bind(PREEMPTOR_KEY).to(PreemptorImpl.class);
           bind(PreemptorImpl.class).in(Singleton.class);
           LOG.info("Preemptor Enabled.");
@@ -356,17 +371,53 @@ public class AsyncModule extends AbstractModule {
       Binder binder,
       final Key<Preemptor> preemptorKey,
       final Amount<Long, Time> reservationDuration) {
-        binder.install(new PrivateModule() {
-          @Override
-          protected void configure() {
-            bind(Preemptor.class).to(preemptorKey);
-            bind(new TypeLiteral<Amount<Long, Time>>() { }).annotatedWith(ReservationDuration.class)
-                .toInstance(reservationDuration);
-            bind(TaskScheduler.class).to(TaskSchedulerImpl.class);
-            bind(TaskSchedulerImpl.class).in(Singleton.class);
-            expose(TaskScheduler.class);
+
+    binder.install(new PrivateModule() {
+      @Override
+      protected void configure() {
+        bind(Preemptor.class).to(preemptorKey);
+        bind(new TypeLiteral<Amount<Long, Time>>() { }).annotatedWith(ReservationDuration.class)
+            .toInstance(reservationDuration);
+        bind(TaskScheduler.class).to(TaskSchedulerImpl.class);
+        bind(TaskSchedulerImpl.class).in(Singleton.class);
+        expose(TaskScheduler.class);
+      }
+    });
+    PubsubEventModule.bindSubscriber(binder, TaskScheduler.class);
+  }
+
+  static class RegisterGauges implements Command {
+    private final StatsProvider statsProvider;
+    private final ScheduledThreadPoolExecutor executor;
+
+    @Inject
+    RegisterGauges(
+        StatsProvider statsProvider,
+        @AsyncExecutor ScheduledThreadPoolExecutor executor) {
+
+      this.statsProvider = requireNonNull(statsProvider);
+      this.executor = requireNonNull(executor);
+    }
+
+    @Override
+    public void execute() throws RuntimeException {
+      statsProvider.makeGauge(
+          TIMEOUT_QUEUE_GAUGE,
+          new Supplier<Integer>() {
+            @Override
+            public Integer get() {
+              return executor.getQueue().size();
+            }
+          });
+      statsProvider.makeGauge(
+          ASYNC_TASKS_GAUGE,
+          new Supplier<Long>() {
+            @Override
+            public Long get() {
+              return executor.getCompletedTaskCount();
+            }
           }
-        });
-        PubsubEventModule.bindSubscriber(binder, TaskScheduler.class);
+      );
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/765f2dd4/src/main/java/org/apache/aurora/scheduler/storage/mem/MemStorage.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/storage/mem/MemStorage.java b/src/main/java/org/apache/aurora/scheduler/storage/mem/MemStorage.java
index 31498fa..2cc76dc 100644
--- a/src/main/java/org/apache/aurora/scheduler/storage/mem/MemStorage.java
+++ b/src/main/java/org/apache/aurora/scheduler/storage/mem/MemStorage.java
@@ -23,14 +23,16 @@ import javax.inject.Inject;
 import javax.inject.Qualifier;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Supplier;
+import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Key;
 import com.twitter.common.inject.Bindings;
 import com.twitter.common.inject.TimedInterceptor.Timed;
 import com.twitter.common.stats.SlidingStats;
-import com.twitter.common.stats.StatImpl;
 import com.twitter.common.stats.Stats;
+import com.twitter.common.stats.StatsProvider;
 
 import org.apache.aurora.scheduler.storage.AttributeStore;
 import org.apache.aurora.scheduler.storage.JobStore;
@@ -79,6 +81,9 @@ public class MemStorage implements Storage {
   @Qualifier
   public @interface Delegated { }
 
+  @VisibleForTesting
+  static final String THREADS_WAITING_GAUGE = "storage_lock_threads_waiting";
+
   @Inject
   MemStorage(
       @Delegated final SchedulerStore.Mutable schedulerStore,
@@ -88,9 +93,10 @@ public class MemStorage implements Storage {
       @Delegated final Storage delegated,
       @Delegated final QuotaStore.Mutable quotaStore,
       @Delegated final AttributeStore.Mutable attributeStore,
-      @Delegated final JobUpdateStore.Mutable updateStore) {
+      @Delegated final JobUpdateStore.Mutable updateStore,
+      StatsProvider statsProvider) {
 
-    this.delegatedStore = delegated;
+    this.delegatedStore = requireNonNull(delegated);
     storeProvider = new MutableStoreProvider() {
       @Override
       public SchedulerStore.Mutable getSchedulerStore() {
@@ -133,28 +139,47 @@ public class MemStorage implements Storage {
       }
     };
 
-    Stats.export(new StatImpl<Integer>("storage_lock_threads_waiting") {
-      @Override
-      public Integer read() {
-        return lockManager.getQueueLength();
-      }
-    });
+    statsProvider.makeGauge(
+        THREADS_WAITING_GAUGE,
+        new Supplier<Integer>() {
+          @Override
+          public Integer get() {
+            return lockManager.getQueueLength();
+          }
+        }
+    );
   }
 
   /**
-   * Creates a new empty in-memory storage for use in testing.
+   * Creates a new empty in-memory storage for use in testing, exporting gauges to the provided
+   * stats provider.  NOTE: Due to the fact that some libraries statically access {@link
Stats},
+   * not all guaranteed to use the stats provider.
    */
   @VisibleForTesting
-  public static Storage newEmptyStorage() {
+  public static Storage newEmptyStorage(final StatsProvider statsProvider) {
     Injector injector = Guice.createInjector(
         DbModule.testModule(Bindings.annotatedKeyFactory(Delegated.class)),
-        new MemStorageModule(Bindings.annotatedKeyFactory(Volatile.class)));
+        new MemStorageModule(Bindings.annotatedKeyFactory(Volatile.class)),
+        new AbstractModule() {
+          @Override
+          protected void configure() {
+            bind(StatsProvider.class).toInstance(statsProvider);
+          }
+        });
 
     Storage storage = injector.getInstance(Key.get(Storage.class, Volatile.class));
     storage.prepare();
     return storage;
   }
 
+  /**
+   * Creates a new empty in-memory storage for use in testing.
+   */
+  @VisibleForTesting
+  public static Storage newEmptyStorage() {
+    return newEmptyStorage(Stats.STATS_PROVIDER);
+  }
+
   private <S extends StoreProvider, T, E extends Exception> T doWork(
       LockType lockType,
       S stores,

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/765f2dd4/src/test/java/org/apache/aurora/scheduler/async/AsyncModuleTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/async/AsyncModuleTest.java b/src/test/java/org/apache/aurora/scheduler/async/AsyncModuleTest.java
new file mode 100644
index 0000000..62d8aab
--- /dev/null
+++ b/src/test/java/org/apache/aurora/scheduler/async/AsyncModuleTest.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.aurora.scheduler.async;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.twitter.common.application.StartupStage;
+import com.twitter.common.application.modules.LifecycleModule;
+import com.twitter.common.base.ExceptionalCommand;
+import com.twitter.common.stats.StatsProvider;
+import com.twitter.common.testing.easymock.EasyMockTest;
+import com.twitter.common.util.Clock;
+
+import org.apache.aurora.scheduler.Driver;
+import org.apache.aurora.scheduler.filter.AttributeAggregate;
+import org.apache.aurora.scheduler.filter.SchedulingFilter;
+import org.apache.aurora.scheduler.state.MaintenanceController;
+import org.apache.aurora.scheduler.state.StateManager;
+import org.apache.aurora.scheduler.state.TaskAssigner;
+import org.apache.aurora.scheduler.storage.AttributeStore;
+import org.apache.aurora.scheduler.storage.Storage;
+import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
+import org.apache.aurora.scheduler.storage.testing.StorageTestUtil;
+import org.apache.aurora.scheduler.testing.FakeStatsProvider;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * TODO(wfarner): Make this test more useful by validating the bindings set up by the module.
+ * Multibindings makes this tricky since it uses an internal binding annotation which makes
a direct
+ * check on injector.getBindings() impossible.
+ */
+public class AsyncModuleTest extends EasyMockTest {
+
+  private FakeStatsProvider statsProvider;
+  private StorageTestUtil storageUtil;
+
+  @Before
+  public void setUp() {
+    statsProvider = new FakeStatsProvider();
+    storageUtil = new StorageTestUtil(this);
+    storageUtil.expectOperations();
+  }
+
+  private Injector createInjector(Module module) {
+    return Guice.createInjector(
+        module,
+        new LifecycleModule(),
+        new AbstractModule() {
+          private <T> void bindMock(Class<T> clazz) {
+            bind(clazz).toInstance(createMock(clazz));
+          }
+
+          @Override
+          protected void configure() {
+            bind(StatsProvider.class).toInstance(statsProvider);
+            bindMock(Clock.class);
+            bindMock(Driver.class);
+            bindMock(SchedulingFilter.class);
+            bindMock(MaintenanceController.class);
+            bindMock(StateManager.class);
+            bindMock(TaskAssigner.class);
+            bindMock(Thread.UncaughtExceptionHandler.class);
+            bind(Storage.class).toInstance(storageUtil.storage);
+          }
+        });
+  }
+
+  @Test
+  public void testBindings() throws Exception {
+    Injector injector = createInjector(new AsyncModule(true));
+
+    control.replay();
+
+    injector.getInstance(Key.get(ExceptionalCommand.class, StartupStage.class)).execute();
+
+    injector.getBindings();
+
+    assertEquals(
+        ImmutableMap.of(AsyncModule.TIMEOUT_QUEUE_GAUGE, 0, AsyncModule.ASYNC_TASKS_GAUGE,
0L),
+        statsProvider.getAllValues()
+    );
+  }
+
+  @Test
+  public void testPreemptorDisabled() throws Exception {
+    Injector injector = createInjector(new AsyncModule(false));
+
+    Supplier<ImmutableSet<IScheduledTask>> taskSupplier =
+        createMock(new Clazz<Supplier<ImmutableSet<IScheduledTask>>>()
{ });
+    AttributeStore attributeStore = createMock(AttributeStore.class);
+
+    control.replay();
+
+    injector.getInstance(Key.get(ExceptionalCommand.class, StartupStage.class)).execute();
+
+    injector.getBindings();
+    assertEquals(
+        Optional.<String>absent(),
+        injector.getInstance(AsyncModule.PREEMPTOR_KEY)
+            .findPreemptionSlotFor("a", new AttributeAggregate(taskSupplier, attributeStore)));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/765f2dd4/src/test/java/org/apache/aurora/scheduler/storage/mem/MemStorageTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/storage/mem/MemStorageTest.java b/src/test/java/org/apache/aurora/scheduler/storage/mem/MemStorageTest.java
index abf6868..463b445 100644
--- a/src/test/java/org/apache/aurora/scheduler/storage/mem/MemStorageTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/storage/mem/MemStorageTest.java
@@ -45,6 +45,7 @@ import org.apache.aurora.scheduler.storage.Storage.StoreProvider;
 import org.apache.aurora.scheduler.storage.Storage.Work;
 import org.apache.aurora.scheduler.storage.entities.IResourceAggregate;
 import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
+import org.apache.aurora.scheduler.testing.FakeStatsProvider;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -57,11 +58,12 @@ import static org.junit.Assert.fail;
 public class MemStorageTest extends TearDownTestCase {
 
   private ExecutorService executor;
+  private FakeStatsProvider statsProvider;
   private Storage storage;
 
   @Before
   public void setUp() {
-    executor = Executors.newSingleThreadExecutor(
+    executor = Executors.newCachedThreadPool(
         new ThreadFactoryBuilder().setNameFormat("SlowRead-%d").setDaemon(true).build());
     addTearDown(new TearDown() {
       @Override
@@ -69,7 +71,8 @@ public class MemStorageTest extends TearDownTestCase {
         new ExecutorServiceShutdown(executor, Amount.of(1L, Time.SECONDS)).execute();
       }
     });
-    storage = MemStorage.newEmptyStorage();
+    statsProvider = new FakeStatsProvider();
+    storage = MemStorage.newEmptyStorage(statsProvider);
   }
 
   @Test
@@ -108,6 +111,13 @@ public class MemStorageTest extends TearDownTestCase {
     assertEquals("fastResult", fastResult);
     slowReadFinished.countDown();
     assertEquals("slowResult", future.get());
+
+    // It would be nice to check the stat values (specifically with simulated lock contention,
but
+    // this value is based off ReentrantReadWriteLock#getQueueLength(), which is documented
as an
+    // approximation and not a guaranteed accurate value.
+    assertEquals(
+        ImmutableSet.of(MemStorage.THREADS_WAITING_GAUGE),
+        statsProvider.getAllValues().keySet());
   }
 
   private IScheduledTask makeTask(String taskId) {

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/765f2dd4/src/test/java/org/apache/aurora/scheduler/testing/FakeStatsProvider.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/testing/FakeStatsProvider.java b/src/test/java/org/apache/aurora/scheduler/testing/FakeStatsProvider.java
index 273129e..768e784 100644
--- a/src/test/java/org/apache/aurora/scheduler/testing/FakeStatsProvider.java
+++ b/src/test/java/org/apache/aurora/scheduler/testing/FakeStatsProvider.java
@@ -16,7 +16,9 @@ package org.apache.aurora.scheduler.testing;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
 
+import com.google.common.base.Function;
 import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import com.twitter.common.stats.Stat;
 import com.twitter.common.stats.StatsProvider;
@@ -37,6 +39,22 @@ public class FakeStatsProvider implements StatsProvider {
     return stats.get(statName).get();
   }
 
+  /**
+   * Gets the current values of all exported stats.
+   *
+   * @return All exported stat names and their associated values.
+   */
+  public Map<String, ? extends Number> getAllValues() {
+    return ImmutableMap.copyOf(Maps.transformValues(
+        stats,
+        new Function<Supplier<? extends Number>, Number>() {
+        @Override
+        public Number apply(Supplier<? extends Number> supplier) {
+          return supplier.get();
+        }
+      }));
+  }
+
   @Override
   public AtomicLong makeCounter(String name) {
     final AtomicLong counter = new AtomicLong();

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/765f2dd4/src/test/java/org/apache/aurora/scheduler/updater/JobUpdaterIT.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/updater/JobUpdaterIT.java b/src/test/java/org/apache/aurora/scheduler/updater/JobUpdaterIT.java
index 61b6b8e..8baec04 100644
--- a/src/test/java/org/apache/aurora/scheduler/updater/JobUpdaterIT.java
+++ b/src/test/java/org/apache/aurora/scheduler/updater/JobUpdaterIT.java
@@ -37,6 +37,7 @@ import com.twitter.common.inject.Bindings.KeyFactory;
 import com.twitter.common.quantity.Amount;
 import com.twitter.common.quantity.Time;
 import com.twitter.common.stats.Stats;
+import com.twitter.common.stats.StatsProvider;
 import com.twitter.common.testing.easymock.EasyMockTest;
 import com.twitter.common.util.Clock;
 import com.twitter.common.util.TruncatedBinaryBackoff;
@@ -92,6 +93,7 @@ import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
 import org.apache.aurora.scheduler.storage.mem.MemStorage.Delegated;
 import org.apache.aurora.scheduler.storage.mem.MemStorageModule;
 import org.apache.aurora.scheduler.testing.FakeScheduledExecutor;
+import org.apache.aurora.scheduler.testing.FakeStatsProvider;
 import org.easymock.EasyMock;
 import org.easymock.IExpectationSetters;
 import org.junit.After;
@@ -164,6 +166,7 @@ public class JobUpdaterIT extends EasyMockTest {
         new AbstractModule() {
           @Override
           protected void configure() {
+            bind(StatsProvider.class).toInstance(new FakeStatsProvider());
             bind(Clock.class).toInstance(clock);
             bind(StateManager.class).to(StateManagerImpl.class);
             bind(Driver.class).toInstance(driver);


Mime
View raw message