package clarifai2.test;

import clarifai2.dto.input.ClarifaiInput;
import clarifai2.dto.model.output.ClarifaiOutput;
import clarifai2.dto.prediction.Concept;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertTrue;

public class ExecuteAsyncTests extends BaseClarifaiAPITest {

  private int simultaneousCallsNum = 10;
  @NotNull private final CountDownLatch loginLatch = new CountDownLatch(simultaneousCallsNum);

  @Test public void shouldMakeSureExecuteAsyncWorks() throws InterruptedException {
    for (int i = 0; i < simultaneousCallsNum; i++) {
      client.getDefaultModels().generalModel().predict()
          .withInputs(ClarifaiInput.forImage(
              "https://developer.clarifai.com/static/images/model-samples/demographics-001.jpg"))
          .executeAsync(resp -> handleResponse(resp),
              failCode -> handleException(failCode),
              io -> handleNetError(io)
          );
    }
    long asyncExecutionsDoneTime = System.nanoTime();
    boolean completed = loginLatch.await(3, TimeUnit.SECONDS);
    assertTrue(completed);
    long timeBetween = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - asyncExecutionsDoneTime);
    assertTrue(timeBetween > 10); // It should take at least 10ms for the asynchronous callbacks to be called.
  }

  private void handleResponse(List<ClarifaiOutput<Concept>> clarifaiOutputs) {
    loginLatch.countDown();
  }
  private void handleException(int errorCode) { }
  private void handleNetError(IOException e) { }
}


@@ -594,16 +594,400 @@
 sNum);%0A%0A
+  // A collection of heuristics that attempt to capture whether these calls are actually%0A  // running asynchronously.  It is theoretically possible for every one of these asserts%0A  // to fail, depending on timeing/thread scheduling, even if things are working properly.%0A  // Nonetheless, on nearly all real world hosts this test will pass if and only if async%0A  // behaves correctly.%0A
   @Test 
@@ -1062,16 +1062,73 @@
 ption %7B%0A
+    long asyncExecutionsStartedTime = System.nanoTime();%0A
     for 
@@ -1588,24 +1588,250 @@
 nanoTime();%0A
+    // the login latch should not already be completed, assuming that the asynchronous%0A    // calls did not actually happen syncronously:%0A    assertTrue(loginLatch.getCount() %3E 0);%0A%0A    // but they should eventually complete:%0A
     boolean 
@@ -1921,23 +1921,27 @@
 ong time
-Between
+ToCallbacks
  = TimeU
@@ -2019,42 +2019,289 @@
     
-assertTrue(timeBetween %3E
+%0A    // The time it takes to make the async calls should be less than 100ms (we're not blocking%0A    // on these calls:%0A    long timeAsyncCalls = TimeUnit.NANOSECONDS.toMillis(asyncExecutionsDoneTime - asyncExecutionsStartedTime);%0A    assertTrue(timeAsyncCalls %3C
  10
+0
 );
- // I
+%0A%0A    // and i
 t sh
@@ -2319,17 +2319,17 @@
 t least 
-1
+3
 0ms for 
@@ -2337,23 +2337,16 @@
 he async
-hronous
  callbac
@@ -2352,21 +2352,96 @@
 cks 
-to be called.
+-- assuming that the calls%0A    // actually happen:%0A    assertTrue(timeToCallbacks %3E 30);
 %0A  %7D

update to async test