/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2010 Oracle and/or its affiliates. All rights reserved. * * Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. * * Contributor(s): * * Portions Copyrighted 2008 Sun Microsystems, Inc. */ package org.netbeans.modules.ruby.testrunner; import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.event.ChangeListener; import org.netbeans.api.extexecution.ExecutionDescriptor; import org.netbeans.api.extexecution.ExecutionService; import org.netbeans.modules.gsf.testrunner.api.Manager; import org.netbeans.modules.gsf.testrunner.api.RerunHandler; import org.netbeans.modules.gsf.testrunner.api.RerunType; import org.netbeans.modules.gsf.testrunner.api.TestSession; import org.netbeans.modules.gsf.testrunner.api.Testcase; import org.netbeans.modules.ruby.platform.execution.RubyExecutionDescriptor; import org.netbeans.modules.ruby.platform.execution.RubyProcessCreator; import org.netbeans.modules.ruby.testrunner.ui.TestHandlerFactory; import org.netbeans.modules.ruby.testrunner.ui.TestRunnerInputProcessorFactory; import org.netbeans.modules.ruby.testrunner.ui.TestRunnerLineConvertor; import org.openide.LifecycleManager; import org.openide.util.ChangeSupport; import org.openide.util.Exceptions; import org.openide.util.RequestProcessor; /** * Handles running and re-running of test executions. * * <i>This class will probably not be needed after migrating to the new Execution API</i> * * @author Erno Mononen */ public final class TestExecutionManager implements RerunHandler { private final static Logger LOGGER = Logger.getLogger(TestExecutionManager.class.getName()); /** * The current execution. */ private ExecutionService execution; private Future<Integer> result; /** * Indicates whether the current execution has finished. */ private boolean finished; private TestRunnerLineConvertor outConvertor, errConvertor; private TestRunnerInputProcessorFactory outFactory, errFactory; private final ChangeSupport changeSupport = new ChangeSupport(this); private final RequestProcessor testExecutionProcessor = new RequestProcessor("Ruby Test Execution Processor"); //NOI18N private static final TestExecutionManager INSTANCE = new TestExecutionManager(); private TestExecutionManager() { } public static TestExecutionManager getInstance() { return INSTANCE; } synchronized void finish() { setFinished(true); } synchronized void reset() { this.finished = false; } /** * Inits our TestExecutionManager with the given RubyExecution. Does not * run the execution. * * @param rubyDescriptor */ synchronized void init(RubyExecutionDescriptor rubyDescriptor) { RubyProcessCreator rpc = new RubyProcessCreator(rubyDescriptor); ExecutionDescriptor descriptor = rubyDescriptor.toExecutionDescriptor(); execution = ExecutionService.newService(rpc, descriptor, rubyDescriptor.getDisplayName()); } /** * Starts a RubyExecution with the given executionDescriptor and testRecognizer. * * @param executionDescriptor * @param testRecognizer */ synchronized void start(RubyExecutionDescriptor rubyDescriptor, TestHandlerFactory handlerFactory, TestSession session) { setFinished(false); session.setRerunHandler(this); final Manager manager = Manager.getInstance(); outConvertor = new TestRunnerLineConvertor(manager, session, handlerFactory); errConvertor = new TestRunnerLineConvertor(manager, session, handlerFactory); session.setOutputLineHandler(new RubyOutputLineHandler(session.getFileLocator())); rubyDescriptor.addOutConvertor(outConvertor); rubyDescriptor.addErrConvertor(errConvertor); outFactory = new TestRunnerInputProcessorFactory(manager, session, handlerFactory.printSummary()); errFactory = new TestRunnerInputProcessorFactory(manager, session, false); rubyDescriptor.setOutProcessorFactory(outFactory); rubyDescriptor.setErrProcessorFactory(errFactory); rubyDescriptor.lineBased(true); RubyProcessCreator rpc = new RubyProcessCreator(rubyDescriptor); final Runnable oldPostExecutionHook = rubyDescriptor.getPostBuild(); ExecutionDescriptor descriptor = rubyDescriptor.toExecutionDescriptor() .postExecution(new Runnable() { public void run() { refresh(); if (oldPostExecutionHook != null) { oldPostExecutionHook.run(); } } }); execution = ExecutionService.newService(rpc, descriptor, rubyDescriptor.getDisplayName()); runExecution(); } private void runExecution() { result = execution.run(); testExecutionProcessor.post(new Runnable() { public void run() { try { result.get(); } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } catch (ExecutionException ex) { Exceptions.printStackTrace(ex); } catch (CancellationException ex) { // ignore } setFinished(result.isDone()); } }); } /** * Checks whether the current execution is finished. * * @return true if the current execution has finished, * false otherwise. */ public synchronized boolean enabled() { return finished || (result != null && result.isDone()); } // gsf.testrunner 1.16: public synchronized boolean enabled(RerunType type) { return RerunType.ALL.equals(type) && (finished || (result != null && result.isDone())); } private void setFinished(boolean finished) { this.finished = finished; changeSupport.fireChange(); } /** * Re-runs the last run test execution. */ public synchronized void rerun() { assert enabled(RerunType.ALL); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Re-running: " + execution); } refresh(); setFinished(false); LifecycleManager.getDefault().saveAll(); runExecution(); } // gsf.testrunner 1.16: public void rerun(Set<Testcase> tests) { //not implemented yet } public void addChangeListener(ChangeListener listener) { changeSupport.addChangeListener(listener); } public void removeChangeListener(ChangeListener listener) { changeSupport.removeChangeListener(listener); } /** * Refreshes the current session, i.e. clears all currently * computed test statuses. */ public synchronized void refresh() { // uh. this is a pretty brain-dead approach; should // redesign the whole test session thing so that "refreshing" // wouldn't be needed in the first place TestSession newSession = null; if (outConvertor != null) { newSession = outConvertor.refreshSession(); } if (errConvertor != null) { errConvertor.refreshSession(); } if (newSession != null && outFactory != null) { outFactory.refreshSession(newSession); } if (newSession != null && errFactory != null) { errFactory.refreshSession(newSession); } } }