Commit e11298125aba318d50cb7eeaafccc8176de95bfa

Authored by Jürgen Knödlseder
1 parent b8ffb0f0

Add initial tutorials version

Showing 1 changed file with 340 additions and 0 deletions
test/tutorials.py 0 → 100755
  1 +#! /usr/bin/env python
  2 +# ==========================================================================
  3 +# This script tests the Sphinx tutorials
  4 +#
  5 +# Usage:
  6 +# ./tutorials.py
  7 +#
  8 +# --------------------------------------------------------------------------
  9 +#
  10 +# Copyright (C) 2021 Juergen Knoedlseder
  11 +#
  12 +# This program is free software: you can redistribute it and/or modify
  13 +# it under the terms of the GNU General Public License as published by
  14 +# the Free Software Foundation, either version 3 of the License, or
  15 +# (at your option) any later version.
  16 +#
  17 +# This program is distributed in the hope that it will be useful,
  18 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20 +# GNU General Public License for more details.
  21 +#
  22 +# You should have received a copy of the GNU General Public License
  23 +# along with this program. If not, see <http://www.gnu.org/licenses/>.
  24 +#
  25 +# ==========================================================================
  26 +import os
  27 +import sys
  28 +import subprocess
  29 +import gammalib
  30 +import ctools
  31 +import cscripts
  32 +
  33 +
  34 +# ===================================== #
  35 +# Test class for tutorials verification #
  36 +# ===================================== #
  37 +class tutorials(gammalib.GPythonTestSuite):
  38 + """
  39 + Test class for tutorials verification
  40 + """
  41 + # Constructor
  42 + def __init__(self):
  43 + """
  44 + Constructor
  45 + """
  46 + # Call base class constructor
  47 + gammalib.GPythonTestSuite.__init__(self)
  48 +
  49 + # Initialise results
  50 + self.results = None
  51 +
  52 + # Return
  53 + return
  54 +
  55 + # Set test functions
  56 + def set(self):
  57 + """
  58 + Set all test functions
  59 + """
  60 + # Set test name
  61 + self.name('Tutorials Verification')
  62 +
  63 + # Append tutorials
  64 + self.append(self.tutorials_1dc, 'Test 1DC tutorial')
  65 +
  66 + # Return
  67 + return
  68 +
  69 + # Test line execution
  70 + def _execute_cmd(self, cmd, args):
  71 + """
  72 + Execute command
  73 + """
  74 + # Create subprocess for tool
  75 + p = subprocess.Popen(cmd.split(' '), stdout=subprocess.PIPE,
  76 + stdin=subprocess.PIPE,
  77 + stderr=subprocess.PIPE)
  78 +
  79 + # Write command arguments parameters
  80 + if len(args) > 0:
  81 + p.stdin.write(b'%s' % args)
  82 + p.stdin.close()
  83 +
  84 + # Get results
  85 + res = p.communicate()
  86 +
  87 + # Set error flag and text
  88 + name = 'Test execution of command %s.' % cmd
  89 + self.test_assert((len(res[1]) == 0), name, res[1])
  90 +
  91 + # Return
  92 + return
  93 +
  94 + # Test line execution
  95 + def _test_line_execution(self, lines):
  96 + """
  97 + Test the execution of a sequence of commands
  98 +
  99 + Parameters
  100 + ----------
  101 + lines : list of str
  102 + Command lines
  103 + """
  104 + # Initialise commands and arguments
  105 + cmd = ''
  106 + args = ''
  107 +
  108 + # Loop over all lines
  109 + for line in lines:
  110 +
  111 + # If line starts with a string then extract or execute command
  112 + if line[0:2] == '$ ':
  113 +
  114 + # If we have a command then execute it
  115 + if cmd != '':
  116 + print(cmd, args)
  117 + self._execute_cmd(cmd, args)
  118 +
  119 + # Set new command
  120 + cmd = line[2:]
  121 + args = ''
  122 +
  123 + # ... otherwise add argument
  124 + else:
  125 + args += '%s\n' % (gammalib.strip_whitespace(line))
  126 +
  127 + # If there is a pending command then execute it
  128 + if cmd != '':
  129 + print(cmd, args)
  130 + self._execute_cmd(cmd, args)
  131 +
  132 + # Return
  133 + return
  134 +
  135 + # Test ctool or cscript execution
  136 + def _test_ctool_execution(self, tool, lines):
  137 + """
  138 + Test the execution of a ctool or cscript
  139 +
  140 + The methods test the execution of a ctool or cscript as executed from
  141 + the command line emulating the entering of the queried parameters. Any
  142 + error that occurs in the execution will be signaled and the Python
  143 + traceback will be put in the error message field.
  144 +
  145 + Parameters
  146 + ----------
  147 + tool : str
  148 + ctool name
  149 + lines : list of str
  150 + Command lines
  151 + """
  152 + # Initialise command
  153 + cmd = ''
  154 +
  155 + # Append lines
  156 + for line in lines:
  157 + pos = line.find(']')
  158 + if pos != -1:
  159 + arg = gammalib.strip_whitespace(line[pos+1:])
  160 + cmd += '%s\n' % arg
  161 +
  162 + # Create subprocess for tool
  163 + p = subprocess.Popen([tool], stdout=subprocess.PIPE,
  164 + stdin=subprocess.PIPE,
  165 + stderr=subprocess.PIPE)
  166 +
  167 + # Write command line parameters
  168 + p.stdin.write(b'%s' % cmd)
  169 +
  170 + # Get results
  171 + res = p.communicate()
  172 +
  173 + # Close pipeline
  174 + p.stdin.close()
  175 +
  176 + # Set error flag and text
  177 + name = 'Test execution of %s.' % tool
  178 + self.test_assert((len(res[1]) == 0), name, res[1])
  179 +
  180 + # Return
  181 + return
  182 +
  183 + # Add workflow step
  184 + def _add_workflow_step(self, tool, lines):
  185 + """
  186 + Add workflow step
  187 +
  188 + Parameters
  189 + ----------
  190 + tool : str
  191 + Tool name
  192 + lines : list of str
  193 + Command lines
  194 +
  195 + Returns
  196 + -------
  197 + cmd : str
  198 + Workflow command
  199 + """
  200 + # If tool is a ctool or cscript then add a ctool or cscript workflow
  201 + # step
  202 + if tool[0:2] == 'ct' or tool[0:2] == 'cs':
  203 + self._test_ctool_execution(tool, lines)
  204 +
  205 + # ... otherwise execute lines
  206 + else:
  207 + all_lines = ['$ %s' % tool]
  208 + all_lines.extend(lines)
  209 + self._test_line_execution(all_lines)
  210 +
  211 + # Return
  212 + return
  213 +
  214 + # Extract workflow
  215 + def _get_workflow(self, filename):
  216 + """
  217 + Extract workflow from Sphinx rst file
  218 +
  219 + Parameters
  220 + ----------
  221 + filename : str
  222 + RST filename
  223 +
  224 + Returns
  225 + -------
  226 + workflow : `~gammalib.GXml`
  227 + Workflow XML file
  228 + """
  229 + # Open RST file
  230 + f = open(filename, 'r')
  231 +
  232 + # Signal code block
  233 + code = False
  234 +
  235 + # Loop over lines
  236 + for line in f:
  237 +
  238 + # If we are not in a code block then check whether a code block
  239 + # starts
  240 + if not code:
  241 + pos = line.find('code-block:: bash')
  242 + if pos != -1:
  243 + code = True
  244 + start = -1
  245 + tool = ''
  246 + lines = []
  247 + continue
  248 +
  249 + # ... otherwise
  250 + else:
  251 +
  252 + # If we have no tool name then find tool name
  253 + if tool == '':
  254 + pos = line.find(' $ ')
  255 + if pos != -1:
  256 + start = pos+1
  257 + tool = line[pos+3:-1]
  258 + continue
  259 +
  260 + # ... otherwise append lines or add workflow step
  261 + else:
  262 + blank = gammalib.strip_whitespace(line[0:start])
  263 + cmd = line[start:-1]
  264 + if len(blank) == 0 and cmd[0] != ' ':
  265 + lines.append(cmd)
  266 + continue
  267 + else:
  268 + self._add_workflow_step(tool, lines)
  269 + code = False
  270 + continue
  271 +
  272 + # Add step if some code is pending
  273 + if code:
  274 + self._add_workflow_step(tool, lines)
  275 +
  276 + # Return
  277 + return
  278 +
  279 + # Test 1DC tutorials
  280 + def tutorials_1dc(self):
  281 + """
  282 + Test 1DC tutorials
  283 + """
  284 + # Set environment variables
  285 + os.environ['CTADATA'] = '/project-data/cta/data/1dc'
  286 + os.environ['CALDB'] = '/project-data/cta/data/1dc/caldb'
  287 +
  288 + # Extract workflow
  289 + #workflow = self._get_workflow('../doc/source/users/tutorials/1dc/first_onoff.rst')
  290 + workflow = self._get_workflow('first_onoff.rst')
  291 +
  292 + # Run workflow
  293 +
  294 + # Return
  295 + return
  296 +
  297 +
  298 +# ======================== #
  299 +# Main routine entry point #
  300 +# ======================== #
  301 +if __name__ == '__main__':
  302 +
  303 + # Allocate test suite container
  304 + suites = gammalib.GTestSuites('ctools tutorials verification')
  305 +
  306 + # Allocate test suite and append it to the container
  307 + suite_tutorials = tutorials()
  308 +
  309 + # Setup test suit
  310 + suite_tutorials.set()
  311 +
  312 + # Append test suite to container
  313 + suites.append(suite_tutorials)
  314 +
  315 + # Create pfiles directory
  316 + try:
  317 + os.mkdir('pfiles')
  318 + except:
  319 + pass
  320 +
  321 + # Copy ctools parameter files into pfiles directory
  322 + os.system('cp -r ../src/*/*.par pfiles/')
  323 +
  324 + # Set PFILES environment variable
  325 + os.environ['PFILES'] = 'pfiles'
  326 +
  327 + # Run test suite
  328 + success = suites.run()
  329 +
  330 + # Save test results
  331 + suites.save('reports/tutorials.xml')
  332 +
  333 + # Set return code
  334 + if success:
  335 + rc = 0
  336 + else:
  337 + rc = 1
  338 +
  339 + # Exit with return code
  340 + sys.exit(rc)