/** * Copyright 2015 Nabarun Mondal * 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 com.noga.njexl.testing; import com.noga.njexl.lang.extension.TypeUtility; import com.noga.njexl.lang.extension.iterators.RangeIterator; import com.noga.njexl.testing.dataprovider.DataSource; import com.noga.njexl.testing.dataprovider.DataSourceTable; import com.noga.njexl.testing.dataprovider.ProviderFactory; import com.noga.njexl.testing.reporting.Reporter; import java.lang.reflect.Array; import java.util.*; /** * Created by noga on 17/04/15. */ public abstract class TestSuiteRunner implements Runnable{ public static final String SCRIPT_OUT = "_o_" ; public enum TestRunEventType{ BEFORE_FEATURE, BEFORE_TEST, OK_TEST, ERROR_TEST, ABORT_TEST, IGNORE_TEST, AFTER_FEATURE } public static class TestRunEvent extends EventObject{ public TestRunEventType type ; public final String feature ; public final DataSourceTable table; public final int row; public Object runObject; public Throwable error; public TestRunEvent(Object source,TestRunEventType type, String feature, DataSourceTable table ,int row) { super(source); this.type = type ; this.feature = feature; this.row = row; this.table = table; } } public interface TestRunEventListener{ void onTestRunEvent(TestRunEvent testRunEvent); } public final Set<TestRunEventListener> testRunEventListeners ; protected Set<Reporter> reporters; public static class DataSourceContainer{ public final TestSuite.DataSource suiteDataSource; public final DataSource dataSource; public DataSourceContainer(TestSuite.DataSource ds )throws Exception{ this.suiteDataSource = ds ; dataSource = ProviderFactory.dataSource(suiteDataSource.location); if ( dataSource == null ){ throw new Exception("Can not create data source!"); } } } protected Map<String,DataSourceContainer> dataSources; protected Map<String,TestSuite.DataSource> tsDataSources; protected Map<String,String> relocationVariables; protected TestSuiteRunner(Map<String,String> v){ testRunEventListeners = new HashSet<>(); relocationVariables = v; } protected void fireTestEvent(String feature, TestRunEventType type, DataSourceTable table, int row){ TestRunEvent event = new TestRunEvent( this, type, feature, table, row); fireTestEvent(event); } protected void fireTestEvent(TestRunEvent event){ switch (event.type ){ case ABORT_TEST: aborts.add( event ); break; case ERROR_TEST: errors.add(event); break; default: break; } for (TestRunEventListener listener : testRunEventListeners ){ try { listener.onTestRunEvent( event ); }catch (Throwable t){ System.err.println("Error dispatching event : " + t); } } } protected abstract TestSuite testSuite(); protected abstract TestSuite.Application application(); protected abstract void prepare() throws Exception; protected abstract void beforeFeature(TestSuite.Feature feature) throws Exception; protected abstract String logLocation(String base, TestSuite.Feature feature) ; protected abstract TestRunEvent runTest( TestRunEvent runEvent) throws Exception; protected abstract void afterFeature(TestSuite.Feature feature) throws Exception; protected abstract void shutdown() throws Exception; protected void prepareDSAndReporters() throws Exception { dataSources = new HashMap<>(); tsDataSources = new HashMap<>(); for (TestSuite.DataSource ds : testSuite.dataSources ){ DataSourceContainer container = new DataSourceContainer(ds); dataSources.put( ds.name, container ); } reporters = new HashSet<>(); for (TestSuite.Reporter r : testSuite.reporters ){ Reporter reporter = (Reporter) Utils.createInstance(r.type); reporter.init( r.params ); reporters.add(reporter); } testRunEventListeners.addAll(reporters); aborts = new ArrayList<>(); errors = new ArrayList<>(); } protected void changeLogDirectory(TestSuite.Feature feature){ String timeStamp = Utils.ts(); String logDir = logLocation(timeStamp, feature); for ( Reporter r : reporters ){ r.location(logDir); } } protected DataSourceTable dataSourceTable(TestSuite.Feature feature) { DataSourceContainer container = dataSources.get(feature.ds) ; if ( container == null ){ System.err.printf("No Such data source : [%s]\n",feature.ds); return null; } DataSourceTable table = container.dataSource.tables.get(feature.table); if ( table == null ){ System.err.printf("No Such data table in Data Source : [%s] [%s]\n",feature.table, feature.ds); } return table; } boolean skipTest(TestSuite.Feature feature, int row){ DataSourceContainer container = dataSources.get(feature.ds) ; DataSourceTable t = container.dataSource.tables.get(feature.table); boolean exist = t.columns().containsKey( container.suiteDataSource.testEnableColumn ); if ( !exist ){ return false ; } String value = t.columnValue(container.suiteDataSource.testEnableColumn, row) ; boolean enable = TypeUtility.castBoolean(value, false); return !enable; } protected TestSuite testSuite ; protected Collection<TestRunEvent> aborts; public Collection<TestRunEvent> aborts(){ return aborts; } protected Collection<TestRunEvent> errors; public Collection<TestRunEvent> errors(){ return errors; } @Override public void run() { // get it first... testSuite = testSuite(); try{ prepareDSAndReporters(); prepare(); }catch (Exception e) { System.err.printf("Failed to prepare test Suite! %d\n", e); return; } TestSuite.Application application = application(); for ( int i = 0 ; i < application.features.size() ;i++){ TestSuite.Feature feature = application.features.get(i); if ( !feature.enabled ){ continue; } try{ beforeFeature(feature); }catch (Exception e){ System.err.printf("Error : %s\n Skipping Feature %s\n", e , feature.name ); continue; } changeLogDirectory(feature); fireTestEvent(feature.name,TestRunEventType.BEFORE_FEATURE, null, -1); DataSourceTable table = dataSourceTable(feature); if ( table == null ){ System.err.println("Sorry, can not create data source!"); fireTestEvent(feature.name,TestRunEventType.AFTER_FEATURE, null, -1); } RangeIterator iterator = new RangeIterator( table.length(), 1); List<Long> rows = iterator.list(); if ( feature.randomize ){ TypeUtility.shuffle(rows); } for ( long lRow : rows ){ int row = (int)lRow; boolean skip = skipTest(feature,row) ; if ( skip ){ fireTestEvent(feature.name, TestRunEventType.IGNORE_TEST, table, row); continue; } fireTestEvent(feature.name, TestRunEventType.BEFORE_TEST, table, row); TestRunEvent runEvent = new TestRunEvent(this, TestRunEventType.ERROR_TEST, feature.name, table, row) ; try { runEvent = runTest(runEvent); }catch (Throwable t){ System.err.println(t); runEvent.error = t ; } fireTestEvent(runEvent); } fireTestEvent(feature.name,TestRunEventType.AFTER_FEATURE, null, -1); try{ afterFeature(feature); }catch (Exception e){ continue; } } try{ testRunEventListeners.clear(); shutdown(); }catch (Exception e){ System.err.println(e); return; } } }