diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /qadevOOo/runner/complexlib | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream/1%7.0.4.tar.xz libreoffice-upstream/1%7.0.4.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'qadevOOo/runner/complexlib')
-rw-r--r-- | qadevOOo/runner/complexlib/Assurance.java | 146 | ||||
-rw-r--r-- | qadevOOo/runner/complexlib/ComplexTestCase.java | 296 | ||||
-rw-r--r-- | qadevOOo/runner/complexlib/MethodThread.java | 118 | ||||
-rw-r--r-- | qadevOOo/runner/complexlib/ShowTargets.java | 102 |
4 files changed, 662 insertions, 0 deletions
diff --git a/qadevOOo/runner/complexlib/Assurance.java b/qadevOOo/runner/complexlib/Assurance.java new file mode 100644 index 000000000..4fbf3755d --- /dev/null +++ b/qadevOOo/runner/complexlib/Assurance.java @@ -0,0 +1,146 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you 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 . + */ + +package complexlib; + +/** + * I have removed the assure(...) functions from ComplexTestCase due to the fact now I can + * use the functions every where and don't need to be a ComplexTestCase any longer. + */ +public class Assurance +{ + /** Used to indicate that we should continue with test method, even if check fails */ + public enum ContinueWithTest { + YES, NO + } + + /** State of the current test method **/ + protected boolean bSuccessful = true; + + /** The message if the test did fail **/ + protected String message = null; + + + /** + * Assure that s is true. + * This function generates "Assure failed." as standard message. + * @param s The condition that should be true. + */ + protected void assure(boolean s) { + assure("Assure failed.", s, ContinueWithTest.NO); + } + + /** + * Assure that s is true. + * The given message will be only evaluated, if s is false. + * @param msg The message that is evaluated. + * @param s The condition that should be true. + */ + protected void assure(String msg, boolean s) { + assure(msg, s, ContinueWithTest.NO); + } + + /** + * Assure that two int values are equal + * @param message the message to print when the equality test fails + * @param expected specifies the expected int value + * @param actual specifies the actual int value + */ + protected void assureEquals( String message, int expected, int actual ) { + assureEquals( message, Integer.valueOf( expected ), Integer.valueOf( actual ), ContinueWithTest.NO ); + } + + /** + * Assure that two string values are equal + * @param message the message to print when the equality test fails + * @param expected specifies the expected string value + * @param actual specifies the actual string value + */ + protected void assureEquals( String message, String expected, String actual ) { + assureEquals( message, expected, actual, ContinueWithTest.NO ); + } + + /** + * assures the two given sequences are of equal length, and have equal content + */ + public <T> void assureEquals( String i_message, T[] i_expected, T[] i_actual, ContinueWithTest i_continue ) + { + if ( i_expected.length != i_actual.length ) + failed( i_message + ": expected element count: " + i_expected.length + ", actual element count: " + i_actual.length ); + for ( int i=0; i<i_expected.length; ++i ) + { + assureEquals( i_message + ": mismatch at element pos " + i, i_expected[i], i_actual[i], i_continue ); + } + } + + /** + * Mark the currently executed method as failed. + * with the given message. + * @param msg The message of the failure. + */ + protected void failed(String msg) { + assure(msg, false, ContinueWithTest.NO); + } + + /** + * Assure that s is true. + * The given message will be only evaluated, if s is false. + * Normally, assure() leaves the current test method, and the next one + * is executed. With the parameter 'cont' set to true, the current test + * method will continue.<br> + * The current method will of course marked as failed. + * @param msg The message that is evaluated. + * @param s The condition that should be true. + * @param cont if YES, continue with test method, even if s is false. + */ + protected void assure(String msg, boolean s, ContinueWithTest cont) { + bSuccessful &= s; + if (!s) { + message += msg + "\r\n"; + if (cont == ContinueWithTest.NO) { + throw new AssureException(msg); + } + } + } + + private void assureEquals( String message, Object expected, Object actual, ContinueWithTest cont ) { + assure( message + " (expected: " + expected.toString() + ", actual: " + actual.toString() + ")", + expected.equals( actual ), cont ); + } + + /** + * Mark the currently executed method as failed. + * with the given message. + * The given message will be only evaluated, if s is false. + * With the parameter 'cont' set to true, the current test + * method will continue.<br> + * The current method will of course marked as failed. + * @param msg The message that is evaluated. + * @param cont if YES, continue with test method, even if s is false. + */ + protected void failed(String msg, ContinueWithTest cont) { + assure(msg, false, cont); + } + + public static class AssureException extends RuntimeException { + + private AssureException(String msg) { + super(msg); + } + } +} diff --git a/qadevOOo/runner/complexlib/ComplexTestCase.java b/qadevOOo/runner/complexlib/ComplexTestCase.java new file mode 100644 index 000000000..ab95d1eed --- /dev/null +++ b/qadevOOo/runner/complexlib/ComplexTestCase.java @@ -0,0 +1,296 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you 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 . + */ +package complexlib; + +import java.lang.reflect.Method; +import share.DescEntry; +import lib.TestParameters; +import lib.StatusException; +import share.LogWriter; +import share.ComplexTest; +import java.io.PrintWriter; + +/** + * Base class for all complex tests. + */ +public abstract class ComplexTestCase extends Assurance implements ComplexTest +{ + + /** The test parameters **/ + protected TestParameters param = null; + /** Log writer **/ + protected LogWriter log = null; + /** + * The method name which will be written into f.e. the data base + **/ + private String mTestMethodName = null; + + private boolean m_bBeforeCalled; + + /** + * is called before the real test starts + */ + private void before() + { + try + { + Method before = this.getClass().getMethod("before", new Class[] {} ); + before.invoke(this, new Object[] {} ); + + m_bBeforeCalled = true; + } + catch (java.lang.NoSuchMethodException e) + { + m_bBeforeCalled = true; + } + catch (java.lang.IllegalAccessException e) + { + log.println("Cannot access the 'before()' method, although it" + " is there. Is this ok?"); + } + catch (java.lang.reflect.InvocationTargetException e) + { + Throwable t = e.getTargetException(); + if (!(t instanceof RuntimeException) || bSuccessful) + { + log.println(t.toString()); + if (message == null) + { + message = "Exception in before() method.\n\r" + t.getMessage(); + } + bSuccessful = false; + t.printStackTrace((PrintWriter) log); + } + } + + } + + /** Description entry **/ + + private void test_method(DescEntry _entry) + { + + /* Maximal time one method is allowed to execute + * Can be set with parameter 'ThreadTimeOut' + **/ + int nThreadTimeOut = param.getInt("ThreadTimeOut"); + if (nThreadTimeOut == 0) + { + nThreadTimeOut = 300000; + } + + for (int i = 0; i < _entry.SubEntries.length; i++) + { + + DescEntry subEntry = _entry.SubEntries[i]; + if (m_bBeforeCalled) + { + bSuccessful = true; + message = ""; + } + else + { + // set all test methods on failed, if 'before()' did not work. + subEntry.State = message; + subEntry.hasErrorMsg = true; + subEntry.ErrorMsg = message; + continue; + } + Method testMethod = null; + try + { + String entryName = subEntry.entryName; + Object[] parameter = null; + + int posLeftParenthesis = entryName.indexOf('('); + if (posLeftParenthesis != -1) + { + String sParameter = entryName.substring(posLeftParenthesis + 1, entryName.indexOf(')')); + mTestMethodName = entryName; + parameter = new String[] { sParameter }; + entryName = entryName.substring(0, posLeftParenthesis); + testMethod = this.getClass().getMethod(entryName, new Class[] { String.class }); + } + else + { + testMethod = this.getClass().getMethod(entryName, new Class[] {} ); + mTestMethodName = entryName; + } + + MethodThread th = new MethodThread(testMethod, this, parameter, (java.io.PrintWriter) log); + log.println("Starting " + mTestMethodName); + th.start(); + + try + { + // some tests are very dynamic in their execution time so that + // a threadTimeOut fails. In this cases the logging mechanism + // is a useful way to detect that an office respective a test + // is running and not death. + // But way ThreadTimeOut? + // There exists a complex test which uses no office. Therefore + // a logging mechanism to detect a stalled test. + int lastPing = -1; + int newPing = 0; + + int sleepingStep = 1000; + int factor = 0; + + while (th.isAlive() && (lastPing != newPing || factor * sleepingStep < nThreadTimeOut)) + { + Thread.sleep(sleepingStep); + factor++; + // if a test starts the office itself it the watcher is a + // new one. + share.Watcher ow = (share.Watcher) param.get("Watcher"); + if (ow != null) + { + lastPing = newPing; + newPing = ow.getPing(); + factor = 0; + } + } + } + catch (InterruptedException e) + { + } + if (th.isAlive()) + { + log.println("Destroy " + mTestMethodName); + th.stopRunning(); + subEntry.State = "Test did sleep for " + (nThreadTimeOut / 1000) + " seconds and has been killed!"; + subEntry.hasErrorMsg = true; + subEntry.ErrorMsg = subEntry.State; + continue; + } + else + { + log.println("Finished " + mTestMethodName); + if (th.hasErrorMessage()) + { + subEntry.State = th.getErrorMessage(); + subEntry.hasErrorMsg = true; + subEntry.ErrorMsg = subEntry.State; + continue; + } + } + } + catch (java.lang.Exception e) + { + log.println(e.getClass().getName()); + String msg = e.getMessage(); + log.println("Message: " + msg); + e.printStackTrace((PrintWriter) log); + subEntry.State = "SKIPPED.FAILED"; + subEntry.hasErrorMsg = true; + subEntry.ErrorMsg = (msg == null ? "" : msg); + continue; + } + subEntry.State = (bSuccessful ? "COMPLETED.OK" : message); + subEntry.hasErrorMsg = !bSuccessful; + subEntry.ErrorMsg = message; + } + } + + /** + * after() is called after the test is done + */ + private void after() + { + if (m_bBeforeCalled) + { + // the after() method + try + { + Method after = this.getClass().getMethod("after", new Class[] {}); + after.invoke(this, new Object[] {} ); + } + catch (java.lang.NoSuchMethodException e) + { + // simply ignore + } + catch (java.lang.IllegalAccessException e) + { + // simply ignore + } + catch (java.lang.reflect.InvocationTargetException e) + { + Throwable t = e.getTargetException(); + if (!(t instanceof StatusException)) + { + log.println(t.toString()); + if (message == null) + { + message = "Exception in after() method.\n\r" + t.getMessage(); + } + else + { + message += "Exception in \'after()\' method.\n\r" + t.getMessage(); + } + log.println("Message: " + message); + t.printStackTrace((PrintWriter) log); + } + } + } + + } + + + + /** + * Call test. It is expected, that an environment is + * given to this test. + * + * @param entry The name of the test method that should be called. + * @param environment The environment for the test. + */ + public void executeMethods(DescEntry entry, TestParameters environment) + { + m_bBeforeCalled = false; + + // get the environment + param = environment; + log = entry.Logger; + + + // start with the before() method + before(); + + //executeMethodTests + test_method(entry); + + // cleanup + after(); + } + + + /** + * Implement this method in the Complex test. + * @return All test method names. + */ + public abstract String[] getTestMethodNames(); + + /** + * Return a name for the test or tested object. + * Override to give an own name. + * @return As default, the name of this class. + */ + public String getTestObjectName() + { + return this.getClass().getName(); + } +} diff --git a/qadevOOo/runner/complexlib/MethodThread.java b/qadevOOo/runner/complexlib/MethodThread.java new file mode 100644 index 000000000..28ea770eb --- /dev/null +++ b/qadevOOo/runner/complexlib/MethodThread.java @@ -0,0 +1,118 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you 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 . + */ + +package complexlib; + +import java.io.PrintWriter; +import java.lang.reflect.Method; + +/** + * Invoke a method of a class in an own thread. Provide a method to end + * the thread. + */ +public class MethodThread extends Thread +{ + + /** The method that should be executed **/ + private final Method mTestMethod; + /** The object that implements the method **/ + private final Object mInvokeClass; + /** A PrintWriter for debug Output **/ + private final PrintWriter mLog; + /** An Error String **/ + private String mErrMessage = null; + /** Did an Exception happen? **/ + private boolean mExceptionHappened = false; + private Object[] mParameter = null; + + public MethodThread(Method testMethod, Object invokeClass, Object[] parameter, PrintWriter log) + { + mTestMethod = testMethod; + mInvokeClass = invokeClass; + mParameter = parameter; + mLog = log; + } + + /** + * Invoke the method. + */ + @Override + public void run() + { + try + { + mTestMethod.invoke(mInvokeClass, mParameter); + } + catch (IllegalAccessException e) + { + e.printStackTrace(mLog); + mErrMessage = e.getMessage(); + mExceptionHappened = true; + } + catch (java.lang.reflect.InvocationTargetException e) + { + Throwable t = e.getTargetException(); + if (!(t instanceof ComplexTestCase.AssureException)) + { + t.printStackTrace(mLog); + mErrMessage = t.getMessage(); + if (mErrMessage == null) + { + mErrMessage = t.toString(); + } + mExceptionHappened = true; + } + + } + } + + /** + * Get the error message + * @return The error message. + */ + public String getErrorMessage() + { + return mErrMessage; + } + + /** + * Is there an error message? + * @return True, if an error did happen. + */ + public boolean hasErrorMessage() + { + return mExceptionHappened; + } + + /** + * Stop the running method. + */ + public void stopRunning() + { + try + { + interrupt(); + } + catch (SecurityException e) + { + e.printStackTrace(mLog); + mErrMessage = e.getMessage(); + mExceptionHappened = true; + } + } +} diff --git a/qadevOOo/runner/complexlib/ShowTargets.java b/qadevOOo/runner/complexlib/ShowTargets.java new file mode 100644 index 000000000..f655e1330 --- /dev/null +++ b/qadevOOo/runner/complexlib/ShowTargets.java @@ -0,0 +1,102 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you 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 . + */ + +package complexlib; + +import java.util.ArrayList; + +public class ShowTargets +{ + public static void main( String[] args ) + { + ArrayList<String> targets = new ArrayList<String>(); + ArrayList<String> descs = new ArrayList<String>(); + + targets.add( "run" ); + descs.add( "runs all complex tests in this module" ); + + int maxTargetLength = 3; + + for ( int i = 0; i < args.length; ++i ) + { + String completePotentialClassName = args[i].replace( '/', '.' ); + + // filter + if ( completePotentialClassName.endsWith( ".TestCase" ) ) + continue; + if ( completePotentialClassName.endsWith( ".TestSkeleton" ) ) + continue; + + // get the class + Class<?> potentialTestClass = null; + try { potentialTestClass = Class.forName( completePotentialClassName ); } + catch( java.lang.ClassNotFoundException e ) + { + continue; + } + + // see if it is derived from complexlib.ComplexTestCase + Class<?> superClass = potentialTestClass.getSuperclass(); + while ( superClass != null ) + { + if ( superClass.getName().equals( "complexlib.ComplexTestCase" ) ) + { + String bareClassName = completePotentialClassName.substring( completePotentialClassName.lastIndexOf( '.' ) + 1 ); + String target = "run_" + bareClassName; + targets.add( target ); + descs.add( getShortTestDescription( potentialTestClass ) ); + + if ( maxTargetLength < target.length() ) + maxTargetLength = target.length(); + break; + } + superClass = superClass.getSuperclass(); + } + } + + System.out.println( "possible targets:" ); + for ( int i=0; i<targets.size(); ++i ) + { + // target + String target = targets.get(i); + // 'tab' + System.out.print( " " + target ); + for ( int s = maxTargetLength - target.length(); s>0; --s ) + System.out.print( " " ); + // description + System.out.println( " (" + descs.get(i) + ")" ); + } + } + + private static String getShortTestDescription( Class<?> _testClass ) + { + java.lang.reflect.Method getShortDescriptionMethod = null; + try { getShortDescriptionMethod = _testClass.getMethod( "getShortTestDescription", new Class[]{} ); } + catch( Exception e ) { } + + if ( getShortDescriptionMethod != null ) + { + try + { + return (String)getShortDescriptionMethod.invoke( null, new Object[]{} ); + } + catch( Exception e ) { } + } + return "no description provided by the test"; + } +} |