/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas.jtests.clients.timer;

import java.util.Date;

import javax.ejb.TimerHandle;
import org.objectweb.jonas.jtests.beans.transacted.Simple;
import org.objectweb.jonas.jtests.util.JTestCase;

/**
 * This is test of the TimerService.
 * tests here are common to entity and session beans.
 * beans used : transacted
 * @author Philippe Durieux (jonas team)
 */
public abstract class A_Timer extends JTestCase {

    /**
     * constructor
     * @param name name of the test suite.
     */
    public A_Timer(String name) {
        super(name);
    }

    /**
     * Sets up the fixture, here load the beans if not loaded yet.
     * This method is called before a test is executed.
     */
    protected void setUp() {
        super.setUp();
        useBeans("transacted", true);
    }

    /**
     * Get an instance of the bean.
     * This method depends on the home used to get it.
     * For entity bean, the arg is used to get a particular instance.
     * For session beans, we get any session bean from the pool.
     */
    public abstract Simple getSimple(int i) throws Exception;

    // --------------------------------------------------------------------
    // test cases
    // --------------------------------------------------------------------

    /**
     * Test single-event timer
     */
    public void testTimer1() throws Exception {
        int duration = 5;
        Simple s = getSimple(random(500000));
        try {
            int oldval = s.getTimerCount();
            int id = s.setTimer(duration, 0);
            sleep(2000);
            assertEquals("timer expired too quickly", oldval, s.getTimerCount());
            sleep(4000);
            assertEquals("timer did not expired", oldval + 1, s.getTimerCount());
        } finally {
            s.remove();
        }
    }

    /**
     * Test with absolute time
     */
    public void testTimerA1() throws Exception {
        Date d = new Date(System.currentTimeMillis() + 1000);
        Simple s = getSimple(random(500000));
        try {
            int oldval = s.getTimerCount();
            int id = s.setTimer(d, 0);
            sleep(2000);
            assertEquals("timer did not expired", oldval + 1, s.getTimerCount());
        } finally {
            s.remove();
        }
    }

    /**
     * Test with absolute time (for persistent timer test)
     */
    public void testTimerAin4mn() throws Exception {
        Date d = new Date(System.currentTimeMillis() + 4000 * 60);
        Simple s = getSimple(random(500000));
        try {
            int oldval = s.getTimerCount();
            int id = s.setTimer(d, 0);
        } finally {
            // Remove this line for persistent timers tests
            s.remove();
        }
    }

    /**
     * Test periodic timer
     * Can be used also to test persistent timers.
     */
    public void testTimer2() throws Exception {
        int duration = 5;
        int period = 7;
        Simple s = getSimple(random(500000));
        try {
            int oldval = s.getTimerCount();
            int id = s.setTimer(duration, period);
            sleep(2000);
            assertEquals("timer expired too quickly", oldval, s.getTimerCount());
            sleep(4000);
            assertEquals("timer did not expired", oldval + 1, s.getTimerCount());
            sleep(period * 1000);
            assertEquals("timer did not expired twice", oldval + 2, s.getTimerCount());
        } finally {
            s.remove();
        }
    }

    /**
     * Test single-event timer Handle
     */
    public void testTimerHandle1() throws Exception {
        int duration = 5;
        Simple s = getSimple(random(500000));
        try {
            int oldval = s.getTimerCount();
            int id = s.setTimerGetHandle(duration, 0);
            sleep(2000);
            assertEquals("timer expired too quickly", oldval, s.getTimerCount());
            sleep(4000);
            assertEquals("timer did not expired", oldval + 1, s.getTimerCount());
        } finally {
            s.remove();
        }
    }

    /**
     * Test periodic timer Handle
     */
    public void testPeriodicTimerHandle1() throws Exception {
        int duration = 5;
        int period = 200;
        Simple s = getSimple(random(500000));
        try {
            int oldval = s.getTimerCount();
            int id = s.setTimerGetHandle(duration, period);
            sleep(2000);
            assertEquals("timer expired too quickly", oldval, s.getTimerCount());
            sleep(4000);
            assertEquals("timer did not expired", oldval + 1, s.getTimerCount());
        } finally {
            s.remove();
        }
    }

    /**
     * test getTimeRemaining on a Timer
     */
    public void testTimeRemaining() throws Exception {
        int duration1 = 5000;
        int duration2 = 2000;
        Simple s = getSimple(random(500000));
        try {
            int id1 = s.setTimer(duration1, 0);
            int id2 = s.setTimer(duration2, 0);
            long t1 = s.getTimeRemaining(id1) / 1000;
            long t2 = s.getTimeRemaining(id2) / 1000;
            sleep(1000);
            assertTrue(t1 < duration1);
            assertTrue(t2 < duration2);
            assertTrue(t1 > duration1 - 2);
            assertTrue(t2 > duration2 - 2);
        } finally {
            s.remove();
        }
    }

    /**
     * Test du cancel Timer
     */
    public void testCancel1() throws Exception {
        int duration = 2;
        Simple s = getSimple(random(500000));
        try {
            int oldval = s.getTimerCount();
            int id = s.setTimer(duration, 0);
            assertEquals("timer expired too quickly", oldval, s.getTimerCount());
            s.cancelTimer(id);
            sleep(1000 * (duration + 1));
            assertEquals("timer did expired", oldval, s.getTimerCount());
        } finally {
            s.remove();
        }
    }

    /**
     * Test of getTimers
     */
    public void testGetTimers() throws Exception {
        Simple s = getSimple(random(500000));
        int [] ids = new int[10];
        int before = s.getTimerNumber();
        try {
            for (int i = 0; i < 10; i++) {
                ids[i] = s.setTimer(i + 1, 100);
            }
            sleep(1000);
            assertEquals("Bad number of timers", 10, s.getTimerNumber() - before);
            for (int i = 0; i < 10; i++) {
                s.cancelTimer(ids[i]);
            }
        } finally {
            s.remove();
        }
    }

    /**
     * Test getTimers with cancel outside tx
     * The cancelled timer should not be returned
     */
    public void testGetTimerCancelled() throws Exception {
        Simple s = getSimple(random(500000));
        int [] ids = new int[10];
        int before = s.getTimerNumber();
        try {
            for (int i = 0; i < 10; i++) {
                ids[i] = s.setTimer(i + 1, 100);
            }
            sleep(1000);
            s.cancelTimer(ids[0]);
            assertEquals("Bad number of timers", 9, s.getTimerNumber() - before);
            for (int i = 1; i < 10; i++) {
                s.cancelTimer(ids[i]);
            }
        } finally {
            s.remove();
        }
    }

    /**
     * Test getTimers with cancel in the transaction.
     * The cancelled timer should not be returned
     */
    public void testGetTimerCancelledInTx() throws Exception {
        Simple s = getSimple(random(500000));
        int [] ids = new int[10];
        int before = s.getTimerNumber();
        // start transaction
        utx.begin();
        try {
            for (int i = 0; i < 10; i++) {
                ids[i] = s.setTimer(i + 1, 100);
            }
            sleep(1000);
            s.cancelTimer(ids[0]);
            assertEquals("Bad number of timers", 9, s.getTimerNumber() - before);
            for (int i = 1; i < 10; i++) {
                s.cancelTimer(ids[i]);
            }
        } finally {
            utx.commit();
            s.remove();
        }
    }

    /**
     * Test getHandle on one-shot timer
     */
    public void testGetHandle1() throws Exception {
        int duration = 2;
        Simple s = getSimple(random(500000));
        try {
            int id = s.setTimer(duration, 0);
            TimerHandle th = s.getTimerHandle(id);
            assertTrue(th != null);
        } finally {
            s.remove();
        }
    }

    /**
     * Test getHandle on one-shot timer that has expired
     */
    public void testGetExpiredHandle1() throws Exception {
        int duration = 1;
        Simple s = getSimple(random(500000));
        try {
            int id = s.setTimer(duration, 0);
            sleep(3000);
            TimerHandle th = s.getTimerHandle(id);
            assertTrue(th == null);
        } finally {
            s.remove();
        }
    }
}
