Package com.sun.sgs.impl.kernel

Source Code of com.sun.sgs.impl.kernel.TestTransactionSchedulerImpl$DependentTask

/*
* Copyright 2007-2010 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server 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, see <http://www.gnu.org/licenses/>.
*
* --
*/

package com.sun.sgs.impl.kernel;

import com.sun.sgs.app.TaskRejectedException;

import com.sun.sgs.auth.Identity;

import com.sun.sgs.kernel.KernelRunnable;
import com.sun.sgs.kernel.NodeType;
import com.sun.sgs.kernel.TaskQueue;
import com.sun.sgs.kernel.TransactionScheduler;
import com.sun.sgs.kernel.schedule.ScheduledTask;
import com.sun.sgs.kernel.schedule.SchedulerRetryAction;
import com.sun.sgs.kernel.schedule.SchedulerRetryPolicy;

import com.sun.sgs.service.Transaction;
import com.sun.sgs.service.TransactionProxy;

import com.sun.sgs.test.util.SgsTestNode;
import com.sun.sgs.test.util.TestAbstractKernelRunnable;
import com.sun.sgs.tools.test.FilteredNameRunner;

import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import java.lang.reflect.Field;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.*;

import org.junit.runner.RunWith;


/**
* Basic tests for the TransactionScheduler interface. Note that reservation
* and scheduling methods are already tested from the tests specific to the
* {@code ApplicationScheduler}s, so there are no duplicated tests here.
*/
@RunWith(FilteredNameRunner.class)
public class TestTransactionSchedulerImpl {

    private SgsTestNode serverNode = null;
    private TransactionSchedulerImpl txnScheduler;
    private Identity taskOwner;

    public TestTransactionSchedulerImpl() { }

    /** Per-test initialization */
    @Before public void startup() throws Exception {
        Properties properties =
            SgsTestNode.getDefaultProperties("TestTransactionSchedulerImpl",
               null, null);
        properties.setProperty(StandardProperties.NODE_TYPE,
                               NodeType.coreServerNode.name());
        serverNode = new SgsTestNode("TestTransactionSchedulerImpl",
                                     null, properties);
        txnScheduler = (TransactionSchedulerImpl) serverNode.
                getSystemRegistry().getComponent(TransactionScheduler.class);
        taskOwner = serverNode.getProxy().getCurrentOwner();
    }

    /** Per-test shutdown */
    @After public void shutdown() throws Exception {
        if (serverNode != null)
            serverNode.shutdown(true);
    }

    /**
     * Test runTask.
     */

    @Test (expected=NullPointerException.class)
        public void runTaskNullTask() throws Exception {
        txnScheduler.runTask(null, taskOwner);
    }

    @Test (expected=NullPointerException.class)
        public void runTaskNullOwner() throws Exception {
        txnScheduler.runTask(new TestAbstractKernelRunnable() {
                public void run() {}
            }, null);
    }

    @Test public void runTaskSingleTask() throws Exception {
        RunCountTestRunner runner = new RunCountTestRunner(1);
        txnScheduler.runTask(runner, taskOwner);
        assertEquals(0, runner.getRunCount());
    }

    @Test public void scheduleSingleTask() throws Exception {
        RunCountTestRunner runner = new RunCountTestRunner(1);
        txnScheduler.scheduleTask(runner, taskOwner);
        Thread.sleep(500L);
        assertEquals(0, runner.getRunCount());
    }

    @Test public void runTaskMultipleTasks() throws Exception {
        RunCountTestRunner runner = new RunCountTestRunner(4);
        txnScheduler.runTask(runner, taskOwner);
        assertEquals(3, runner.getRunCount());
        txnScheduler.runTask(runner, taskOwner);
        assertEquals(2, runner.getRunCount());
        txnScheduler.runTask(runner, taskOwner);
        assertEquals(1, runner.getRunCount());
        txnScheduler.runTask(runner, taskOwner);
        assertEquals(0, runner.getRunCount());
    }

    @Test public void runTaskTransactional() throws Exception {
        final TransactionProxy proxy = serverNode.getProxy();
        txnScheduler.runTask(new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    proxy.getCurrentTransaction();
                    proxy.getCurrentOwner();
                }
            }, taskOwner);
    }

    @Test public void runTransactionInTransaction() throws Exception {
        final TransactionProxy proxy = serverNode.getProxy();
        KernelRunnable task = new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    final Transaction t = proxy.getCurrentTransaction();
                    txnScheduler.runTask(new TestAbstractKernelRunnable() {
                            public void run() throws Exception {
                                Transaction t2 = proxy.getCurrentTransaction();
                                assertTrue(t.equals(t2));
                            }
                        }, taskOwner);
                }
            };
        txnScheduler.runTask(task, taskOwner);
    }

    @Test public void runTransactionFromScheduledTask() throws Exception {
        final RunCountTestRunner countRunner = new RunCountTestRunner(1);
        KernelRunnable task = new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    txnScheduler.runTask(countRunner, taskOwner);
                }
            };
        txnScheduler.scheduleTask(task, taskOwner);
        Thread.sleep(500L);
        assertEquals(0, countRunner.getRunCount());
    }

    /**
     * Test runUnboundedTask
     */
    @Test (expected=NullPointerException.class)
    public void runUnboundedTaskNullTask() throws Exception {
        txnScheduler.runUnboundedTask(null, taskOwner);
    }

    @Test (expected=NullPointerException.class)
    public void runUnboundedTaskNullOwner() throws Exception {
        txnScheduler.runUnboundedTask(new TestAbstractKernelRunnable() {
            public void run() {
            }
        }, null);
    }

    @Test
    public void runUnboundedTaskSingleTask() throws Exception {
        RunCountTestRunner runner = new RunCountTestRunner(1);
        txnScheduler.runUnboundedTask(runner, taskOwner);
        assertEquals(0, runner.getRunCount());
    }

    @Test(timeout=2000)
    public void runUnboundedTaskLongTransaction() throws Exception {
        LongTransactionRunner runner = new LongTransactionRunner(1000L);
        txnScheduler.runUnboundedTask(runner, taskOwner);
        assertTrue(runner.isFinished());
    }


    /**
     * Test interruption.
     */

    @Test public void scheduleTransactionRetryAfterInterrupt()
        throws Exception
    {
        final AtomicInteger i = new AtomicInteger(0);
        final KernelRunnable r = new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    if (i.getAndIncrement() == 0)
                        throw new InterruptedException("test");
                }
            };
        txnScheduler.scheduleTask(r, taskOwner);
        Thread.sleep(200L);
        assertEquals(i.get(), 2);
    }

    @Test public void runTransactionInterrupted() throws Exception {
        final AtomicInteger i = new AtomicInteger(0);
        final KernelRunnable r = new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    if (i.getAndIncrement() == 0)
                        throw new InterruptedException("test");
                }
            };
        try {
            txnScheduler.runTask(r, taskOwner);
            fail("Expected Interrupted Exception");
        } catch (InterruptedException ie) {}
        assertEquals(i.get(), 1);
    }

    /**
     * Test transaction handling.
     */

    @Test public void runTaskWithRetry() throws Exception {
        RetryTestRunner runner = new RetryTestRunner();
        txnScheduler.runTask(runner, taskOwner);
        assertTrue(runner.isFinished());
    }

    @Test (expected=RuntimeException.class)
        public void runNonRetriedTask() throws Exception {
        txnScheduler.runTask(new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    throw new RuntimeException("intentionally thrown");
                }
            }, taskOwner);
    }

    @Test (expected=RuntimeException.class)
        public void runNonRetriedTaskExplicitAbort() throws Exception {
        final TransactionProxy proxy = serverNode.getProxy();
        txnScheduler.runTask(new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    RuntimeException re = new RuntimeException("intentional");
                    proxy.getCurrentTransaction().abort(re);
                    throw re;
                }
            }, taskOwner);
    }

    @Test (expected=Error.class)
        public void testRunTransactionThrowsError() throws Exception {
        txnScheduler.runTask(new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    throw new Error("intentionally thrown");
                }
            }, taskOwner);
    }

    /**
     * Test createTaskQueue.
     */

    @Test public void scheduleQueuedTasks() throws Exception {
        TaskQueue queue = txnScheduler.createTaskQueue();
        AtomicInteger runCount = new AtomicInteger(0);
        for (int i = 0; i < 10; i++)
            queue.addTask(new DependentTask(runCount), taskOwner);
        Thread.sleep(500L);
        assertEquals(10, runCount.get());
    }

    @Test (expected=NullPointerException.class)
        public void scheduleQueuedTasksNull() throws Exception {
        TaskQueue queue = txnScheduler.createTaskQueue();
        queue.addTask(null, taskOwner);
    }

    @Test (expected=NullPointerException.class)
        public void scheduleQueuedTasksOwnerNull() throws Exception {
        TaskQueue queue = txnScheduler.createTaskQueue();
        queue.addTask(new DependentTask(null), null);
    }

    /**
     * Test retry policy
     */

    @Test public void dropFailedTask() throws Exception {
        final Exception result = new Exception("task failed");
        replaceRetryPolicy(createRetryPolicy(SchedulerRetryAction.DROP));
        final AtomicInteger i = new AtomicInteger(0);
        final KernelRunnable r = new TestAbstractKernelRunnable() {
            public void run() throws Exception {
                if (i.getAndIncrement() == 0)
                    throw result;
            }
        };
        try {
            txnScheduler.runTask(r, taskOwner);
            fail("expected Exception");
        } catch(Exception e) {
            assertEquals(result, e);
        } finally {
            assertEquals(i.get(), 1);
        }
    }

    @Test public void retryFailedTask() throws Exception {
        final Exception result = new Exception("task failed");
        replaceRetryPolicy(createRetryPolicy(SchedulerRetryAction.RETRY_NOW));
        final AtomicInteger i = new AtomicInteger(0);
        final KernelRunnable r = new TestAbstractKernelRunnable() {
            public void run() throws Exception {
                if (i.getAndIncrement() == 0)
                    throw result;
            }
        };
        txnScheduler.runTask(r, taskOwner);
        assertEquals(i.get(), 2);
    }

    @Test public void handoffFailedTask() throws Exception {
        final Exception result = new Exception("task failed");
        replaceRetryPolicy(createRetryPolicy(SchedulerRetryAction.RETRY_LATER));
        final AtomicInteger i = new AtomicInteger(0);
        final KernelRunnable r = new TestAbstractKernelRunnable() {
            public void run() throws Exception {
                if (i.getAndIncrement() == 0)
                    throw result;
            }
        };
        txnScheduler.runTask(r, taskOwner);
        assertEquals(i.get(), 2);
    }

    /**
     * Utility methods.
     */

    private void replaceRetryPolicy(SchedulerRetryPolicy policy)
            throws Exception {
        Field policyField =
              TransactionSchedulerImpl.class.getDeclaredField("retryPolicy");
        policyField.setAccessible(true);
        policyField.set((TransactionSchedulerImpl) txnScheduler, policy);
    }

    private SchedulerRetryPolicy createRetryPolicy(final SchedulerRetryAction action) {
        return new SchedulerRetryPolicy() {
            public SchedulerRetryAction getRetryAction(ScheduledTask task) {
                return action;
            }
        };
    }

    /**
     * Utility classes.
     */

    private class LongTransactionRunner implements KernelRunnable {
        private boolean finished = false;
        private long sleep = 0;
        LongTransactionRunner(long sleep) {
            this.sleep = sleep;
        }
        public String getBaseTaskType() {
            return LongTransactionRunner.class.getName();
        }
        public void run() throws Exception {
            Thread.sleep(sleep);
            finished = true;
            serverNode.getProxy().getCurrentTransaction();
        }
        public boolean isFinished() {
            return finished;
        }
    }

    private class RunCountTestRunner implements KernelRunnable {
        private int runCount;
        RunCountTestRunner(int initialCount) {
            this.runCount = initialCount;
        }
        public String getBaseTaskType() {
            return RunCountTestRunner.class.getName();
        }
        public void run() throws Exception {
            runCount--;
        }
        int getRunCount() {
            return runCount;
        }
    }

    private class RetryTestRunner implements KernelRunnable {
        private boolean hasRun = false;
        private boolean finished = false;
        public String getBaseTaskType() {
            return RetryTestRunner.class.getName();
        }
        public void run() throws Exception {
            if (! hasRun) {
                hasRun = true;
                throw new TaskRejectedException("test");
            }
            finished = true;
        }
        public boolean isFinished() {
            return finished;
        }
    }

    public static class DependentTask implements KernelRunnable {
        private static final Object lock = new Object();
        private static boolean isRunning = false;
        private static int objNumberSequence = 0;
        private static volatile int nextExpectedObjNumber = 0;
        private final int objNumber;
        private final AtomicInteger runCounter;
        public DependentTask(AtomicInteger runCounter) {
            synchronized (lock) {
                objNumber = objNumberSequence++;
            }
            this.runCounter = runCounter;
        }
        public String getBaseTaskType() {
            return DependentTask.class.getName();
        }
        public void run() throws Exception {
            synchronized (lock) {
                if (isRunning)
                    throw new RuntimeException("another task was running");
                isRunning = true;
            }
            if (nextExpectedObjNumber != objNumber)
                throw new RuntimeException("tasks ran out-of-order");
            nextExpectedObjNumber++;
            runCounter.incrementAndGet();
            isRunning = false;
        }
    }
}
TOP

Related Classes of com.sun.sgs.impl.kernel.TestTransactionSchedulerImpl$DependentTask

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.