/*
 * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.controller.cluster.datastore;

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.pattern.Patterns;
import akka.testkit.JavaTestKit;
import akka.util.Timeout;
import com.google.common.util.concurrent.Uninterruptibles;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.Assert;
import org.opendaylight.controller.cluster.raft.client.messages.FindLeader;
import org.opendaylight.controller.cluster.raft.client.messages.FindLeaderReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;
import scala.concurrent.duration.FiniteDuration;

public class ShardTestKit extends JavaTestKit {
    private static final Logger LOG = LoggerFactory.getLogger(ShardTestKit.class);

    public ShardTestKit(final ActorSystem actorSystem) {
        super(actorSystem);
    }

    public void waitForLogMessage(final Class<?> logLevel, final ActorRef subject, final String logMessage) {
        // Wait for a specific log message to show up
        final boolean result =
            new JavaTestKit.EventFilter<Boolean>(logLevel
            ) {
                @Override
                protected Boolean run() {
                    return true;
                }
            }.from(subject.path().toString())
                .message(logMessage)
                .occurrences(1).exec();

        Assert.assertEquals(true, result);

    }

    @SuppressWarnings("checkstyle:IllegalCatch")
    public static String waitUntilLeader(final ActorRef shard) {
        FiniteDuration duration = Duration.create(100, TimeUnit.MILLISECONDS);
        for (int i = 0; i < 20 * 5; i++) {
            Future<Object> future = Patterns.ask(shard, FindLeader.INSTANCE, new Timeout(duration));
            try {
                final Optional<String> maybeLeader = ((FindLeaderReply) Await.result(future, duration))
                        .getLeaderActor();
                if (maybeLeader.isPresent()) {
                    return maybeLeader.get();
                }
            } catch (TimeoutException e) {
                LOG.trace("FindLeader timed out", e);
            } catch (Exception e) {
                LOG.error("FindLeader failed", e);
            }

            Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
        }

        Assert.fail("Leader not found for shard " + shard.path());
        return null;
    }

    @SuppressWarnings("checkstyle:IllegalCatch")
    public void waitUntilNoLeader(final ActorRef shard) {
        FiniteDuration duration = Duration.create(100, TimeUnit.MILLISECONDS);
        Object lastResponse = null;
        for (int i = 0; i < 20 * 5; i++) {
            Future<Object> future = Patterns.ask(shard, FindLeader.INSTANCE, new Timeout(duration));
            try {
                final Optional<String> maybeLeader = ((FindLeaderReply) Await.result(future, duration))
                        .getLeaderActor();
                if (!maybeLeader.isPresent()) {
                    return;
                }

                lastResponse = maybeLeader.get();
            } catch (TimeoutException e) {
                lastResponse = e;
            } catch (Exception e) {
                LOG.error("FindLeader failed", e);
                lastResponse = e;
            }

            Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS);
        }

        if (lastResponse instanceof Throwable) {
            throw (AssertionError)new AssertionError(
                    String.format("Unexpected error occurred from FindLeader for shard %s", shard.path()))
                            .initCause((Throwable)lastResponse);
        }

        Assert.fail(String.format("Unexpected leader %s found for shard %s", lastResponse, shard.path()));
    }
}

@@ -374,16 +374,99 @@
 store;%0A%0A
+import static org.junit.Assert.assertEquals;%0Aimport static org.junit.Assert.fail;%0A%0A
 import a
@@ -566,20 +566,65 @@
 testkit.
-Java
+javadsl.EventFilter;%0Aimport akka.testkit.javadsl.
 TestKit;
@@ -824,33 +824,8 @@
 on;%0A
-import org.junit.Assert;%0A
 impo
@@ -1224,20 +1224,16 @@
 extends 
-Java
 TestKit 
@@ -1588,17 +1588,17 @@
   final 
-b
+B
 oolean r
@@ -1608,215 +1608,47 @@
 lt =
-%0A            new JavaTestKit.EventFilter%3CBoolean%3E(logLevel%0A            ) %7B%0A                @Override%0A                protected Boolean run() %7B%0A                    return true;%0A                %7D%0A            %7D
+ new EventFilter(logLevel, getSystem())
 .fro
@@ -1716,49 +1716,54 @@
 age)
-%0A                .occurrences(1).exec();%0A
+.occurrences(1).intercept(() -%3E Boolean.TRUE);
 %0A   
@@ -1767,23 +1767,16 @@
         
-Assert.
 assertEq
@@ -1784,12 +1784,20 @@
 als(
-true
+Boolean.TRUE
 , re
@@ -1803,17 +1803,16 @@
 esult);%0A
-%0A
     %7D%0A%0A 
@@ -2715,31 +2715,24 @@
  %7D%0A%0A        
-Assert.
 fail(%22Leader
@@ -4071,23 +4071,16 @@
         
-Assert.
 fail(Str

Migrate ShardTestKit to javadsl.TestKit