/* This file is part of VoltDB.
 * Copyright (C) 2008-2016 VoltDB Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

package org.voltdb.iv2;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import junit.framework.TestCase;

import org.json_voltpatches.JSONException;
import org.json_voltpatches.JSONObject;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.voltcore.messaging.Mailbox;
import org.voltcore.messaging.TransactionInfoBaseMessage;
import org.voltcore.utils.CoreUtils;
import org.voltcore.zk.MapCache;
import org.voltdb.CommandLog;
import org.voltdb.ProcedureRunner;
import org.voltdb.SnapshotCompletionMonitor;
import org.voltdb.StarvationTracker;
import org.voltdb.VoltDBInterface;
import org.voltdb.messaging.CompleteTransactionMessage;

import com.google_voltpatches.common.collect.ImmutableMap;
import org.voltdb.messaging.Iv2InitiateTaskMessage;

public class TestSpSchedulerSpHandle extends TestCase
{
    Mailbox mbox;
    SnapshotCompletionMonitor snapMonitor;
    MapCache iv2masters;
    VoltDBInterface vdbi;
    ProcedureRunner runner;
    Scheduler dut;
    RandomMsgGenerator msgGen;

    static final String MockSPName = "MOCKSP";
    static final long dut_hsid = 11223344l;


    private static SiteTaskerQueue getSiteTaskerQueue() {
        SiteTaskerQueue queue = new SiteTaskerQueue();
        queue.setStarvationTracker(new StarvationTracker(0));
        return queue;
    }

    @Override
    public void setUp()
    {
        msgGen = new RandomMsgGenerator();
    }

    public void createObjs() throws JSONException
    {
        mbox = mock(Mailbox.class);
        when(mbox.getHSId()).thenReturn(dut_hsid);
        iv2masters = mock(MapCache.class);
        snapMonitor = mock(SnapshotCompletionMonitor.class);

        // make fake MapCache of iv2masters
        HashMap<String,JSONObject> fakecache = new HashMap<String, JSONObject>();
        fakecache.put("0", new JSONObject("{hsid:0}"));
        when(iv2masters.pointInTimeCache()).thenReturn(ImmutableMap.copyOf(fakecache));

        final CommandLog cl = mock(CommandLog.class);
        doReturn(CoreUtils.COMPLETED_FUTURE).when(cl).log(any(Iv2InitiateTaskMessage.class), anyLong(), any(int[].class),
                                                          any(CommandLog.DurabilityListener.class),
                                                          any(TransactionTask.class));

        dut = new SpScheduler(0, getSiteTaskerQueue(), snapMonitor);
        dut.setMailbox(mbox);
        dut.setCommandLog(cl);
        dut.setLock(mbox);
    }

    // Validate the contract on the SP handles generated by the SpScheduler at the master for a partition.
    // Every new message replicated by the partition master to its partition
    // replicas should have a unique, constantly increasing SP handle.
    // Read-only invocations and fragments are not replicated but advance the internal SP handle
    // CompleteTransactionMessages get farmed out everywhere for every MP transaction, regardless of
    // type

    @Test
    public void testBasicSpHandleMessageStream() throws Exception
    {
        TxnEgo currentHandle = TxnEgo.makeZero(0);
        // SpScheduler calls advance before assignment

        createObjs();
        dut.setLeaderState(true);
        List<Long> replicas = new ArrayList<Long>();
        replicas.add(2l);
        dut.updateReplicas(replicas, null);
        int msgcount = 0;
        for (int i = 0; i < 4000; i++) {
            TransactionInfoBaseMessage msg = msgGen.generateRandomMessageInStream();
            dut.deliver(msg);
            // only non-reads should do checks, all others just keep moving
            // Capture the InitiateTaskMessage that gets sent to the replica so we can test it,
            // use it for response construction, etc.
            if (!msg.isReadOnly() || msg instanceof CompleteTransactionMessage)
            {
                currentHandle = currentHandle.makeNext();
                msgcount++;
                ArgumentCaptor<TransactionInfoBaseMessage> replmsg =
                    ArgumentCaptor.forClass(TransactionInfoBaseMessage.class);
                verify(mbox, times(msgcount)).send(eq(new long[] {2l}), replmsg.capture());
                assertEquals("Failed on msg: " + replmsg.getValue(),
                        currentHandle.getTxnId(), replmsg.getValue().getSpHandle());
            }
        }
    }
}

@@ -1312,65 +1312,181 @@
 ito.
-*;%0A%0Aimport java.util.ArrayList;%0Aimport java.util.HashMap;
+doReturn;%0Aimport static org.mockito.Mockito.mock;%0Aimport static org.mockito.Mockito.times;%0Aimport static org.mockito.Mockito.verify;%0Aimport static org.mockito.Mockito.when;%0A
 %0Aimp
@@ -1503,23 +1503,27 @@
 til.
+Array
 List;%0A
-%0A
 import j
 unit
@@ -1522,31 +1522,47 @@
 rt j
-unit.framework.TestCase
+ava.util.HashMap;%0Aimport java.util.List
 ;%0A%0Ai
@@ -2078,35 +2078,31 @@
 ssaging.
-CompleteTransaction
+Iv2InitiateTask
 Message;
@@ -2166,57 +2166,39 @@
 ap;%0A
+%0A
 import 
-org.voltdb.messaging.Iv2InitiateTaskMessag
+junit.framework.TestCas
 e;%0A%0A
@@ -4902,84 +4902,8 @@
 g);%0A
-            // only non-reads should do checks, all others just keep moving%0A
     
@@ -5052,106 +5052,8 @@
 tc.%0A
-            if (!msg.isReadOnly() %7C%7C msg instanceof CompleteTransactionMessage)%0A            %7B%0A    
     
@@ -5114,20 +5114,16 @@
         
-    
 msgcount
@@ -5130,36 +5130,32 @@
 ++;%0A            
-  
-  
 ArgumentCaptor%3CT
@@ -5191,20 +5191,16 @@
 plmsg =%0A
-    
         
@@ -5278,20 +5278,16 @@
         
-    
 verify(m
@@ -5366,20 +5366,16 @@
         
-   
- 
 assertEq
@@ -5419,20 +5419,16 @@
 alue(),%0A
-    
         
@@ -5504,22 +5504,8 @@
 ));%0A
-            %7D%0A
     

Fix bad test.