Changeset 4091 for palm/trunk


Ignore:
Timestamp:
Jul 11, 2019 4:22:09 PM (2 years ago)
Author:
knoop
Message:

Added palmtutorial script to automatically build and test tutorials. Tutorials have been separated from tests. The new palmtutorial works like palmtest.

Location:
palm/trunk
Files:
4 added
1 edited
3 copied
6 moved

Legend:

Unmodified
Added
Removed
  • palm/trunk/SCRIPTS/palmtest

    r3682 r4091  
    8181
    8282
     83def disable_color():
     84    global disable_colored_output
     85    disable_colored_output = True
     86
     87
    8388version = '1.0.1'
    8489
    85 scripts_dir = os.path.dirname(os.path.realpath(__file__))
    86 trunk_dir = os.path.realpath(os.path.join(scripts_dir, '..'))
    87 workspace_dir = os.path.realpath(os.path.join(trunk_dir, '..'))
    88 
    89 trunk_tests_dir = os.path.join(trunk_dir, 'TESTS')
    90 trunk_tests_cases_dir = os.path.join(trunk_tests_dir, 'cases')
    91 trunk_tests_builds_dir = os.path.join(trunk_tests_dir, 'builds')
    92 
    93 tests_dir = os.path.join(workspace_dir, 'tests')
    94 
    95 available_cores = multiprocessing.cpu_count()
    96 terminal_columns, terminal_lines = shutil.get_terminal_size()
    97 hline = '#' * min(terminal_columns, 300) + '\n'
    98 table_width_intro = 12
    99 table_width_builds = len(max([s for s in next(os.walk(trunk_tests_builds_dir))[1] if not s[0] == '.'], key=len)) + len('_debug')
    100 table_width_cases = len(max([s for s in next(os.walk(trunk_tests_cases_dir))[1] if not s[0] == '.'], key=len))
    101 table_width_cores = 7
    102 table_width_total = table_width_intro + table_width_builds + table_width_cases + table_width_cores + 3
    103 
    104 task_table_line_template = \
    105     '{:' + str(table_width_intro) + '} ' + \
    106     '{:' + str(table_width_cases) + '} ' + \
    107     '{:' + str(table_width_builds) + '} ' + \
    108     '{:' + str(table_width_cores) + '} '
    109 
    110 config_table_line_template = \
    111     '{:' + str(table_width_intro) + '} ' + \
    112     '{:' + str(max(table_width_builds, table_width_cases)) + '} ' + \
    113     '{:8} '
    114 
    115 file_table_line_template = \
    116     '{:' + str(table_width_intro) + '} ' + \
    117     '{:' + str(table_width_cases + 13) + '} '
    118 
    119 # for debugging
    120 exist_ok = False
     90
     91class Environment:
     92
     93    scripts_dir = os.path.dirname(os.path.realpath(__file__))
     94    trunk_dir = os.path.realpath(os.path.join(scripts_dir, '..'))
     95    workspace_dir = os.path.realpath(os.path.join(trunk_dir, '..'))
     96
     97    trunk_tests_dir = os.path.join(trunk_dir, 'TESTS')
     98    trunk_tests_cases_dir = os.path.join(trunk_tests_dir, 'cases')
     99    trunk_tests_builds_dir = os.path.join(trunk_tests_dir, 'builds')
     100
     101    tests_dir = os.path.join(workspace_dir, 'tests')
     102
     103
     104class LogFormatter:
     105
     106    terminal_columns, terminal_lines = shutil.get_terminal_size()
     107    hline = '#' * min(terminal_columns, 300) + '\n'
     108    table_width_intro = 12
     109    table_width_builds = len(max([s for s in next(os.walk(Environment.trunk_tests_builds_dir))[1] if not s[0] == '.'], key=len)) + len('_debug')
     110    table_width_cases = len(max([s for s in next(os.walk(Environment.trunk_tests_cases_dir))[1] if not s[0] == '.'], key=len))
     111    table_width_cores = 7
     112    table_width_total = table_width_intro + table_width_builds + table_width_cases + table_width_cores + 3
     113
     114    intro_table_line_template = \
     115        '{:' + str(table_width_intro) + '} '
     116
     117    task_table_line_template = \
     118        '{:' + str(table_width_intro) + '} ' + \
     119        '{:' + str(table_width_cases) + '} ' + \
     120        '{:' + str(table_width_builds) + '} ' + \
     121        '{:' + str(table_width_cores) + '} '
     122
     123    config_table_line_template = \
     124        '{:' + str(table_width_intro) + '} ' + \
     125        '{:' + str(max(table_width_builds, table_width_cases)) + '} ' + \
     126        '{:8} '
     127
     128    file_table_line_template = \
     129        '{:' + str(table_width_intro) + '} ' + \
     130        '{:' + str(table_width_cases + 13) + '} '
    121131
    122132
     
    208218        with Logger(cwd, verbose=verbose) as logger:
    209219            # read line without blocking
    210             logger.to_log(hline)
     220            logger.to_log(LogFormatter.hline)
    211221            logger.to_log('CMD: ' + cmd_str + '\n')
    212             logger.to_log(hline)
     222            logger.to_log(LogFormatter.hline)
    213223            while t.is_alive():
    214224                try:
     
    226236                else:  # got line
    227237                    logger.to_log(line.decode("utf-8"))
    228             logger.to_log(hline)
     238            logger.to_log(LogFormatter.hline)
    229239
    230240        rc = p.poll()
     
    379389        self.job_name = self.setup_name + '__' + build_name + '__' + str(self.cores)
    380390        self.job_dir = os.path.join(self.test_dir, 'JOBS', self.job_name)
    381         self.ref_monitoring_dir = os.path.join(trunk_tests_cases_dir, self.setup_name, 'MONITORING')
    382         self.ref_output_dir = os.path.join(trunk_tests_cases_dir, self.setup_name, 'OUTPUT')
     391        self.ref_monitoring_dir = os.path.join(Environment.trunk_tests_cases_dir, self.setup_name, 'MONITORING')
     392        self.ref_output_dir = os.path.join(Environment.trunk_tests_cases_dir, self.setup_name, 'OUTPUT')
    383393        self.res_monitoring_dir = os.path.join(self.job_dir, 'MONITORING')
    384394        self.res_output_dir = os.path.join(self.job_dir, 'OUTPUT')
     
    449459                ext_list = [file_dict['extension']] if file_dict['extension'] else []
    450460                file_specific_ending = '.'.join([file_dict['postfix']] + file_dict['cycle_info'] + ext_list )
    451                 logger.to_all(file_table_line_template.format('Checking:', self.setup_name + file_specific_ending))
     461                logger.to_all(LogFormatter.file_table_line_template.format('Checking:', self.setup_name + file_specific_ending))
    452462                ref_file_path = os.path.join(file_dict['ref_path'], self.setup_name + file_specific_ending)
    453463                res_file_path = os.path.join(file_dict['res_path'], self.job_name + file_specific_ending)
     
    530540        if os.path.isdir(source_data_dir_path) and re.match('.+_d3d.*', source_data_dir):
    531541            job_restart_dir = os.path.join(self.test_dir, 'JOBS', name, 'RESTART')
    532             os.makedirs(job_restart_dir, exist_ok=exist_ok)
     542            os.makedirs(job_restart_dir, exist_ok=False)
    533543            job_data_dir_path = os.path.join(job_restart_dir, name + '_d3d')
    534544            os.symlink(source_data_dir_path, job_data_dir_path, target_is_directory=True)
     
    593603        if not attempted:
    594604            with Logger(self.test_dir, verbose=self.verbose) as logger:
    595                 status_prefix = task_table_line_template.format('Testing:', self.test_case.name, build_name, self.cores)
     605                status_prefix = LogFormatter.task_table_line_template.format('Testing:', self.test_case.name, build_name, self.cores)
    596606                logger.to_all(status_prefix)
    597607                logger.to_log('[started]' + '\n')
     
    601611
    602612                input_dir = os.path.join(self.test_dir, 'JOBS', name, 'INPUT')
    603                 os.makedirs(input_dir, exist_ok=exist_ok)
     613                os.makedirs(input_dir, exist_ok=False)
    604614
    605615                # copying needs to be done per file, because input files need to be renamed
     
    672682    def configure(self):
    673683        try:
    674             with open(os.path.join(trunk_tests_builds_dir, self.build_name, 'build_config.yml'), 'r') as f:
     684            with open(os.path.join(Environment.trunk_tests_builds_dir, self.build_name, 'build_config.yml'), 'r') as f:
    675685                build_config = yaml.load(f)
    676686        except:
     
    745755
    746756        try:
    747             with open(os.path.join(workspace_dir, 'palmtest.yml'), 'r') as f:
     757            with open(os.path.join(Environment.workspace_dir, 'palmtest.yml'), 'r') as f:
    748758                palmtest_config = yaml.load(f)
    749759        except:
     
    758768        except:
    759769            try:
    760                 with open(os.path.join(scripts_dir, '.palm.config.default.in'), 'r') as palm_config_template_file:
     770                with open(os.path.join(Environment.scripts_dir, '.palm.config.default.in'), 'r') as palm_config_template_file:
    761771                    template = palm_config_template_file.read()
    762772            except:
     
    770780        cpp_options_str = ['-D' + s for s in self.compiler['definitions']]
    771781        template = template.replace('@PALM_CPP_OPTIONS_STR@', ' '.join(cpp_options_str))
    772         template = template.replace('@PALM_CORES@', str(available_cores))
     782        template = template.replace('@PALM_CORES@', str(multiprocessing.cpu_count()))
    773783        template = template.replace('@PALM_COMPILER_OPTIONS@', '{{palmtest.compiler.options}} ' + ' '.join(self.compiler['includes']))
    774784        template = template.replace('@PALM_LINKER_OPTIONS@', ' '.join(self.linker['options']))
     
    873883        if not attempted:
    874884            with Logger(self.test_dir, verbose=self.verbose) as logger:
    875                 status_prefix = task_table_line_template.format('Building:', '', build_name, '')
     885                status_prefix = LogFormatter.task_table_line_template.format('Building:', '', build_name, '')
    876886                logger.to_all(status_prefix)
    877887                logger.to_log('[started]' + '\n')
     
    907917        self.verbose = verbose
    908918        self.dry_run = dry_run
    909         self.user_code_dir = os.path.join(trunk_tests_cases_dir, self.name, 'USER_CODE')
    910         self.input_dir = os.path.join(trunk_tests_cases_dir, self.name, 'INPUT')
     919        self.user_code_dir = os.path.join(Environment.trunk_tests_cases_dir, self.name, 'USER_CODE')
     920        self.input_dir = os.path.join(Environment.trunk_tests_cases_dir, self.name, 'INPUT')
    911921        self.number_of_cores = []
    912922        self.build_names = []
     
    915925
    916926    def configure(self, requested_build_names, requested_cores):
    917         f_name = os.path.join(trunk_tests_cases_dir, self.name, 'case_config.yml')
     927        f_name = os.path.join(Environment.trunk_tests_cases_dir, self.name, 'case_config.yml')
    918928        try:
    919929            with open(f_name, 'r') as f:
     
    983993
    984994    def prepare(self):
    985         global disable_colored_output
    986         disable_colored_output = self.no_color
    987         self.test_dir = os.path.join(tests_dir, self.test_id)
     995        if self.no_color:
     996            disable_color()
     997        self.test_dir = os.path.join(Environment.tests_dir, self.test_id)
    988998        try:
    989             os.makedirs(self.test_dir, exist_ok=exist_ok)
     999            os.makedirs(self.test_dir, exist_ok=False)
    9901000        except:
    9911001            print('ERROR: Found existing test directory: ' + self.test_dir)
    9921002            exit(1)
    9931003        with Logger(self.test_dir, verbose=self.verbose) as logger:
    994             logger.to_all(hline)
     1004            logger.to_all(LogFormatter.hline)
    9951005            logger.to_all('This is the PALM tester  (version: ' + version + ')' + '\n')
    996             logger.to_all(hline)
     1006            logger.to_all(LogFormatter.hline)
    9971007            try:
    998                 with open(os.path.join(workspace_dir, 'palmtest.yml'), 'r') as f:
     1008                with open(os.path.join(Environment.workspace_dir, 'palmtest.yml'), 'r') as f:
    9991009                    pass
    10001010            except:
     
    10051015
    10061016            self.execution_trunk_dir = os.path.join(self.test_dir, 'trunk')
    1007             os.symlink(trunk_dir, self.execution_trunk_dir)
     1017            os.symlink(Environment.trunk_dir, self.execution_trunk_dir)
    10081018            self.execution_jobs_dir = os.path.join(self.test_dir, 'JOBS')
    1009             os.makedirs(self.execution_jobs_dir, exist_ok=exist_ok)
     1019            os.makedirs(self.execution_jobs_dir, exist_ok=False)
    10101020
    10111021            try:
    1012                 with open(os.path.join(scripts_dir, '.palm.iofiles'), 'r') as iofiles_template_file:
     1022                with open(os.path.join(Environment.scripts_dir, '.palm.iofiles'), 'r') as iofiles_template_file:
    10131023                    iofiles_template = iofiles_template_file.read()
    10141024                with open(os.path.join(self.test_dir, '.palm.iofiles'), 'w') as iofiles_file:
     
    10181028                exit(1)
    10191029
     1030            available_cores = multiprocessing.cpu_count()
    10201031            final_cores_list = list(filter(lambda x: x <= available_cores, self.requested_cores))
    10211032
    1022             logger.to_all(config_table_line_template.format('Object:', 'Name:', 'Action:') + 'Status:\n')
    1023             logger.to_all(hline)
     1033            logger.to_all(LogFormatter.config_table_line_template.format('Object:', 'Name:', 'Action:') + 'Status:\n')
     1034            logger.to_all(LogFormatter.hline)
    10241035
    10251036            if 'all' in self.requested_build_names:
    1026                 self.requested_build_names = [name for name in next(os.walk(trunk_tests_builds_dir))[1] if not name[0] == '.']
     1037                self.requested_build_names = [name for name in next(os.walk(Environment.trunk_tests_builds_dir))[1] if not name[0] == '.']
    10271038            found_build_names = []
    10281039            for build_name in self.requested_build_names:
     
    10321043                    self.build_database[build_name] = build
    10331044                    found_build_names.append(build_name)
    1034                     logger.to_all(config_table_line_template.format('Build', build_name, 'approved'))
     1045                    logger.to_all(LogFormatter.config_table_line_template.format('Build', build_name, 'approved'))
    10351046                    logger.to_all(message + '\n')
    10361047                else:
    1037                     logger.to_all(config_table_line_template.format('Build', build_name, 'rejected'))
     1048                    logger.to_all(LogFormatter.config_table_line_template.format('Build', build_name, 'rejected'))
    10381049                    logger.to_all(message + '\n')
    10391050            final_build_list = found_build_names
    10401051
    10411052            if 'all' in self.test_case_names:
    1042                 self.test_case_names = sorted([name for name in next(os.walk(trunk_tests_cases_dir))[1] if not name[0] == '.'])
     1053                self.test_case_names = sorted([name for name in next(os.walk(Environment.trunk_tests_cases_dir))[1] if not name[0] == '.'])
    10431054
    10441055            additional_initial_runs_2 = [self.test_case_names]
     
    10791090                        # removing as configuration failed should only apply to added dependencies
    10801091                        approved_test_case_order[i].remove(test_case_name)
    1081                         logger.to_all(config_table_line_template.format(info, test_case_name, 'rejected'))
     1092                        logger.to_all(LogFormatter.config_table_line_template.format(info, test_case_name, 'rejected'))
    10821093                        logger.to_all(message + '\n')
    10831094                    elif test_case.requires_binary_files:
     
    10851096                            # removing as dependency is already removed
    10861097                            approved_test_case_order[i].remove(test_case_name)
    1087                             logger.to_all(config_table_line_template.format(info, test_case_name, 'disabled'))
     1098                            logger.to_all(LogFormatter.config_table_line_template.format(info, test_case_name, 'disabled'))
    10881099                            logger.to_all(colored('[requires dependency \"' + test_case.use_binary_files_from + '\"]', 'red') + '\n')
    10891100                        else:
    1090                             logger.to_all(config_table_line_template.format(info, test_case_name, 'approved'))
     1101                            logger.to_all(LogFormatter.config_table_line_template.format(info, test_case_name, 'approved'))
    10911102                            logger.to_all(message + '\n')
    10921103                    else:
    1093                         logger.to_all(config_table_line_template.format(info, test_case_name, 'approved'))
     1104                        logger.to_all(LogFormatter.config_table_line_template.format(info, test_case_name, 'approved'))
    10941105                        logger.to_all(message + '\n')
    10951106
     
    11231134                if not test_case_configuration_failed:
    11241135                    self.test_case_queue.append(test_case)
    1125             logger.to_all(hline)
    1126 
    1127             r = '{:' + str(table_width_intro) + '} '
    1128 
    1129             logger.to_all(r.format('Test ID:') + self.test_id + '\n')
    1130             logger.to_all(r.format('Builds:') + str('\n' + r.format('')).join(sorted(self.build_database.keys())) + '\n')
    1131             logger.to_all(r.format('Cases:') + str('\n' + r.format('')).join([c.name for c in self.test_case_queue]) + '\n')
    1132             logger.to_all(r.format('Cores:') + ' '.join([str(i) for i in final_cores_list]) + '\n')
     1136            logger.to_all(LogFormatter.hline)
     1137
     1138            logger.to_all(LogFormatter.intro_table_line_template.format('Test ID:') +
     1139                          self.test_id + '\n')
     1140            logger.to_all(LogFormatter.intro_table_line_template.format('Builds:') +
     1141                          str('\n' + LogFormatter.intro_table_line_template.format('')).join(sorted(self.build_database.keys())) + '\n')
     1142            logger.to_all(LogFormatter.intro_table_line_template.format('Cases:') +
     1143                          str('\n' + LogFormatter.intro_table_line_template.format('')).join([c.name for c in self.test_case_queue]) + '\n')
     1144            logger.to_all(LogFormatter.intro_table_line_template.format('Cores:') +
     1145                          ' '.join([str(i) for i in final_cores_list]) + '\n')
    11331146
    11341147    def _execute(self, test_case, build_name, cores):
     
    11861199    def execute(self):
    11871200        with Logger(self.test_dir, verbose=self.verbose) as logger:
    1188             logger.to_all(hline)
    1189             logger.to_all(task_table_line_template.format('Task:', 'Case:', 'Build:', 'Cores:') + 'Status:\n')
    1190             logger.to_all(hline)
     1201            logger.to_all(LogFormatter.hline)
     1202            logger.to_all(LogFormatter.task_table_line_template.format('Task:', 'Case:', 'Build:', 'Cores:') + 'Status:\n')
     1203            logger.to_all(LogFormatter.hline)
    11911204            self.test_report = dict()
    11921205            for test_case in self.test_case_queue:
    1193                 logger.to_log(hline)
    1194                 logger.to_file(hline)
    1195                 logger.to_file(hline)
     1206                logger.to_log(LogFormatter.hline)
     1207                logger.to_file(LogFormatter.hline)
     1208                logger.to_file(LogFormatter.hline)
    11961209                status_dict = dict()
    11971210                for build_name in test_case.build_names:
     
    12001213                        status_dict[build_name][cores] = self._execute(test_case, build_name, cores)
    12011214                self.test_report[test_case.name] = status_dict
    1202                 logger.to_log(hline)
     1215                logger.to_log(LogFormatter.hline)
    12031216                logger.to_file('\n' * 10)
    12041217
    12051218    def report(self):
    12061219        with Logger(self.test_dir, verbose=self.verbose) as logger:
    1207             logger.to_all(hline)
     1220            logger.to_all(LogFormatter.hline)
    12081221            r = '{:10}' + '    total: ' + '{:<3d}' + \
    12091222                             '    ok: ' + colored('{:<3d}', 'green') + \
     
    12741287
    12751288    def get_items(self):
    1276         case_names = [name for name in next(os.walk(trunk_tests_cases_dir))[1] if not name[0] == '.']
     1289        case_names = [name for name in next(os.walk(Environment.trunk_tests_cases_dir))[1] if not name[0] == '.']
    12771290        return case_names + ['all']
    12781291
     
    12811294
    12821295    def get_items(self):
    1283         build_names = [name for name in next(os.walk(trunk_tests_builds_dir))[1] if not name[0] == '.']
     1296        build_names = [name for name in next(os.walk(Environment.trunk_tests_builds_dir))[1] if not name[0] == '.']
    12841297        return build_names + ['all']
    12851298
     
    13671380            action='store',
    13681381            dest='cores',
    1369             default=[i for i in range(1, available_cores+1)],
    1370             choices=[i for i in range(1, available_cores+1)],
     1382            default=[i for i in range(1, multiprocessing.cpu_count()+1)],
     1383            choices=[i for i in range(1, multiprocessing.cpu_count()+1)],
    13711384            help='The number of cores tests are supposed to be executed on. (default: %(default)s)',
    13721385            nargs='+',
Note: See TracChangeset for help on using the changeset viewer.