Monday 11 May 2015

Creating .CAB files with Powershell


Syntax for creating a cab file
New-CabinetFile -Name MyCabinet.cab -File "File01.exe","File02.txt"
--This creates a new MyCabinet.cab file in the current directory and adds the File01.exe and File02.txt files to it, also from the current directory.
Syntax for extracting a cab file
Get-ChildItem C:\CabFile\ | New-CabinetFile -Name MyCabinet.cab -DestinationPath C:\Users\UserA\Documents
--This creates a new C:\Users\UserA\Documents\MyCabinet.cab file and adds all files within the C:\CabFile\ directory into it.
Code for the New-CabinetFile function:
function New-CabinetFile {
    [CmdletBinding()]
    Param(
        [Parameter(HelpMessage="Target .CAB file name.", Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [Alias("FilePath")]
        [string] $Name,
        [Parameter(HelpMessage="File(s) to add to the .CAB.", Position=1, Mandatory=$true, ValueFromPipeline=$true)]
        [ValidateNotNullOrEmpty()]
        [Alias("FullName")]
        [string[]] $File,
        [Parameter(HelpMessage="Default intput/output path.", Position=2, ValueFromPipelineByPropertyName=$true)]
        [AllowNull()]
        [string[]] $DestinationPath,
        [Parameter(HelpMessage="Do not overwrite any existing .cab file.")]
        [Switch] $NoClobber
        )
    Begin { 
        ## If $DestinationPath is blank, use the current directory by default
        if ($DestinationPath -eq $null) { $DestinationPath = (Get-Location).Path; }
        Write-Verbose "New-CabinetFile using default path '$DestinationPath'.";
        Write-Verbose "Creating target cabinet file '$(Join-Path $DestinationPath $Name)'.";
        ## Test the -NoClobber switch
        if ($NoClobber) {
            ## If file already exists then throw a terminating error
            if (Test-Path -Path (Join-Path $DestinationPath $Name)) { throw "Output file '$(Join-Path $DestinationPath $Name)' already exists."; }
        }
        ## Cab files require a directive file, see 'http://msdn.microsoft.com/en-us/library/bb417343.aspx#dir_file_syntax' for more info
        $ddf = ";*** MakeCAB Directive file`r`n";
        $ddf += ";`r`n";
        $ddf += ".OPTION EXPLICIT`r`n";
        $ddf += ".Set CabinetNameTemplate=$Name`r`n";
        $ddf += ".Set DiskDirectory1=$DestinationPath`r`n";
        $ddf += ".Set MaxDiskSize=0`r`n";
        $ddf += ".Set Cabinet=on`r`n";
        $ddf += ".Set Compress=on`r`n";
        ## Redirect the auto-generated Setup.rpt and Setup.inf files to the temp directory
        $ddf += ".Set RptFileName=$(Join-Path $ENV:TEMP "setup.rpt")`r`n";
        $ddf += ".Set InfFileName=$(Join-Path $ENV:TEMP "setup.inf")`r`n";

        ## If -Verbose, echo the directive file
        if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
            foreach ($ddfLine in $ddf -split [Environment]::NewLine) {
                Write-Verbose $ddfLine;
            }
        }
    }
    Process {
         ## Enumerate all the files add to the cabinet directive file
        foreach ($fileToAdd in $File) {
            ## Test whether the file is valid as given and is not a directory
            if (Test-Path $fileToAdd -PathType Leaf) {
                Write-Verbose """$fileToAdd""";
                $ddf += """$fileToAdd""`r`n";
            }
            ## If not, try joining the $File with the (default) $DestinationPath
            elseif (Test-Path (Join-Path $DestinationPath $fileToAdd) -PathType Leaf) {
                Write-Verbose """$(Join-Path $DestinationPath $fileToAdd)""";
                $ddf += """$(Join-Path $DestinationPath $fileToAdd)""`r`n";
            }
            else { Write-Warning "File '$fileToAdd' is an invalid file or container object and has been ignored."; }
        }       
    }
    End {
        $ddfFile = Join-Path $DestinationPath "$Name.ddf";
        $ddf | Out-File $ddfFile -Encoding ascii | Out-Null;
        Write-Verbose "Launching 'MakeCab /f ""$ddfFile""'.";
        $makeCab = Invoke-Expression "MakeCab /F ""$ddfFile""";
        ## If Verbose, echo the MakeCab response/output
        if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {
            ## Recreate the output as Verbose output
            foreach ($line in $makeCab -split [environment]::NewLine) {
                if ($line.Contains("ERROR:")) { throw $line; }
                else { Write-Verbose $line; }
            }
        }
        ## Delete the temporary .ddf file
        Write-Verbose "Deleting the directive file '$ddfFile'.";
        Remove-Item $ddfFile;
        ## Return the newly created .CAB FileInfo object to the pipeline
        Get-Item (Join-Path $DestinationPath $Name);
    }
}

Wednesday 6 May 2015

unexpected popups handling in CodedUI

A lot of times, while running a UI test, our test runs into an unexpected page\state, say an unexpected error dialog, or an pop-up window, which would make our test fail and if that happens, rather than having the test rerun from the start, all we want is for it to resume when the page is loaded.
I am taking the example of a winforms application with an alert window. The steps would be no different if you were trying the same on any other supported technology.
Suppose let me say upon clicking a button there was an unexpected pop-up appearing. This pop-up blocks my TestMethod and makes it fail as it will not be able to perform any action as per the TestMethod. In this case these are the following steps which are to be followed
  1. Set a retry count- Playback.PlaybackSettings.MaximumRetryCount, i.e. you can specifiy the number of times you want a failed action to be retried. This is not a mandatory argument, if no value is set, the default value will be 1.
  2. Add a retry handler for the failed step. This is nothing but the handler function which will get called in case of a failure. You can add\remove this handler for any step in the coded UI test method, or even in test\class initialize as a generic handler for all failures.
  3.                         Playback.PlaybackError += Playback_PlaybackError;
  4. The handler method signature is as shown below
      1. private void Playback_PlaybackError(object sender, PlaybackErrorEventArgs e)
                {
                    Console.WriteLine("Retrying .... ");
                      // By default, the exception will be thrown. Over here we are switching to retry mode.
                      e.Result = PlaybackErrorOptions.Retry;
                        // Just a simple enter to dismiss the Alert. If you are sure of any specific properties for
                        // a popup dialog or any other specific action you need to do, this is the place to 
                        // implement them.
                        Keyboard.SendKeys("{Enter}");
                    }
        1. Now simply setting the PlaybackErrorOptions to Retry will retry your failed step over and over until either the step passes or the MaximumRetryCount is hit. If you want to do any special handling, like say dismissing an alert, you can add the code for the same within the handler.
        2. TestMethod code looks like below
            TestMethod()
                    {
                        using (ApplicationUnderTest aut = ApplicationUnderTest.Launch("UnexpectedPopupAut.exe"))
                        {
                            #region Variable Declarations
                            #endregion
            // Important to set the MaximumRetryCount count for the retry handler to be invoked.
                            Playback.PlaybackSettings.MaximumRetryCount = 3;
                            // Add the error handler.
                            Playback.PlaybackError += Playback_PlaybackError;
            //Code of your TestMethod
                            Playback.PlaybackError -= Playback_PlaybackError;
          This is supported only for the following exceptions:-
          1. PlaybackFailureException
          2. UITestControlNotFoundException
          3. UITestControlNotAvailableException
          4. TechnologyNotSupportedException
          5. InvalidUITestExtensionPackageException
          6. DecodingFailedException
          7. FailedToPerformActionsOnBlockedControlException
          8. FailedToPerformActionsOnHiddenControlException
          9. UITestControlNotVisibleException
          10. ValidationFailedException
          11. FailedToLaunchApplicationException
          12. ActionNotSupportedOnDisabledControlExcept