/* * $Id$ * * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.javatest; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.*; import com.sun.interview.ErrorQuestion; import com.sun.interview.FinalQuestion; import com.sun.interview.Interview; import com.sun.interview.Question; import com.sun.javatest.tool.CustomPropagationController; import com.sun.javatest.tool.FileHistory; import com.sun.javatest.util.BackupPolicy; import com.sun.javatest.util.I18NResourceBundle; import com.sun.javatest.util.Properties; /** * Configuration parameters provided via an interview. * * @since 3.0 */ public abstract class InterviewParameters extends Interview implements Parameters { /** * Indicates problems when accessing the work directory. */ public static class WorkDirFault extends Interview.Fault { /** * Create a fault with an internationalized message. * @param i18n The bundle from which to get the string. * @param s The key for getting the string to be displayed from the * supplied bundle. */ public WorkDirFault(ResourceBundle i18n, String s) { super(i18n, s); } /** * Create a fault with an internationalized message. * @param i18n The bundle from which to get the string. * @param s The key for getting the string to be displayed from the * supplied bundle. * @param o Parameter to use when resolving the string from the bundle. * @see java.text.MessageFormat */ public WorkDirFault(ResourceBundle i18n, String s, Object o) { super(i18n, s, o); } /** * Create a fault with an internationalized message. * @param i18n The bundle from which to get the string. * @param s The key for getting the string to be displayed from the * supplied bundle. * @param o Parameters to use when resolving the string from the bundle. * @see java.text.MessageFormat */ public WorkDirFault(ResourceBundle i18n, String s, Object[] o) { super(i18n, s, o); } } /** * Indicates problems when accessing the test suite. */ public static class TestSuiteFault extends Interview.Fault { /** * Create a fault with an internationalized message. * @param i18n The bundle from which to get the string. * @param s The key for getting the string to be displayed from the * supplied bundle. */ public TestSuiteFault(ResourceBundle i18n, String s) { super(i18n, s); } /** * Create a fault with an internationalized message. * @param i18n The bundle from which to get the string. * @param s The key for getting the string to be displayed from the * supplied bundle. * @param o Parameter to use when resolving the string from the bundle. * @see java.text.MessageFormat */ public TestSuiteFault(ResourceBundle i18n, String s, Object o) { super(i18n, s, o); } /** * Create a fault with an internationalized message. * @param i18n The bundle from which to get the string. * @param s The key for getting the string to be displayed from the * supplied bundle. * @param o Parameters to use when resolving the string from the bundle. * @see java.text.MessageFormat */ public TestSuiteFault(ResourceBundle i18n, String s, Object[] o) { super(i18n, s, o); } } /** * Indicates problems when accessing the configuration file. */ public static class JTIFault extends Interview.Fault { /** * Create a fault with an internationalized message. * @param i18n The bundle from which to get the string. * @param s The key for getting the string to be displayed from the * supplied bundle. */ public JTIFault(ResourceBundle i18n, String s) { super(i18n, s); } /** * Create a fault with an internationalized message. * @param i18n The bundle from which to get the string. * @param s The key for getting the string to be displayed from the * supplied bundle. * @param o Parameter to use when resolving the string from the bundle. * @see java.text.MessageFormat */ public JTIFault(ResourceBundle i18n, String s, Object o) { super(i18n, s, o); } /** * Create a fault with an internationalized message. * @param i18n The bundle from which to get the string. * @param s The key for getting the string to be displayed from the * supplied bundle. * @param o Parameters to use when resolving the string from the bundle. * @see java.text.MessageFormat */ public JTIFault(ResourceBundle i18n, String s, Object[] o) { super(i18n, s, o); } } /** * The template manager is used to change behavior of * template saving, the default implementation is * the context manager of corresponding test suite. */ public interface TemplateManager { /** * This method is invoked each time before saving template. * The template will be saved only if this method returns true. * @param file template file * @return true if this operation is allowed, false otherwise */ public boolean canSaveTemplate(File file); } public void setPropagationController(CustomPropagationController pc) { this.pc = pc; } public CustomPropagationController getPropagationController() { return pc; } private TemplateManager templateManager = null; /** * Create an InterviewParameters object. * @param tag The tag used to qualify questions in this interview */ protected InterviewParameters(String tag) { super(tag); } /** * Set the work directory to be used for this test run. * @param workDir the work directory to be used for this test run. * It must match the test suite to be used for this test run */ public abstract void setWorkDirectory(WorkDirectory workDir); /** * Set given template manager for this InterviewParameters. * @param tm new template manager */ public void setTemplateManger(TemplateManager tm) { this.templateManager = tm; } /** * Return the template manager for this InterviewParameters. */ public TemplateManager getTemplateManger() { return templateManager; } /** * Initialize an InterviewParameters object. * This method is called when the object is created * from an entry in a .jtt file. * By default, the method throws an exception if any arguments * are given. It should be redefined by any test suites that wish * to support this type of initialization. * @param args test suite specific args with which to initialize * this InterviewParameters object * @throws Interview.Fault if any problems occurred while processing the arguments */ public void init(String[] args) throws Fault { if (args != null && args.length > 0) throw new Fault(i18n, "ip.unknownArgs"); } /** * Clean up an InterviewParameters object. * This method should be invoked at the moment InterviewParameters object * becomes useless by the code, that controls it's lifecycle. For example, * at the end of the method which created it's local instance. * * Any following invocations on this object may result in unpredictable * exceptions because of object inconsistence. */ public void dispose() { kflFiles = null; backupPolicy = null; cachedExcludeListFilter = null; cachedKeywordsFilter = null; cachedRelevantTestFilter = null; cachedRelevantTestFilterEnv = null; cachedStatusFilter = null; cachedTestFilters = null; pc = null; templateManager = null; } //---------------------------------------------------------------------------- /** * Get the name for this configuration. * By default and for backwards compatibility, this defaults to the * name of the test environment, which means that the whole environment * may need to be evaluated to get the required value. Subtypes may * choose to override this method to provide a more efficient * implementation. * *
Since the default implementation gets the name from the test
* environment, clients should not use this method to determine
* the name for the test environment, unless this method is redefined.
* The default implementation detects such a circular usage, and
* returns null in this case.
*
* @return the name for this configuration, or null if not known.
*/
public synchronized String getName() {
if (inGetName)
return null;
try {
inGetName = true;
EnvParameters eParams = getEnvParameters();
if (eParams != null) {
// getName to get the name for the environment
TestEnvironment e = eParams.getEnv();
if (e != null)
return e.getName();
}
return null;
}
finally {
inGetName = false;
}
}
private boolean inGetName;
/**
* Get a description for this configuration.
* By default and for backwards compatibility, this defaults to the
* description entry in the test environment, which means that the
* whole environment may need to be evaluated to get the required value.
* Subtypes may choose to override this method to provide a more efficient
* implementation.
* @return a description for this configuration, or null if not known
*/
public String getDescription() {
EnvParameters eParams = getEnvParameters();
if (eParams != null) {
TestEnvironment e = eParams.getEnv();
if (e != null)
return e.getDescription();
}
return null;
}
//----------------------------------------------------------------------------
/**
* Get the next question to the asked after the initial prolog
* of questions.
* The default value is the result of getEnvFirstQuestion.
* @return the next question to be asked after the initial prolog
* of questions.
* @see #setFirstQuestion
*/
protected Question getPrologSuccessorQuestion() {
return getEnvFirstQuestion();
}
//----------------------------------------------------------------------------
public TestEnvironment getEnv() {
EnvParameters eParams = getEnvParameters();
if (eParams == null)
throw new NullPointerException();
else
return eParams.getEnv();
}
/**
* Get the first question to be asked concerning the environment to be
* set up and used for each test to be run. If these questions are
* contained in an interview, this method can be simply implemented as:
* return callInterview(
envInterview, getEnvSuccessorQuestion);
* @return the first question to be asked concerning the environment to be
* set up and used for each test to be run.
* @see #getEnvSuccessorQuestion
*/
protected abstract Question getEnvFirstQuestion();
/**
* Get the next question to be asked after those concerning
* the environment to be set up and used for each test to be run.
* The default value is the result of getTestsFirstQuestion.
* @return the next question to be asked after those concerning
* the environment to be set up and used for each test to be run.
* @see #getEnvFirstQuestion
*/
protected Question getEnvSuccessorQuestion() {
return getTestsFirstQuestion();
}
public String[] getTests() {
TestsParameters iParams = getTestsParameters();
return (iParams == null ? null : iParams.getTests());
}
/**
* Get the first question to be asked concerning the set of tests
* and folders of tests to be run.
* @return the first question to be asked concerning the set of tests
* and folders of tests to be run.
* @see #getTestsSuccessorQuestion
*/
protected abstract Question getTestsFirstQuestion();
/**
* Get the next question to be asked after those concerning
* the tests and folders of tests to be run.
* The default value is the result of getExcludeListFirstQuestion.
* @return the next question to be asked after those concerning
* the tests and folders of tests to be run.
* @see #getTestsFirstQuestion
*/
protected Question getTestsSuccessorQuestion() {
return getExcludeListFirstQuestion();
}
public ExcludeList getExcludeList() {
ExcludeListParameters eParams = getExcludeListParameters();
return (eParams == null ? new ExcludeList() : eParams.getExcludeList());
}
/**
* Get the combined known failures list.
* Interviews expecting to use known failures lists should generally override
* this method and add support for users to change it.
* @since 4.4
* @see #setKnownFailureFiles(java.io.File[])
* @see com.sun.javatest.interview.BasicInterviewParameters
* @return Current known failures list - combined from the one or more
* file specified by the user.
*/
public KnownFailuresList getKnownFailuresList() {
try {
if (kflFiles != null) {
return new KnownFailuresList(getKnownFailureFiles());
}
else {
return null;
}
}
catch (IOException e){
return null;
}
catch (KnownFailuresList.Fault f) {
// report it?
return null;
}
}
/**
* Set the set of KFL files.
* @since 4.4
* @param files The known failures list files. The array should contain
* one or more elements.
*/
public void setKnownFailureFiles(File[] files) {
kflFiles = files;
}
/**
* Get the current set of known failures list files.
* The default implementation will return the value in the kflFiles
* field, which subclasses may set.
* @since 4.4
* @see #setKnownFailureFiles(java.io.File[])
* @return The list of known failure list files. Null if none.
*/
public File[] getKnownFailureFiles() {
return kflFiles;
}
/**
* Get the first question to be asked concerning the exclude list
* to be used to exclude tests from the test run.
* @return the first question to be asked concerning the exclude list
* to be used to exclude tests from the test run.
* @see #getExcludeListSuccessorQuestion
*/
protected abstract Question getExcludeListFirstQuestion();
/**
* Get the first question to be asked concerning the exclude list
* to be used to exclude tests from the test run.
* @return the first question to be asked concerning the exclude list
* to be used to exclude tests from the test run
* @deprecated Use getExcludeListFirstQuestion().
* @see #getExcludeListFirstQuestion
*/
protected Question getExcludeTableFirstQuestion() {
return getExcludeListFirstQuestion();
}
/**
* Get the next question to be asked after those concerning
* the exclude list to be used to exclude tests from the test run.
* The default value is the result of getKeywordsFirstQuestion,
* @return the next question to be asked after those concerning
* the exclude list to be used to exclude tests from the test run.
* @see #getExcludeListFirstQuestion
*/
protected Question getExcludeListSuccessorQuestion() {
return getKeywordsFirstQuestion();
}
/**
* Get the next question to be asked after those concerning
* the exclude list to be used to exclude tests from the test run.
* @return the next question to be asked after those concerning
* the exclude list to be used to exclude tests from the test run
* @deprecated Use getExcludeListFirstQuestion().
* @see #getExcludeListSuccessorQuestion
*/
protected Question getExcludeTableSuccessorQuestion() {
return getExcludeListSuccessorQuestion();
}
public Keywords getKeywords() {
KeywordsParameters kParams = getKeywordsParameters();
return (kParams == null ? null : kParams.getKeywords());
}
/**
* Get the first question to be asked concerning the keywords
* that may be used to select tests for the test run.
* @return the first question to be asked concerning the keywords
* that may be used to select tests for the test run.
* @see #getKeywordsSuccessorQuestion
*/
protected abstract Question getKeywordsFirstQuestion();
/**
* Get the next question to be asked after those concerning
* the keywords that may be used to select tests for the test run.
* The default value is the result of getPriorStatusQuestion.
* @return the next question to be asked after those concerning
* the keywords that may be used to select tests for the test run.
* @see #getKeywordsFirstQuestion
*/
protected Question getKeywordsSuccessorQuestion() {
return getPriorStatusFirstQuestion();
}
public boolean[] getPriorStatusValues() {
PriorStatusParameters sParams = getPriorStatusParameters();
return (sParams == null ? null : sParams.getPriorStatusValues());
}
/**
* Get the first question to be asked concerning whether tests should
* be selected for execution according to their prior execution status.
* @return the first question to be asked concerning whether tests should
* be selected for execution according to their prior execution status.
* @see #getPriorStatusSuccessorQuestion
*/
protected abstract Question getPriorStatusFirstQuestion();
/**
* Get the next question to be asked after those concerning
* whether tests should be selected for execution according to their
* prior execution status.
* The default value is the result of getConcurrencyFirstQuestion
* @return the next question to be asked after those concerning
* whether tests should be selected for execution according to their
* prior execution status.
* @see #getPriorStatusFirstQuestion
*/
protected Question getPriorStatusSuccessorQuestion() {
return getConcurrencyFirstQuestion();
}
public int getConcurrency() {
ConcurrencyParameters cParams = getConcurrencyParameters();
return (cParams == null ? 1 : cParams.getConcurrency());
}
/**
* Get the first question concerning the number of tests that
* may be run in parallel.
* @return the first question concerning the number of tests that
* may be run in parallel.
* @see #getConcurrencySuccessorQuestion
*/
protected abstract Question getConcurrencyFirstQuestion();
/**
* Get the next question after those concerning the number
* of tests that may be run in parallel.
* The default is the result of getTimeoutFactorFirstQuestion
* @return the next question after those concerning the number
* of tests that may be run in parallel.
* @see #getConcurrencyFirstQuestion
*/
protected Question getConcurrencySuccessorQuestion() {
return getTimeoutFactorFirstQuestion();
}
public float getTimeoutFactor() {
TimeoutFactorParameters tParams = getTimeoutFactorParameters();
return (tParams == null ? 1 : tParams.getTimeoutFactor());
}
/**
* Get the first question concerning the scale factor to
* be applied to the standard timeout for each test.
* @return the first question concerning the scale factor to
* be applied to the standard timeout for each test.
* @see #getTimeoutFactorSuccessorQuestion
*/
protected abstract Question getTimeoutFactorFirstQuestion();
/**
* Get the next question after those concerning the scale factor to
* be applied to the standard timeout for each test.
* The default is the result of getEpilogFirstQuestion
* @return the next question after those concerning the scale factor to
* be applied to the standard timeout for each test.
* @see #getTimeoutFactorFirstQuestion
*/
protected Question getTimeoutFactorSuccessorQuestion() {
return getEpilogFirstQuestion();
}
/**
* Get the first question of the epilog, which should be asked after
* all the other questions in the configuration interview have been asked.
* The epilog should terminate in the standard way with a FinalQuestion.
* @return the first question of the epilog, which should be asked after
* all the other questions in the configuration interview have been asked.
*/
protected abstract Question getEpilogFirstQuestion();
//----------------------------------------------------------------------------
/**
* Determine whether all the configuration values are valid, by
* checking if the interview has been completed.
* If so, the result will be true; if not, the result will be false,
* and getErrorMessage will provide details about at least one of the
* invalid values.
* @return true if and only if all the configuration values are valid
* @see #getErrorMessage
* @see #isFinishable
*/
public boolean isValid() {
return isFinishable();
}
/**
* If there is an error in any of the configuration values,
* as indicated by isValid, this method will provide a detail
* message about the first question for which there is a problem.
* @return a detail message about the first question with an invalid answer,
* or null if none.
* @see #isValid
*/
public String getErrorMessage() {
Question[] path = getPath();
Question lastQuestion = path[path.length - 1];
if (lastQuestion instanceof FinalQuestion)
return null;
else if (lastQuestion instanceof ErrorQuestion)
return lastQuestion.getText();
else {
String v = lastQuestion.getStringValue();
return i18n.getString("ip.noAnswer",
new Object[] { lastQuestion.getSummary(),
lastQuestion.getText(),
lastQuestion.getTag(),
new Integer(v == null ? 0 : 1),
trim(v),
} );
}
}
private String trim(String text) {
return (text == null ? null
: text.length() < 40 ? text
: text.substring(0, 37) + "...");
}
//----------------------------------------------------------------------------
/**
* Get a filter which will filter tests according to the result
* of getExcludeList(). If the result of getExcludeList is null
* or an empty exclude list, the result of this method will also be null.
* @return a filter which will filter tests according to the result
* of getExcludeList()
* @deprecated Use getExcludeListFilter().
* @see #getExcludeListFilter
*/
public TestFilter getExcludeTableFilter() {
return getExcludeListFilter();
}
public TestFilter getExcludeListFilter() {
ExcludeList t = getExcludeList();
if (t == null)
cachedExcludeListFilter = null;
else if (cachedExcludeListFilter == null
|| cachedExcludeListFilter.getExcludeList() != t)
cachedExcludeListFilter = new ExcludeListFilter(t);
return cachedExcludeListFilter;
}
private ExcludeListFilter cachedExcludeListFilter;
public TestFilter getKeywordsFilter() {
Keywords k = getKeywords();
if (k == null)
cachedKeywordsFilter = null;
else if (cachedKeywordsFilter == null
|| cachedKeywordsFilter.getKeywords() != k)
cachedKeywordsFilter = new KeywordsFilter(k);
return cachedKeywordsFilter;
}
private KeywordsFilter cachedKeywordsFilter;
public TestFilter getPriorStatusFilter() {
WorkDirectory wd = getWorkDirectory();
TestResultTable r = (wd == null ? null : wd.getTestResultTable());
boolean[] s = getPriorStatusValues();
if (r == null || s == null)
cachedStatusFilter = null;
else if (cachedStatusFilter == null
|| cachedStatusFilter.getTestResultTable() != r
|| !equal(cachedStatusFilter.getStatusValues(), s))
cachedStatusFilter = new StatusFilter(s, r);
// else
// cachedStatusFilter is OK
return cachedStatusFilter;
}
private StatusFilter cachedStatusFilter;
public TestFilter getRelevantTestFilter() {
TestSuite ts = getTestSuite();
TestEnvironment env = getEnv();
if (ts == null || env == null)
cachedRelevantTestFilter = null;
else if (cachedRelevantTestFilter == null ||
ts != cachedRelevantTestFilterTestSuite ||
env != cachedRelevantTestFilterEnv) {
cachedRelevantTestFilter = ts.createTestFilter(env);
}
return cachedRelevantTestFilter;
}
private TestFilter cachedRelevantTestFilter;
private TestSuite cachedRelevantTestFilterTestSuite; // do we need this?
private TestEnvironment cachedRelevantTestFilterEnv;
public synchronized TestFilter[] getFilters() {
Vector