Tuesday, May 22, 2012

vbscript gerp utility


DisplayLineNumber = False
ExactMatch = False
IgnoreCase = True

Set oFSO = CreateObject("Scripting.FileSystemObject")


if WScript.Arguments.Count = 0 Then
    Wscript.StdOut.Writeline "Incorrect arguments. syntax: egrep  [filename] [-n] [-x] [-cs]"
    Wscript.StdOut.Writeline "-n          : Display Line Number"
    Wscript.StdOut.Writeline "-x          : Exact Match"
    Wscript.StdOut.Writeline "-cs         : Case Sensitive. By Default it ignore Case"
    Wscript.StdOut.Writeline "Example: egrep @ EULA.txt" & vbNewLine & "Example: egrep /b.*@gmail.com EULA.txt -n -x -cs" & vbnewline & "Example: ipconfig | egrep ""IP Add"""

    Wscript.Quit
Else
    Pattern = WScript.Arguments.item(0)

    if WScript.Arguments.Count => 2 Then
 FileName = WScript.Arguments.item(1)
 if oFSO.FileExists(FileName) Then
  Set oInputStream = oFSO.OpenTextFile(FileName,1)
 Else
  Set oInputStream = Wscript.Stdin
 End if
    Else
 Set oInputStream = Wscript.Stdin
    End if

    For i = 0 to  (WScript.Arguments.Count - 1)
        Select Case Lcase(WScript.Arguments.item(i))
        Case "-n" DisplayLineNumber = True
        Case "-x" ExactMatch = True
        Case "-cs" IgnoreCase = False
        Case Else
        End Select

    Next


End if




Dim StrLine, LineCount

if Pattern = "*" Then : Pattern = ".*" : End If

Set oRegX = New RegExp

oRegX.Pattern = Pattern
oRegX.IgnoreCase = IgnoreCase
oRegX.Global = True

LineCount = 0

Do Until oInputStream.AtEndOfStream
        StrLine = oInputStream.ReadLine
 TextToPrint = ""
        LineCount = LineCount + 1
        Set oMatches = oRegX.Execute(StrLine)

        if oRegX.Test(StrLine) Then
            Set oMatches = oRegX.Execute(StrLine)
            if ExactMatch then
                For each oMatch in oMatches
                    TextToPrint = TextToPrint & oMatch.Value
                Next
            else
                TextToPrint = StrLine
            end if
            
            If DisplayLineNumber Then
                TextToPrint = LineCount & "::" & TextToPrint
            End if
            Wscript.StdOut.WriteLine TextToPrint

        End if

Loop

'================ BAT ===============

@echo off
Set CurrentDirectory=%~dp0
cscript //nologo %CurrentDirectory%egrepvbs.vbs %1 %2 %3 %4
Save bat file in a folder present in path variable

Sunday, April 15, 2012

Some Imp function

Function getTimeStamp()
    sHour = CStr(String(2 - Len(Hour(Now)), "0") & Hour(Now))
    sMin = CStr(String(2 - Len(Minute(Now)), "0") & Minute(Now))
    sSecond = CStr(String(2 - Len(Second(Now)), "0") & Second(Now))
    sMillSecond = CStr(Right(Replace(Timer, ".", ""), 2))
    getTimeStamp = Day(Now) & MonthName(Month(Now), True) & Year(Now) & "_" & sHour & sMin & sSecond & sMillSecond
End Function

Wednesday, February 1, 2012

Using Classes in QTP/VBScript

Using Classes in QTP

QTP works on VBscript which is a scripting language not a programming language but it still supports “Class” concept in a limited manner. It does not support inheritance (which I believe is a major drawback) but you can leverage encapsulation and beautify your code.
Reasons to use Classes in QTP/VBscript:
1.       Achieve Encapsulation
2.       Create logical structure/packaging of functions
3.       Make code more readable
4.       Passing variables make easy

Achieve Encapsulation:

Some time we end up creating some variables global variables which can be accessed through multiple functions. Creating a Public Variable at function library level means that it can be modified by any of the function, even to those functions which should be modifying it. You can restrict it by creating it Private at class level.

Logical Structure/packaging and better readability:

Say example, I have a bunch of functions which does reporting, lying in function library. We log at different places like adding a node at XML , marking a row pass in Excel , adding a step at QC and saving screen print in Word. So my function library looks like this:

‘Reporting functions
‘-----------------------XML functions starts ----------------------------------------------------
Sub CreateXML(FilePath)
End Sub

Sub AddNodeToXML(NodeName,NodeText,ParentXPath)
End Sub

Sub SaveXML(FilePath)
End Sub
‘-----------------------XML functions ends----------------------------------------------------
‘-----------------------Excel functions starts ----------------------------------------------------
Sub CreateExcel(FilePath)
End Sub

Sub MarkTestCasePassInExcel(TestCaseName)
End Sub

Sub SaveExcel(FilePath)
End Sub
‘-----------------------Excel functions starts ----------------------------------------------------
‘-----------------------QC functions starts ----------------------------------------------------
Sub AddStepToQC(StepStatus, StepName, StepDescription,StepExpected,StepAtual)
End Sub

Sub DeleteStepFromQC(StepID)
End Sub
‘-----------------------QC functions Ends----------------------------------------------------
‘-----------------------Word functions starts ----------------------------------------------------
Sub CreateWord(FilePath)
End Sub

Sub AddTextToTestProof(Text)
End Sub

Sub SaveScreenShotToTestProof()
End Sub

Sub SaveTestProof(FilePath)
End Sub
‘-----------------------Word functions Ends ----------------------------------------------------

Lets “Class-ify” it

‘Reporting functions
‘-----------------------XML Class starts ----------------------------------------------------
Class XMLReporting
                Sub Create(FilePath)
                End Sub

                Sub AddNode(NodeName,NodeText,ParentXPath)
                End Sub

                Sub Save(FilePath)
                End Sub
End Class
‘-----------------------XML Class ends----------------------------------------------------
‘-----------------------Excel Class starts ----------------------------------------------------
Class XLReporting
                Sub Create(FilePath)
                End Sub

                Sub MarkTestCasePass(TestCaseName)
                End Sub

                Sub Save(FilePath)
                End Sub
End Class
‘-----------------------Excel Class starts ----------------------------------------------------
‘-----------------------QC Class starts ----------------------------------------------------
Class QCFunctions
                Sub AddStep(StepStatus, StepName, StepDescription,StepExpected,StepAtual)
                End Sub

                Sub DeleteStep(StepID)
                End Sub
End Class
‘-----------------------QC Class Ends----------------------------------------------------
‘-----------------------Word Class starts ----------------------------------------------------
Class TestProof
                Sub Create(FilePath)
                End Sub

                Sub AddText(Text)
                End Sub

                Sub SaveScreenShot()
                End Sub

                Sub Save(FilePath)
                End Sub
End Class
‘-----------------------Word Class Ends ----------------------------------------------------

This Code looks more structured then the previous one and is more readable
Function Calls will Look Like This
Set XML = New XMLReporting
XML.Create “C:\Temp.xml”
XML.AddNode “Step”, “Loan Booked”, “.//”

The one I have implemented in my project looks like this
‘Previous Call
QCUploadAttachmentToCurrentTestInstance “C:\Temp.xml”
QCDownloadAttachmentFromTestPlanFolder  “Subject\TestFolder\TestData.xls”

‘Now it looks like
QC.Upload.ToCurentTest “C:\Temp.xml”
QC.Download.FromTestPlan “Subject\TestFolder\TestData.xls”

Data Passing:

If you wanted to pass a new argument to a function which is called from multiple places, then you have to do a lot of rework changing every call of that function. However in order to deal with this we use work around like
a.       Making some variable Public so that it can be used inside function
b.      Passing multiple comma separated values in a single argument
c.       Passing an array
d.      Passing dictionary object

Another workaround can be passing Custom defined data structure.
Let’s consider that you are testing mortgage calculator functionality. Calculator takes some details of applicant and displays eligibility criteria of Mortgage loan. You are replicating calculation logic in your automation script in order to validate the eligibility criteria displayed on application.

‘Code Snippet 1
ApplicantName = "John"
ApplicantAge = 30
ApplicantIncome = 100  'Poor Chap
ApplicantAddress = "CyberWorld"

Eligiblity = CalculateEligibilityCriteria(ApplicantName, ApplicantAge, ApplicantIncome, ApplicantAddress)

Function CalculateEligibilityCriteria (Name, Age, AnualIncome, Address)
                'Calculate Eligibilty and Return Value
End Function

‘Code Snippet 2
Class ApplicantDetails
                Public Name
                Public Age
                Public AnualIncome
                Public Address
End Class


Set Applicant = New ApplicantDetails

Applicant.Name = "John"
Applicant.Age = 30
Applicant.Income = 100 'Poor Chap
Applicant.Address = "CyberWorld"

Eligiblity = CalculateEligibilityCriteria(Applicant)

Function CalculateEligibilityCriteria (objApplicant)
                'Calculate Eligibility and Return Value
End Function

Using Class to pass custom data structure makes it more readable and more flexible to accommodate changes

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