Skip to content

Commit 7e86b2a

Browse files
test: improving testing performance (#3703)
* test: refactor check_stds and post_mortem_checks * test: backing off algorithm * chore: adding changelog file 3703.added.md [dependabot-skip] * fix: codacity warnings * feat: using get_value to obtain the n elements * revert: revert "feat: using get_value to obtain the n elements" Performance is not as go This reverts commit 877f803. * feat: using get_value to obtain the n elements * revert: revert "feat: using get_value to obtain the n elements" Performance is not as go This reverts commit 877f803. * feat: using mapdl.exit when raising final error. * test: fix test by avoiding killing mapdl. --------- Co-authored-by: pyansys-ci-bot <[email protected]>
1 parent a2f91e6 commit 7e86b2a

File tree

7 files changed

+213
-42
lines changed

7 files changed

+213
-42
lines changed

doc/changelog.d/3703.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test: improving testing performance

src/ansys/mapdl/core/errors.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333

3434
SIGINT_TRACKER: List = []
3535

36+
# Configuration of 'protect_grpc' wrapper
37+
N_ATTEMPTS = 5
38+
INITIAL_BACKOFF = 0.1
39+
MULTIPLIER_BACKOFF = 2
40+
3641

3742
LOCKFILE_MSG: str = """
3843
Another ANSYS job with the same job name is already running in this
@@ -307,9 +312,9 @@ def wrapper(*args, **kwargs):
307312
old_handler = signal.signal(signal.SIGINT, handler)
308313

309314
# Capture gRPC exceptions
310-
n_attempts = 5
311-
initial_backoff = 0.1
312-
multiplier_backoff = 2
315+
n_attempts = kwargs.get("n_attempts", N_ATTEMPTS)
316+
initial_backoff = kwargs.get("initial_backoff", INITIAL_BACKOFF)
317+
multiplier_backoff = kwargs.get("multiplier_backoff", MULTIPLIER_BACKOFF)
313318

314319
i_attemps = 0
315320

@@ -321,7 +326,6 @@ def wrapper(*args, **kwargs):
321326
break
322327

323328
except grpc.RpcError as error:
324-
325329
mapdl = retrieve_mapdl_from_args(args)
326330
mapdl._log.debug("A gRPC error has been detected.")
327331

@@ -331,14 +335,16 @@ def wrapper(*args, **kwargs):
331335
wait = (
332336
initial_backoff * multiplier_backoff**i_attemps
333337
) # Exponential backoff
334-
sleep(wait)
335338

336339
# reconnect
337340
mapdl._log.debug(
338341
f"Re-connection attempt {i_attemps} after waiting {wait:0.3f} seconds"
339342
)
340343

341-
connected = mapdl._connect(timeout=wait)
344+
if not mapdl.is_alive:
345+
connected = mapdl._connect(timeout=wait)
346+
else:
347+
sleep(wait)
342348

343349
# Retry again
344350
continue
@@ -455,12 +461,8 @@ def handle_generic_grpc_error(
455461

456462
else:
457463
# Making sure we do not keep executing gRPC calls.
458-
mapdl._exited = True
459-
mapdl._exiting = True
460-
461464
# Must close unfinished processes
462-
mapdl._close_process()
463-
mapdl._exiting = False
465+
mapdl.exit()
464466
raise MapdlExitedError(msg)
465467

466468

src/ansys/mapdl/core/mapdl_grpc.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -637,10 +637,12 @@ def process_is_alive(self):
637637
"""Check if the MAPDL process is alive"""
638638
return self._is_alive_subprocess()
639639

640-
def _post_mortem_checks(self):
640+
def _post_mortem_checks(self, process=None):
641641
"""Check possible reasons for not having a successful connection."""
642642
# Check early exit
643-
process = self._mapdl_process
643+
if process is None:
644+
process = self._mapdl_process
645+
644646
if process is None or not self.is_grpc:
645647
return
646648

@@ -651,9 +653,7 @@ def _post_mortem_checks(self):
651653

652654
def _read_stds(self):
653655
"""Read the stdout and stderr from the subprocess."""
654-
from ansys.mapdl.core.launcher import (
655-
_get_std_output, # Avoid circular import error
656-
)
656+
from ansys.mapdl.core.launcher import _get_std_output
657657

658658
if self._mapdl_process is None or not self._mapdl_process.stdout:
659659
return

tests/common.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ def is_exited(mapdl: Mapdl):
267267
try:
268268
# to connect
269269
mapdl = Mapdl(port=port, ip=ip)
270+
warn("MAPDL disconnected during testing, reconnected.")
270271

271272
except MapdlConnectionError as err:
272273
from conftest import DEBUG_TESTING, ON_LOCAL
@@ -294,6 +295,7 @@ def is_exited(mapdl: Mapdl):
294295
log_apdl="pymapdl.apdl" if DEBUG_TESTING else None,
295296
mapdl_output="apdl.out" if (DEBUG_TESTING and ON_LOCAL) else None,
296297
)
298+
warn("MAPDL died during testing, relaunched.")
297299

298300
LOG.info("Successfully re-connected to MAPDL")
299301

tests/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,8 @@ def mapdl(request, tmpdir_factory):
637637
with pytest.raises(MapdlExitedError):
638638
mapdl._send_command_stream("/PREP7")
639639

640-
# Delete Mapdl object
641-
del mapdl
640+
# Delete Mapdl object
641+
del mapdl
642642

643643

644644
################################################################

tests/test_grpc.py

Lines changed: 94 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import os
2525
import re
2626
import shutil
27+
import subprocess
2728
import sys
2829
from unittest.mock import patch
2930

@@ -34,6 +35,8 @@
3435
from ansys.mapdl.core.common_grpc import DEFAULT_CHUNKSIZE
3536
from ansys.mapdl.core.errors import (
3637
MapdlCommandIgnoredError,
38+
MapdlConnectionError,
39+
MapdlDidNotStart,
3740
MapdlExitedError,
3841
MapdlgRPCError,
3942
MapdlRuntimeError,
@@ -577,19 +580,101 @@ def test_input_compatibility_api_change(mapdl, cleared):
577580

578581

579582
@requires("grpc")
580-
@requires("local")
581-
@requires("nostudent")
582-
def test__check_stds():
583+
def test__check_stds(mapdl):
583584
"""Test that the standard input is checked."""
584-
from ansys.mapdl.core import launch_mapdl
585+
from ansys.mapdl.core.launcher import _check_server_is_alive, _get_std_output
586+
587+
cmd = "counter=1; while true; do echo $counter; ((counter++)); sleep 1; done"
588+
589+
process = subprocess.Popen(
590+
["bash", "-c", cmd], stdout=subprocess.PIPE, stderr=subprocess.PIPE
591+
) # nosec B603 B607
592+
593+
if not hasattr(mapdl, "_stdout_queue"):
594+
mapdl._stdout_queue = None
595+
if not hasattr(mapdl, "_stdout_thread"):
596+
mapdl._stdout_thread = None
597+
598+
with (
599+
# To avoid overwriting the values for the rest of the tests.
600+
patch.object(mapdl, "_stdout_queue"),
601+
patch.object(mapdl, "_stdout_thread"),
602+
patch.object(mapdl, "_mapdl_process"),
603+
patch(
604+
"ansys.mapdl.core.launcher._get_std_output", autospec=True
605+
) as mock_get_std_output,
606+
):
607+
608+
mock_get_std_output.side_effect = _get_std_output
609+
610+
mapdl._mapdl_process = process
611+
mapdl._create_process_stds_queue(process)
612+
613+
# this should raise no issues
614+
mapdl._post_mortem_checks(process)
585615

586-
mapdl = launch_mapdl(port=50058)
616+
with pytest.raises(MapdlDidNotStart):
617+
_check_server_is_alive(mapdl._stdout_queue, 0.5)
587618

588-
mapdl._read_stds()
589-
assert mapdl._stdout is not None
590-
assert mapdl._stderr is not None
619+
assert isinstance(mapdl._stdout, list)
620+
assert isinstance(mapdl._stderr, list)
591621

592-
mapdl.exit(force=True)
622+
assert (
623+
mapdl._stdout
624+
and len(mapdl._stdout) > 0
625+
and mapdl._stdout[-1]
626+
and mapdl._stdout[-1].strip().isdigit()
627+
)
628+
629+
mock_get_std_output.assert_called()
630+
631+
632+
@requires("grpc")
633+
@requires("nowindows") # since we are using bash
634+
def test__post_mortem_checks(mapdl):
635+
"""Test that the standard input is checked."""
636+
from ansys.mapdl.core.launcher import _get_std_output
637+
638+
bash_command = """
639+
counter=1; while true; do
640+
echo $counter;
641+
((counter++));
642+
sleep 0.1;
643+
if [ $counter -eq 7 ]; then
644+
echo "";
645+
echo "ERROR: Expected MapdlConnection error";
646+
echo "";
647+
fi;
648+
done
649+
"""
650+
process = subprocess.Popen(
651+
["bash", "-c", bash_command], stdout=subprocess.PIPE, stderr=subprocess.PIPE
652+
)
653+
654+
if not hasattr(mapdl, "_stdout_queue"):
655+
mapdl._stdout_queue = None
656+
if not hasattr(mapdl, "_stdout_thread"):
657+
mapdl._stdout_thread = None
658+
659+
with (
660+
# To avoid overwriting the values for the rest of the tests.
661+
patch.object(mapdl, "_stdout_queue"),
662+
patch.object(mapdl, "_stdout_thread"),
663+
patch.object(mapdl, "_mapdl_process"),
664+
patch(
665+
"ansys.mapdl.core.launcher._get_std_output", autospec=True
666+
) as mock_get_std_output,
667+
):
668+
669+
mock_get_std_output.side_effect = _get_std_output
670+
671+
mapdl._mapdl_process = process
672+
mapdl._create_process_stds_queue(process)
673+
674+
with pytest.raises(
675+
MapdlConnectionError, match="Expected MapdlConnection error"
676+
):
677+
mapdl._post_mortem_checks(process)
593678

594679

595680
def test_subscribe_to_channel(mapdl, cleared):

0 commit comments

Comments
 (0)