/* * ProActive Parallel Suite(TM): * The Open Source library for parallel and distributed * Workflows & Scheduling, Orchestration, Cloud Automation * and Big Data Analysis on Enterprise Grids & Clouds. * * Copyright (c) 2007 - 2017 ActiveEon * Contact: contact@activeeon.com * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation: version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * If needed, contact us to obtain a release under GPL Version 2 or 3 * or a different license than the AGPL. */ package functionaltests.jmx; import static org.junit.Assert.assertEquals; import java.io.Serializable; import java.util.HashMap; import java.util.List; import javax.management.JMX; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import org.junit.Assert; import org.junit.Test; import org.ow2.proactive.jmx.naming.JMXTransportProtocol; import org.ow2.proactive.scheduler.common.JobFilterCriteria; import org.ow2.proactive.scheduler.common.Scheduler; import org.ow2.proactive.scheduler.common.SchedulerAuthenticationInterface; import org.ow2.proactive.scheduler.common.SchedulerState; import org.ow2.proactive.scheduler.common.job.JobId; import org.ow2.proactive.scheduler.common.job.JobInfo; import org.ow2.proactive.scheduler.common.job.JobState; import org.ow2.proactive.scheduler.common.job.TaskFlowJob; import org.ow2.proactive.scheduler.common.task.JavaTask; import org.ow2.proactive.scheduler.common.task.OnTaskError; import org.ow2.proactive.scheduler.common.task.ParallelEnvironment; import org.ow2.proactive.scheduler.common.task.TaskResult; import org.ow2.proactive.scheduler.common.task.executable.JavaExecutable; import org.ow2.proactive.scheduler.core.jmx.SchedulerJMXHelper; import org.ow2.proactive.scheduler.core.jmx.mbean.RuntimeDataMBean; import functionaltests.utils.SchedulerFunctionalTestNoRestart; import functionaltests.utils.TestUsers; /** * Test against SCHEDULING-1676 . * <p> * Test checks that RuntimeDataMBean reports correct tasks number in * case if task was restarted after failure. * * @author ProActive team * */ public class SchedulerRuntimeDataMBeanTest extends SchedulerFunctionalTestNoRestart { public static class FailingTestJavaTask extends JavaExecutable { @Override public Serializable execute(TaskResult... results) throws Throwable { throw new Exception("Test exception"); } } @Test public void test() throws Exception { testAsAdmin(); testAsUser(); } private void testAsAdmin() throws Exception { final SchedulerAuthenticationInterface auth = schedulerHelper.getSchedulerAuth(); final HashMap<String, Object> env = new HashMap<>(1); env.put(JMXConnector.CREDENTIALS, new Object[] { TestUsers.DEMO.username, TestUsers.DEMO.password }); JMXConnector adminJmxConnector = JMXConnectorFactory.connect(new JMXServiceURL(auth.getJMXConnectorURL(JMXTransportProtocol.RMI)), env); List<JobInfo> existingFinishedJobs = schedulerHelper.getSchedulerInterface() .getJobs(0, 1000, new JobFilterCriteria(false, false, true, true), null) .getList(); int nbFinishedTasks = 0; int nbTotalTasks = 0; for (JobInfo existingFinishedJob : existingFinishedJobs) { nbFinishedTasks += existingFinishedJob.getNumberOfFinishedTasks(); nbTotalTasks += existingFinishedJob.getTotalNumberOfTasks(); } try { MBeanServerConnection connection = adminJmxConnector.getMBeanServerConnection(); final ObjectName beanName = new ObjectName(SchedulerJMXHelper.RUNTIMEDATA_MBEAN_NAME); RuntimeDataMBean bean = JMX.newMXBeanProxy(connection, beanName, RuntimeDataMBean.class); checkDataConsistent(bean); JobId jobId; jobId = schedulerHelper.submitJob(createJobWithFailingTask()); schedulerHelper.waitForEventTaskWaitingForRestart(jobId, "task1"); checkDataConsistent(bean); schedulerHelper.waitForEventTaskWaitingForRestart(jobId, "task1"); checkDataConsistent(bean); schedulerHelper.waitForEventJobFinished(jobId, 60000); checkDataConsistent(bean); checkTasksData(bean, 0, 0, 1 + nbFinishedTasks, 1 + nbTotalTasks); checkJobData(bean, jobId); jobId = schedulerHelper.submitJob(createJobWithMultinodeTask(100)); Thread.sleep(5000); checkDataConsistent(bean); checkTasksData(bean, 1, 0, 1 + nbFinishedTasks, 2 + nbTotalTasks); schedulerHelper.getSchedulerInterface().killJob(jobId); checkDataConsistent(bean); checkTasksData(bean, 0, 0, 1 + nbFinishedTasks, 2 + nbTotalTasks); } finally { adminJmxConnector.close(); } } private void testAsUser() throws Exception { final SchedulerAuthenticationInterface auth = schedulerHelper.getSchedulerAuth(); final HashMap<String, Object> env = new HashMap<>(1); env.put(JMXConnector.CREDENTIALS, new Object[] { TestUsers.USER.username, TestUsers.USER.password }); JMXConnector userJmxConnector = JMXConnectorFactory.connect(new JMXServiceURL(auth.getJMXConnectorURL(JMXTransportProtocol.RMI)), env); try { MBeanServerConnection connection = userJmxConnector.getMBeanServerConnection(); final ObjectName beanName = new ObjectName(SchedulerJMXHelper.RUNTIMEDATA_MBEAN_NAME); RuntimeDataMBean bean = JMX.newMXBeanProxy(connection, beanName, RuntimeDataMBean.class); checkDataConsistent(bean); } finally { userJmxConnector.close(); } } private void checkJobData(RuntimeDataMBean bean, JobId jobId) throws Exception { JobState jobState = schedulerHelper.getSchedulerInterface().getJobState(jobId); long pendingTime = bean.getJobPendingTime(jobId.value()); long runningTime = bean.getJobRunningTime(jobId.value()); assertEquals("Unexpected pending time", jobState.getStartTime() - jobState.getSubmittedTime(), pendingTime); assertEquals("Unexpected running time", jobState.getFinishedTime() - jobState.getStartTime(), runningTime); assertEquals("Unexpected nodes number", 1, bean.getTotalNumberOfNodesUsed(jobId.value())); bean.getMeanTaskPendingTime(jobId.value()); bean.getMeanTaskRunningTime(jobId.value()); } private void checkTasksData(RuntimeDataMBean bean, int pendingTasks, int runningTasks, int finishedTasks, int totalTasks) throws Exception { int pending = bean.getPendingTasksCount(); int running = bean.getRunningTasksCount(); int finished = bean.getFinishedTasksCount(); int total = bean.getTotalTasksCount(); assertEquals("Invalid pending tasks", pendingTasks, pending); assertEquals("Invalid running tasks", runningTasks, running); assertEquals("Invalid finished tasks", finishedTasks, finished); assertEquals("Invalid total tasks", totalTasks, total); } private void checkDataConsistent(RuntimeDataMBean bean) throws Exception { Scheduler scheduler = schedulerHelper.getSchedulerInterface(); int pendingJobs = bean.getPendingJobsCount(); int runningJobs = bean.getRunningJobsCount(); int finishedJobs = bean.getFinishedJobsCount(); int totalJobs = bean.getTotalJobsCount(); int pendingTasks = bean.getPendingTasksCount(); int runningTasks = bean.getRunningTasksCount(); int finishedTasks = bean.getFinishedTasksCount(); int totalTasks = bean.getTotalTasksCount(); System.out.println("Jobs: pending: " + pendingJobs + ", running: " + runningJobs + " " + ", finished " + finishedJobs + ", total: " + totalJobs); System.out.println("Tasks: pending: " + pendingTasks + ", running: " + runningTasks + ", finished " + finishedTasks + ", total " + totalTasks); SchedulerState state = scheduler.getState(); assertEquals(state.getPendingJobs().size(), bean.getPendingJobsCount()); assertEquals(state.getRunningJobs().size(), bean.getRunningJobsCount()); assertEquals(state.getFinishedJobs().size(), bean.getFinishedJobsCount()); assertEquals(bean.getPendingJobsCount() + bean.getRunningJobsCount() + bean.getFinishedJobsCount(), bean.getTotalJobsCount()); Assert.assertTrue("Invalid pending tasks: " + pendingTasks, pendingTasks >= 0); Assert.assertTrue("Invalid running tasks: " + runningTasks, runningTasks >= 0); Assert.assertTrue("Invalid finished tasks: " + finishedTasks, finishedTasks >= 0); } private TaskFlowJob createJobWithFailingTask() throws Exception { TaskFlowJob job = new TaskFlowJob(); job.setName(this.getClass().getSimpleName() + "_FailingTask"); job.setOnTaskError(OnTaskError.CONTINUE_JOB_EXECUTION); JavaTask task = new JavaTask(); task.setExecutableClassName(FailingTestJavaTask.class.getName()); task.setName("task1"); task.setMaxNumberOfExecution(3); task.setOnTaskError(OnTaskError.NONE); job.addTask(task); return job; } private TaskFlowJob createJobWithMultinodeTask(int nodes) throws Exception { TaskFlowJob job = new TaskFlowJob(); job.setName(this.getClass().getSimpleName() + "_MultinodeTask"); JavaTask task = new JavaTask(); task.setExecutableClassName(FailingTestJavaTask.class.getName()); task.setName("task1"); ParallelEnvironment env = new ParallelEnvironment(nodes); task.setParallelEnvironment(env); job.addTask(task); return job; } }