package com.basho.riak.client.core;


import com.basho.riak.client.api.commands.ChunkedResponseIterator;
import org.junit.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.TransferQueue;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;

/**
 * @author Alex Moore <amoore at basho dot com>
 */
public class ChunkedResponseIteratorTest
{
    /*
      NB: Disable this test if you want to use code coverage tools.
      The Thread interrupt it generates triggers a shutdown hook race bug in Java,
      which then doesn't allow EMMA to cleanly shutdown.
      https://bugs.openjdk.java.net/browse/JDK-8154017
     */
    @Test
    public void testInterruptedExceptionDealtWith() throws InterruptedException
    {
        final boolean[] caught = {false};
        final InterruptedException[] ie = {null};
        int timeout = 1000;

        Thread t = new Thread(() ->
        {
            try
            {
                @SuppressWarnings("unchecked") TransferQueue<FakeResponse> fakeQueue =
                        (TransferQueue<FakeResponse>) mock(TransferQueue.class);
                when(fakeQueue.poll(timeout,
                                    TimeUnit.MILLISECONDS)).thenThrow(new InterruptedException(
                        "foo"));

                @SuppressWarnings("unchecked") PBStreamingFutureOperation<FakeResponse, Void, Void>
                        coreFuture = (PBStreamingFutureOperation<FakeResponse, Void, Void>) mock(
                        PBStreamingFutureOperation.class);

                when(coreFuture.getResultsQueue()).thenReturn(fakeQueue);

                // ChunkedResponseIterator polls the response queue when created,
                // so we'll use that to simulate a Thread interrupt.
                new ChunkedResponseIterator<>(coreFuture,
                                              timeout,
                                              Long::new,
                                              FakeResponse::iterator);
            }
            catch (RuntimeException ex)
            {
                caught[0] = true;
                ie[0] = (InterruptedException) ex.getCause();
            }
            catch (InterruptedException e)
            {
                // Mocking TransferQueue::poll(timeout) requires this CheckedException be dealt with
                // If we actually catch one here we've failed at our jobs.
                caught[0] = false;
            }

            assertTrue(Thread.currentThread().isInterrupted());
        });

        t.start();
        t.join();

        assertTrue(caught[0]);
        assertEquals("foo", ie[0].getMessage());
    }

    static abstract class FakeResponse implements Iterable<Integer> {}
}

@@ -120,16 +120,168 @@
 it.Test;
+%0Aimport org.junit.runner.RunWith;%0Aimport org.powermock.core.classloader.annotations.PrepareForTest;%0Aimport org.powermock.modules.junit4.PowerMockRunner;
 %0A%0Aimport
@@ -387,28 +387,17 @@
 .Assert.
-assertEquals
+*
 ;%0Aimport
@@ -412,31 +412,50 @@
 org.
-junit.Assert.assertTrue
+powermock.api.mockito.PowerMockito.doThrow
 ;%0Aim
@@ -627,16 +627,98 @@
 om%3E%0A */%0A
+@RunWith(PowerMockRunner.class)%0A@PrepareForTest(PBStreamingFutureOperation.class)%0A
 public c
@@ -1144,75 +1144,22 @@
 nal 
-boolean%5B%5D caught = %7Bfalse%7D;%0A        final InterruptedException%5B%5D ie
+Throwable%5B%5D ex
  = %7B
@@ -1210,16 +1210,25 @@
 Thread t
+estThread
  = new T
@@ -1325,16 +1325,32 @@
 hecked%22)
+%0A               
  Transfe
@@ -1463,16 +1463,17 @@
 class);%0A
+%0A
         
@@ -1512,44 +1512,8 @@
 out,
-%0A                                   
  Tim
@@ -1572,33 +1572,8 @@
 ion(
-%0A                        
 %22foo
@@ -1624,16 +1624,32 @@
 hecked%22)
+%0A               
  PBStrea
@@ -1693,16 +1693,29 @@
 d, Void%3E
+ coreFuture =
 %0A       
@@ -1730,29 +1730,16 @@
         
- coreFuture =
  (PBStre
@@ -1795,33 +1795,8 @@
 ock(
-%0A                        
 PBSt
@@ -2344,16 +2344,17 @@
 ception 
+r
 ex)%0A    
@@ -2383,86 +2383,19 @@
     
-caught%5B0%5D = true;%0A                ie%5B0%5D = (InterruptedException) ex.getCause()
+ex%5B0%5D = rex
 ;%0A  
@@ -2659,25 +2659,28 @@
     
-caught%5B0%5D = false
+fail(e.getMessage())
 ;%0A  
@@ -2778,16 +2778,25 @@
        t
+estThread
 .start()
@@ -2806,16 +2806,25 @@
        t
+estThread
 .join();
@@ -2837,77 +2837,347 @@
     
-assertTrue(caught%5B0%5D);%0A        assertEquals(%22foo%22, ie%5B0%5D.getMessage()
+Throwable caughtException = ex%5B0%5D;%0A        assertNotNull(caughtException);%0A%0A        Throwable wrappedException = caughtException.getCause();%0A        assertNotNull(caughtException.getMessage(), wrappedException);%0A        assertEquals(%22foo%22, wrappedException.getMessage());%0A        assertTrue(wrappedException instanceof InterruptedException
 );%0A 

Fix test that stubs a final method