diff --git a/autosubmit/autosubmit.py b/autosubmit/autosubmit.py index 627c2bb31e0d69111b3129370fde728227236137..8d3516c370e3905522c6e205f41e559005894c1c 100644 --- a/autosubmit/autosubmit.py +++ b/autosubmit/autosubmit.py @@ -1473,6 +1473,7 @@ class Autosubmit: :rtype: bool """ try: + Log.info(f"Inspecting experiment {expid}") Autosubmit._check_ownership(expid, raise_error=True) exp_path = os.path.join(BasicConfig.LOCAL_ROOT_DIR, expid) tmp_path = os.path.join(exp_path, BasicConfig.LOCAL_TMP_DIR) diff --git a/autosubmit/job/job_list.py b/autosubmit/job/job_list.py index 883a6bd5a5d65b0e940455cd7f5f4c7ccf2ca5af..d83a3df66d90113d7ac47f9707f9196f1567483e 100644 --- a/autosubmit/job/job_list.py +++ b/autosubmit/job/job_list.py @@ -1876,7 +1876,7 @@ class JobList(object): """ unsubmitted = [job for job in self._job_list if (platform is None or job.platform.name == platform.name) and ( - job.status != Status.SUBMITTED and job.status != Status.QUEUING and job.status == Status.RUNNING and job.status == Status.COMPLETED)] + job.status != Status.SUBMITTED and job.status != Status.QUEUING and job.status != Status.RUNNING)] if wrapper: return [job for job in unsubmitted if job.packed is False] diff --git a/autosubmit/platforms/headers/slurm_header.py b/autosubmit/platforms/headers/slurm_header.py index a99b3997f7bcbb5c02c4877189cd828953d4fff3..31450c2ddd1f4eeac07b0da1269ab0bac3083c3a 100644 --- a/autosubmit/platforms/headers/slurm_header.py +++ b/autosubmit/platforms/headers/slurm_header.py @@ -127,10 +127,10 @@ class SlurmHeader(object): :rtype: str """ if het > -1 and len(job.het['EXCLUSIVE']) > 0: - if job.het['EXCLUSIVE'][het] != '': + if str(job.parameters['EXCLUSIVE']).lower() == 'true': return "SBATCH --exclusive" else: - if job.parameters['EXCLUSIVE'] != '': + if str(job.parameters['EXCLUSIVE']).lower() == 'true': return "SBATCH --exclusive" return "" diff --git a/test/unit/files/base_ecaccess.cmd b/test/unit/files/base_ecaccess.cmd new file mode 100644 index 0000000000000000000000000000000000000000..b3fca68280e19027429ef1c0aa5a511d72335e27 --- /dev/null +++ b/test/unit/files/base_ecaccess.cmd @@ -0,0 +1,27 @@ +#!/bin/bash + +############################################################################### +# BASE_ECACCESS t000 EXPERIMENT +############################################################################### +# +#SBATCH --qos=nf +# +# +#SBATCH -A whatever +# +#SBATCH --cpus-per-task=1 +# +# +#SBATCH -n 1 +# +#SBATCH -t 00:01:00 +#SBATCH -J t000_BASE_ECACCESS +#SBATCH --output=/tmp/pytest-of-dbeltran/pytest-15/scheduler_tests0/scratch/whatever/dbeltran/t000/LOG_t000/t000_BASE_ECACCESS.cmd.out.0 +#SBATCH --error=/tmp/pytest-of-dbeltran/pytest-15/scheduler_tests0/scratch/whatever/dbeltran/t000/LOG_t000/t000_BASE_ECACCESS.cmd.err.0 + +# +# +############################################################################### +################### +# Autosubmit header +################### \ No newline at end of file diff --git a/test/unit/files/base_pjm.cmd b/test/unit/files/base_pjm.cmd new file mode 100644 index 0000000000000000000000000000000000000000..b6b52eb7912a1ce022f4a11535246ce42eb7aa52 --- /dev/null +++ b/test/unit/files/base_pjm.cmd @@ -0,0 +1,23 @@ +#!/bin/bash + +############################################################################### +# BASE_PJM t000 EXPERIMENT +############################################################################### +# +#PJM -N t000_BASE_PJM +#PJM -L elapse=00:01:00 +#PJM -L rscgrp=dummy +#PJM -g whatever +# + +export OMP_NUM_THREADS=1 +# +# + +#PJM -o /tmp/pytest-of-dbeltran/pytest-0/scheduler_tests0/scratch/whatever/dbeltran/t000/LOG_t000/t000_BASE_PJM.cmd.out.0 +#PJM -e /tmp/pytest-of-dbeltran/pytest-0/scheduler_tests0/scratch/whatever/dbeltran/t000/LOG_t000/t000_BASE_PJM.cmd.err.0 +# +# +############################################################################### +################### +# Autosubmit header \ No newline at end of file diff --git a/test/unit/files/base_ps.cmd b/test/unit/files/base_ps.cmd new file mode 100644 index 0000000000000000000000000000000000000000..ae2f9c0aeceb7353be10f4ac7831cfba5527eb10 --- /dev/null +++ b/test/unit/files/base_ps.cmd @@ -0,0 +1,7 @@ +#!/bin/bash + +############################################################################### +# BASE_PS t000 EXPERIMENT +############################################################################### +################### +# Autosubmit header \ No newline at end of file diff --git a/test/unit/files/base_slurm.cmd b/test/unit/files/base_slurm.cmd new file mode 100644 index 0000000000000000000000000000000000000000..6116a60dddaa3e0055d71d84b03bd9657170d9d9 --- /dev/null +++ b/test/unit/files/base_slurm.cmd @@ -0,0 +1,26 @@ +#!/bin/bash + +############################################################################### +# BASE_SLURM t000 EXPERIMENT +############################################################################### +# +#SBATCH --qos=gp_debug +# +# +#SBATCH -A whatever +# +#SBATCH --cpus-per-task=1 +# +# +#SBATCH -n 1 +# +#SBATCH -t 00:01:00 +#SBATCH -J t000_BASE_SLURM +#SBATCH --output=/tmp/pytest-of-dbeltran/pytest-0/scheduler_tests0/scratch/whatever/dbeltran/t000/LOG_t000/t000_BASE_SLURM.cmd.out.0 +#SBATCH --error=/tmp/pytest-of-dbeltran/pytest-0/scheduler_tests0/scratch/whatever/dbeltran/t000/LOG_t000/t000_BASE_SLURM.cmd.err.0 + +# +# +############################################################################### +################### +# Autosubmit header diff --git a/test/unit/test_migrate.py b/test/unit/test_migrate.py index 63a656e5d2bcb60dce1726f8db949140edad7013..0dd87f2e8be5a4fd06c574a082d60a47b96c267a 100644 --- a/test/unit/test_migrate.py +++ b/test/unit/test_migrate.py @@ -9,7 +9,7 @@ import os import pwd from log.log import AutosubmitCritical -from test.unit.utils.common import create_database, generate_expid +from test.unit.utils.common import create_database, init_expid class TestMigrate: @@ -53,7 +53,7 @@ path = {folder} os.environ['AUTOSUBMIT_CONFIGURATION'] = str(folder.join('autosubmitrc')) create_database(str(folder.join('autosubmitrc'))) assert "tests.db" in [Path(f).name for f in folder.listdir()] - generate_expid(str(folder.join('autosubmitrc')), platform='pytest-local') + init_expid(str(folder.join('autosubmitrc')), platform='pytest-local',create=False) assert "t000" in [Path(f).name for f in folder.listdir()] return folder diff --git a/test/unit/test_scheduler_general.py b/test/unit/test_scheduler_general.py new file mode 100644 index 0000000000000000000000000000000000000000..46e62ef792b4dba50fcf6c3056e7dc87854823f9 --- /dev/null +++ b/test/unit/test_scheduler_general.py @@ -0,0 +1,191 @@ +import pytest +from pathlib import Path +from autosubmit.autosubmit import Autosubmit +import os +import pwd + +from test.unit.utils.common import create_database, init_expid + +def _get_script_files_path() -> Path: + return Path(__file__).resolve().parent / 'files' + +# Maybe this should be a regression test + +@pytest.fixture +def scheduler_tmpdir(tmpdir_factory): + folder = tmpdir_factory.mktemp(f'scheduler_tests') + os.mkdir(folder.join('scratch')) + os.mkdir(folder.join('scheduler_tmp_dir')) + file_stat = os.stat(f"{folder.strpath}") + file_owner_id = file_stat.st_uid + file_owner = pwd.getpwuid(file_owner_id).pw_name + folder.owner = file_owner + + # Write an autosubmitrc file in the temporary directory + autosubmitrc = folder.join('autosubmitrc') + autosubmitrc.write(f''' +[database] +path = {folder} +filename = tests.db + +[local] +path = {folder} + +[globallogs] +path = {folder} + +[structures] +path = {folder} + +[historicdb] +path = {folder} + +[historiclog] +path = {folder} + +[defaultstats] +path = {folder} + +''') + os.environ['AUTOSUBMIT_CONFIGURATION'] = str(folder.join('autosubmitrc')) + create_database(str(folder.join('autosubmitrc'))) + assert "tests.db" in [Path(f).name for f in folder.listdir()] + init_expid(str(folder.join('autosubmitrc')), platform='local', create=False) + assert "t000" in [Path(f).name for f in folder.listdir()] + return folder + +@pytest.fixture +def prepare_scheduler(scheduler_tmpdir): + # touch as_misc + platforms_path = Path(f"{scheduler_tmpdir.strpath}/t000/conf/platforms_t000.yml") + jobs_path = Path(f"{scheduler_tmpdir.strpath}/t000/conf/jobs_t000.yml") + # Add each platform to test + with platforms_path.open('w') as f: + f.write(f""" +PLATFORMS: + pytest-pjm: + type: pjm + host: 127.0.0.1 + user: {scheduler_tmpdir.owner} + project: whatever + scratch_dir: {scheduler_tmpdir}/scratch + MAX_WALLCLOCK: 48:00 + TEMP_DIR: '' + MAX_PROCESSORS: 99999 + queue: dummy + pytest-slurm: + type: slurm + host: 127.0.0.1 + user: {scheduler_tmpdir.owner} + project: whatever + scratch_dir: {scheduler_tmpdir}/scratch + QUEUE: gp_debug + ADD_PROJECT_TO_HOST: false + MAX_WALLCLOCK: 48:00 + TEMP_DIR: '' + MAX_PROCESSORS: 99999 + pytest-ecaccess: + type: ecaccess + version: slurm + host: 127.0.0.1 + QUEUE: nf + EC_QUEUE: hpc + user: {scheduler_tmpdir.owner} + project: whatever + scratch_dir: {scheduler_tmpdir}/scratch + pytest-ps: + type: ps + host: 127.0.0.1 + user: {scheduler_tmpdir.owner} + project: whatever + scratch_dir: {scheduler_tmpdir}/scratch + """) + # add a job of each platform type + with jobs_path.open('w') as f: + f.write(f""" +JOBS: + job: + SCRIPT: | + echo "Hello World" + For: + PLATFORM: [ pytest-pjm , pytest-slurm, pytest-ecaccess, pytest-ps] + QUEUE: [dummy, gp_debug, nf, hpc] + NAME: [pjm, slurm, ecaccess, ps] + RUNNING: once + wallclock: 00:01 + PROCESSORS: 5 + nodes: 2 + threads: 40 + tasks: 90 + base: + SCRIPT: | + echo "Hello World" + For: + PLATFORM: [ pytest-pjm , pytest-slurm, pytest-ecaccess, pytest-ps] + QUEUE: [dummy, gp_debug, nf, hpc] + NAME: [pjm, slurm, ecaccess, ps] + RUNNING: once + wallclock: 00:01 + """) + + + + expid_dir = Path(f"{scheduler_tmpdir.strpath}/scratch/whatever/{scheduler_tmpdir.owner}/t000") + dummy_dir = Path(f"{scheduler_tmpdir.strpath}/scratch/whatever/{scheduler_tmpdir.owner}/t000/dummy_dir") + real_data = Path(f"{scheduler_tmpdir.strpath}/scratch/whatever/{scheduler_tmpdir.owner}/t000/real_data") + # write some dummy data inside scratch dir + os.makedirs(expid_dir, exist_ok=True) + os.makedirs(dummy_dir, exist_ok=True) + os.makedirs(real_data, exist_ok=True) + + with open(dummy_dir.joinpath('dummy_file'), 'w') as f: + f.write('dummy data') + # create some dummy absolute symlinks in expid_dir to test migrate function + (real_data / 'dummy_symlink').symlink_to(dummy_dir / 'dummy_file') + return scheduler_tmpdir + +@pytest.fixture +def generate_cmds(prepare_scheduler): + init_expid(os.environ["AUTOSUBMIT_CONFIGURATION"], platform='local', expid='t000', create=True) + Autosubmit.inspect(expid='t000',check_wrapper=False,force=True, lst=None, filter_chunks=None, filter_status=None, filter_section=None) + return prepare_scheduler + +@pytest.mark.parametrize("scheduler", ['pjm', 'slurm', 'ecaccess', 'ps']) +def test_default_parameters(scheduler: str, generate_cmds): + """ + Test that the default parameters are correctly set in the scheduler files. It is a comparasion line to line, so the new templates must match the same line order as the old ones. Additional default parameters must be filled in the files/base_{scheduler}.yml as well as any change in the order + :param generate_cmds: fixture that generates the templates. + :return: + """ + + # Load the base file for each scheduler + scheduler = scheduler.upper() + expected_data = {} + for base_f in _get_script_files_path().glob('base_*.cmd'): + if scheduler in base_f.stem.split('_')[1].upper(): + expected_data = Path(base_f).read_text() + break + if not expected_data: + raise NotImplemented + + # Get the actual default parameters for the scheduler + actual = Path(f"{generate_cmds.strpath}/t000/tmp/t000_BASE_{scheduler}.cmd").read_text() + # Remove all after # Autosubmit header + # ################### + # count number of lines in expected + expected_lines = expected_data.split('\n') + actual = actual.split('\n')[:len(expected_lines)] + actual = '\n'.join(actual) + # Compare line to line + for i, (line1, line2) in enumerate(zip(expected_data.split('\n'), actual.split('\n'))): + if "PJM -o" in line1 or "PJM -e" in line1 or "#SBATCH --output" in line1 or "#SBATCH --error" in line1: # output error will be different + continue + elif "##" in line1 or "##" in line2: # comment line + continue + elif "header" in line1 or "header" in line2: # header line + continue + else: + assert line1 == line2 + + + diff --git a/test/unit/utils/common.py b/test/unit/utils/common.py index 5f767bb7dede9719f8c8bf9391804bc8e8599cf0..50f613c3496a2bb71ead0cd3aadd26729f059404 100644 --- a/test/unit/utils/common.py +++ b/test/unit/utils/common.py @@ -6,9 +6,13 @@ def create_database(envirom): BasicConfig.read() Autosubmit.install() -def generate_expid(envirom, platform="local"): +def init_expid(envirom, platform="local", expid=None, create=True): os.environ['AUTOSUBMIT_CONFIGURATION'] = envirom - expid = Autosubmit.expid("pytest", hpc=platform, copy_id='', dummy=True, minimal_configuration=False, git_repo="", git_branch="", git_as_conf="", operational=False, testcase = True, use_local_minimal=False) - Autosubmit.create(expid, True,False, force=True) + if not expid: + expid = Autosubmit.expid("pytest", hpc=platform, copy_id='', dummy=True, minimal_configuration=False, git_repo="", git_branch="", git_as_conf="", operational=False, testcase = True, use_local_minimal=False) + if create: + Autosubmit.create(expid, True,False, force=True) return expid + +