System.Data.SQLite
Check-in [e791e34148]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add automation capable of deploying and running the .NET Compact Framework test application.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e791e34148b8e4609df3bbccf65b178d01211555
User & Date: mistachkin 2012-10-09 08:45:23
Context
2012-10-09
09:40
Add wrapper batch file for the Windows CE test automation and update the version history docs. check-in: 305bd4b0ab user: mistachkin tags: trunk
08:45
Add automation capable of deploying and running the .NET Compact Framework test application. check-in: e791e34148 user: mistachkin tags: trunk
03:26
Enhancements to the 'testce' project that allow it to be automated. check-in: 3c8aa6ed17 user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Added Setup/deployAndTestCe.eagle.

            1  +###############################################################################
            2  +#
            3  +# deployAndTestCe.eagle -- Windows CE Deployment & Testing Tool
            4  +#
            5  +# Written by Joe Mistachkin.
            6  +# Released to the public domain, use at your own risk!
            7  +#
            8  +###############################################################################
            9  +
           10  +package require Eagle
           11  +
           12  +proc usage { error } {
           13  +  if {[string length $error] > 0} then {puts stdout $error}
           14  +
           15  +  puts stdout "usage:\
           16  +[file tail [info nameofexecutable]]\
           17  +[file tail [info script]] \[year\] \[platform\] \[configuration\]\
           18  +\[culture\] \[platformId\] \[deviceId\] \[quiet\]"
           19  +
           20  +  #
           21  +  # NOTE: Indicate to the caller, if any, that we have failed.
           22  +  #
           23  +  exit 1
           24  +}
           25  +
           26  +#
           27  +# NOTE: This procedure will output a diagnostic message, typically to the
           28  +#       standard output channel, using the [puts] command unless the global
           29  +#       variable "quiet" is non-zero.
           30  +#
           31  +proc qputs { args } {
           32  +  if {!$::quiet} then {
           33  +    eval puts $args; flush stdout
           34  +  }
           35  +}
           36  +
           37  +#
           38  +# NOTE: This procedure looks up and returns the target device based on the
           39  +#       locale, platform Id, and device Id.
           40  +#
           41  +proc getDevice { cultureInfo platformId deviceId } {
           42  +  set datastoreManager [object create -alias \
           43  +      Microsoft.SmartDevice.Connectivity.DatastoreManager \
           44  +      [$cultureInfo LCID]]
           45  +
           46  +  set platform [$datastoreManager -alias GetPlatform [object create \
           47  +      Microsoft.SmartDevice.Connectivity.ObjectId $platformId]]
           48  +
           49  +  if {[string length $deviceId] == 0} then {
           50  +    set deviceId [$platform GetDefaultDeviceId]
           51  +  }
           52  +
           53  +  set device [$platform -alias GetDevice $deviceId]
           54  +
           55  +  qputs stdout [appendArgs \
           56  +      "returning device \"" [$device Name] "\" of platform \"" \
           57  +      [$device Platform.ToString] "\" with Id \"" [$device Id.ToString] \
           58  +      \"...]
           59  +
           60  +  return $device
           61  +}
           62  +
           63  +#
           64  +# NOTE: This procedure starts a process on the target device and optionally
           65  +#       waits for it to complete.
           66  +#
           67  +proc startRemoteProcess { device fileName arguments {wait true} } {
           68  +  set remoteProcess [$device -alias GetRemoteProcess]
           69  +
           70  +  if {![$remoteProcess Start $fileName $arguments]} then {
           71  +    error [appendArgs "could not start remote process \"" $fileName \"]
           72  +  }
           73  +
           74  +  if {$wait} then {
           75  +    qputs stdout [appendArgs \
           76  +        "waiting for remote process " [$remoteProcess GetId] ...]
           77  +
           78  +    while {![$remoteProcess HasExited]} {
           79  +      qputs -nonewline stdout .
           80  +      after 1000
           81  +    }
           82  +
           83  +    qputs stdout ""
           84  +    return [$remoteProcess GetExitCode]
           85  +  }
           86  +
           87  +  return -1
           88  +}
           89  +
           90  +set argc [llength $argv]
           91  +
           92  +if {$argc >= 0 && $argc <= 7} then {
           93  +  #
           94  +  # NOTE: Setup the default values for all command line options.
           95  +  #
           96  +  array set default {
           97  +            year 2008
           98  +        platform {Pocket PC 2003 (ARMV4)}
           99  +   configuration Release
          100  +         culture en-US
          101  +      platformId 3c41c503-53ef-4c2a-8dd4-a8217cad115e
          102  +        deviceId {}
          103  +           quiet false
          104  +  }
          105  +
          106  +  #
          107  +  # NOTE: Process all the command line options.  If a command line option
          108  +  #       is not present, use the default value.
          109  +  #
          110  +  set names [list \
          111  +      year platform configuration culture platformId deviceId quiet]
          112  +
          113  +  for {set index 0} {$index < [llength $names]} {incr index} {
          114  +    set name [lindex $names $index]; set value ""
          115  +
          116  +    if {$argc > $index} then {
          117  +      set value [string trim [lindex $argv $index]]
          118  +    }
          119  +
          120  +    if {[string length $value] > 0} then {
          121  +      set $name $value
          122  +    } else {
          123  +      set $name $default($name)
          124  +    }
          125  +  }
          126  +
          127  +  #
          128  +  # NOTE: Grab the culture instance based on the configured culture name.
          129  +  #
          130  +  set cultureInfo [object invoke -alias System.Globalization.CultureInfo \
          131  +      GetCultureInfo $culture]
          132  +
          133  +  #
          134  +  # NOTE: Build the list of .NET Compact Framework packages that need to be
          135  +  #       deployed to the target device.
          136  +  #
          137  +  if {![info exists packages]} then {
          138  +    #
          139  +    # NOTE: The two letter ISO language name is needed when building the
          140  +    #       default list of .NET Compact Framework packages because one of
          141  +    #       them is a localized resource package.
          142  +    #
          143  +    set language [string toupper [$cultureInfo TwoLetterISOLanguageName]]
          144  +
          145  +    #
          146  +    # NOTE: The default list of .NET Compact Framework packages contains the
          147  +    #       .NET Compact Framework 3.5 installation CAB file for ARMV4 on the
          148  +    #       Pocket PC and its associated resource installation CAB file.
          149  +    #
          150  +    set packages [list abd785f0-cda7-41c5-8375-2451a7cbff37 \
          151  +        \\windows\\NETCFv35.ppc.armv4.cab c0ccf48e-4bfb-4d84-827c-981a595e40c5 \
          152  +        [appendArgs \\windows\\NETCFv35.Messages. $language .cab]]
          153  +  }
          154  +
          155  +  #
          156  +  # NOTE: Save the path where this script is running from.
          157  +  #
          158  +  set path [file dirname [info script]]
          159  +
          160  +  #
          161  +  # NOTE: The base path should be the project root directory, which should
          162  +  #       be one level above the one containing this script.
          163  +  #
          164  +  set base_path [file dirname $path]
          165  +
          166  +  #
          167  +  # NOTE: The managed binaries to be deployed to the target device should
          168  +  #       be located in the "<base>\bin\<year>\<configuration>Compact\bin"
          169  +  #       directory.
          170  +  #
          171  +  set managed_directory [file join \
          172  +      $base_path bin $year [appendArgs $configuration Compact] bin]
          173  +
          174  +  #
          175  +  # NOTE: The native binaries to be deployed to the target device should
          176  +  #       be located in the "<base>\bin\<year>\<platform>\<configuration>"
          177  +  #       directory.
          178  +  #
          179  +  set native_directory [file join \
          180  +      $base_path bin $year $platform $configuration]
          181  +
          182  +  #
          183  +  # NOTE: Build the list of all application files that need to be deployed to
          184  +  #       the target device, including all the native and managed binaries.
          185  +  #
          186  +  if {![info exists fileNames]} then {
          187  +    #
          188  +    # NOTE: Grab the assembly name instance based on the primary managed
          189  +    #       assembly file name.  This is needed because the build portion of
          190  +    #       the assembly version is used when building the default list of
          191  +    #       application files to be deployed to the target device.
          192  +    #
          193  +    set assemblyName [object invoke -alias System.Reflection.AssemblyName \
          194  +        GetAssemblyName [file join $managed_directory System.Data.SQLite.dll]]
          195  +
          196  +    #
          197  +    # NOTE: The default list of application files includes the test application
          198  +    #       itself, the System.Data.SQLite managed assembly, the SQLite interop
          199  +    #       assembly, and the test application configuration file.
          200  +    #
          201  +    set fileNames [list [file join $managed_directory testce.exe] [file \
          202  +        join $managed_directory System.Data.SQLite.dll] [file join \
          203  +        $native_directory [appendArgs SQLite.Interop. [format %03d \
          204  +        [$assemblyName Version.Build]] .dll]] [file join $managed_directory \
          205  +        test.cfg]]
          206  +  }
          207  +
          208  +  #
          209  +  # NOTE: Setup the directory on the target device where the application files
          210  +  #       should be deployed to.
          211  +  #
          212  +  if {![info exists device_directory]} then {
          213  +    set device_directory "\\Program Files\\testce\\"
          214  +  }
          215  +
          216  +  #
          217  +  # NOTE: Load the managed assembly that allows us to communicate with the
          218  +  #       target device.  If this fails, the necessary SDK components are
          219  +  #       probably not available on this system.
          220  +  #
          221  +  object load Microsoft.Smartdevice.Connectivity
          222  +
          223  +  #
          224  +  # NOTE: Lookup the necessary device based on the platform and device Ids.
          225  +  #
          226  +  set device [getDevice $cultureInfo $platformId $deviceId]
          227  +
          228  +  #
          229  +  # NOTE: Attempt to connect to the target device, which may be an emulator.
          230  +  #       By default, we attempt to connect to the "Pocket PC 2003 SE Emulator"
          231  +  #       device of the "Pocket PC 2003" platform (English).  If this fails,
          232  +  #       the target device is probably unavailable, either because it is not
          233  +  #       connected or some SDK components are missing.
          234  +  #
          235  +  $device Connect
          236  +
          237  +  #
          238  +  # NOTE: Grab the file deployer instance for the target device.  This will
          239  +  #       be used to download packages and send files to the target device.
          240  +  #
          241  +  set fileDeployer [$device -alias GetFileDeployer]
          242  +
          243  +  #
          244  +  # NOTE: Process each entry in the list of packages to be downloaded to the
          245  +  #       target device.  The package list must contain the package Id and the
          246  +  #       file name (relative to the target device), in that order, for each
          247  +  #       package to be downloaded to the target device.
          248  +  #
          249  +  foreach {packageId packageFileName} $packages {
          250  +    qputs stdout [appendArgs \
          251  +        "downloading package \"" $packageId "\" to device..."]
          252  +
          253  +    $fileDeployer DownloadPackage [object create \
          254  +        Microsoft.SmartDevice.Connectivity.ObjectId $packageId]
          255  +
          256  +    qputs stdout [appendArgs \
          257  +        "installing package file \"" $packageFileName "\" on device..."]
          258  +
          259  +    startRemoteProcess $device wceload.exe [appendArgs "/noui " \
          260  +        $packageFileName]
          261  +  }
          262  +
          263  +  #
          264  +  # NOTE: Process each application file to be sent to the target device.
          265  +  #
          266  +  foreach fileName $fileNames {
          267  +    qputs stdout [appendArgs \
          268  +        "sending file \"" $fileName "\" to device..."]
          269  +
          270  +    #
          271  +    # NOTE: All the application files are sent to the same directory on the
          272  +    #       target device and the SendFile method requires a fully qualified
          273  +    #       file name; therefore, grab the file name only from the source file
          274  +    #       name and append that to the directory name on the target device.
          275  +    #       Using [file join] and/or [file normalize] should be avoided here
          276  +    #       because the directory name on the target device is not necessarily
          277  +    #       valid a file name on this system and vice versa.
          278  +    #
          279  +    $fileDeployer SendFile $fileName [appendArgs $device_directory \
          280  +        [file tail $fileName]] true false
          281  +  }
          282  +
          283  +  #
          284  +  # NOTE: Run the test application on the target device in "automatic" mode
          285  +  #       (i.e. no user interaction is required) and capture the exit code.
          286  +  #       The exit code will be zero upon success (i.e. all tests passed) or
          287  +  #       non-zero otherwise.
          288  +  #
          289  +  set testFileName [file nativename [file join $device_directory testce.exe]]
          290  +  set exitCode [startRemoteProcess $device $testFileName true]
          291  +
          292  +  #
          293  +  # NOTE: Is the target device actually an emulator running on this system?
          294  +  #
          295  +  set isEmulator [$device IsEmulator]
          296  +
          297  +  #
          298  +  # NOTE: We no longer need to be connected to the target device.
          299  +  #
          300  +  $device Disconnect
          301  +
          302  +  #
          303  +  # NOTE: Also, if the device is an emulator, attempt to shutdown the process
          304  +  #       containing it now (since we probably caused it to start).
          305  +  #
          306  +  if {$isEmulator} then {
          307  +    #
          308  +    # NOTE: Try to find the top-level window for the device emulator process
          309  +    #       based on the "LCDDisplay" window class name.  Using this method
          310  +    #       of finding the target window is somewhat fragile and may not work
          311  +    #       reliably in the future.
          312  +    #
          313  +    set hWnd [lindex [lindex [info windows LCDDisplay] 0] 0]; # FIXME: ???
          314  +
          315  +    #
          316  +    # NOTE: Make sure we found it before trying to lookup the parent process.
          317  +    #
          318  +    if {[string is integer -strict $hWnd] && $hWnd != 0} then {
          319  +      #
          320  +      # NOTE: Attempt to lookup the parent process for the target window.
          321  +      #
          322  +      qputs stdout [appendArgs "found device emulator window handle " $hWnd \
          323  +          ", looking up the process Id..."]
          324  +
          325  +      set processId 0; set threadId 0; set error null
          326  +
          327  +      if {[object invoke -flags +NonPublic \
          328  +          Eagle._Components.Private.WindowOps GetWindowThreadProcessId \
          329  +          [object create IntPtr $hWnd] processId threadId error] eq "Ok" && \
          330  +          [string is integer -strict $processId] && $processId != 0} then {
          331  +        #
          332  +        # NOTE: This is not ideal; however, if we simply try to close the
          333  +        #       target window, it will prompt to save state changes and that
          334  +        #       requires user interaction.  We never want to save the state;
          335  +        #       therefore, just forcibly kill the process containing the
          336  +        #       emulator.
          337  +        #
          338  +        qputs stdout [appendArgs "found device emulator process Id " \
          339  +            $processId ", killing..."]
          340  +
          341  +        kill -force $processId
          342  +      }
          343  +    }
          344  +  }
          345  +
          346  +  #
          347  +  # NOTE: Print the overall result of running the test application and exit
          348  +  #       using the exit code from the test application on the target device.
          349  +  #
          350  +  qputs stdout [expr {$exitCode == 0 ? "SUCCESS" : "FAILURE"}]
          351  +  exit $exitCode
          352  +} else {
          353  +  usage ""
          354  +}

Changes to Setup/verify.lst.

   503    503   ###############################################################################
   504    504   #
   505    505   # NOTE: This is the list of interop and other files that should be present in
   506    506   #       the standard "PocketPC" binary archives (i.e. for the .NET Compact
   507    507   #       Framework).
   508    508   #
   509    509   set sds_manifests(binaryCompact) {
   510         -  "SQLite.Interop.[format %03d $build].dll"
   511         -  "SQLite.Interop.[format %03d $build].pdb"
          510  +  [appendArgs SQLite.Interop. [format %03d $build] .dll]
          511  +  [appendArgs SQLite.Interop. [format %03d $build] .pdb]
   512    512     test.cfg
   513    513     testce.exe
   514    514     testce.pdb
   515    515   }
   516    516   
   517    517   ###############################################################################
   518    518   #

Changes to testce/TestCases.cs.

    67     67         if (param2 == "Field3") return -1;
    68     68         return String.Compare(param1, param2, true);
    69     69       }
    70     70     }
    71     71   
    72     72     internal class TestCases
    73     73     {
    74         -    private bool autoClose;
    75     74       internal Form1 frm;
    76         -    internal int total;
    77         -    internal int passed;
    78         -    internal int failed;
           75  +
           76  +    private bool autoClose;
           77  +    private int total;
           78  +    private int passed;
           79  +    private int failed;
    79     80   
    80     81       internal TestCases(bool autoExit)
    81     82       {
    82     83           this.autoClose = autoExit;
    83     84       }
    84     85   
    85     86       internal bool Succeeded()