/**
 * Copyright 2017 Pivotal Software, Inc.
 *
 * 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 io.micrometer.spring.scheduling;

import io.micrometer.core.annotation.Timed;
import io.micrometer.spring.EnableMetrics;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.LongTaskTimer;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.CountDownLatch;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MetricsSchedulingAspectTest {

    static CountDownLatch longTaskStarted = new CountDownLatch(1);
    static CountDownLatch longTaskShouldComplete = new CountDownLatch(1);

    static CountDownLatch shortBeepsExecuted = new CountDownLatch(2);

    @Autowired
    MeterRegistry registry;

    @Autowired
    ThreadPoolTaskScheduler scheduler;

    @Test
    public void scheduledIsInstrumented() throws InterruptedException {
        shortBeepsExecuted.await();
        while(scheduler.getActiveCount() > 1) {}

        Assertions.assertThat(registry.findMeter(Timer.class, "beeper"))
                .hasValueSatisfying(t -> assertThat(t.count()).isEqualTo(2));

        Assertions.assertThat(registry.findMeter(Gauge.class, "beeper.quantiles", "quantile", "0.5")).isNotEmpty();
        assertThat(registry.findMeter(Gauge.class, "beeper.quantiles", "quantile", "0.95")).isNotEmpty();

        longTaskStarted.await();

        Assertions.assertThat(registry.findMeter(LongTaskTimer.class, "longBeep"))
                .hasValueSatisfying(t -> assertThat(t.activeTasks()).isEqualTo(1));

        // make sure longBeep continues running until we have a chance to observe it in the active state
        longTaskShouldComplete.countDown();

        while(scheduler.getActiveCount() > 0) {}

        // now the long beeper has contributed to the beep count as well
        assertThat(registry.findMeter(Timer.class, "beeper"))
                .hasValueSatisfying(t -> assertThat(t.count()).isEqualTo(3));
    }

    @SpringBootApplication
    @EnableMetrics
    @EnableScheduling
    static class MetricsApp {
        @Bean
        MeterRegistry registry() {
            return new SimpleMeterRegistry();
        }

        @Bean
        ThreadPoolTaskScheduler scheduler() {
            ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
            // this way, executing longBeep doesn't block the short tasks from running
            scheduler.setPoolSize(6);
            return scheduler;
        }

        @Timed("beeper")
        @Timed(value = "longBeep", longTask = true)
        @Scheduled(fixedRate = 1000)
        void longBeep() throws InterruptedException {
            longTaskStarted.countDown();
            longTaskShouldComplete.await();
            System.out.println("beep");
        }

        @Timed("beeper")
        @Scheduled(fixedRate = 1000)
        void beep1() {
            shortBeepsExecuted.countDown();
            System.out.println("beep");
        }

        @Timed(value = "beeper", quantiles = {0.5, 0.95})
        @Scheduled(fixedRate = 1000)
        void beep2() {
            shortBeepsExecuted.countDown();
            System.out.println("beep");
        }

        @Timed // not instrumented because @Timed lacks a metric name
        @Scheduled(fixedRate = 1000)
        void beep3() {
            System.out.println("beep");
        }

        @Scheduled(fixedRate = 1000) // not instrumented because it isn't @Timed
        void beep4() {
            System.out.println("beep");
        }
    }
}

@@ -2126,18 +2126,20 @@
 id s
-cheduledIs
+hortTasksAre
 Inst
@@ -2269,35 +2269,24 @@
 %7B%7D%0A%0A        
-Assertions.
 assertThat(r
@@ -2410,35 +2410,24 @@
 );%0A%0A        
-Assertions.
 assertThat(r
@@ -2613,24 +2613,113 @@
 NotEmpty();%0A
+    %7D%0A%0A    @Test%0A    public void longTasksAreInstrumented() throws InterruptedException %7B
 %0A        lon
@@ -2749,27 +2749,16 @@
         
-Assertions.
 assertTh
@@ -2809,28 +2809,24 @@
 longBeep%22))%0A
-    
             
@@ -3039,25 +3039,24 @@
 ountDown();%0A
-%0A
         whil
@@ -3097,81 +3097,8 @@
 %7B%7D%0A%0A
-        // now the long beeper has contributed to the beep count as well%0A
     
@@ -3123,32 +3123,40 @@
 istry.findMeter(
+LongTask
 Timer.class, %22be
@@ -3149,38 +3149,36 @@
 mer.class, %22
-b
+longB
 eep
-er
 %22))%0A
-    
             
@@ -3207,37 +3207,43 @@
 -%3E assertThat(t.
-count
+activeTasks
 ()).isEqualTo(3)
@@ -3240,17 +3240,17 @@
 EqualTo(
-3
+0
 ));%0A    
@@ -3765,33 +3765,8 @@
  %7D%0A%0A
-        @Timed(%22beeper%22)%0A
     
@@ -4044,188 +4044,8 @@
  %7D%0A%0A
-        @Timed(%22beeper%22)%0A        @Scheduled(fixedRate = 1000)%0A        void beep1() %7B%0A            shortBeepsExecuted.countDown();%0A            System.out.println(%22beep%22);%0A        %7D%0A%0A
     
@@ -4152,13 +4152,17 @@
 oid 
-b
+shortB
 eep
-2
 () %7B
@@ -4381,13 +4381,20 @@
 oid 
-beep3
+noMetricName
 () %7B
@@ -4543,13 +4543,16 @@
 oid 
-beep4
+notTimed
 () %7B

Fix flaky scheduling test