Repository: ESMCI/cime

Issue:
testreporter.pl not being copied to testing directory
Bug in test_scheduler.py was failing to copy testreporter.pl to the testing directory.
 


Discussion:

Resolving patch:
diff --git a/scripts/Tools/testreporter.py b/scripts/Tools/testreporter.py
new file mode 100755
--- /dev/null
+++ b/scripts/Tools/testreporter.py
@@ -0,0 +1,228 @@
+#!/usr/bin/env python
+
+"""
+
+Simple script to populate CESM test database with test results. 
+
+"""
+
+from standard_script_setup import *
+
+from CIME.XML.env_build             import EnvBuild
+from CIME.XML.env_case              import EnvCase
+from CIME.XML.env_test              import EnvTest
+from CIME.XML.test_reporter         import TestReporter
+from CIME.utils                     import expect
+from CIME.XML.generic_xml import GenericXML
+
+
+import glob
+
+
+
+###############################################################################
+def parse_command_line(args):
+###############################################################################
+    parser = argparse.ArgumentParser()
+
+    CIME.utils.setup_standard_logging_options(parser)
+
+    # Parse command line options
+
+#    parser = argparse.ArgumentParser(description='Arguements for testreporter')
+    parser.add_argument("--tagname", 
+                        help="Name of the tag being tested.")
+    parser.add_argument("--testid", 
+                        help="Test id, ie c2_0_a6g_ing,c2_0_b6g_gnu.")
+    parser.add_argument("--testroot", 
+                        help="Root directory for tests to populate the database.")
+    parser.add_argument("--testtype", 
+                        help="Type of test, prealpha or prebeta.")
+    parser.add_argument("--dryrun",action="store_true", 
+                        help="Do a dry run, database will not be populated.")
+    parser.add_argument("--dumpxml",action="store_true", 
+                        help="Dump XML test results to sceen.")
+    args = parser.parse_args()
+    CIME.utils.handle_standard_logging_options(args)
+
+
+    return args.testroot, args.testid, args.tagname, args.testtype, args.dryrun, args.dumpxml
+
+###############################################################################
+def get_testreporter_xml(testroot, testid, tagname, testtype):
+###############################################################################
+    os.chdir(testroot)
+
+    #
+    # Retrieve compiler name and mpi library
+    #
+    xml_file=glob.glob("*"+testid+"/env_build.xml")
+    expect(len(xml_file) > 0, "Tests not found.  It's possible your testid, %s is wrong." %testid )
+    envxml=(EnvBuild(".",infile=xml_file[0]))
+    compiler=envxml.get_value("COMPILER")
+    mpilib=envxml.get_value("MPILIB")
+
+    #
+    # Retrieve machine name
+    #
+    xml_file=glob.glob("*"+testid+"/env_case.xml")
+    envxml=(EnvCase(".",infile=xml_file[0]))
+    machine=envxml.get_value("MACH")
+
+    #
+    # Retrieve baseline tag to compare to 
+    #
+    xml_file=glob.glob("*"+testid+"/env_test.xml")
+    envxml=(EnvTest(".",infile=xml_file[0]))
+    baseline = envxml.get_value("BASELINE_NAME_CMP")
+
+    #
+    # Create XML header
+    #
+
+    testxml=TestReporter()
+    testxml.setup_header(tagname,machine,compiler,mpilib,testroot,testtype,baseline)
+
+    #
+    # Create lists on tests based on the testid in the testroot directory.
+    #
+    test_names=glob.glob("*"+testid)
+    #
+    # Loop over all tests and parse the test results
+    #
+    test_status={}
+    for test_name in test_names:  
+        if not os.path.isfile(test_name+"/TestStatus"):
+            continue
+        test_status['COMMENT']=""
+        test_status['BASELINE']='----'
+        test_status['MEMCOMP']='----'
+        test_status['MEMLEAK']='----'
+        test_status['NLCOMP']='----'
+        test_status['STATUS']='----'
+        test_status['TPUTCOMP']='----'
+        #
+        # Check to see if TestStatus is present, if not then continue
+        # I might want to set the status to fail
+        #
+        try:
+            lines = [line.rstrip('\n') for line in open(test_name+"/TestStatus")]
+        except:
+            test_status['STATUS']="FAIL"
+            test_status['COMMENT']="TestStatus missing. "
+            continue
+        #
+        # Loop over each line of TestStatus, and check for different types of failures.
+        #
+        for line in lines:
+            if "NLCOMP" in line:
+                test_status['NLCOMP']=line[0:4]
+            if "MEMLEAK" in line:
+                test_status['MEMLEAK']=line[0:4]
+            if "MEMCOMP" in line:
+                test_status['MEMCOMP']=line[0:4]
+            if "BASELINE" in line:
+                test_status['BASELINE']=line[0:4]
+            if "TPUTCOMP" in line:
+                test_status['TPUTCOMP']=line[0:4]
+            if "INIT" in line:
+                test_status['INIT']=line[0:4]
+                if line[0:4] == "FAIL":
+                    test_status['STATUS']="SFAIL"
+                    test_status['COMMENT']+="INIT fail! "
+                    break
+            if "CREATE_NEWCASE" in line:
+                test_status['CREATE_NEWCASE']=line[0:4]
+                if line[0:4] == "FAIL":
+                    test_status['STATUS']="SFAIL"
+                    test_status['COMMENT']+="CREATE_NEWCASE fail! "
+                    break
+            if "XML" in line:
+                test_status['XML']=line[0:4]
+                if line[0:4] == "FAIL":
+                    test_status['STATUS']="SFAIL"
+                    test_status['COMMENT']+="XML fail! "
+                    break
+            if "SETUP" in line:
+                test_status['SETUP']=line[0:4]
+                if line[0:4] == "FAIL":
+                    test_status['STATUS']="SFAIL"
+                    test_status['COMMENT']+="SETUP fail! "
+                    break
+            if "SHAREDLIB_BUILD" in line:
+                test_status['SHAREDLIB_BUILD']=line[0:4]
+                if line[0:4] == "FAIL":
+                    test_status['STATUS']="CFAIL"
+                    test_status['COMMENT']+="SHAREDLIB_BUILD fail! "
+                    break
+            if "MODEL_BUILD" in line:
+                test_status['MODEL_BUILD']=line[0:4]
+                if line[0:4] == "FAIL":
+                    test_status['STATUS']="CFAIL"
+                    test_status['COMMENT']+="MODEL_BUILD fail! "
+                    break
+            if "SUBMIT" in line:
+                test_status['STATUS']=line[0:4]
+                if line[0:4] == "FAIL":
+                    test_status['COMMENT']+="SUBMIT fail! "
+                    break
+            if "RUN" in line:
+                test_status['STATUS']=line[0:4]
+                if line[0:4] == "FAIL":
+                    test_status['COMMENT']+="RUN fail! "
+                    break
+            if "COMPARE_base_rest" in line:
+                test_status['STATUS']=line[0:4]
+                if line[0:4] == "FAIL":
+                    test_status['COMMENT']+="Restart fail! "
+                    break
+            if "COMPARE_base_hybrid" in line:
+                test_status['STATUS']=line[0:4]
+                if line[0:4] == "FAIL":
+                    test_status['COMMENT']+="Hybrid fail! "
+                    break
+
+            #
+            #  Do not include time comments.  Just a preference to have cleaner comments in the test database
+            #
+            try:
+                if 'time=' not in line:
+                    test_status['COMMENT']+=line.split(' ',3)[3]+' '
+            except:
+                pass
+
+        #
+        # Fill in the xml with the test results
+        #
+        testxml.add_result(test_name,test_status)
+  
+    return testxml       
+
+
+##############################################################################
+def _main_func():
+###############################################################################
+
+    testroot, testid, tagname, testtype, dryrun, dumpxml = parse_command_line(sys.argv)
+
+    testxml = get_testreporter_xml(testroot, testid, tagname, testtype)
+
+    #
+    # Dump xml to a file.
+    #
+    if dumpxml:
+        GenericXML.write(testxml,outfile="TestRecord.xml")
+
+
+    #
+    # Prompt for username and password, then post the XML string to the test database website
+    #
+    if not dryrun:
+        testxml.push2testdb()
+
+###############################################################################
+
+if __name__ == "__main__":
+    _main_func()
+
+


Test patch:
diff --git a/scripts/lib/CIME/XML/test_reporter.py b/scripts/lib/CIME/XML/test_reporter.py
new file mode 100644
--- /dev/null
+++ b/scripts/lib/CIME/XML/test_reporter.py
@@ -0,0 +1,113 @@
+"""
+Interface to the testreporter xml.  This class inherits from GenericXML.py
+
+"""
+
+from CIME.XML.standard_module_setup import *
+from CIME.XML.generic_xml import GenericXML
+from CIME.utils import expect,get_model
+
+import urllib
+
+
+
+class TestReporter(GenericXML):
+
+    def __init__(self):
+        """
+        initialize an object
+        """
+
+        expect(get_model() == 'cesm', "testreport is only meant to populate the CESM test database." )
+        self.root = None
+
+        GenericXML.__init__(self)
+
+    def setup_header(self, tagname,machine,compiler,mpilib,testroot,testtype,baseline):
+        #
+        # Create the XML header that the testdb is expecting to recieve 
+        #
+        tlelem    = ET.Element("testrecord")
+        elem      = ET.Element('tag_name')
+        elem.text = tagname
+        tlelem.append(elem)
+        elem                = ET.Element('mach')
+        elem.text           = machine
+        tlelem.append(elem)
+        elem                = ET.Element('compiler',attrib={"version":""})
+        elem.text           = compiler
+        tlelem.append(elem)
+        elem                = ET.Element('mpilib',attrib={"version":""})
+        elem.text           = mpilib
+        tlelem.append(elem)
+        elem                = ET.Element('testroot')
+        elem.text           = testroot
+        tlelem.append(elem)
+        elem                = ET.Element('testtype')
+        elem.text           = testtype
+        tlelem.append(elem)
+        elem   = ET.Element('baselinetag')
+        elem.text   = baseline
+        tlelem.append(elem)
+    
+        self.root=tlelem
+
+        
+    def add_result(self,test_name,test_status):
+        #
+        # Add a test result to the XML structure.
+        #
+        tlelem      = ET.Element('tests',attrib={"testname":test_name})
+        elem=ET.Element('category',attrib={"name":"casestatus"})
+        tlelem.append(elem) 
+        elem=ET.Element('category',attrib={"name":"comment"})
+        elem.text= test_status['COMMENT']
+        tlelem.append(elem) 
+
+        elem=ET.Element('category',attrib={"name":"compare"})
+        elem.text= test_status['BASELINE']
+        tlelem.append(elem) 
+
+        elem=ET.Element('category',attrib={"name":"memcomp"})
+        elem.text= test_status['MEMCOMP']
+        tlelem.append(elem) 
+
+        elem=ET.Element('category',attrib={"name":"memleak"})
+        elem.text= test_status['MEMLEAK']
+        tlelem.append(elem) 
+
+        elem=ET.Element('category',attrib={"name":"nlcomp"})
+        elem.text= test_status['NLCOMP']
+        tlelem.append(elem) 
+
+        elem=ET.Element('category',attrib={"name":"status"})
+        elem.text= test_status['STATUS']
+        tlelem.append(elem) 
+
+        elem=ET.Element('category',attrib={"name":"tputcomp"})
+        elem.text= test_status['TPUTCOMP']
+        tlelem.append(elem) 
+
+        self.root.append(tlelem)
+
+
+
+    def push2testdb(self):
+        #
+        # Post test result XML to CESM test database
+        #
+        xmlstr = ET.tostring(self.root,method="xml",encoding="UTF-8")
+        username=raw_input("Username:")
+        os.system("stty -echo")
+        password=raw_input("Password:")
+        os.system("stty echo")
+        params={'username':username,'password':password,'testXML':xmlstr}
+        url="https://csegweb.cgd.ucar.edu/testdb/cgi-bin/processXMLtest.cgi"
+        params = urllib.urlencode(params)
+        f = urllib.urlopen(url, params)
+        #
+        # Print any messages from the post command
+        #
+        print f.read()
+        print f.code
+
diff --git a/scripts/lib/CIME/test_scheduler.py b/scripts/lib/CIME/test_scheduler.py
--- a/scripts/lib/CIME/test_scheduler.py
+++ b/scripts/lib/CIME/test_scheduler.py
@@ -8,7 +8,7 @@
 they can be run outside the context of TestScheduler.
 """
 
-import shutil, traceback, stat, threading, time, glob
+import traceback, stat, threading, time, glob
 from CIME.XML.standard_module_setup import *
 import CIME.compare_namelists
 import CIME.utils
@@ -774,11 +774,16 @@ def _setup_cs_files(self):
                 os.chmod(cs_submit_file,
                          os.stat(cs_submit_file).st_mode | stat.S_IXUSR | stat.S_IXGRP)
 
-            if get_model == "cesm":
-                testreporter =  os.path.join(self._test_root,"testreporter.pl")
-                shutil.copy(os.path.join(self._cime_root,"scripts","Testing","testreporter.pl"),
-                            testreporter)
-                os.chmod(testreporter, os.stat(testreporter).st_mode | stat.S_IXUSR | stat.S_IXGRP)
+            if get_model() == "cesm":
+                template_file = os.path.join(python_libs_root, "testreporter.template")
+                template = open(template_file, "r").read()
+                template = template.replace("<PATH>",
+                                            os.path.join(self._cime_root, "scripts", "Tools"))
+                testreporter_file = os.path.join(self._test_root, "testreporter")
+                with open(testreporter_file, "w") as fd:
+                    fd.write(template)
+                os.chmod(testreporter_file, os.stat(testreporter_file).st_mode
+                         | stat.S_IXUSR | stat.S_IXGRP)
 
         except Exception as e:
             logger.warning("FAILED to set up cs files: %s" % str(e))