content: /**
   * 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.sla;
  
  import java.util.concurrent.CountDownLatch;
  import java.util.concurrent.ScheduledExecutorService;
  import java.util.concurrent.ScheduledThreadPoolExecutor;
  
  import com.google.common.collect.ImmutableList;
  import com.google.common.collect.ImmutableMap;
  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 org.apache.aurora.common.quantity.Time;
  import org.apache.aurora.common.stats.StatsProvider;
  import org.apache.aurora.common.testing.easymock.EasyMockTest;
  import org.apache.aurora.common.util.Clock;
  import org.apache.aurora.common.util.testing.FakeClock;
  import org.apache.aurora.gen.ServerInfo;
  import org.apache.aurora.scheduler.TierManager;
  import org.apache.aurora.scheduler.app.LifecycleModule;
  import org.apache.aurora.scheduler.base.Query;
  import org.apache.aurora.scheduler.config.types.TimeAmount;
  import org.apache.aurora.scheduler.sla.SlaModule.SlaUpdater;
  import org.apache.aurora.scheduler.storage.Storage;
  import org.apache.aurora.scheduler.storage.entities.IServerInfo;
  import org.apache.aurora.scheduler.storage.testing.StorageTestUtil;
  import org.easymock.EasyMock;
  import org.junit.Before;
  import org.junit.Test;
  
  import static org.apache.aurora.gen.ScheduleStatus.PENDING;
  import static org.apache.aurora.scheduler.base.TaskTestUtil.TIER_MANAGER;
  import static org.apache.aurora.scheduler.sla.MetricCalculator.MetricCategory.JOB_UPTIMES;
  import static org.apache.aurora.scheduler.sla.MetricCalculator.MetricCategory.MEDIANS;
  import static org.apache.aurora.scheduler.sla.MetricCalculator.MetricCategory.PLATFORM_UPTIME;
  import static org.easymock.EasyMock.expect;
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertNotNull;
  
  public class SlaModuleTest extends EasyMockTest {
  
    private static final String CLUSTER_NAME = "test_cluster";
    private static final String STATS_URL_PREFIX = "fake_url";
  
    private Injector injector;
    private FakeClock clock;
    private StorageTestUtil storageUtil;
    private StatsProvider statsProvider;
    private SlaModule module;
  
    @Before
    public void setUp() {
      storageUtil = new StorageTestUtil(this);
      clock = new FakeClock();
      statsProvider = createMock(StatsProvider.class);
      SlaModule.Options options = new SlaModule.Options();
      options.slaRefreshInterval = new TimeAmount(5L, Time.MILLISECONDS);
      options.slaProdMetrics = ImmutableList.of(JOB_UPTIMES, MEDIANS, PLATFORM_UPTIME);
      options.slaNonProdMetrics = ImmutableList.of(JOB_UPTIMES, MEDIANS, PLATFORM_UPTIME);
      module = new SlaModule(options);
      injector = Guice.createInjector(
          ImmutableList.<Module>builder()
              .add(module)
              .add(new LifecycleModule())
              .add(new AbstractModule() {
                @Override
                protected void configure() {
                  bind(Clock.class).toInstance(clock);
                  bind(Storage.class).toInstance(storageUtil.storage);
                  bind(StatsProvider.class).toInstance(statsProvider);
                  bind(TierManager.class).toInstance(TIER_MANAGER);
                  bind(IServerInfo.class).toInstance(
                      IServerInfo.build(
                          new ServerInfo()
                              .setClusterName(CLUSTER_NAME)
                              .setStatsUrlPrefix(STATS_URL_PREFIX)));
                }
              }).build()
      );
    }
  
    @Test
    public void testNoSchedulingOnStart() {
      assertNotNull(module);
  
      control.replay();
  
      ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) injector.getInstance(
          Key.get(ScheduledExecutorService.class, SlaModule.SlaExecutor.class));
  
      assertEquals(0, executor.getQueue().size());
      assertEquals(0, executor.getActiveCount());
    }
  
    @Test
    public void testSchedulingOnEvent() throws Exception {
      assertNotNull(module);
  
      final CountDownLatch latch = new CountDownLatch(1);
      StatsProvider untracked = createMock(StatsProvider.class);
      expect(statsProvider.untracked()).andReturn(untracked).anyTimes();
      expect(untracked.makeGauge(EasyMock.anyString(), EasyMock.anyObject()))
          .andReturn(EasyMock.anyObject())
          .andAnswer(() -> {
            latch.countDown();
            return null;
          }).anyTimes();
  
      storageUtil.expectTaskFetch(
          Query.unscoped(),
          SlaTestUtil.makeTask(ImmutableMap.of(clock.nowMillis() - 1000, PENDING), 0)).anyTimes();
      storageUtil.expectOperations();
  
      control.replay();
  
      injector.getInstance(SlaUpdater.class).startAsync().awaitRunning();
      latch.await();
    }
  }
  