package de.is24.util.monitoring;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.text.NumberFormat;
import java.util.Random;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;


public class ConcurrentcyTest {
  private static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance();

  static {
    NUMBER_FORMAT.setGroupingUsed(true);
    NUMBER_FORMAT.setMinimumFractionDigits(3);
    NUMBER_FORMAT.setMaximumFractionDigits(3);
  }

  private static final int THREADS = 10, RUNS = 50;

  private ThreadPoolExecutor executor;
  private Job observerJob, timerJob;
  private Random rnd;

  private AtomicLong timerSum;

  @BeforeClass
  public static void beforeClass() {
    InApplicationMonitor.resetInstanceForTesting();
  }

  @Before
  public void setUp() throws Exception {
    this.observerJob = new ObserverJob();
    this.timerJob = new TimerJob();
    this.rnd = new Random();
    this.timerSum = new AtomicLong();
  }

  @Test
  public void testConcurency() throws InterruptedException {
    createExecutor(10);

    executeJobs(timerJob, observerJob);

  }

  private void createExecutor(int threads) {
    this.executor = new ScheduledThreadPoolExecutor(threads);
    this.executor.setMaximumPoolSize(threads);
  }


  private void executeJobs(Runnable... jobs) throws InterruptedException {
    for (int i = 0; i < RUNS; i++) {
      for (Runnable job : jobs) {
        executor.execute(job);
      }
    }
    executor.shutdown();

    executor.awaitTermination(100, TimeUnit.SECONDS);
  }

  private abstract class Job implements Runnable {
    public void run() {
      doJob();
    }

    protected abstract void doJob();
  }


  private class ObserverJob extends Job {
    @Override
    protected void doJob() {
      try {
        InApplicationMonitor.getInstance().addReportableObserver(new ReportableObserver() {
            @Override
            public void addNewReportable(Reportable reportable) {
              try {
                Thread.sleep(1);
              } catch (InterruptedException e) {
                Thread.interrupted();
              }
            }
          });
      } catch (RuntimeException e) {
        e.printStackTrace();
      }
    }

  }

  private class TimerJob extends Job {
    @Override
    protected void doJob() {
      try {
        String key = "t" + rnd.nextInt(100000);
        InApplicationMonitor.getInstance().addTimerMeasurement(key, 1);
      } catch (RuntimeException e) {
        e.printStackTrace();
      }
    }

  }
}

@@ -59,39 +59,8 @@
 e;%0D%0A
-import org.junit.BeforeClass;%0D%0A
 impo
@@ -331,16 +331,105 @@
 cLong;%0D%0A
+import static org.junit.Assert.assertThat;%0D%0Aimport static org.hamcrest.CoreMatchers.is;%0D%0A
 %0D%0A%0D%0Apubl
@@ -749,9 +749,21 @@
 S = 
-5
+10, LOOPS = 1
 0;%0D%0A
@@ -892,131 +892,19 @@
 ong 
-timerSum;%0D%0A%0D%0A  @BeforeClass%0D%0A  public static void beforeClass() %7B%0D%0A    InApplicationMonitor.resetInstanceForTesting();%0D%0A  %7D
+exceptions;
 %0D%0A%0D%0A
@@ -1079,16 +1079,18 @@
 his.
-timerSum
+exceptions
  = n
@@ -1147,16 +1147,17 @@
 stConcur
+r
 ency() t
@@ -1182,24 +1182,120 @@
 xception %7B%0D%0A
+    for (int i = 0; i %3C LOOPS; i++) %7B%0D%0A      InApplicationMonitor.resetInstanceForTesting();%0D%0A  
     createEx
@@ -1305,16 +1305,23 @@
 tor(
-10
+THREADS
 );%0D%0A%0D%0A
+  
     
@@ -1356,16 +1356,66 @@
 erJob);%0D
+%0A    %7D%0D%0A    assertThat(exceptions.get(), is(0L));%0D
 %0A%0D%0A  %7D%0D%0A
@@ -1952,24 +1952,118 @@
 %0D%0A      
-doJob();
+try %7B%0D%0A        doJob();%0D%0A      %7D catch (Exception e) %7B%0D%0A        exceptions.incrementAndGet();%0D%0A      %7D
 %0D%0A    %7D%0D
@@ -2196,39 +2196,24 @@
  doJob() %7B%0D%0A
-      try %7B%0D%0A  
       InAppl
@@ -2301,18 +2301,16 @@
         
-  
 @Overrid
@@ -2312,18 +2312,16 @@
 erride%0D%0A
-  
         
@@ -2385,35 +2385,31 @@
             
- 
- 
 try %7B%0D%0A
-  
             
@@ -2424,26 +2424,24 @@
 .sleep(1);%0D%0A
-  
             
@@ -2486,26 +2486,24 @@
             
- 
- 
 Thread.inter
@@ -2517,39 +2517,35 @@
 );%0D%0A            
-  
 %7D%0D%0A
-  
           %7D%0D%0A   
@@ -2533,34 +2533,32 @@
 %7D%0D%0A          %7D%0D%0A
-  
         %7D);%0D%0A   
@@ -2558,85 +2558,8 @@
 );%0D%0A
-      %7D catch (RuntimeException e) %7B%0D%0A        e.printStackTrace();%0D%0A      %7D%0D%0A
     
@@ -2651,39 +2651,24 @@
  doJob() %7B%0D%0A
-      try %7B%0D%0A  
       String
@@ -2698,26 +2698,24 @@
 t(100000);%0D%0A
-  
       InAppl
@@ -2777,85 +2777,8 @@
 );%0D%0A
-      %7D catch (RuntimeException e) %7B%0D%0A        e.printStackTrace();%0D%0A      %7D%0D%0A
     

Test repdoducably foud two issues that have now been fixed (CorePlugin reprtable abserver handling and InApplicationMonitor getInstance /initInstance duplicate JMX mean registration)