5

I came across some situations (twice in one day, and I see they will not be rare) when test can run infinite time.

Like there is a wait realisation for some account operation but there is an error message displayed over progress bar which is not known by autotest. Message is not closed, progressbar is still on, test is running, running...

And there is another chance to get infinite execution is when UFT failes and displayes error message (which could not be handled by UFT itself), e.g.:

Error on UFT fail

There is some information about the question I've found:

I suppose that (because of no multithreading in UFT's VBScript) there is no possibility to set limit test execution time with the means of UFT (some proof found in post time limit for QTP script\'s execution).

Possible solution is to start test & timeout to kill UFT process at once in the .bat file

Bat-file to start test testexec.bat:

start "TestExecutionTimer" "C:\_qtp\resources\testexectimer.bat" [max exec time in seconds]
cscript.exe "C:\_qtp\resources\RunTest.vbs" "[path to test]"

Bat-file with UFT process killer testexectimer.bat:

timeout /t %~1
taskkill /im UFTPro.exe

exit

And part of RunTest.vbs VBScript that runs test (it should kill timer if test is completed):

...
'kill timer which is used to close test that runs too long
Wscript.Echo "kill timer"
oShell.Run "taskkill /fi ""WINDOWTITLE eq testexectimer*"" /f /t", , True
Wscript.Echo "timer is killed"

So architecture would look like this:

enter image description here

Does anyone use better solutions?

1

Wow... you're making this much harder than it has to be.

QTP actually DOES have a timing system built in, you can set and check MANY timers as needed.

Here's how I wait for something that could take forever:

Seconds_to_Wait = 60  'one minute timer
(Messages_Displayed = 0  'optional

MercuryTimers("simple timer").Start

Do
    'check for success
    if CheckIfWorkSucceeded() then
        print "yay it worked"
        exit do
    end if  

    'check for timeout
    If MercuryTimers("simple timer").ElapsedTime > Seconds_to_Wait * 1000 Then
        print "boo it failed"   
        exittest 'or, goto subroutine to handle graceful exit       
    End If

    'optional
    If (MercuryTimers("simple timer").ElapsedTime > (Messages_Displayed * 5) * 1000) Then 'every 5 seconds
        print round(Seconds_to_Wait - (MercuryTimers("simple timer").ElapsedTime / 1000)) & " seconds remaining before timeout."
        Messages_Displayed = Messages_Displayed + 1
    End If
Loop
0

You could also run a fork of your main vbs and kill it once the timeout is reached:

Sub RunMeWithTimeout(ByVal timeout_ms)
  If WScript.Arguments.Named.Exists("fork") Then Exit Sub
  Dim process, endtime, cmd, arg
  For Each arg In WScript.Arguments: cmd = cmd & " " & arg: Next
  cmd = WScript.FullName & " """ & WScript.ScriptFullName & """" & cmd & " /fork"
  Set process = CreateObject("WScript.Shell").Exec(cmd)
  endtime = Now + (timeout_ms / 86400000)
  Do Until process.Status
    If Now > endtime Then
      On Error Resume Next
      process.Terminate
      WScript.Quit 1
    End If
    WScript.Sleep 60
  Loop
  WScript.Quit
End Sub


Call RunMeWithTimeout(3000)

WScript.Echo "This process will be killed in 3 seconds"
WScript.Sleep 60000
  • Thanks, but architecture is the same as I proposed (my fork process is started as testexectimer.bat). Searching for something that would simplify it – Ivan Gerasimenko Mar 3 '16 at 19:38
0

Java allows to control execution time of the process (threadNew.join() causes the current thread to pause execution until threadNew terminates). So I finally came to the solution of Java-starter for UFT test.

But it is needed external library (Java-COM Bridge) for Java to deal with UFT directly. And VBScript does not need any libraries to start UFT (and also there are some logic was already in RunTest.vbs) so I have used linear structure of calls:

structure of calls

And UFT is killed from inside Java program if timeout is expired and there is no exitcode from RunTest.vbs. Here is RunUftTest.java:

import static java.lang.System.out;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.TimeoutException;

public class RunUftTest {

    public static void main(String[] args) {
        // Args: TESTPATH DISTRICT ENVIRONMENT

        String testPath = args[0];
        String district = args[1];
        String environment = args[2];

        System.out.println("{ testPath: "+ testPath + ";\r\n  district: " + district + ";\r\n  environment: " + environment + " }\r\n");

        String runCommand = "cscript.exe RunTest.vbs \"" + testPath + "\" " + district + "-" + environment;
        String execDirectory = "C:\\_qtp\\resources\\VBscripts";
        long timeout = 600000;

        ExecProcessInfo execProcessInfo = execProcess(runCommand, execDirectory, timeout);

        System.out.println("\r\n==============================================================");
        System.out.println("RunTest.vbs - OUTPUT:\r\n");
        printBuffer(execProcessInfo.inputStream);

        System.exit(execProcessInfo.getExitStatus());

    }

    private static class Worker extends Thread {
        private final Process process;
        private Integer exit;

        private Worker(Process process) {
            this.process = process;
        }

        public void run() {
            try {
                exit = process.waitFor();
            } catch (InterruptedException ignore) {
                return;
            }
        }
    }

    private static class ExecProcessInfo {
        private Integer exitStatus;
        public BufferedReader inputStream;

        ExecProcessInfo() {
            setExitStatus(-1); // Fail status by default
            inputStream = null;
        }

        public Integer getExitStatus() { return exitStatus; }
        public void setExitStatus(Integer exitStatus) { this.exitStatus = exitStatus; }
    }


    private static void printBuffer(BufferedReader bufferedReader) {
        try {
            String s;
            while ((s = bufferedReader.readLine()) != null) {
                out.println(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static ExecProcessInfo execProcess(String runCommand, String execDirectory, long timeout) {
        ExecProcessInfo execProcessInfo = new ExecProcessInfo();

        try {

            Process process = Runtime.getRuntime().exec(runCommand, null, new File(execDirectory));

            System.out.println("Initializing process  <" + runCommand + ">...");
            System.out.println("              in dir  <" + execDirectory + ">");
            System.out.println("        with timeout  " + timeout + "ms\r\n");
            execProcessInfo.inputStream = new BufferedReader(new InputStreamReader(process.getInputStream()));

            Worker worker = new Worker(process);
            worker.start();
            long startTime = 0;

            try {
                startTime = System.currentTimeMillis();
                worker.join(timeout);

                if (worker.exit != null) {  // process exited by himself
                    System.out.println("         exit status  " + worker.exit);
                    execProcessInfo.setExitStatus(worker.exit);
                }
                else {
                    long procExecDuration = System.currentTimeMillis() - startTime;
                    System.out.println("Process was interrupted after " + procExecDuration + "ms.");
                    throw new TimeoutException();
                }
            } catch (InterruptedException ex) {
                worker.interrupt();
                long procExecDuration = System.currentTimeMillis() - startTime;
                System.out.println("InterruptedException. After " + procExecDuration + "ms of execution.");
                ex.printStackTrace();
                killUftProcess();
                Thread.currentThread().interrupt();
                throw ex;
            } catch (TimeoutException e) {
                killUftProcess();
            } finally {
                process.destroy();
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return execProcessInfo;
    }

    private static void killUftProcess() throws IOException {
        System.out.println("Killing <UFT.exe> process");
        Runtime.getRuntime().exec("taskkill /F /IM UFT.exe");
    }
}

You can incorporate all code inside RunUftTest.java to avoid RunTest.vbs usage if you wish.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.