test.py
changeset 6068 a2127017ecb4
parent 6046 46665d75667d
child 6083 a4a7ded174dc
equal deleted inserted replaced
6067:ccbdc2b19ea5 6068:a2127017ecb4
    25 import threading
    25 import threading
    26 import Queue
    26 import Queue
    27 import signal
    27 import signal
    28 import xml.dom.minidom
    28 import xml.dom.minidom
    29 import shutil
    29 import shutil
       
    30 import re
    30 
    31 
    31 #
    32 #
    32 # XXX This should really be part of a waf command to list the configuration
    33 # XXX This should really be part of a waf command to list the configuration
    33 # items relative to optional ns-3 pieces.
    34 # items relative to optional ns-3 pieces.
    34 #
    35 #
   132     ("tutorial/hello-simulator", "True", "True"),
   133     ("tutorial/hello-simulator", "True", "True"),
   133     ("tutorial/second", "True", "True"),
   134     ("tutorial/second", "True", "True"),
   134     ("tutorial/third", "True", "True"),
   135     ("tutorial/third", "True", "True"),
   135     ("tutorial/fourth", "True", "True"),
   136     ("tutorial/fourth", "True", "True"),
   136     ("tutorial/fifth", "True", "True"),
   137     ("tutorial/fifth", "True", "True"),
       
   138     ("tutorial/sixth", "True", "True"),
   137 
   139 
   138     ("udp/udp-echo", "True", "True"),
   140     ("udp/udp-echo", "True", "True"),
   139 
   141 
   140     ("wireless/mixed-wireless", "True", "True"),
   142     ("wireless/mixed-wireless", "True", "True"),
   141     ("wireless/multirate", "False", "True"), # Takes too long to run
   143     ("wireless/multirate", "False", "True"), # Takes too long to run
   583         for path in NS3_MODULE_PATH:
   585         for path in NS3_MODULE_PATH:
   584             os.environ["LD_LIBRARY_PATH"] += ":" + path
   586             os.environ["LD_LIBRARY_PATH"] += ":" + path
   585         if options.verbose:
   587         if options.verbose:
   586             print "os.environ[\"LD_LIBRARY_PATH\"] == %s" % os.environ["LD_LIBRARY_PATH"]
   588             print "os.environ[\"LD_LIBRARY_PATH\"] == %s" % os.environ["LD_LIBRARY_PATH"]
   587 
   589 
       
   590 #
       
   591 # Short note on generating suppressions:
       
   592 #
       
   593 # See the valgrind documentation for a description of suppressions.  The easiest
       
   594 # way to generate a suppression expression is by using the valgrind 
       
   595 # --gen-suppressions option.  To do that you have to figure out how to run the 
       
   596 # test in question.
       
   597 #
       
   598 # If you do "test.py -v -g -s <suitename> then test.py will output most of what
       
   599 # you need.  For example, if you are getting a valgrind error in the
       
   600 # devices-mesh-dot11s-regression test suite, you can run:
       
   601 #
       
   602 #   ./test.py -v -g -s devices-mesh-dot11s-regression 
       
   603 #
       
   604 # You should see in the verbose output something that looks like:
       
   605 #
       
   606 #   Synchronously execute valgrind --suppressions=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/testpy.supp
       
   607 #   --leak-check=full --error-exitcode=2 /home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build/debug/utils/test-runner 
       
   608 #   --suite=devices-mesh-dot11s-regression --basedir=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev 
       
   609 #   --tempdir=testpy-output/2010-01-12-22-47-50-CUT 
       
   610 #   --out=testpy-output/2010-01-12-22-47-50-CUT/devices-mesh-dot11s-regression.xml
       
   611 #
       
   612 # You need to pull out the useful pieces, and so could run the following to 
       
   613 # reproduce your error:
       
   614 #
       
   615 #   valgrind --suppressions=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/testpy.supp
       
   616 #   --leak-check=full --error-exitcode=2 /home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build/debug/utils/test-runner 
       
   617 #   --suite=devices-mesh-dot11s-regression --basedir=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev 
       
   618 #   --tempdir=testpy-output 
       
   619 #
       
   620 # Hint: Use the first part of the command as is, and point the "tempdir" to 
       
   621 # somewhere real.  You don't need to specify an "out" file.
       
   622 #
       
   623 # When you run the above command you should see your valgrind error.  The 
       
   624 # suppression expression(s) can be generated by adding the --gen-suppressions=yes
       
   625 # option to valgrind.  Use something like:
       
   626 #
       
   627 #   valgrind --gen-suppressions=yes --suppressions=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/testpy.supp
       
   628 #   --leak-check=full --error-exitcode=2 /home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build/debug/utils/test-runner 
       
   629 #   --suite=devices-mesh-dot11s-regression --basedir=/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev 
       
   630 #   --tempdir=testpy-output 
       
   631 #
       
   632 # Now when valgrind detects an error it will ask:
       
   633 #
       
   634 #   ==27235== ---- Print suppression ? --- [Return/N/n/Y/y/C/c] ----
       
   635 #
       
   636 # to which you just enter 'y'<ret>.
       
   637 #
       
   638 # You will be provided with a suppression expression that looks something like
       
   639 # the following:
       
   640 #   {
       
   641 #     <insert_a_suppression_name_here>
       
   642 #     Memcheck:Addr8
       
   643 #     fun:_ZN3ns36dot11s15HwmpProtocolMac8SendPreqESt6vectorINS0_6IePreqESaIS3_EE
       
   644 #     fun:_ZN3ns36dot11s15HwmpProtocolMac10SendMyPreqEv
       
   645 #     fun:_ZN3ns36dot11s15HwmpProtocolMac18RequestDestinationENS_12Mac48AddressEjj
       
   646 #     ...
       
   647 #     the rest of the stack frame
       
   648 #     ...
       
   649 #   }
       
   650 #
       
   651 # You need to add a supression name which will only be printed out by valgrind in 
       
   652 # verbose mode (but it needs to be there in any case).  The entire stack frame is
       
   653 # shown to completely characterize the error, but in most cases you won't need 
       
   654 # all of that info.  For example, if you want to turn off all errors that happen
       
   655 # when the function (fun:) is called, you can just delete the rest of the stack
       
   656 # frame.  You can also use wildcards to make the mangled signatures more readable.
       
   657 #
       
   658 # I added the following to the testpy.supp file for this particular error:
       
   659 #
       
   660 #   {
       
   661 #     Supress invalid read size errors in SendPreq() when using HwmpProtocolMac
       
   662 #     Memcheck:Addr8
       
   663 #     fun:*HwmpProtocolMac*SendPreq*
       
   664 #   }
       
   665 #
       
   666 # Now, when you run valgrind the error will be suppressed.
       
   667 #
       
   668 VALGRIND_SUPPRESSIONS_FILE = "testpy.supp"
       
   669 
   588 def run_job_synchronously(shell_command, directory, valgrind):
   670 def run_job_synchronously(shell_command, directory, valgrind):
       
   671     (base, build) = os.path.split (NS3_BUILDDIR)
       
   672     suppressions_path = os.path.join (base, VALGRIND_SUPPRESSIONS_FILE)
   589     path_cmd = os.path.join (NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command)
   673     path_cmd = os.path.join (NS3_BUILDDIR, NS3_ACTIVE_VARIANT, shell_command)
   590     if valgrind:
   674     if valgrind:
   591         cmd = "valgrind --leak-check=full --error-exitcode=2 %s" % path_cmd
   675         cmd = "valgrind --suppressions=%s --leak-check=full --show-reachable=yes --error-exitcode=2 %s" % (suppressions_path, 
       
   676             path_cmd)
   592     else:
   677     else:
   593         cmd = path_cmd
   678         cmd = path_cmd
   594 
   679 
   595     if options.verbose:
   680     if options.verbose:
   596         print "Synchronously execute %s" % cmd
   681         print "Synchronously execute %s" % cmd
   598     start_time = time.time()
   683     start_time = time.time()
   599     proc = subprocess.Popen(cmd, shell = True, cwd = directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
   684     proc = subprocess.Popen(cmd, shell = True, cwd = directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
   600     stdout_results, stderr_results = proc.communicate()
   685     stdout_results, stderr_results = proc.communicate()
   601     elapsed_time = time.time() - start_time
   686     elapsed_time = time.time() - start_time
   602 
   687 
       
   688     retval = proc.returncode
       
   689 
       
   690     #
       
   691     # valgrind sometimes has its own idea about what kind of memory management
       
   692     # errors are important.  We want to detect *any* leaks, so the way to do 
       
   693     # that is to look for the presence of a valgrind leak summary section.
       
   694     #
       
   695     # If another error has occurred (like a test suite has failed), we don't 
       
   696     # want to trump that error, so only do the valgrind output scan if the 
       
   697     # test has otherwise passed (return code was zero).
       
   698     #
       
   699     if valgrind and retval == 0 and "== LEAK SUMMARY:" in stderr_results:
       
   700         retval = 2
       
   701     
   603     if options.verbose:
   702     if options.verbose:
   604         print "Return code = ", proc.returncode
   703         print "Return code = ", retval
   605         print "stderr = ", stderr_results
   704         print "stderr = ", stderr_results
   606 
   705 
   607     return (proc.returncode, stdout_results, stderr_results, elapsed_time)
   706     return (retval, stdout_results, stderr_results, elapsed_time)
   608 
   707 
   609 #
   708 #
   610 # This class defines a unit of testing work.  It will typically refer to
   709 # This class defines a unit of testing work.  It will typically refer to
   611 # a test suite to run using the test-runner, or an example to run directly.
   710 # a test suite to run using the test-runner, or an example to run directly.
   612 #
   711 #