diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46ebc759e6..b948fb1ca9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,12 +84,12 @@ jobs: uses: ansys/actions/branch-name-style@v7 - commit-name: + pull-request-name: if: github.event_name == 'pull_request' - name: Check the name of the commit + name: Check the name of the pull-request runs-on: ubuntu-latest steps: - - name: Check commit name + - name: Check pull-request name uses: ansys/actions/commit-style@v7 with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/doc/changelog.d/3427.added.md b/doc/changelog.d/3427.added.md new file mode 100644 index 0000000000..ce52a9880d --- /dev/null +++ b/doc/changelog.d/3427.added.md @@ -0,0 +1 @@ +perf: reduce-testing-time \ No newline at end of file diff --git a/src/ansys/mapdl/core/launcher.py b/src/ansys/mapdl/core/launcher.py index 51f98937b8..349602c667 100644 --- a/src/ansys/mapdl/core/launcher.py +++ b/src/ansys/mapdl/core/launcher.py @@ -1663,21 +1663,7 @@ def launch_mapdl( return if _debug_no_launch: - return pack_parameters( - port, - ip, - add_env_vars, - replace_env_vars, - cleanup_on_exit, - loglevel, - set_no_abort, - remove_temp_dir_on_exit, - log_apdl, - use_vtk, - start_parm, - start_instance, - version, - ) # type: ignore + return pack_parameters(locals()) # type: ignore mapdl = MapdlGrpc( ip=ip, @@ -1821,21 +1807,7 @@ def launch_mapdl( elif mode == "grpc": if _debug_no_launch: # Early exit, just for testing - return pack_parameters( - port, - ip, - add_env_vars, - replace_env_vars, - cleanup_on_exit, - loglevel, - set_no_abort, - remove_temp_dir_on_exit, - log_apdl, - use_vtk, - start_parm, - start_instance, - version, - ) # type: ignore + return pack_parameters(locals()) # type: ignore port, actual_run_location, process = launch_grpc( port=port, @@ -2283,34 +2255,22 @@ def get_value( return exec_file, jobname, nproc, ram, additional_switches -def pack_parameters( - port, - ip, - add_env_vars, - replace_env_vars, - cleanup_on_exit, - loglevel, - set_no_abort, - remove_temp_dir_on_exit, - log_apdl, - use_vtk, - start_parm, - start_instance, - version, -): +def pack_parameters(locals_var): # pack all the arguments in a dict for debugging purposes + # We prefer to explicitly output the desired output dict_ = {} - dict_["port"] = port - dict_["ip"] = ip - dict_["add_env_vars"] = add_env_vars - dict_["replace_env_vars"] = replace_env_vars - dict_["cleanup_on_exit"] = cleanup_on_exit - dict_["loglevel"] = loglevel - dict_["set_no_abort"] = set_no_abort - dict_["remove_temp_dir_on_exit"] = remove_temp_dir_on_exit - dict_["log_apdl"] = log_apdl - dict_["use_vtk"] = use_vtk - dict_["start_parm"] = start_parm - dict_["start_instance"] = start_instance - dict_["version"] = version + dict_["port"] = locals_var["port"] + dict_["ip"] = locals_var["ip"] + dict_["add_env_vars"] = locals_var["add_env_vars"] + dict_["replace_env_vars"] = locals_var["replace_env_vars"] + dict_["cleanup_on_exit"] = locals_var["cleanup_on_exit"] + dict_["loglevel"] = locals_var["loglevel"] + dict_["set_no_abort"] = locals_var["set_no_abort"] + dict_["remove_temp_dir_on_exit"] = locals_var["remove_temp_dir_on_exit"] + dict_["log_apdl"] = locals_var["log_apdl"] + dict_["use_vtk"] = locals_var["use_vtk"] + dict_["start_parm"] = locals_var["start_parm"] + dict_["start_instance"] = locals_var["start_instance"] + dict_["version"] = locals_var["version"] + dict_["additional_switches"] = locals_var["additional_switches"] return dict_ diff --git a/src/ansys/mapdl/core/mapdl_core.py b/src/ansys/mapdl/core/mapdl_core.py index c11430d38d..76a300376c 100644 --- a/src/ansys/mapdl/core/mapdl_core.py +++ b/src/ansys/mapdl/core/mapdl_core.py @@ -283,6 +283,7 @@ def __init__( self._start_parm: Dict[str, Any] = start_parm self._jobname: str = start_parm.get("jobname", "file") self._path: Union[str, pathlib.Path] = start_parm.get("run_location", None) + self._path_cache = None # Cache self._print_com: bool = print_com # print the command /COM input. self.check_parameter_names = start_parm.get("check_parameter_names", True) @@ -510,10 +511,14 @@ def directory(self) -> str: # new line to fix path issue, see #416 self._path = repr(self._path)[1:-1] else: # pragma: no cover - raise IOError( - f"The directory returned by /INQUIRE is not valid ('{self._path}')." - ) + if self._path_cache: + return self._path_cache + else: + raise IOError( + f"The directory returned by /INQUIRE is not valid ('{self._path}')." + ) + self._path_cache = self._path # update return self._path @directory.setter @@ -1895,7 +1900,13 @@ def _flush_stored(self): Overridden by gRPC. """ + if not self._stored_commands: + self._log.debug("There is no commands to be flushed.") + self._store_commands = False + return + self._log.debug("Flushing stored commands") + rnd_str = random_string() tmp_out = os.path.join(tempfile.gettempdir(), f"tmp_{rnd_str}.out") self._stored_commands.insert(0, f"/OUTPUT, {tmp_out}") @@ -1904,25 +1915,25 @@ def _flush_stored(self): if self._apdl_log: self._apdl_log.write(commands + "\n") - self._store_commands = False - self._stored_commands = [] + self._store_commands = False + self._stored_commands = [] - # write to a temporary input file - self._log.debug( - "Writing the following commands to a temporary " "apdl input file:\n%s", - commands, - ) + # write to a temporary input file + self._log.debug( + "Writing the following commands to a temporary " "apdl input file:\n%s", + commands, + ) - tmp_inp = os.path.join(tempfile.gettempdir(), f"tmp_{random_string()}.inp") - with open(tmp_inp, "w") as f: - f.writelines(commands) + tmp_inp = os.path.join(tempfile.gettempdir(), f"tmp_{random_string()}.inp") + with open(tmp_inp, "w") as f: + f.writelines(commands) - # interactive result - _ = self.input(tmp_inp, write_to_log=False) + # interactive result + _ = self.input(tmp_inp, write_to_log=False) - time.sleep(0.1) # allow MAPDL to close the file - if os.path.isfile(tmp_out): - self._response = "\n" + open(tmp_out).read() + time.sleep(0.1) # allow MAPDL to close the file + if os.path.isfile(tmp_out): + self._response = "\n" + open(tmp_out).read() if self._response is None: # pragma: no cover self._log.warning("Unable to read response from flushed commands") diff --git a/src/ansys/mapdl/core/mapdl_grpc.py b/src/ansys/mapdl/core/mapdl_grpc.py index 903622b609..632c38b80b 100644 --- a/src/ansys/mapdl/core/mapdl_grpc.py +++ b/src/ansys/mapdl/core/mapdl_grpc.py @@ -899,6 +899,7 @@ def _run_at_connect(self): with self.run_as_routine("POST26"): self.numvar(200, mute=True) + self.inquire("", "DIRECTORY") self.show(self._file_type_for_plots) self.version # Caching version self.file_type_for_plots # Setting /show,png and caching it. @@ -1038,7 +1039,7 @@ def _threaded_heartbeat(self): continue @protect_from(ValueError, "I/O operation on closed file.") - def exit(self, save=False, force=False): + def exit(self, save=False, force=False, **kwargs): """Exit MAPDL. Parameters @@ -1069,8 +1070,6 @@ def exit(self, save=False, force=False): elif self._exited: # Already exited. return - else: - mapdl_path = self.directory if save: self._log.debug("Saving MAPDL database") @@ -1094,17 +1093,21 @@ def exit(self, save=False, force=False): self._exiting = True self._log.debug("Exiting MAPDL") - if self._local: - self._cache_pids() # Recache processes + if not kwargs.pop("fake_exit", False): + # This cannot should not be faked + if self._local: + mapdl_path = self.directory + self._cache_pids() # Recache processes - if os.name == "nt": + if os.name == "nt": + self._kill_server() + self._close_process() + self._remove_lock_file(mapdl_path) + else: self._kill_server() - self._close_process() - self._remove_lock_file(mapdl_path) - else: - self._kill_server() self._exited = True + self._exiting = False if self._remote_instance: # pragma: no cover # No cover: The CI is working with a single MAPDL instance @@ -2031,6 +2034,11 @@ def _flush_stored(self): """Writes stored commands to an input file and runs the input file. Used with non_interactive. """ + if not self._stored_commands: + self._log.debug("There is no commands to be flushed.") + self._store_commands = False + return + self._log.debug("Flushing stored commands") commands = "\n".join(self._stored_commands) diff --git a/src/ansys/mapdl/core/pool.py b/src/ansys/mapdl/core/pool.py index 28a74e2809..16b8c94159 100755 --- a/src/ansys/mapdl/core/pool.py +++ b/src/ansys/mapdl/core/pool.py @@ -219,7 +219,7 @@ def __init__( self._n_instances = n_instances # Getting debug arguments - _debug_no_launch = kwargs.pop("_debug_no_launch", None) + _debug_no_launch = kwargs.get("_debug_no_launch", None) if run_location is None: run_location = create_temp_dir() @@ -338,7 +338,6 @@ def __init__( "exec_file": exec_file, "n_instances": n_instances, } - return # Converting ip or hostname to ip self._ips = [socket.gethostbyname(each) for each in self._ips] @@ -357,6 +356,11 @@ def __init__( ) for i, (ip, port) in enumerate(zip(ips, ports)) ] + + # Early exit due to debugging + if _debug_no_launch: + return + if wait: [thread.join() for thread in threads] diff --git a/tests/test_launcher.py b/tests/test_launcher.py index f497d9ca3e..5be0570c31 100644 --- a/tests/test_launcher.py +++ b/tests/test_launcher.py @@ -24,7 +24,6 @@ import os import tempfile -from time import sleep import warnings import psutil @@ -34,7 +33,6 @@ from ansys.mapdl.core.errors import ( DeprecationError, LicenseServerConnectionError, - MapdlDidNotStart, NotEnoughResources, PortAlreadyInUseByAnMAPDLInstance, ) @@ -184,75 +182,20 @@ def test_launch_console(version): @requires("local") @requires("nostudent") -def test_license_type_keyword(mapdl): - checks = [] - for license_name, license_description in LICENSES.items(): - try: - mapdl_ = launch_mapdl( - license_type=license_name, - start_timeout=start_timeout, - port=mapdl.port + 1, - additional_switches=QUICK_LAUNCH_SWITCHES, - ) - - # Using first line to ensure not picking up other stuff. - checks.append(license_description in mapdl_.__str__().split("\n")[0]) - mapdl_.exit() - del mapdl_ - sleep(2) - - except MapdlDidNotStart as e: - if "ANSYS license not available" in str(e): - continue - else: - raise e +@pytest.mark.parametrize("license_name", LICENSES) +def test_license_type_keyword_names(mapdl, license_name): + args = launch_mapdl(license_type=license_name, _debug_no_launch=True) + assert f"-p {license_name}" in args["additional_switches"] - assert any(checks) - - -@requires("local") -@requires("nostudent") -def test_license_type_keyword_names(mapdl): - # This test might became a way to check available licenses, which is not the purpose. - - successful_check = False - for license_name, license_description in LICENSES.items(): - mapdl_ = launch_mapdl( - license_type=license_name, - start_timeout=start_timeout, - port=mapdl.port + 1, - additional_switches=QUICK_LAUNCH_SWITCHES, - ) - - # Using first line to ensure not picking up other stuff. - successful_check = ( - license_description in mapdl_.__str__().split("\n")[0] or successful_check - ) - assert license_description in mapdl_.__str__().split("\n")[0] - mapdl_.exit() - assert successful_check # if at least one license is ok, this should be true. - - -@requires("local") -@requires("nostudent") -def test_license_type_additional_switch(mapdl): - # This test might became a way to check available licenses, which is not the purpose. - successful_check = False - for license_name, license_description in LICENSES.items(): - mapdl_ = launch_mapdl( - additional_switches=QUICK_LAUNCH_SWITCHES + " -p " + license_name, - start_timeout=start_timeout, - port=mapdl.port + 1, - ) - - # Using first line to ensure not picking up other stuff. - successful_check = ( - license_description in mapdl_.__str__().split("\n")[0] or successful_check - ) - mapdl_.exit() - - assert successful_check # if at least one license is ok, this should be true. +# @requires("local") +@pytest.mark.parametrize("license_name", LICENSES) +def test_license_type_additional_switch(mapdl, license_name): + args = launch_mapdl( + additional_switches=QUICK_LAUNCH_SWITCHES + " -p " + license_name, + _debug_no_launch=True, + ) + assert f"-p {license_name}" in args["additional_switches"] @requires("ansys-tools-path") @@ -447,7 +390,9 @@ def test_find_ansys(mapdl): assert find_ansys(version=version) is not None # Checking floats - assert find_ansys(version=22.2) is not None + with pytest.raises(ValueError): + find_ansys(version=22.2) + assert find_ansys(version=mapdl.version) is not None with pytest.raises(ValueError): diff --git a/tests/test_mapdl.py b/tests/test_mapdl.py index bebf02622e..1de6fe4958 100644 --- a/tests/test_mapdl.py +++ b/tests/test_mapdl.py @@ -1926,56 +1926,32 @@ def test_igesin_whitespace(mapdl, cleared, tmpdir): assert int(n_ent[0]) > 0 -@requires("local") -@requires("nostudent") -@pytest.mark.xfail(reason="Save on exit is broken.") def test_save_on_exit(mapdl, cleared): - mapdl2 = launch_mapdl( - license_server_check=False, - additional_switches=QUICK_LAUNCH_SWITCHES, - port=PORT1, - ) - mapdl2.parameters["my_par"] = "initial_value" + with mapdl.non_interactive: + mapdl.exit(save=True, fake_exit=True) + mapdl._exited = False # avoiding set exited on the class. - db_name = mapdl2.jobname + ".db" - db_dir = mapdl2.directory - db_path = os.path.join(db_dir, db_name) + lines = "\n".join(mapdl._stored_commands.copy()) + assert "SAVE" in lines.upper() - mapdl2.save(db_name) - assert os.path.exists(db_path) + mapdl._stored_commands = [] # resetting + mapdl.prep7() - mapdl2.parameters["my_par"] = "final_value" - mapdl2.exit(force=True) + mapdl.prep7() - mapdl2 = launch_mapdl( - license_server_check=False, - additional_switches=QUICK_LAUNCH_SWITCHES, - port=PORT1, - ) - mapdl2.resume(db_path) - if mapdl.version >= 24.2: - assert mapdl2.parameters["my_par"] == "initial_value" - else: - # This fails in earlier versions of MAPDL - assert mapdl2.parameters["my_par"] != "initial_value" - assert mapdl2.parameters["my_par"] == "final_value" - - mapdl2.parameters["my_par"] = "new_initial_value" - db_name = mapdl2.jobname + ".db" # reupdating db path - db_dir = mapdl2.directory - db_path = os.path.join(db_dir, db_name) - mapdl2.exit(save=True, force=True) - - mapdl2 = launch_mapdl( - license_server_check=False, - additional_switches=QUICK_LAUNCH_SWITCHES, - port=PORT1, - ) - mapdl2.resume(db_path) - assert mapdl2.parameters["my_par"] == "new_initial_value" - # cleaning up - mapdl2.exit(force=True) +def test_save_on_exit_not(mapdl, cleared): + with mapdl.non_interactive: + mapdl.exit(save=False, fake_exit=True) + mapdl._exited = False # avoiding set exited on the class. + + lines = "\n".join(mapdl._stored_commands.copy()) + assert "SAVE" not in lines.upper() + + mapdl._stored_commands = [] # resetting + mapdl.prep7() + + mapdl.prep7() def test_input_strings_inside_non_interactive(mapdl, cleared): @@ -2470,3 +2446,14 @@ def test_cleanup_loggers(mapdl): assert mapdl.logger is not None assert mapdl.logger.std_out_handler is None assert mapdl.logger.file_handler is None + + +def test_no_flush_stored(mapdl): + assert not mapdl._store_commands + mapdl._store_commands = True + mapdl._stored_commands = [] + + mapdl._flush_stored() + + assert not mapdl._store_commands + assert mapdl._stored_commands == [] diff --git a/tests/test_pool.py b/tests/test_pool.py index 467b4e285b..4a17ed0fa0 100644 --- a/tests/test_pool.py +++ b/tests/test_pool.py @@ -22,7 +22,6 @@ import os from pathlib import Path -import socket import time import numpy as np @@ -276,7 +275,6 @@ def test_directory_names_default_with_restart(self, pool): assert pool._names(i) in dirs_path_pool assert f"Instance_{i}" in dirs_path_pool - @requires("local") @skip_if_ignore_pool def test_directory_names_custom_string(self, tmpdir): pool = MapdlPool( @@ -287,15 +285,12 @@ def test_directory_names_custom_string(self, tmpdir): names="my_instance", port=50056, additional_switches=QUICK_LAUNCH_SWITCHES, + _debug_no_launch=True, ) - dirs_path_pool = os.listdir(pool._root_dir) - assert "my_instance_0" in dirs_path_pool - assert "my_instance_1" in dirs_path_pool - - pool.exit(block=True) + time.sleep(2) + assert all(["my_instance" in each for each in dirs_path_pool]) - @requires("local") @skip_if_ignore_pool def test_directory_names_function(self, tmpdir): def myfun(i): @@ -313,6 +308,7 @@ def myfun(i): names=myfun, run_location=tmpdir, additional_switches=QUICK_LAUNCH_SWITCHES, + _debug_no_launch=True, ) dirs_path_pool = os.listdir(pool._root_dir) @@ -334,16 +330,17 @@ def test_num_instances(self): @skip_if_ignore_pool @requires("local") def test_only_one_instance(self): - pool = MapdlPool( + pool_ = MapdlPool( 1, exec_file=EXEC_FILE, nproc=NPROC, additional_switches=QUICK_LAUNCH_SWITCHES, + _debug_no_launch=True, ) - pool_sz = len(pool) - _ = pool.map(lambda mapdl: mapdl.prep7()) - assert len(pool) == pool_sz - pool.exit() + args = pool_._debug_no_launch + pool_sz = len(pool_) + assert len(args["ips"]) == 1 + assert len(args["ports"]) == 1 def test_ip(self, monkeypatch): monkeypatch.delenv("PYMAPDL_START_INSTANCE", raising=False) @@ -417,8 +414,6 @@ def test_multiple_ips(self, monkeypatch): conf = MapdlPool(ip=ips, _debug_no_launch=True)._debug_no_launch - ips = [socket.gethostbyname(each) for each in ips] - assert conf["ips"] == ips assert conf["ports"] == [50052 for i in range(len(ips))] assert conf["start_instance"] is False @@ -786,9 +781,6 @@ def test_ip_port_n_instance( n_instances=n_instances, ip=ip, port=port, _debug_no_launch=True )._debug_no_launch - if exp_ip: - exp_ip = [socket.gethostbyname(each) for each in exp_ip] - assert conf["n_instances"] == exp_n_instances assert len(conf["ips"]) == exp_n_instances assert len(conf["ports"]) == exp_n_instances