/*
* The MIT License
*
* Copyright (c) 2010, Stellar Science Ltd Co, K. R. Walker
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.plugins.measurement_plots;
/**
* Apply a TestResultOutputOperation to the text-based outputs of a
* TestResult.
* @author krwalker
*/
class OutputOperationApplicator implements TestResultOperation {
private static final java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger(OutputOperationApplicator.class.getName());
private static java.lang.reflect.Method getStdout = null;
private static java.lang.reflect.Method getStderr = null;
static {
try {
getStdout = hudson.tasks.test.TestResult.class.getMethod("getStdout");
} catch (NoSuchMethodException exception) {
LOGGER.log(java.util.logging.Level.SEVERE, "Unable to get output.", exception);
}
try {
getStderr = hudson.tasks.test.TestResult.class.getMethod("getStderr");
} catch (NoSuchMethodException exception) {
LOGGER.log(java.util.logging.Level.SEVERE, "Unable to get output.", exception);
}
}
private TestResultOutputOperation outputOperation;
OutputOperationApplicator(TestResultOutputOperation outputOperation) {
this.outputOperation = outputOperation;
}
@Override
public void apply(hudson.tasks.test.TestResult result) {
applyToOutputFromMethod(result, getStdout);
applyToOutputFromMethod(result, getStderr);
}
/**
* Avoid code duplication by using reflection to select the method to call.
* This has the ugly side effect of making it necessary
* to handle reflection-related exceptions.
*
* @param result The TestResult from which to get the output.
* @param outputMethod The method to call on TestResult to get the output.
*/
private void applyToOutputFromMethod(hudson.tasks.test.TestResult result, java.lang.reflect.Method outputMethod) {
try {
String output = (String)outputMethod.invoke(result);
if (isValidOutput(result, outputMethod, output)) {
outputOperation.apply(result, output);
}
} catch (IllegalAccessException exception) {
LOGGER.log(java.util.logging.Level.SEVERE, "Attempted to invoke method with restricted access.", exception);
} catch (java.lang.reflect.InvocationTargetException exception) {
LOGGER.log(java.util.logging.Level.SEVERE, "Attempted to invoke method on object that doesn't support it.", exception);
}
}
/**
* The hudson.tasks.junit package implements getStdout and getStderr in
* ways that make walking the test tree using the general interfaces
* difficult. CaseResult returns its own output if it has any, otherwise
* it returns the SuiteResult output if it has any. TestResult loops
* over all suites and concatenates the output from each SuiteResult.
*
* The only way to determine whether or not the output is
* genuinely from the leaf is to compare it's result with those of
* all its parents'.
*
* The only way currently known to invalidate the output from a TestResult
* is to test if the result is a junit.TestResult.
*
* @param result The TestResult from which to start searching for parents.
* @param outputMethod The method to call on parent results.
* @param output The output being checked for validity.
* @return true if valid for the leaf.
*/
private static boolean isValidOutput(
hudson.tasks.test.TestResult result,
java.lang.reflect.Method outputMethod,
String output) {
if (output != null && output.length() > 0 && outputMethod != null) {
// Ignore output from junit.TestResult
if (result instanceof hudson.tasks.junit.TestResult) {
return false;
}
// Search for parents with the exact same output. If one is found,
// consider this output invalid.
hudson.tasks.test.TestObject parentObject = result;
while ((parentObject = parentObject.getParent()) != null) {
hudson.tasks.test.TestResult parentResult =
(hudson.tasks.test.TestResult)parentObject;
try {
if (parentResult != null && outputMethod.invoke(parentResult) == output) {
return false;
}
} catch (IllegalAccessException exception) {
LOGGER.log(java.util.logging.Level.SEVERE, "Attempted to invoke method with restricted access.", exception);
} catch (java.lang.reflect.InvocationTargetException exception) {
LOGGER.log(java.util.logging.Level.SEVERE, "Attempted to invoke method on object that doesn't support it.", exception);
}
}
return true;
}
return false;
}
private void apply(hudson.tasks.test.TestResult result, String text) {
outputOperation.apply(result, text);
}
}