multirunner.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. """
  2. Testing framework module for running tests in Python unittest fashion
  3. Copyright (C) 2014-2021 by the GRASS Development Team
  4. This program is free software under the GNU General Public
  5. License (>=v2). Read the file COPYING that comes with GRASS GIS
  6. for details.
  7. :authors: Vaclav Petras
  8. """
  9. from __future__ import print_function
  10. import sys
  11. import os
  12. import argparse
  13. import subprocess
  14. import locale
  15. try:
  16. from itertools import izip as zip
  17. except ImportError: # will be 3.x series
  18. pass
  19. if sys.version_info.major >= 3:
  20. unicode = str
  21. def _get_encoding():
  22. encoding = locale.getdefaultlocale()[1]
  23. if not encoding:
  24. encoding = "UTF-8"
  25. return encoding
  26. def decode(bytes_, encoding=None):
  27. if isinstance(bytes_, bytes):
  28. return bytes_.decode(_get_encoding())
  29. else:
  30. return bytes_
  31. def encode(string, encoding=None):
  32. if isinstance(string, unicode):
  33. return string.encode(_get_encoding())
  34. else:
  35. return string
  36. def text_to_string(text):
  37. """Convert text to str. Useful when passing text into environments,
  38. in Python 2 it needs to be bytes on Windows, in Python 3 in needs unicode.
  39. """
  40. if sys.version[0] == "2":
  41. # Python 2
  42. return encode(text)
  43. else:
  44. # Python 3
  45. return decode(text)
  46. def main():
  47. parser = argparse.ArgumentParser(description="Run tests with new")
  48. parser.add_argument(
  49. "--location",
  50. "-l",
  51. required=True,
  52. action="append",
  53. dest="locations",
  54. metavar="LOCATION",
  55. help="Directories with reports",
  56. )
  57. parser.add_argument(
  58. "--location-type",
  59. "-t",
  60. action="append",
  61. dest="location_types",
  62. default=[],
  63. metavar="TYPE",
  64. help="Add repeated values to a list",
  65. )
  66. parser.add_argument(
  67. "--grassbin",
  68. required=True,
  69. help="Use file timestamp instead of date in test summary",
  70. )
  71. # TODO: rename since every src can be used?
  72. parser.add_argument(
  73. "--grasssrc", required=True, help="GRASS GIS source code (to take tests from)"
  74. )
  75. parser.add_argument(
  76. "--grassdata", required=True, help="GRASS GIS data base (GISDBASE)"
  77. )
  78. parser.add_argument(
  79. "--create-main-report",
  80. help="Create also main report for all tests",
  81. action="store_true",
  82. default=False,
  83. dest="main_report",
  84. )
  85. args = parser.parse_args()
  86. gisdb = args.grassdata
  87. locations = args.locations
  88. locations_types = args.location_types
  89. # TODO: if locations empty or just one we can suppose the same all the time
  90. if len(locations) != len(locations_types):
  91. print(
  92. "ERROR: Number of locations and their tags must be the same",
  93. file=sys.stderr,
  94. )
  95. return 1
  96. main_report = args.main_report
  97. grasssrc = args.grasssrc # TODO: can be guessed from dist
  98. # TODO: create directory according to date and revision and create reports there
  99. # some predefined variables, name of the GRASS launch script + location/mapset
  100. # grass8bin = 'C:\Program Files (x86)\GRASS GIS 8.0.git\grass.bat'
  101. grass8bin = args.grassbin # TODO: can be used if pressent
  102. # Software
  103. # query GRASS GIS 8 itself for its GISBASE
  104. # we assume that GRASS GIS' start script is available and in the PATH
  105. # the shell=True is here because of MS Windows? (code taken from wiki)
  106. startcmd = grass8bin + " --config path"
  107. p = subprocess.Popen(
  108. startcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
  109. )
  110. out, err = p.communicate()
  111. if p.returncode != 0:
  112. print(
  113. "ERROR: Cannot find GRASS GIS 8 start script (%s):\n%s" % (startcmd, err),
  114. file=sys.stderr,
  115. )
  116. return 1
  117. gisbase = decode(out.strip())
  118. # set GISBASE environment variable
  119. os.environ["GISBASE"] = text_to_string(gisbase)
  120. # define GRASS Python environment
  121. grass_python_dir = os.path.join(gisbase, "etc", "python")
  122. sys.path.append(grass_python_dir)
  123. # Data
  124. # define GRASS DATABASE
  125. # Set GISDBASE environment variable
  126. os.environ["GISDBASE"] = text_to_string(gisdb)
  127. # import GRASS Python package for initialization
  128. import grass.script.setup as gsetup
  129. # launch session
  130. # we need some location and mapset here
  131. # TODO: can init work without it or is there some demo location in dist?
  132. location = locations[0].split(":")[0]
  133. mapset = "PERMANENT"
  134. gsetup.init(gisbase, gisdb, location, mapset)
  135. reports = []
  136. for location, location_type in zip(locations, locations_types):
  137. # here it is quite a good place to parallelize
  138. # including also type to make it unique and preserve it for sure
  139. report = "report_for_" + location + "_" + location_type
  140. absreport = os.path.abspath(report)
  141. p = subprocess.Popen(
  142. [
  143. sys.executable,
  144. "-tt",
  145. "-m",
  146. "grass.gunittest.main",
  147. "--grassdata",
  148. gisdb,
  149. "--location",
  150. location,
  151. "--location-type",
  152. location_type,
  153. "--output",
  154. absreport,
  155. ],
  156. cwd=grasssrc,
  157. )
  158. returncode = p.wait()
  159. reports.append(report)
  160. if main_report:
  161. # TODO: solve the path to source code (work now only for grass source code)
  162. arguments = [
  163. sys.executable,
  164. grasssrc + "/python/grass/gunittest/" + "multireport.py",
  165. "--timestapms",
  166. ]
  167. arguments.extend(reports)
  168. p = subprocess.Popen(arguments)
  169. returncode = p.wait()
  170. if returncode != 0:
  171. print("ERROR: Creation of main report failed.", file=sys.stderr)
  172. return 1
  173. return 0
  174. if __name__ == "__main__":
  175. sys.exit(main())