/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2013 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ package org.pentaho.di.job; import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.pentaho.di.core.database.util.DatabaseLogExceptionFactory; import org.pentaho.di.core.exception.KettleXMLException; import org.pentaho.di.core.gui.JobTracker; import org.pentaho.di.core.logging.LogLevel; import org.pentaho.di.core.parameters.UnknownParamException; @RunWith( value = Parameterized.class ) public class JobTrackerExecutionTest extends JobTrackerExecution { private Result res; public JobTrackerExecutionTest( Result res ) { this.res = res; } /** * Simulates log table exception at job start 5 cases: not set, set at kettle-variables (2) or kettle.properties (2) * * @return */ private static Result[] testJobStartLogException() { // this is default behavior out of the box Result res = new Result(); res.fileName = "log_job_1.kjb"; res.assertMessage = "[1] Log exception at start and end job execution: Job trackers shows positive result for all records."; res.jobTrackerStatus = new Boolean[] { null, null, true, null, true, true }; // this is when kettle.properties key-value is set false Result resVarNotDef = new Result(); resVarNotDef.fileName = "log_job_1.kjb"; resVarNotDef.assertMessage = "[1-1] Log exception at start and end job execution: Job trackers shows positive result for all records."; resVarNotDef.jobTrackerStatus = new Boolean[] { null, null, true, null, true, true }; resVarNotDef.setAsVariable = false; // this is when kettle.properties key-value is set to true Result resVarDefTrue = new Result(); resVarDefTrue.fileName = "log_job_1.kjb"; resVarDefTrue.assertMessage = "[1-2] Log exception at start and end job execution: Job trackers shows negative result, job is failed."; resVarDefTrue.jobTrackerStatus = new Boolean[] { null, false }; resVarDefTrue.setAsVariable = true; return new Result[] { res, resVarNotDef, resVarDefTrue }; } /** * Simulates log table issue at job start and job end * * @return */ private static Result[] testJobEndLogException() { Result res = new Result(); res.fileName = "log_job_2.kjb"; res.assertMessage = "[2] Log exception at end only: Job trackers shows positive result for all records."; res.jobTrackerStatus = new Boolean[] { null, null, true, null, true, true }; Result resVarFalse = new Result(); resVarFalse.fileName = "log_job_2.kjb"; resVarFalse.assertMessage = "[2-1] Log exception at end only: Job trackers shows positive result for all records."; resVarFalse.jobTrackerStatus = new Boolean[] { null, null, true, null, true, true }; resVarFalse.setAsVariable = false; Result resParFalse = new Result(); resParFalse.fileName = "log_job_2.kjb"; resParFalse.assertMessage = "[2-2] Log exception at end only: Job trackers shows negative result, job failed"; resParFalse.jobTrackerStatus = new Boolean[] { null, null, true, null, true, true, false }; resParFalse.setAsVariable = true; return new Result[] { res, resVarFalse, resParFalse }; } /** * Simulates log table issue when job has child job, and child job throws exception * * @return */ private static Result[] testJobLogCallerAtStartLogException() { Result res = new Result(); res.fileName = "log_job_1_caller.kjb"; res.assertMessage = "[3] Log exception at start (see [1] log_job_1.kjb results) in job call from parent job: " + "Job trackers shows positive result for all records."; res.jobTrackerStatus = new Boolean[] { null, null, true, null, null, true, null, true, true }; Result resVarFalse = new Result(); resVarFalse.fileName = "log_job_1_caller.kjb"; resVarFalse.assertMessage = "[3-1] Log exception at start (see [1] log_job_1.kjb results) in job call from parent job: " + "Job trackers shows positive result for all records."; resVarFalse.jobTrackerStatus = new Boolean[] { null, null, true, null, null, true, null, true, true }; resVarFalse.setAsVariable = false; Result resParFalse = new Result(); resParFalse.fileName = "log_job_1_caller.kjb"; resParFalse.assertMessage = "[3-2] Log exception at start (see [1] log_job_1.kjb results) in job call from parent job: " + "Job trackers shows negative result, job failed."; resParFalse.jobTrackerStatus = new Boolean[] { null, null, true, null, null, false, null, false, false }; resParFalse.setAsVariable = true; return new Result[] { res, resVarFalse, resParFalse }; } /** * Simulates log table issue when job has child job and child job throws exception at the end of his execution * * @return */ private static Result[] testJobLogCallerAtEndLogException() { Result res = new Result(); res.fileName = "log_job_2_caller.kjb"; res.assertMessage = "[4] Log exception at end (see [1] log_job_2.kjb results) in job call from parent job: " + "Job trackers shows positive result for all records."; res.jobTrackerStatus = new Boolean[] { null, null, true, null, null, true, null, true, true }; Result resFalse = new Result(); resFalse.fileName = "log_job_2_caller.kjb"; resFalse.assertMessage = "[4-1] Log exception at end (see [1] log_job_2.kjb results) in job call from parent job: " + "Job trackers shows positive result for all records."; resFalse.jobTrackerStatus = new Boolean[] { null, null, true, null, null, true, null, true, true }; resFalse.setAsVariable = false; Result resTrue = new Result(); resTrue.fileName = "log_job_2_caller.kjb"; resTrue.assertMessage = "[4-2] Log exception at end (see [1] log_job_2.kjb results) in job call from parent job: " + "Job trackers shows negative result, job failed."; resTrue.jobTrackerStatus = new Boolean[] { null, null, true, null, null, false, null, false, false }; resTrue.setAsVariable = true; return new Result[] { /* res, resFalse, */resTrue, res, resFalse }; } /** * Simulates log table issue at trans start and trans end. Trans is called form parent job. * * @return */ private static Result[] testJobLogTransCallerStartException() { Result res = new Result(); res.fileName = "log_trans_1_caller.kjb"; res.assertMessage = "[5] Log exception at transformation start and end when it was called by job: " + "Job trackers shows positive result for all records."; res.jobTrackerStatus = new Boolean[] { null, null, true, null, true, null, true, true }; Result resFalse = new Result(); resFalse.fileName = "log_trans_1_caller.kjb"; resFalse.assertMessage = "[5-1] Log exception at transformation start and end when it was called by job: " + "Job trackers shows positive result for all records."; resFalse.jobTrackerStatus = new Boolean[] { null, null, true, null, true, null, true, true }; resFalse.setAsVariable = false; Result resTrue = new Result(); resTrue.fileName = "log_trans_1_caller.kjb"; resTrue.assertMessage = "[5-2] Log exception at transformation start and end when it was called by job: " + "Job trackers shows negative result, job failed."; resTrue.jobTrackerStatus = new Boolean[] { null, null, true, null, false, null, false, false }; resTrue.setAsVariable = true; return new Result[] { res, resFalse, resTrue }; } /** * Simulates log table issue at trans end when transaction is called by parent job. * * @return */ private static Result[] testJobLogTransCallerEndException() { Result res = new Result(); res.fileName = "log_trans_2_caller.kjb"; res.assertMessage = "[6] Log exception at transformation and end when it was called by job: " + "Job trackers shows positive result for all records."; res.jobTrackerStatus = new Boolean[] { null, null, true, null, true, null, true, true }; Result resFalse = new Result(); resFalse.fileName = "log_trans_2_caller.kjb"; resFalse.assertMessage = "[6-1] Log exception at transformation and end when it was called by job: " + "Job trackers shows positive result for all records."; resFalse.jobTrackerStatus = new Boolean[] { null, null, true, null, true, null, true, true }; resFalse.setAsVariable = false; Result resTrue = new Result(); resTrue.fileName = "log_trans_2_caller.kjb"; resTrue.assertMessage = "[6-2] Log exception at transformation and end when it was called by job: " + "Job trackers shows negative result, job failed."; resTrue.jobTrackerStatus = new Boolean[] { null, null, true, null, false, null, false, false }; resTrue.setAsVariable = true; return new Result[] { res, resFalse, resTrue }; } /** * Test data provider. For better readability test data generation is moved to isolated methods. Every method call * generates Object with unique test data and test results. See specific methods javadoc for details. * * @return */ @Parameters public static List<Result[]> data() { ArrayList<Result> results = new ArrayList<Result>(); results.addAll( Arrays.asList( testJobLogCallerAtEndLogException() ) ); results.addAll( Arrays.asList( testJobStartLogException() ) ); results.addAll( Arrays.asList( testJobEndLogException() ) ); results.addAll( Arrays.asList( testJobLogCallerAtStartLogException() ) ); results.addAll( Arrays.asList( testJobLogTransCallerStartException() ) ); results.addAll( Arrays.asList( testJobLogTransCallerEndException() ) ); results.trimToSize(); Result[][] data = new Result[results.size()][1]; for ( int i = 0; i < results.size(); i++ ) { data[i][0] = results.get( i ); } return Arrays.asList( data ); } @Test public void testJobTracker() throws UnknownParamException, KettleXMLException, URISyntaxException, IOException { if ( res.setAsVariable != null ) { System.getProperties().setProperty( DatabaseLogExceptionFactory.KETTLE_GLOBAL_PROP_NAME, res.setAsVariable.toString() ); } try { Job job = new Job( null, getJobMeta( res.fileName ) ); job.setLogLevel( LogLevel.BASIC ); job.start(); job.waitUntilFinished(); // this simulates - Spoon 'Job Metrics' tab attempt to refresh: JobTracker tracker = job.getJobTracker(); List<JobTracker> trackers = tracker.getJobTrackers(); Assert.assertEquals( "Job trackers count is correct: " + res.assertMessage, res.jobTrackerStatus.length, trackers .size() ); for ( int i = 0; i < res.jobTrackerStatus.length; i++ ) { JobTracker record = trackers.get( i ); Boolean actual; JobEntryResult jer = record.getJobEntryResult(); // don't look into nested JobTrackers if ( jer == null ) { actual = null; } else { actual = record.getJobEntryResult().getResult() == null ? null : Boolean.valueOf( record.getJobEntryResult() .getResult().getResult() ); } Assert.assertEquals( res.assertMessage + ": " + i, res.jobTrackerStatus[i], actual ); } } finally { System.getProperties().remove( DatabaseLogExceptionFactory.KETTLE_GLOBAL_PROP_NAME ); } } private static class Result { /** * filename of job to reproduce issue */ String fileName; /** * assert message for fine grained report */ String assertMessage; /** * array illustrates job tracker with boolean value of specific job tracker record result */ Boolean[] jobTrackerStatus; /** * when value is overridden (for example when user wants to edit default value - it will be set in * kettle.properties.) */ Boolean setAsVariable = null; } }