package org.opendaylight.controller.cluster.datastore;

import akka.actor.ActorRef;
import akka.actor.DeadLetter;
import akka.actor.Props;
import akka.testkit.JavaTestKit;
import org.junit.Test;
import org.mockito.Mockito;
import org.opendaylight.controller.cluster.datastore.messages.DataChanged;
import org.opendaylight.controller.cluster.datastore.messages.DataChangedReply;
import org.opendaylight.controller.cluster.datastore.messages.EnableNotification;
import org.opendaylight.controller.md.cluster.datastore.model.CompositeModel;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;

public class DataChangeListenerTest extends AbstractActorTest {

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Test
    public void testDataChangedWhenNotificationsAreEnabled(){
        new JavaTestKit(getSystem()) {{
            final AsyncDataChangeEvent mockChangeEvent = Mockito.mock(AsyncDataChangeEvent.class);
            final AsyncDataChangeListener mockListener = Mockito.mock(AsyncDataChangeListener.class);
            final Props props = DataChangeListener.props(mockListener);
            final ActorRef subject = getSystem().actorOf(props, "testDataChangedNotificationsEnabled");

            // Let the DataChangeListener know that notifications should be enabled
            subject.tell(new EnableNotification(true), getRef());

            subject.tell(new DataChanged(CompositeModel.createTestContext(), mockChangeEvent),
                    getRef());

            expectMsgClass(DataChangedReply.class);

            Mockito.verify(mockListener).onDataChanged(mockChangeEvent);
        }};
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Test
    public void testDataChangedWhenNotificationsAreDisabled(){
        new JavaTestKit(getSystem()) {{
            final AsyncDataChangeEvent mockChangeEvent = Mockito.mock(AsyncDataChangeEvent.class);
            final AsyncDataChangeListener mockListener = Mockito.mock(AsyncDataChangeListener.class);
            final Props props = DataChangeListener.props(mockListener);
            final ActorRef subject =
                getSystem().actorOf(props, "testDataChangedNotificationsDisabled");

            subject.tell(new DataChanged(CompositeModel.createTestContext(), mockChangeEvent),
                    getRef());

            new Within(duration("1 seconds")) {
                @Override
                protected void run() {
                    expectNoMsg();

                    Mockito.verify(mockListener, Mockito.never()).onDataChanged(
                            Mockito.any(AsyncDataChangeEvent.class));
                }
            };
        }};
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Test
    public void testDataChangedWithNoSender(){
        new JavaTestKit(getSystem()) {{
            final AsyncDataChangeEvent mockChangeEvent = Mockito.mock(AsyncDataChangeEvent.class);
            final AsyncDataChangeListener mockListener = Mockito.mock(AsyncDataChangeListener.class);
            final Props props = DataChangeListener.props(mockListener);
            final ActorRef subject = getSystem().actorOf(props, "testDataChangedWithNoSender");

            // Let the DataChangeListener know that notifications should be enabled
            subject.tell(new EnableNotification(true), ActorRef.noSender());

            subject.tell(new DataChanged(CompositeModel.createTestContext(), mockChangeEvent),
                    ActorRef.noSender());

            getSystem().eventStream().subscribe(getRef(), DeadLetter.class);
            new Within(duration("1 seconds")) {
                @Override
                protected void run() {
                    expectNoMsg();
                }
            };
        }};
    }
}

@@ -165,16 +165,41 @@
 estKit;%0A
+import org.junit.Assert;%0A
 import o
@@ -3321,154 +3321,70 @@
     
-// Let the DataChangeListener know that notifications should be enabled%0A            subject.tell(new EnableNotification(true), ActorRef.noSender()
+getSystem().eventStream().subscribe(getRef(), DeadLetter.class
 );%0A%0A
@@ -3537,238 +3537,623 @@
     
-getSystem().eventStream().subscribe(getRef(), DeadLetter.class);%0A            new Within(duration(%221 seconds%22)) %7B%0A                @Override%0A                protected void run() %7B%0A                    expectNoMsg();%0A                %7D
+// Make sure no DataChangedReply is sent to DeadLetters.%0A            while(true) %7B%0A                DeadLetter deadLetter;%0A                try %7B%0A                    deadLetter = expectMsgClass(duration(%221 seconds%22), DeadLetter.class);%0A                %7D catch (AssertionError e) %7B%0A                    // Timed out - got no DeadLetter - this is good%0A                    break;%0A                %7D%0A%0A                // We may get DeadLetters for other messages we don't care about.%0A                Assert.assertFalse(%22Unexpected DataChangedReply%22,%0A                        deadLetter.message() instanceof DataChangedReply);
 %0A   
@@ -4154,33 +4154,32 @@
 );%0A            %7D
-;
 %0A        %7D%7D;%0A   

Fix intermittent failure in DataChangeListenerTest