diff --git a/.ci/collect_mapdl_logs_locals.sh b/.ci/collect_mapdl_logs_locals.sh new file mode 100755 index 0000000000..5b4eff1c4a --- /dev/null +++ b/.ci/collect_mapdl_logs_locals.sh @@ -0,0 +1,12 @@ + +mkdir "$LOG_NAMES" && echo "Successfully generated directory $LOG_NAMES" + +cp *.log ./"$LOG_NAMES"/ || echo "No log files could be found" +cp *apdl.out ./"$LOG_NAMES"/ || echo "No APDL log files could be found" +cp *pymapdl.apdl ./"$LOG_NAMES"/ || echo "No PYMAPDL APDL log files could be found" + + +ls -la ./"$LOG_NAMES" + +echo "Tar files..." +tar cvzf ./"$LOG_NAMES".tgz ./"$LOG_NAMES" || echo "Failed to compress" \ No newline at end of file diff --git a/.ci/collect_mapdl_logs.sh b/.ci/collect_mapdl_logs_remote.sh similarity index 100% rename from .ci/collect_mapdl_logs.sh rename to .ci/collect_mapdl_logs_remote.sh diff --git a/.ci/display_logs_locals.sh b/.ci/display_logs_locals.sh new file mode 100755 index 0000000000..c4db9eb59c --- /dev/null +++ b/.ci/display_logs_locals.sh @@ -0,0 +1,19 @@ + +##### +# Displaying files +FILE_PAT=./"$LOG_NAMES"/pymapdl.log +FILE_DESCRIPTION="PyMAPDL log" + +if compgen -G "$FILE_PAT" > /dev/null ;then for f in "$FILE_PAT"; do echo "::group:: $FILE_DESCRIPTION: $f" && cat "$f" && echo "::endgroup::" ; done; fi || echo "Failed to show $FILE_DESCRIPTION file" + +##### +FILE_PAT=./"$LOG_NAMES"/pymapdl.apdl +FILE_DESCRIPTION="PyMAPDL APDL log" + +if compgen -G "$FILE_PAT" > /dev/null ;then for f in "$FILE_PAT"; do echo "::group:: $FILE_DESCRIPTION: $f" && cat "$f" && echo "::endgroup::" ; done; fi || echo "Failed to show $FILE_DESCRIPTION file" + +##### +FILE_PAT=./"$LOG_NAMES"/apdl.out +FILE_DESCRIPTION="MAPDL Output" + +if compgen -G "$FILE_PAT" > /dev/null ;then for f in "$FILE_PAT"; do echo "::group:: $FILE_DESCRIPTION: $f" && cat "$f" && echo "::endgroup::" ; done; fi || echo "Failed to show $FILE_DESCRIPTION file" \ No newline at end of file diff --git a/.ci/display_logs.sh b/.ci/display_logs_remote.sh similarity index 100% rename from .ci/display_logs.sh rename to .ci/display_logs_remote.sh diff --git a/.ci/requirements_minimal.txt b/.ci/requirements_minimal.txt new file mode 100644 index 0000000000..8d55e3ac3c --- /dev/null +++ b/.ci/requirements_minimal.txt @@ -0,0 +1,6 @@ +pyfakefs==5.7.2 +pytest-cov==6.0.0 +pytest-random-order==1.1.1 +pytest-rerunfailures==15.0 +pytest-timeout==2.3.1 +pytest==8.3.4 \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7684589d34..3712c825a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,7 @@ env: PYTEST_ARGUMENTS: '-vvv -rxXsa --color=yes --durations=10 --random-order --random-order-bucket=class --maxfail=10 --reruns 3 --reruns-delay 4 --cov=ansys.mapdl.core --cov-report=html --timeout=40' BUILD_CHEATSHEET: True + PYMAPDL_DEBUG_TESTING: True # Following env vars when changed will "reset" the mentioned cache, # by changing the cache file name. It is rendered as ...-v%RESET_XXX%-... @@ -337,7 +338,7 @@ jobs: MAPDL_INSTANCE: MAPDL_0 LOG_NAMES: logs-build-docs run: | - .ci/collect_mapdl_logs.sh + .ci/collect_mapdl_logs_remote.sh - name: "Upload logs to GitHub" if: always() @@ -352,7 +353,7 @@ jobs: MAPDL_INSTANCE: MAPDL_0 LOG_NAMES: logs-build-docs run: | - .ci/display_logs.sh + .ci/display_logs_remote.sh build-test-remote-matrix: name: "Build remote test matrix" @@ -577,7 +578,7 @@ jobs: MAPDL_INSTANCE: MAPDL_0 LOG_NAMES: logs-remote-${{ matrix.mapdl-version }} run: | - .ci/collect_mapdl_logs.sh + .ci/collect_mapdl_logs_remote.sh - name: "Upload logs to GitHub" if: always() @@ -592,7 +593,7 @@ jobs: MAPDL_INSTANCE: MAPDL_0 LOG_NAMES: logs-remote-${{ matrix.mapdl-version }} run: | - .ci/display_logs.sh + .ci/display_logs_remote.sh build-test-local-minimal-matrix: name: "Build test matrix for minimal and local" @@ -714,6 +715,27 @@ jobs: --reset_only_failed --add_missing_images \ --cov-report=xml:${{ matrix.mapdl-version }}-local.xml + - name: "Collect logs on failure" + if: always() + env: + LOG_NAMES: logs-local-${{ matrix.mapdl-version }} + run: | + .ci/collect_mapdl_logs_locals.sh + + - name: "Upload logs to GitHub" + if: always() + uses: actions/upload-artifact@master + with: + name: logs-local-${{ matrix.mapdl-version }}.tgz + path: ./logs-local-${{ matrix.mapdl-version }}.tgz + + - name: "Display files structure" + if: always() + env: + LOG_NAMES: logs-local-${{ matrix.mapdl-version }} + run: | + .ci/display_logs_locals.sh + - name: "Adding the directory as safe directory for later step" run: | git config --global --add safe.directory $GITHUB_WORKSPACE @@ -822,7 +844,7 @@ jobs: - name: "Unit testing requirements installation" run: | - python -m pip install pytest pytest-rerunfailures pytest-cov pytest-random-order pyfakefs pytest-timeout + python -m pip install -r .ci/requirements_minimal.txt - name: "Unit testing" env: @@ -851,6 +873,27 @@ jobs: ${{ env.PYTEST_ARGUMENTS }} \ --cov-report=xml:${{ matrix.mapdl-version }}-minimal.xml + - name: "Collect logs on failure" + if: always() + env: + LOG_NAMES: logs-minimal-${{ matrix.mapdl-version }} + run: | + .ci/collect_mapdl_logs_locals.sh + + - name: "Upload logs to GitHub" + if: always() + uses: actions/upload-artifact@master + with: + name: logs-minimal-${{ matrix.mapdl-version }}.tgz + path: ./logs-minimal-${{ matrix.mapdl-version }}.tgz + + - name: "Display files structure" + if: always() + env: + LOG_NAMES: logs-minimal-${{ matrix.mapdl-version }} + run: | + .ci/display_logs_locals.sh + - uses: codecov/codecov-action@v5 name: "Upload coverage to Codecov" with: @@ -930,7 +973,7 @@ jobs: - name: "Unit testing requirements installation" run: | - python -m pip install pytest pytest-rerunfailures pytest-cov pytest-random-order pyfakefs pytest-timeout + python -m pip install -r .ci/requirements_minimal.txt - name: "Unit testing" env: @@ -959,6 +1002,27 @@ jobs: ${{ env.PYTEST_ARGUMENTS }} \ --cov-report=xml:${{ matrix.mapdl-version }}-minimal-console.xml + - name: "Collect logs on failure" + if: always() + env: + LOG_NAMES: logs-minimal-console-${{ matrix.mapdl-version }} + run: | + .ci/collect_mapdl_logs_locals.sh + + - name: "Upload logs to GitHub" + if: always() + uses: actions/upload-artifact@master + with: + name: logs-minimal-console-${{ matrix.mapdl-version }}.tgz + path: ./logs-minimal-console-${{ matrix.mapdl-version }}.tgz + + - name: "Display files structure" + if: always() + env: + LOG_NAMES: logs-minimal-console-${{ matrix.mapdl-version }} + run: | + .ci/display_logs_locals.sh + - uses: codecov/codecov-action@v5 name: "Upload coverage to Codecov" with: diff --git a/doc/changelog.d/3594.maintenance.md b/doc/changelog.d/3594.maintenance.md new file mode 100644 index 0000000000..3784e19adf --- /dev/null +++ b/doc/changelog.d/3594.maintenance.md @@ -0,0 +1 @@ +feat: activate debug mode on testing using `PYMAPDL_DEBUG_TESTING` envvar \ No newline at end of file diff --git a/tests/common.py b/tests/common.py index 0ff9a64632..a42b29a27e 100644 --- a/tests/common.py +++ b/tests/common.py @@ -157,14 +157,14 @@ def testing_minimal(): return os.environ.get("TESTING_MINIMAL", "NO").upper().strip() in ["YES", "TRUE"] -def log_apdl() -> bool: - if os.environ.get("PYMAPDL_LOG_APDL"): - log_apdl = os.environ.get("PYMAPDL_LOG_APDL") +def debug_testing() -> bool: + if os.environ.get("PYMAPDL_DEBUG_TESTING"): + debug_testing = os.environ.get("PYMAPDL_DEBUG_TESTING") - if log_apdl.lower() in ["true", "false", "yes", "no"]: - return log_apdl.lower() in ["true", "yes"] + if debug_testing.lower() in ["true", "false", "yes", "no"]: + return debug_testing.lower() in ["true", "yes"] else: - return log_apdl + return debug_testing else: return False @@ -228,7 +228,7 @@ def log_test_start(mapdl: Mapdl) -> None: ) mapdl.run("!") - mapdl.run(f"! PyMAPDL running test: {test_name}") + mapdl.run(f"! PyMAPDL running test: {test_name}"[:639]) mapdl.run("!") # To see it also in MAPDL terminal output @@ -241,6 +241,7 @@ def log_test_start(mapdl: Mapdl) -> None: types_ = ["File path", "Test function"] mapdl._run("/com,Running test in:", mute=True) + for type_, name_ in zip(types_, test_name): mapdl._run(f"/com, {type_}: {name_}", mute=True) diff --git a/tests/conftest.py b/tests/conftest.py index cc0ffe1c11..023bbddd10 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -35,6 +35,7 @@ from common import ( Element, Node, + debug_testing, get_details_of_elements, get_details_of_nodes, has_dpf, @@ -44,7 +45,6 @@ is_on_ubuntu, is_running_on_student, is_smp, - log_apdl, log_test_start, make_sure_not_instances_are_left_open, restart_mapdl, @@ -58,6 +58,7 @@ # --------------------------- # +DEBUG_TESTING = debug_testing() TESTING_MINIMAL = testing_minimal() ON_LOCAL = is_on_local() @@ -74,7 +75,6 @@ HAS_DPF = has_dpf() SUPPORT_PLOTTING = support_plotting() IS_SMP = is_smp() -LOG_APDL = log_apdl() QUICK_LAUNCH_SWITCHES = "-smp -m 100 -db 100" VALID_PORTS = [] @@ -183,6 +183,17 @@ def requires_dependency(dependency: str): return pytest.mark.skip(reason=f"Requires '{dependency}' package") +if DEBUG_TESTING: + from ansys.mapdl.core import LOG + + LOG.setLevel("DEBUG") + + # If the following file name is changed, update `ci.yml`. + LOG.log_to_file("pymapdl.log") + + # the following files are also generated by MAPDL gRPC: + # - "pymapdl.apdl": The APDL commands sent to MAPDL by PyMAPDL + # - "apdl.out" : MAPDL console output. Very likely only contains the output until connected. ################################################################ # # Importing packages @@ -265,7 +276,7 @@ def pytest_report_header(config, start_path, startdir): text = [] text += ["Testing variables".center(get_terminal_size()[0], "-")] text += [ - f"Session dependent: ON_CI ({ON_CI}), TESTING_MINIMAL ({TESTING_MINIMAL}), SUPPORT_PLOTTING ({SUPPORT_PLOTTING})" + f"Session dependent: DEBUG_TESTING ({DEBUG_TESTING}), ON_CI ({ON_CI}), TESTING_MINIMAL ({TESTING_MINIMAL}), SUPPORT_PLOTTING ({SUPPORT_PLOTTING})" ] text += [ f"OS dependent: ON_LINUX ({ON_LINUX}), ON_UBUNTU ({ON_UBUNTU}), ON_WINDOWS ({ON_WINDOWS}), ON_MACOS ({ON_MACOS})" @@ -429,7 +440,7 @@ def run_before_and_after_tests( mapdl = restart_mapdl(mapdl) # Write test info to log_apdl - if LOG_APDL: + if DEBUG_TESTING: log_test_start(mapdl) # check if the local/remote state has changed or not @@ -546,7 +557,9 @@ def mapdl_console(request): "Valid versions are up to 2020R2." ) - mapdl = launch_mapdl(console_path, mode="console", log_apdl=LOG_APDL) + mapdl = launch_mapdl( + console_path, mode="console", log_apdl="pymapdl.apdl" if DEBUG_TESTING else None + ) from ansys.mapdl.core.mapdl_console import MapdlConsole assert isinstance(mapdl, MapdlConsole) @@ -577,8 +590,12 @@ def mapdl(request, tmpdir_factory): cleanup_on_exit=cleanup, license_server_check=False, start_timeout=50, - log_apdl=LOG_APDL, + loglevel="DEBUG" if DEBUG_TESTING else "ERROR", + # If the following file names are changed, update `ci.yml`. + log_apdl="pymapdl.apdl" if DEBUG_TESTING else None, + mapdl_output="apdl.out" if (DEBUG_TESTING and ON_LOCAL) else None, ) + mapdl._show_matplotlib_figures = False # CI: don't show matplotlib figures MAPDL_VERSION = mapdl.version # Caching version diff --git a/tests/test_grpc.py b/tests/test_grpc.py index fd2454a4d0..d5cc35e4ca 100644 --- a/tests/test_grpc.py +++ b/tests/test_grpc.py @@ -577,13 +577,19 @@ def test_input_compatibility_api_change(mapdl, cleared): @requires("grpc") @requires("local") -def test__check_stds(mapdl, cleared): +@requires("nostudent") +def test__check_stds(): """Test that the standard input is checked.""" + from ansys.mapdl.core import launch_mapdl + + mapdl = launch_mapdl(port=50058) mapdl._read_stds() assert mapdl._stdout is not None assert mapdl._stderr is not None + mapdl.exit(force=True) + def test_subscribe_to_channel(mapdl, cleared): assert mapdl.channel_state in [ diff --git a/tests/test_logging.py b/tests/test_logging.py index 3c416706be..0b97a7c5c6 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -287,7 +287,12 @@ def test_log_to_file(tmpdir): LOG.logger.setLevel("ERROR") LOG.std_out_handler.setLevel("ERROR") - if not LOG.file_handler: + if LOG.file_handler is None: + old_logger = None + LOG.log_to_file(file_path) + else: + # the logger has been already instantiated + old_logger = LOG.file_handler.baseFilename LOG.log_to_file(file_path) LOG.error(file_msg_error) @@ -313,6 +318,9 @@ def test_log_to_file(tmpdir): assert file_msg_debug in text + if old_logger is not None: + LOG.log_to_file(old_logger) + def test_log_instance_name(mapdl, cleared): # verify we can access via an instance name