Saturday, December 24, 2011

QTP Grid

Launch QTP scripts on remote machine from any machine (even from linux)
This will allow you to trigger QTP scripts (Stored in Local Drive Or Shared Drive Or on QC Server)on a remote machine through a command line.
This trigger is independent which means that it is not dependent on QC or QTP (QC or QTP is not required to be installed on the machine from where you are triggering the script)
Trigger is also cross platform. hence you can trigger QTP scripts from Linux machine as well. You can also integrate this with any of Automated Build Tool. So as soon as code drop happens, QTP script on remote machine will start automatically.

How to Do it?
1. Save Code from all three locations.
http://paurushc.blogspot.com/2011/12/qtpgridserverjavatxt.html             >  with name QTPGridServer.java
http://paurushc.blogspot.com/2011/12/qtpgridclientjavatxt.html               > with name QTPGridClient.java
http://paurushc.blogspot.com/2011/12/qtptriggervbstxt.html                   > with name QTPTrigger.vbs

2. Compile and create Class files from java files. use any online compiler in case you don't have java compiler.
Place QTPGridServer.Class and QTPTrigger.vbs on the remote execution machine under same folder (for ex: C:\QTPGrid)

3. Start Server on remote machine by typing command "java C:\QTPGrid\QTPGridServer". You should see "waiting for Connection" in command prompt.
=================

Thats it.. you are done.. now for launching Script on remote machine just type below command from any of the machine

java QTPGridClient 192.168.xx.xx "<QTPGrid><TestCaseNames>C:\QTPScripts\Addition,C:\QTPScripts\Division</TestCaseNames></QTPGrid>"

where 192.168.xx.xx is remote machine IP add where server is runing

Above command will start script C:\QTPScripts\Addition script saved on local. you can replace it with shared drive path as well. in order to run multiple scripts give comma separated values.

Now if your scripts are saved on QC server then you need to single line value in below format:

<QTPGrid>
<scriptstoredat>QC</scriptstoredat>
<qcurl>http://qualitycenter.com/qcbin</qcurl>
<loginid>userid</loginid>
<loginpass>password</loginpass>
<qcdomain>ProjectDomain</qcdomain>
<qcproject>ProjectName</qcproject>
<testsetfolderpath>Subject\CalculaterTesting\Release1</testsetfolderpath>
<testsetname>PhaseOneRegression</testsetname>
<testcasenames>Addition,Division</testcasenames>
<emailids>abc@gmail.com,xyz@gmail.com</emailids>
</QTPGrid>

Note: If you want to execute complete Test Set then do not mention TestCaseName tag. then it will start executing all scripts present in testset.

in whole command will be:
java QTPGridClient 10.10.10.10 "<QTPGrid><scriptstoredat>QC</scriptstoredat><qcurl>http://qualitycenter.com/qcbin</qcurl><loginid>userid</loginid><loginpass>password</loginpass><qcdomain>ProjectDomain</qcdomain><qcproject>ProjectName</qcproject><testsetfolderpath>Subject\CalculaterTesting\Release1</testsetfolderpath> <testsetname>PhaseOneRegression</testsetname>  <testcasenames>Addition,Division</testcasenames> <emailids>abc@gmail.com,xyz@gmail.com</emailids></QTPGrid>"

See this in Action: http://www.youtube.com/watch?v=aclyWHMjoFI




QTPGridServer.java.txt

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class QTPGridServer{
    ServerSocket providerSocket;
    Socket connection = null;
    ObjectOutputStream out;
    ObjectInputStream in;
    String message;
    QTPGridServer(){}
    void run()
    {
        try{
            //1. creating a server socket
            providerSocket = new ServerSocket(2004, 10);
            //2. Wait for connection
            System.out.println("Waiting for connection");
            connection = providerSocket.accept();
            System.out.println("Connection received from " + connection.getInetAddress().getHostName());
            //3. get Input and Output streams
            out = new ObjectOutputStream(connection.getOutputStream());
            out.flush();
            in = new ObjectInputStream(connection.getInputStream());
            sendMessage("Connection successful");
            //4. The two parts communicate via the input and output streams
            do{
                try{
                    message = (String)in.readObject();
                    System.out.println("client>" + message);
                    if (message.toLowerCase().equals("ping")){
                        sendMessage("Reply: Server running fine");
                    }else if (message.toLowerCase().equals("kill")){
                        sendMessage("Kill Request Recived.!! Shutting down server. You will not be able to connect to this server anymore.");
                        System.exit(0);
                    }else if (message.equals("Terminate Connection")){
                        //Do Nothing
                    }else{
                        sendMessage("Launching QTPTrigger.vbs with provided parameters: " + message);
                        String CurrentDirectory = System.getProperty("user.dir");
                        System.out.println(CurrentDirectory);
                        String cmd = "cmd.exe /c start \"\" \"" + CurrentDirectory + "\\QTPTrigger.vbs\" \"" + message + "\"";
                        System.out.println(cmd);
                        Runtime.getRuntime().exec(cmd);
                    }
                      
                }catch(ClassNotFoundException classnot){
                    System.err.println("Data received in unknown format");
                }
            }while(!message.equals("Terminate Connection"));
        }
        catch(IOException ioException){
            ioException.printStackTrace();
        }
        finally{
            //4: Closing connection
            try{
                in.close();
                out.close();
                providerSocket.close();
            }
            catch(IOException ioException){
                ioException.printStackTrace();
            }
        }
    }
    void sendMessage(String msg)
    {
        try{
            out.writeObject(msg);
            out.flush();
            System.out.println("server>" + msg);
        }
        catch(IOException ioException){
            ioException.printStackTrace();
        }
    }
    public static void main(String args[])
    {
        QTPGridServer server = new QTPGridServer();
        while(true){
            server.run();
        }
    }
}

QTPGridClient.java.txt

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class QTPGridClient{
    Socket requestSocket;
    ObjectOutputStream out;
     ObjectInputStream in;
     String message;
    static String Msg;
    static String IPAdd;
    QTPGridClient(){}
    void run()
    {
        try{
            //1. creating a socket to connect to the server
            requestSocket = new Socket(IPAdd, 2004);
            System.out.println("Connected to " + IPAdd);
            //2. get Input and Output streams
            out = new ObjectOutputStream(requestSocket.getOutputStream());
            out.flush();
            in = new ObjectInputStream(requestSocket.getInputStream());
            //3: Communicating with the server
            try{
                message = (String)in.readObject();
                System.out.println("server>" + message);
                sendMessage(Msg);
                message = (String)in.readObject();
                System.out.println("server>" + message);
                sendMessage("Terminate Connection");
            }catch(ClassNotFoundException classNot){
                System.err.println("Error: data received in unknown format");
            }
           
        }catch(UnknownHostException unknownHost){
            System.err.println("Error: You are trying to connect to an unknown host!");
        }catch(IOException ioException){
            System.err.println("Error: Server might not be running on: " + IPAdd);
            //ioException.printStackTrace();
        }
        finally{
            //4: Closing connection
            try{
                in.close();
                out.close();
                requestSocket.close();
            }catch(IOException ioException){
                //ioException.printStackTrace();
            }
        }
    }
    void sendMessage(String msg)
    {
        try{
            out.writeObject(msg);
            out.flush();
            //System.out.println("client>" + msg);
        }
        catch(IOException ioException){
            //ioException.printStackTrace();
        }
    }
    public static void main(String args[])
    {
        try{
            IPAdd = args[0];
            Msg = args[1];
            QTPGridClient client = new QTPGridClient();
            client.run();
            System.out.println("Exiting Program..");
        }catch(Exception e){
            System.err.println("Error: Unable to send message. Terminating Program!!");
        }
    }
}

QTPTrigger.vbs.txt

    'On Error Resume Next

    XMLVariables = Wscript.Arguments.item(0)

    'Variables which will be sent through XML
    Dim ScriptStoredAt
    Dim QCURL
    Dim loginID
    Dim loginPass
    Dim QCDomain
    Dim QCProject
    Dim TestSetFolderPath
    Dim TestSetName
    Dim EmailIDs
    Dim AdditionalComments
    Dim TestCaseNames


    Set oXMLDoc = CreateObject("MSXML2.DOMDocument")
    oXMLDoc.LoadXML XMLVariables
    Set oChilds = oXMLDoc.DocumentElement.ChildNodes
    For Each oChild In oChilds
        Execute oChild.nodeName & " = """ & oChild.nodeTypedValue & """"
    Next
    If LCase(ScriptStoredAt) = "qc" Then    ' This means that test scripts are stored in QC server

        'Identify if it is running for Test Case or complete Test Set. If Test Case Names is not provided then it will execute for complete Test Set
        If Len(Trim(TestCaseNames)) > 0 Then
            ItsForTestSet = False
        Else
            ItsForTestSet = True
        End If

        'Connecting to QC
        Set TDC = CreateObject("TDApiOle80.TDConnection")
        TDC.InitConnectionEx QCURL
        TDC.Login loginID, loginPass
        TDC.Connect QCDomain, QCProject

        'Navigating to Test Set
        Set tsFolder = TDC.TestSetTreeManager.NodeByPath(TestSetFolderPath)
        Set tsList = tsFolder.FindTestSets(TestSetName)

        'In case multiple Test Set exists of Same name under differnt sub folder then filter out by matching Test Set Folder absolute path
        If tsList.Count > 1 Then
            For Each Testsets In tsList
                If Testsets.TestSetfolder.Path & "\" = TestSetFolderPath Then
                    Set theTestSet = Testsets
                    Exit For
                End If
            Next
        Else
            Set theTestSet = tsList.Item(1)
        End If


        'if not executing complete test Set
        If Not (ItsForTestSet) Then
            'Get Testinstacne ID for all Test scripts
            Set TestInstanceList = theTestSet.TSTestFactory.NewList("")
       
            arrTestCasesNames = Split(TestCaseNames, ",")
            TestInstance = ""
       
            For i = 0 To UBound(arrTestCasesNames)
                For Each TestInstance In TestInstanceList
                    If LCase(TestInstance.Name) = LCase(arrTestCasesNames(i)) Then
                        TestInstanceIds = TestInstanceIds & TestInstance.ID & ","
                        Exit For
                    End If
                Next    'Testinstance
            Next    'TestCase Name

       
            If Len(TestInstanceIds) > 0 Then
                'Remove last comma
                TestInstanceIds = Left(TestInstanceIds, Len(TestInstanceIds) - 1)
            Else
                'If none of the test instance is provided then exit program
                Wscript.Quit
            End If

        End If
   
        'Email Execution start alert
        If Len(EmailIDs) > 0 Then
            Set oNet = CreateObject("Wscript.Network")
            LocalPCName = oNet.ComputerName
            Set oNet = Nothing
            If ItsForTestSet = True Then
                varMailBody = "<h1>Test Execution Started</h1><br><br><br>Execution Started for Complete TestSet :<br><br>"
                varMailBody = varMailBody & TestSetFolderPath & "\" & TestSetName
                varMailBody = varMailBody & "<br><br> Started at: " & LocalPCName & "<br><br>" & AdditionalComments
            Else
                varMailBody = "<h1>Test Execution Started</h1><br><br><br>Execution Started for Below TestCases :<br><br>"
                varMailBody = varMailBody & TestSetFolderPath & "\" & TestSetName & "<br> Test Case(s) : " & TestCaseNames
                varMailBody = varMailBody & "<br> Started at: " & LocalPCName & "<br><br>" & AdditionalComments
            End If
            TDC.SendMail EmailIDs, , "Test Execution -> Started @ " & LocalPCName, varMailBody
        End If

        'Starting Test Shecdular
        Set oScheduler = theTestSet.StartExecution("")
        oScheduler.RunAllLocally = True
   
        If ItsForTestSet Then
            oScheduler.Run
        Else
            oScheduler.Run (TestInstanceIds)
        End If

        Set execStatus = oScheduler.ExecutionStatus
        RunFinished = False
        startdatetime = Now
   
        'Sync till script execution completes. Cut off of 12 hours is implemented just to avoid infinte loop
        While ((RunFinished = False) And (CInt(ExecuteHours) <= 12))
       
            execStatus.RefreshExecStatusInfo "all", True
            RunFinished = execStatus.Finished
            'wscript.sleep (10000)     'Wait for 10 seconds
            ExecuteHours = DateDiff("h", CDate(startdatetime), Now)
            TDC.Connect QCDomain, QCProject  'Reconnecting to keep session alive
        Wend

        'Email Execution report
        If Len(EmailIDs) > 0 Then
            Report = ""
            TDC.Connect QCDomain, QCProject
            execStatus.RefreshExecStatusInfo "all", True
            For i = 1 To execStatus.Count
                Set TestExecStatusObj = execStatus.Item(i)
                TestIName = TDC.TSTestFactory.Item(TestExecStatusObj.TSTestID).Name
                If InStr(1, TestExecStatusObj.Message, "Fail",1) > 0 Then
                    Report = Report & "<font color = ""red""><br>Name: " & TestIName & " | Message: " & TestExecStatusObj.Message & " | status: " & TestExecStatusObj.Status & "</font>"
                ElseIf InStr(1, TestExecStatusObj.Message, "Pass",1) > 0 Then
                    Report = Report & "<font color = ""Green""><br>Name: " & TestIName & " | Message: " & TestExecStatusObj.Message & " | status: " & TestExecStatusObj.Status & "</font>"
                Else
                    Report = Report & "<font color = ""red""><br>Name: " & TestIName & " | Message: " & TestExecStatusObj.Message & " | status: " & TestExecStatusObj.Status & "</font>"
                End If
            Next
            Report = "<h1>Test Execution Summary</h1><br><br>Please see the results Below:<br><br><br><br>" & Report & "<br><br>======= End Of Report ======="
            TDC.SendMail EmailIDs, , "Test Execution -> Completed @ " & LocalPCName, Report
        End If


        TDC.Disconnect
        TDC.LogOut
        TDC.ReleaseConnection
       
        Set oQTP = CreateObject("QuickTest.Application")
        oQTP.Quit
   
    Else
   
        'Email Start Notification
        If Len(EmailIDs) > 0 Then
            'Connecting to QC. This use QC Sendmail function to email
            Set TDC = CreateObject("TDApiOle80.TDConnection")
            TDC.InitConnectionEx QCURL
            TDC.Login loginID, loginPass
            TDC.Connect QCDomain, QCProject
   
            Set oNet = CreateObject("Wscript.Network")
            LocalPCName = oNet.ComputerName
            Set oNet = Nothing
            varMailBody = "<h1>Test Execution Started</h1><br><br><br>Execution Started for Below TestCases :<br><br>"
            varMailBody = varMailBody & "<br> Test Case(s) : " & TestCaseNames
            varMailBody = varMailBody & "<br> Started at: " & LocalPCName & "<br><br>" & AdditionalComments
            TDC.SendMail EmailIDs, , "Test Execution -> Started @ " & LocalPCName, varMailBody

        End If
   
        Set oQTP = CreateObject("QuickTest.Application")
        oQTP.Launch
        oQTP.Visible = True
        arrTestCaseNames = Split(TestCaseNames, ",")
        For Each TestCase In arrTestCaseNames
            oQTP.Open TestCase, True, False
            oQTP.Test.Run
            oQTP.Test.Close
        Next
   
   
        'Email Execution Completion alert
        If Len(EmailIDs) > 0 Then
            TDC.Connect QCDomain, QCProject
            TDC.SendMail EmailIDs, , "Test Execution -> Completed @ " & LocalPCName, "Execution Completed"
            TDC.Disconnect
            TDC.LogOut
            TDC.ReleaseConnection
        End If


        oQTP.Quit
   
    End If