/*
 * Copyright (C) 2009-2019 Lightbend Inc. <https://www.lightbend.com>
 */

package javaguide.cache;

import akka.Done;
import com.google.common.collect.ImmutableMap;
import org.junit.Test;
import play.Application;
import play.cache.AsyncCacheApi;
import play.cache.Cached;
import play.core.j.JavaHandlerComponents;
import play.mvc.*;
import play.test.WithApplication;

import javaguide.testhelpers.MockJavaAction;

import java.lang.Throwable;
import java.util.Collections;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
import java.util.Optional;

import static javaguide.testhelpers.MockJavaActionHelper.call;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static play.test.Helpers.*;

public class JavaCache extends WithApplication {

  @Override
  protected Application provideApplication() {
    return fakeApplication(
        ImmutableMap.of("play.cache.bindCaches", Collections.singletonList("session-cache")));
  }

  private class News {}

  @Test
  public void inject() {
    // Check that we can instantiate it
    app.injector().instanceOf(javaguide.cache.inject.Application.class);
    // Check that we can instantiate the qualified one
    app.injector().instanceOf(javaguide.cache.qualified.Application.class);
  }

  @Test
  public void simple() {
    AsyncCacheApi cache = app.injector().instanceOf(AsyncCacheApi.class);

    News frontPageNews = new News();
    {
      // #simple-set
      CompletionStage<Done> result = cache.set("item.key", frontPageNews);
      // #simple-set
      block(result);
    }
    {
      // #time-set
      // Cache for 15 minutes
      CompletionStage<Done> result = cache.set("item.key", frontPageNews, 60 * 15);
      // #time-set
      block(result);
    }
    // #get
    CompletionStage<Optional<News>> news = cache.get("item.key");
    // #get
    assertThat(block(news).get(), equalTo(frontPageNews));
    // #get-or-else
    CompletionStage<News> maybeCached =
        cache.getOrElseUpdate("item.key", this::lookUpFrontPageNews);
    // #get-or-else
    assertThat(block(maybeCached), equalTo(frontPageNews));
    {
      // #remove
      CompletionStage<Done> result = cache.remove("item.key");
      // #remove

      // #removeAll
      CompletionStage<Done> resultAll = cache.removeAll();
      // #removeAll
      block(result);
    }
    assertThat(cache.sync().get("item.key"), equalTo(Optional.empty()));
  }

  private CompletionStage<News> lookUpFrontPageNews() {
    return CompletableFuture.completedFuture(new News());
  }

  public static class Controller1 extends MockJavaAction {

    Controller1(JavaHandlerComponents javaHandlerComponents) {
      super(javaHandlerComponents);
    }

    // #http
    @Cached(key = "homePage")
    public Result index() {
      return ok("Hello world");
    }
    // #http
  }

  @Test
  public void http() {
    AsyncCacheApi cache = app.injector().instanceOf(AsyncCacheApi.class);

    assertThat(
        contentAsString(
            call(new Controller1(instanceOf(JavaHandlerComponents.class)), fakeRequest(), mat)),
        equalTo("Hello world"));
    assertThat(cache.sync().get("homePage").get(), notNullValue());
    cache.sync().set("homePage", Results.ok("something else"));
    assertThat(
        contentAsString(
            call(new Controller1(instanceOf(JavaHandlerComponents.class)), fakeRequest(), mat)),
        equalTo("something else"));
  }

  private static <T> T block(CompletionStage<T> stage) {
    try {
      return stage.toCompletableFuture().get();
    } catch (Throwable e) {
      throw new RuntimeException(e);
    }
  }
}

@@ -2977,67 +2977,38 @@
 s);%0A
-%0A
     
-assertThat(%0A        contentAsString(%0A            call(
+Controller1 controller1 = 
 new 
@@ -3051,32 +3051,82 @@
 mponents.class))
+;%0A%0A    assertThat(contentAsString(call(controller1
 , fakeRequest(),
@@ -3128,32 +3128,24 @@
 st(), mat)),
-%0A       
  equalTo(%22He
@@ -3154,24 +3154,25 @@
 o world%22));%0A
+%0A
     assertTh
@@ -3170,36 +3170,35 @@
  assertThat(
-cache.sync()
+block(cache
 .get(%22homePa
@@ -3201,16 +3201,17 @@
 mePage%22)
+)
 .get(), 
@@ -3231,24 +3231,154 @@
 ));%0A
+%0A
     
-cache.sync()
+// Set a new value to the cache key. We are blocking to ensure%0A    // the test will continue only when the value set is done.%0A    block(cache
 .set
@@ -3419,17 +3419,19 @@
  else%22))
-;
+);%0A
 %0A    ass
@@ -3438,25 +3438,16 @@
 ertThat(
-%0A        
 contentA
@@ -3458,82 +3458,24 @@
 ing(
-%0A            call(new Controller1(instanceOf(JavaHandlerComponents.class))
+call(controller1
 , fa
@@ -3493,24 +3493,16 @@
 , mat)),
-%0A       
  equalTo

Fix JavaCache flaky test