Changeset 4127


Ignore:
Timestamp:
Jan 16, 2014, 10:51:33 AM (11 years ago)
Author:
mmc
Message:

Added a "-auto" option to "rappture -tester" so you can run all tests
without the GUI in the background. This is needed as we try to run
regressions automatically during the contribtool process. In order to
do this, I had to split the Tool object into a "Task" that can run
without the GUI, and the "Tool" that acts as a ControlOwner?. I also
had to support for resource file processing into the generic Rappture
package. As a result, "rappture -tester -auto" can run without an
X window connection.

Added support for "job_protocol mx" in the resources file. If you
specify this, then Rappture will execute "mx cmd arg arg..." to run
each job.

Location:
trunk
Files:
2 added
7 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/gui/apps/launcher.tcl

    r3177 r4127  
    2424#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    2525# ======================================================================
    26 package require RapptureGUI
    27 set guidir $RapptureGUI::library
    28 
    29 package require RapptureBuilder
    30 set blddir $RapptureBuilder::library
    31 
    32 package require RapptureTester
    33 set testdir $RapptureTester::library
    34 
    35 set mainscript [file join $guidir scripts main.tcl]
     26set mainscript ""
    3627set alist ""
    3728set toolxml ""
     
    4536        switch -- $opt {
    4637            -run {
     38                package require RapptureGUI
     39                set guidir $RapptureGUI::library
    4740                set mainscript [file join $guidir scripts main.tcl]
     41                set reqpkgs Tk
    4842            }
    4943            -builder {
     44                package require RapptureBuilder
     45                set blddir $RapptureBuilder::library
    5046                set mainscript [file join $blddir scripts main.tcl]
     47                set reqpkgs Tk
    5148            }
    5249            -tester {
     50                package require RapptureTester
     51                set testdir $RapptureTester::library
    5352                set mainscript [file join $testdir scripts main.tcl]
     53                set reqpkgs Tk
    5454            }
    5555            -tool {
     
    6565                lappend alist $opt [lindex $argv 0]
    6666                set argv [lrange $argv 1 end]
     67            }
     68            -auto {
     69                # for the tester in automatic mode -- don't load Tk
     70                package require RapptureTester
     71                set testdir $RapptureTester::library
     72                set mainscript [file join $testdir scripts auto.tcl]
     73                set reqpkgs ""
    6774            }
    6875            -load {
     
    8188                puts stderr "  rappture ?-run? ?-tool toolFile? ?-nosim 0/1? ?-load file file ...?"
    8289                puts stderr "  rappture -builder ?-tool toolFile?"
    83                 puts stderr "  rappture -tester ?-tool toolFile? ?-testdir directory?"
     90                puts stderr "  rappture -tester ?-auto? ?-tool toolFile? ?-testdir directory?"
    8491                exit 1
    8592            }
    8693        }
    8794    }
     95}
     96
     97# If no arguments, assume that it's the -run option
     98if {$mainscript eq ""} {
     99    package require RapptureGUI
     100    set guidir $RapptureGUI::library
     101    set mainscript [file join $guidir scripts main.tcl]
     102    set reqpkgs Tk
    88103}
    89104
     
    97112#       blt::bgexec.  It doesn't try to redirect stderr into a file.
    98113set argv $alist
    99 package require Tk
     114foreach name $reqpkgs {
     115    package require $name
     116}
    100117source  $mainscript
  • trunk/gui/apps/rappture.in

    r3177 r4127  
    1616dir=`dirname $0`
    1717. $dir/rappture.env
    18 exec tclsh $dir/launcher.tcl -- "$@"
     18exec tclsh $dir/launcher.tcl "$@"
  • trunk/gui/scripts/Makefile.in

    r4012 r4127  
    9898                $(srcdir)/pushbutton.tcl \
    9999                $(srcdir)/radiodial.tcl \
    100                 $(srcdir)/resources.tcl \
    101100                $(srcdir)/resultset.tcl \
    102101                $(srcdir)/resultselector.tcl \
  • trunk/gui/scripts/tool.tcl

    r3811 r4127  
    1111# ======================================================================
    1212#  AUTHOR:  Michael McLennan, Purdue University
    13 #  Copyright (c) 2004-2012  HUBzero Foundation, LLC
     13#  Copyright (c) 2004-2014  HUBzero Foundation, LLC
    1414#
    1515#  See the file "license.terms" for information on usage and
    1616#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
    1717# ======================================================================
    18 package require BLT
    1918
    2019itcl::class Rappture::Tool {
    2120    inherit Rappture::ControlOwner
    2221
    23     constructor {xmlobj installdir args} {
     22    constructor {xmlobj installdir} {
    2423        Rappture::ControlOwner::constructor ""
    2524    } { # defined below }
     
    2726    destructor { # defined below }
    2827
    29     public method installdir {} { return $_installdir }
     28    public method installdir {} {
     29        return [$_task installdir]
     30    }
     31    public method run {args} {
     32        sync  ;# sync all widget values to XML
     33        eval $_task run $args
     34    }
     35    public method abort {} {
     36        $_task abort
     37    }
     38    public method reset {} {
     39        $_task reset
     40    }
    3041
    31     public method run {args}
    32     public method abort {}
    33     public method reset {}
     42    private variable _task ""  ;# underlying task for the tool
    3443
    35     protected method _mkdir {dir}
    36     protected method _output {data}
    37 
    38     private variable _origxml ""     ;# copy of original XML (for reset)
    39     private variable _installdir ""  ;# installation directory for this tool
    40     private variable _outputcb ""    ;# callback for tool output
    41     private common job               ;# array var used for blt::bgexec jobs
    42     private common jobnum 0          ;# counter for unique job number
    43 
    44     # get global resources for this tool session
    45     public proc resources {{option ""}}
    46 
    47     public common _resources
    48     public proc setAppName {name}   { set _resources(-appname) $name }
    49     public proc setHubName {name}   { set _resources(-hubname) $name }
    50     public proc setHubURL {name}    { set _resources(-huburl) $name }
    51     public proc setSession {name}   { set _resources(-session) $name }
    52     public proc setJobPrt {name}    { set _resources(-jobprotocol) $name }
    53     public proc setResultDir {name} { set _resources(-resultdir) $name }
    54 }
    55 
    56 # must use this name -- plugs into Rappture::resources::load
    57 proc tool_init_resources {} {
    58     Rappture::resources::register \
    59         application_name  Rappture::Tool::setAppName \
    60         application_id    Rappture::Tool::setAppId \
    61         hub_name          Rappture::Tool::setHubName \
    62         hub_url           Rappture::Tool::setHubURL \
    63         session_token     Rappture::Tool::setSession \
    64         job_protocol      Rappture::Tool::setJobPrt \
    65         results_directory Rappture::Tool::setResultDir
     44    # global resources for this tool session (from task)
     45    public proc resources {{option ""}} {
     46        eval ::Rappture::Task::resources $option
     47    }
    6648}
    6749
     
    6951# CONSTRUCTOR
    7052# ----------------------------------------------------------------------
    71 itcl::body Rappture::Tool::constructor {xmlobj installdir args} {
     53itcl::body Rappture::Tool::constructor {xmlobj installdir} {
    7254    if {![Rappture::library isvalid $xmlobj]} {
    7355        error "bad value \"$xmlobj\": should be Rappture::Library"
    7456    }
     57
     58    set _task [Rappture::Task ::#auto $xmlobj $installdir \
     59        -logger ::Rappture::Logger::log]
     60
     61    # save a reference to the tool XML in the ControlOwner
    7562    set _xmlobj $xmlobj
    76 
    77     # stash a copy of the original XML for later "reset" operations
    78     set _origxml [Rappture::LibraryObj ::#auto "<?xml version=\"1.0\"?><run/>"]
    79     $_origxml copy "" from $_xmlobj ""
    80 
    81     if {![file exists $installdir]} {
    82         error "directory \"$installdir\" doesn't exist"
    83     }
    84     set _installdir $installdir
    85 
    86     eval configure $args
    8763}
    8864
     
    9167# ----------------------------------------------------------------------
    9268itcl::body Rappture::Tool::destructor {} {
    93     itcl::delete object $_origxml
     69    itcl::delete object $_task
    9470}
    95 
    96 # ----------------------------------------------------------------------
    97 # USAGE: resources ?-option?
    98 #
    99 # Clients use this to query information about the tool.
    100 # ----------------------------------------------------------------------
    101 itcl::body Rappture::Tool::resources {{option ""}} {
    102     if {$option == ""} {
    103         return [array get _resources]
    104     }
    105     if {[info exists _resources($option)]} {
    106         return $_resources($option)
    107     }
    108     return ""
    109 }
    110 
    111 # ----------------------------------------------------------------------
    112 # USAGE: run ?<path1> <value1> <path2> <value2> ...? ?-output <callbk>?
    113 #
    114 # This method causes the tool to run.  All widgets are synchronized
    115 # to the current XML representation, and a "driver.xml" file is
    116 # created as the input for the run.  That file is fed to the tool
    117 # according to the <tool><command> string, and the job is executed.
    118 #
    119 # Any "<path> <value>" arguments are used to override the current
    120 # settings from the GUI.  This is useful, for example, when filling
    121 # in missing simulation results from the analyzer.
    122 #
    123 # If the -output argument is included, then the next arg is a
    124 # callback command for output messages.  Any output that comes in
    125 # while the tool is running is sent back to the caller, so the user
    126 # can see progress running the tool.
    127 #
    128 # Returns a list of the form {status result}, where status is an
    129 # integer status code (0=success) and result is the output from the
    130 # simulator.  Successful output is something like {0 run1293921.xml},
    131 # where 0=success and run1293921.xml is the name of the file containing
    132 # results.
    133 # ----------------------------------------------------------------------
    134 itcl::body Rappture::Tool::run {args} {
    135     global env errorInfo
    136 
    137     #
    138     # Make sure that we save the proper application name.
    139     # Actually, the best place to get this information is
    140     # straight from the "installtool" script, but just in
    141     # case we have an older tool, we should insert the
    142     # tool name from the resources config file.
    143     #
    144     if {[info exists _resources(-appname)]
    145           && "" != $_resources(-appname)
    146           && "" == [$_xmlobj get tool.name]} {
    147         $_xmlobj put tool.name $_resources(-appname)
    148     }
    149 
    150     # sync all widgets to the XML tree
    151     sync
    152 
    153     # if there are any args, use them to override parameters
    154     set _outputcb ""
    155     foreach {path val} $args {
    156         if {$path == "-output"} {
    157             set _outputcb $val
    158         } else {
    159             $_xmlobj put $path.current $val
    160         }
    161     }
    162 
    163     foreach item {control output error} { set job($item) "" }
    164 
    165     # write out the driver.xml file for the tool
    166     set file "driver[pid].xml"
    167     set status [catch {
    168         set fid [open $file w]
    169         puts $fid "<?xml version=\"1.0\"?>"
    170         puts $fid [$_xmlobj xml]
    171         close $fid
    172     } result]
    173 
    174     # Set limits for cpu time
    175     set limit [$_xmlobj get tool.limits.cputime]
    176     if { $limit == "unlimited" } {
    177         set limit 43200;                # 12 hours
    178     } else {
    179         if { [scan $limit "%d" dum] != 1 } {
    180             set limit 14400;            # 4 hours by default
    181         } elseif { $limit > 43200 } {
    182             set limit 43200;            # limit to 12 hrs.
    183         } elseif { $limit < 10 } {
    184             set limit 10;               # lower bound is 10 seconds.
    185         }
    186     }
    187     Rappture::rlimit set cputime $limit 
    188     # execute the tool using the path from the tool description
    189     if {$status == 0} {
    190         set cmd [$_xmlobj get tool.command]
    191         regsub -all @tool $cmd $_installdir cmd
    192         regsub -all @driver $cmd $file cmd
    193         regsub -all {\\} $cmd {\\\\} cmd
    194         set cmd [string trimleft $cmd " "]
    195         if { $cmd == "" } {
    196             puts stderr "cmd is empty"
    197             return [list 1 "Command is empty.\n\nThere is no command specified by\n\n <command>\n </command>\n\nin the tool.xml file."]
    198         }
    199         # if job_protocol is "submit", then use use submit command
    200         if {[resources -jobprotocol] == "submit"} {
    201             set cmd [linsert $cmd 0 submit --local]
    202         }
    203         $_xmlobj put tool.execute $cmd
    204 
    205         # starting job...
    206         Rappture::Logger::log run started
    207         Rappture::rusage mark
    208 
    209         if {0 == [string compare -nocase -length 5 $cmd "ECHO "] } {
    210             set status 0;
    211             set job(output) [string range $cmd 5 end]
    212         } else {
    213             set status [catch {
    214                 set ::Rappture::Tool::job(control) ""
    215                 eval blt::bgexec \
    216                     ::Rappture::Tool::job(control) \
    217                     -keepnewline yes \
    218                     -killsignal SIGTERM \
    219                     -onoutput [list [itcl::code $this _output]] \
    220                     -output ::Rappture::Tool::job(output) \
    221                     -error ::Rappture::Tool::job(error) \
    222                     $cmd
    223             } result]
    224 
    225             if { $status != 0 } {
    226                 # We're here because the exec-ed program failed
    227                 set logmesg $result
    228                 if { $::Rappture::Tool::job(control) != "" } {
    229                     foreach { token pid code mesg } \
    230                         $::Rappture::Tool::job(control) break
    231                     if { $token == "EXITED" } {
    232                         # This means that the program exited normally but
    233                         # returned a non-zero exitcode.  Consider this an
    234                         # invalid result from the program.  Append the stderr
    235                         # from the program to the message.
    236                         set logmesg "Program finished: exit code is $code"
    237                         set result "$logmesg\n\n$::Rappture::Tool::job(error)"
    238                     } elseif { $token == "abort" }  {
    239                         # The user pressed the abort button.
    240                         set logmesg "Program terminated by user."
    241                         set result "$logmesg\n\n$::Rappture::Tool::job(output)"
    242                     } else {
    243                         # Abnormal termination
    244                         set logmesg "Abnormal program termination: $mesg"
    245                         set result "$logmesg\n\n$::Rappture::Tool::job(output)"
    246                     }
    247                 }
    248                 Rappture::Logger::log run failed [list $logmesg]
    249                 return [list $status $result]
    250             }
    251         }
    252         # ...job is finished
    253         array set times [Rappture::rusage measure]
    254 
    255         if {[resources -jobprotocol] != "submit"} {
    256             set id [$_xmlobj get tool.id]
    257             set vers [$_xmlobj get tool.version.application.revision]
    258             set simulation simulation
    259             if { $id != "" && $vers != "" } {
    260                 set pid [pid]
    261                 set simulation ${pid}_${id}_r${vers}
    262             }
    263             puts stderr "MiddlewareTime: job=[incr jobnum] event=$simulation start=$times(start) walltime=$times(walltime) cputime=$times(cputime) status=$status"
    264 
    265             #
    266             # Scan through stderr channel and look for statements that
    267             # represent grid jobs that were executed.  The statements
    268             # look like this:
    269             #
    270             # MiddlewareTime: job=1 event=simulation start=3.001094 ...
    271             #
    272             set subjobs 0
    273             while {[regexp -indices {(^|\n)MiddlewareTime:( +[a-z]+=[^ \n]+)+(\n|$)} $job(error) match]} {
    274                 foreach {p0 p1} $match break
    275                 if {[string index $job(error) $p0] == "\n"} { incr p0 }
    276 
    277                 catch {unset data}
    278                 array set data {
    279                     job 1
    280                     event simulation
    281                     start 0
    282                     walltime 0
    283                     cputime 0
    284                     status 0
    285                 }
    286                 foreach arg [lrange [string range $job(error) $p0 $p1] 1 end] {
    287                     foreach {key val} [split $arg =] break
    288                     set data($key) $val
    289                 }
    290                 set data(job) [expr {$jobnum+$data(job)}]
    291                 set data(event) "subsimulation"
    292                 set data(start) [expr {$times(start)+$data(start)}]
    293 
    294                 set stmt "MiddlewareTime:"
    295                 foreach key {job event start walltime cputime status} {
    296                     # add required keys in a particular order
    297                     append stmt " $key=$data($key)"
    298                     unset data($key)
    299                 }
    300                 foreach key [array names data] {
    301                     # add anything else that the client gave -- venue, etc.
    302                     append stmt " $key=$data($key)"
    303                 }
    304                 puts stderr $stmt
    305                 incr subjobs
    306 
    307                 # done -- remove this statement
    308                 set job(error) [string replace $job(error) $p0 $p1]
    309             }
    310             incr jobnum $subjobs
    311         }
    312 
    313     } else {
    314         set job(error) "$result\n$errorInfo"
    315     }
    316     if {$status == 0} {
    317         file delete -force -- $file
    318     }
    319 
    320     # see if the job was aborted
    321     if {[regexp {^KILLED} $job(control)]} {
    322         Rappture::Logger::log run aborted
    323         return [list 0 "ABORT"]
    324     }
    325 
    326     #
    327     # If successful, return the output, which should include
    328     # a reference to the run.xml file containing results.
    329     #
    330     if {$status == 0} {
    331         set result [string trim $job(output)]
    332         if {[regexp {=RAPPTURE-RUN=>([^\n]+)} $result match file]} {
    333             set status [catch {Rappture::library $file} result]
    334             if {$status == 0} {
    335                 # add cputime info to run.xml file
    336                 $result put output.walltime $times(walltime)
    337                 $result put output.cputime $times(cputime)
    338                 if {[info exists env(SESSION)]} {
    339                     $result put output.session $env(SESSION)
    340                 }
    341             } else {
    342                 global errorInfo
    343                 set result "$result\n$errorInfo"
    344             }
    345 
    346             # if there's a results_directory defined in the resources
    347             # file, then move the run.xml file there for storage
    348             if {$status == 0 && [info exists _resources(-resultdir)]
    349                   && $_resources(-resultdir) ne ""} {
    350                 catch {
    351                     if {![file exists $_resources(-resultdir)]} {
    352                         _mkdir $_resources(-resultdir)
    353                     }
    354                     set tail [file tail $file]
    355                     set fid [open [file join $_resources(-resultdir) $tail] w]
    356                     puts $fid "<?xml version=\"1.0\"?>"
    357                     puts $fid [$result xml]
    358                     close $fid
    359                     file delete -force -- $file
    360                 }
    361             }
    362         } else {
    363             set status 1
    364             set result "Can't find result file in output.\nDid you call Rappture
    365 ::result in your simulator?"
    366         }
    367     } elseif {$job(output) ne "" || $job(error) ne ""} {
    368         set result [string trim "$job(output)\n$job(error)"]
    369     }
    370 
    371     # log final status for the run
    372     if {$status == 0} {
    373         Rappture::Logger::log run finished
    374     } else {
    375         Rappture::Logger::log run failed [list $result]
    376     }
    377 
    378     return [list $status $result]
    379 }
    380 
    381 # ----------------------------------------------------------------------
    382 # USAGE: _mkdir <directory>
    383 #
    384 # Used internally to create the <directory> in the file system.
    385 # The parent directory is also created, as needed.
    386 # ----------------------------------------------------------------------
    387 itcl::body Rappture::Tool::_mkdir {dir} {
    388     set parent [file dirname $dir]
    389     if {"." != $parent && "/" != $parent} {
    390         if {![file exists $parent]} {
    391             _mkdir $parent
    392         }
    393     }
    394     file mkdir $dir
    395 }
    396 
    397 
    398 # ----------------------------------------------------------------------
    399 # USAGE: abort
    400 #
    401 # Clients use this during a "run" to abort the current job.
    402 # Kills the job and forces the "run" method to return.
    403 # ----------------------------------------------------------------------
    404 itcl::body Rappture::Tool::abort {} {
    405     Rappture::Logger::log run abort
    406     set job(control) "abort"
    407 }
    408 
    409 # ----------------------------------------------------------------------
    410 # USAGE: reset
    411 #
    412 # Resets all input values to their defaults.  Sometimes used just
    413 # before a run to reset to a clean state.
    414 # ----------------------------------------------------------------------
    415 itcl::body Rappture::Tool::reset {} {
    416     $_xmlobj copy "" from $_origxml ""
    417     foreach path [Rappture::entities -as path $_xmlobj input] {
    418         if {[$_xmlobj element -as type $path.default] ne ""} {
    419             set defval [$_xmlobj get $path.default]
    420             $_xmlobj put $path.current $defval
    421         }
    422     }
    423 }
    424 
    425 # ----------------------------------------------------------------------
    426 # USAGE: _output <data>
    427 #
    428 # Used internally to send each bit of output <data> coming from the
    429 # tool onto the caller, so the user can see progress.
    430 # ----------------------------------------------------------------------
    431 itcl::body Rappture::Tool::_output {data} {
    432     if {[string length $_outputcb] > 0} {
    433         uplevel #0 $_outputcb [list $data]
    434     }
    435 }
  • trunk/lang/tcl/scripts/Makefile.in

    r3056 r4127  
    4343                $(srcdir)/library.tcl \
    4444                $(srcdir)/objects.tcl \
     45                $(srcdir)/resources.tcl \
    4546                $(srcdir)/result.tcl \
     47                $(srcdir)/task.tcl \
    4648                $(srcdir)/units.tcl
    4749
  • trunk/tester/scripts/Makefile.in

    r3471 r4127  
    1818
    1919FILES           = \
     20                $(srcdir)/auto.tcl \
    2021                $(srcdir)/main.tcl \
    2122                $(srcdir)/legend.tcl \
  • trunk/tester/scripts/main.tcl

    r3177 r4127  
    1717#  USAGE: tester.tcl ?-tool tool.xml? ?-testdir tests?
    1818# ======================================================================
    19 #  AUTHOR: Ben Rafferty, Purdue University
     19#  AUTHORS:  Michael McLennan, Ben Rafferty, Purdue University
    2020#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
    2121#
     
    136136set installdir [file dirname [file normalize $params(-tool)]]
    137137set xmlobj [Rappture::library $params(-tool)]
    138 set ToolObj [Rappture::Tool ::#auto $xmlobj $installdir]
     138set TaskObj [Rappture::Task ::#auto $xmlobj $installdir]
     139
     140# tasks in the tester run quietly and discard results
     141$TaskObj configure -jobstats "" -resultdir ""
     142
    139143set DiffShow ""  ;# used to track which diff objects are being displayed
    140144
     
    296300set testtree [.pw pane 0].tree
    297301foreach file [glob -nocomplain -directory $params(-testdir) *.xml] {
    298     set testobj [Rappture::Tester::Test ::#auto $ToolObj $file]
     302    set testobj [Rappture::Tester::Test ::#auto $TaskObj $file]
    299303    if {[$testobj getTestInfo test.label] eq ""} {
    300304        puts stderr "ERROR:  Missing test label in $file"
Note: See TracChangeset for help on using the changeset viewer.