/* Copyright (C) 2014 InfiniDB, Inc.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; version 2 of
   the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA. */

/***************************************************************************
 *   jrodriguez@calpont.com   *
 *                                                                         *
 ***************************************************************************/

using namespace std;
#include <iostream>
#include <cstdlib>
#include <sys/types.h>
#include <unistd.h>
#include "sessionmonitor.h"
#include "sessionmanager.h"

#include <cppunit/extensions/HelperMacros.h>

using namespace execplan;

int maxNewTxns = 1000;
int maxTxns = 1000;

class ExecPlanTest : public CppUnit::TestFixture
{
  CPPUNIT_TEST_SUITE(ExecPlanTest);

  CPPUNIT_TEST(MonitorTestPlan_1);
  CPPUNIT_TEST_SUITE_END();

 private:
 public:
  void setUp()
  {
  }

  void tearDown()
  {
  }

  int verifyLen;
  SessionManager* manager;
  SessionManager::TxnID managerTxns[1000];

  int createTxns(const int& start, const int& end)
  {
    int first = start;
    int last = end;
    int newTxns = 0;

    verifyLen = manager->verifySize();

    for (int idx = first; idx < last && verifyLen < maxNewTxns; idx++)
    {
      managerTxns[idx] = manager->newTxnID((uint32_t)idx + 1000);
      CPPUNIT_ASSERT(managerTxns[idx].id > 0);
      CPPUNIT_ASSERT(managerTxns[idx].valid == true);
      verifyLen = manager->verifySize();
      CPPUNIT_ASSERT(verifyLen > 0);
      newTxns++;
    }

    CPPUNIT_ASSERT(newTxns == last - first);
    return newTxns;
  }

  int closeTxns(const int& start, const int& end)
  {
    int first = start;
    int last = end;
    int totalClosed = 0;

    for (int idx = first; idx < last; idx++)
    {
      try
      {
        SessionManager::TxnID tmp = manager->getTxnID(idx + 1000);

        if (tmp.valid == true)
        {
          manager->committed(tmp);
          CPPUNIT_ASSERT(tmp.valid == false);
          totalClosed++;
        }
      }
      catch (exception& e)
      {
        cerr << e.what() << endl;
        continue;
      }
    }

    return totalClosed;

  }  // closeTxns

  void MonitorTestPlan_1()
  {
    int currStartTxn = 0;
    int currEndTxn = 5;
    int txnCntIncr = 5;
    const int sleepTime = 1;
    const int iterMax = 1;
    vector<SessionMonitor::MonSIDTIDEntry*> toTxns;

    manager = new SessionManager();
    // CPPUNIT_ASSERT(manager->verifySize()==0);

    SessionMonitor* monitor = NULL;

    for (int jdx = 0; jdx < iterMax; jdx++)
    {
      // store the current state of the SessionManager
      monitor = new SessionMonitor();
      monitor->AgeLimit(sleepTime);
      delete monitor;
      int idx = 0;
      int grpStart = currStartTxn;

      for (idx = 0; idx < 3; idx++)
      {
        createTxns(currStartTxn, currEndTxn);
        // CPPUNIT_ASSERT(manager->verifySize()==(idx+1)*txnCntIncr);

        currStartTxn += txnCntIncr;
        currEndTxn += txnCntIncr;
        sleep(sleepTime + 1);  // make sessions time out

        monitor = new SessionMonitor();  // read Monitor data
        monitor->AgeLimit(sleepTime);
        toTxns.clear();
        toTxns = monitor->timedOutTxns();  // get timed out txns
        CPPUNIT_ASSERT(toTxns.size() == (uint32_t)txnCntIncr * idx);

        delete monitor;
      }

      int grpEnd = currEndTxn;
      monitor = new SessionMonitor();
      monitor->AgeLimit(sleepTime);
      closeTxns(grpStart, grpEnd);  // close this iteration of txns
      // CPPUNIT_ASSERT(manager->verifySize()==0);
      toTxns = monitor->timedOutTxns();  // get timed out txns
      CPPUNIT_ASSERT(toTxns.size() == 0);

      delete monitor;
    }

    monitor = new SessionMonitor();  // readload Monitor data
    monitor->AgeLimit(sleepTime - 1);

    toTxns.clear();
    toTxns = monitor->timedOutTxns();  // get timed out txns
    CPPUNIT_ASSERT(toTxns.size() == 0);
    delete monitor;

    // CPPUNIT_ASSERT(manager->verifySize()==0);
    delete manager;
  }

};  // test suite

CPPUNIT_TEST_SUITE_REGISTRATION(ExecPlanTest);

#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>

int main(int argc, char* argv[])
{
  CppUnit::TextUi::TestRunner runner;
  CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry();
  runner.addTest(registry.makeTest());
  bool wasSuccessful = runner.run("", false);
  return (wasSuccessful ? 0 : 1);
}
