diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d275c5..efde7a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,7 +67,7 @@ jobs: run: | twine check dist/* - test: + test-linux-container: runs-on: ubuntu-latest needs: build-check strategy: @@ -250,3 +250,55 @@ jobs: docker rm -f "${{ env.RUN_CFG__MACHINE2_NAME }}" || true # Delete the network (it will be deleted successfully, since all containers in it have already been destroyed) docker network rm "${{ env.RUN_CFG__NETWORK_NAME }}" || true + + test-macos-14: + runs-on: macos-14 + needs: build-check + strategy: + fail-fast: false + matrix: + python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + + env: + BASE_SIGN: "macos-py${{ matrix.python }}" + + steps: + - name: Prepare variables + run: | + echo "RUN_CFG__NOW=$(date +'%Y%m%d_%H%M%S')" >> $GITHUB_ENV + echo "RUN_CFG__LOGS_DIR=logs-${{ env.BASE_SIGN }}" >> $GITHUB_ENV + echo "---------- [$GITHUB_ENV]" + cat $GITHUB_ENV + + - name: Checkout + uses: actions/checkout@v7 + + - name: Prepare logs folder on the host + run: mkdir -p "${{ env.RUN_CFG__LOGS_DIR }}" + + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v7 + with: + python-version: ${{ matrix.python }} + cache: 'pip' + + - name: Run native tests (LocalOperations only) + run: | + set -eux + echo "HELLO FROM MACOS RUNNER" + echo "HOME DIR IS [$(realpath ~/)]" + echo "WORK DIR IS [$(pwd)]" + + export TEST_CFG__LOG_DIR="${{ github.workspace }}/${{ env.RUN_CFG__LOGS_DIR }}" + + export TEST_FILTER="not remote" + export PYTHON_BINARY="python3" + + bash run_tests3.sh + + - name: Upload Logs + uses: actions/upload-artifact@v7 + if: always() + with: + name: testgres.os_ops--test_logs--${{ env.RUN_CFG__NOW }}-${{ env.BASE_SIGN }}-id${{ github.run_id }} + path: "${{ env.RUN_CFG__LOGS_DIR }}/" diff --git a/run_tests3.sh b/run_tests3.sh index f97de54..0d0c809 100755 --- a/run_tests3.sh +++ b/run_tests3.sh @@ -1,6 +1,10 @@ #!/bin/bash set -eux +if [ -z ${TEST_FILTER+x} ]; \ +then export TEST_FILTER=""; \ +fi + # prepare python environment VENV_PATH="/tmp/testgres_venv" rm -rf $VENV_PATH @@ -13,6 +17,6 @@ pip install -r tests/requirements.txt export -p # run builtin tests -pytest -l -vvv -n 4 +pytest -l -vvv -n 4 --color=yes -k "${TEST_FILTER}" set +eux diff --git a/tests/helpers/run_conditions.py b/tests/helpers/run_conditions.py index f847d87..ea20e5b 100644 --- a/tests/helpers/run_conditions.py +++ b/tests/helpers/run_conditions.py @@ -11,3 +11,13 @@ class RunConditions: def skip_if_windows(): if platform.system().lower() == "windows": pytest.skip("This test does not support Windows.") + + @staticmethod + def skip_if_darwin(): + if platform.system().lower() == "darwin": + pytest.skip("This test does not support Darwin.") + + @staticmethod + def skip_if_linux(): + if platform.system().lower() == "linux": + pytest.skip("This test does not support Linux.") diff --git a/tests/test_os_ops_common.py b/tests/test_os_ops_common.py index abe0819..97725b3 100644 --- a/tests/test_os_ops_common.py +++ b/tests/test_os_ops_common.py @@ -225,7 +225,7 @@ def test_get_platform__is_known(self, os_ops_descr: OsOpsDescr): p = os_ops.get_platform() assert p is not None assert type(p) is str - assert p in {"win32", "linux"} + assert p in {"win32", "linux", "darwin"} return def test_create_clone( @@ -422,11 +422,12 @@ def test_exec_command_with_exec_env__2(self, os_ops_descr: OsOpsDescr): assert not os_ops.path_exists(tmp_file) return - def test_exec_command_with_cwd(self, os_ops_descr: OsOpsDescr): + def test_exec_command_with_cwd__linux(self, os_ops_descr: OsOpsDescr): assert type(os_ops_descr) is OsOpsDescr assert isinstance(os_ops_descr.os_ops, OsOperations) RunConditions.skip_if_windows() + RunConditions.skip_if_darwin() os_ops = os_ops_descr.os_ops assert isinstance(os_ops, OsOperations) @@ -616,7 +617,7 @@ def test_makedirs_and_rmdirs_success( assert not os_ops.path_exists(path) return - def test_makedirs_failure( + def test_makedirs_failure__linux( self, os_ops_descr: OsOpsDescr, name_with_surprize: tagNameWithSurprize, @@ -633,6 +634,7 @@ def test_makedirs_failure( assert isinstance(os_ops, OsOperations) RunConditions.skip_if_windows() + RunConditions.skip_if_darwin() path = "/root/test_dir-{}-{}".format( name_with_surprize.value, @@ -651,6 +653,42 @@ def test_makedirs_failure( __class__.helper__bug_check__unknown_os_ops_type(os_ops) return + def test_makedirs_failure__darwin( + self, + os_ops_descr: OsOpsDescr, + name_with_surprize: tagNameWithSurprize, + ): + """ + Test makedirs for failure. + """ + # Try to create a directory in a read-only location + assert type(os_ops_descr) is OsOpsDescr + assert type(name_with_surprize) is __class__.tagNameWithSurprize + assert isinstance(os_ops_descr.os_ops, OsOperations) + + os_ops = os_ops_descr.os_ops + assert isinstance(os_ops, OsOperations) + + RunConditions.skip_if_windows() + RunConditions.skip_if_linux() + + path = "/root/test_dir-{}-{}".format( + name_with_surprize.value, + uuid.uuid4().bytes.hex(), + ) + + # Test makedirs + with pytest.raises(Exception) as x: + os_ops.makedirs(path) + + if type(os_ops).__name__ == "LocalOperations": + assert type(x.value) is OSError + elif type(os_ops).__name__ == "RemoteOperations": + assert type(x.value) is ExecUtilException + else: + __class__.helper__bug_check__unknown_os_ops_type(os_ops) + return + def test_listdir( self, os_ops_descr: OsOpsDescr, @@ -2559,13 +2597,16 @@ def test_is_abs_path__no( return # -------------------------------------------------------------------- - def test_get_abs_path( + def test_get_abs_path__linux( self, os_ops_descr: OsOpsDescr, ): assert type(os_ops_descr) is OsOpsDescr assert isinstance(os_ops_descr.os_ops, OsOperations) + RunConditions.skip_if_windows() + RunConditions.skip_if_darwin() + os_ops = os_ops_descr.os_ops assert isinstance(os_ops, OsOperations) @@ -3154,7 +3195,7 @@ def test_readlines__BIN( assert lines == result_bin return - def test_prove_environment_isolation( + def test_prove_environment_isolation__linux( self, os_ops_descr: OsOpsDescr, ): @@ -3166,6 +3207,9 @@ def test_prove_environment_isolation( os_ops = os_ops_descr.os_ops assert isinstance(os_ops, OsOperations) + RunConditions.skip_if_windows() + RunConditions.skip_if_darwin() + logging.info("=================== COKANUM PROOF START ===================") logging.info(f"Target environment type: [{os_ops_descr.sign}]") @@ -5130,7 +5174,7 @@ def test_popen_replace_env_of_os_ops( return - def test_popen_cwd( + def test_popen_cwd__linux( self, os_ops_descr: OsOpsDescr, ): @@ -5138,6 +5182,7 @@ def test_popen_cwd( assert isinstance(os_ops_descr.os_ops, OsOperations) RunConditions.skip_if_windows() + RunConditions.skip_if_darwin() os_ops = os_ops_descr.os_ops @@ -5908,7 +5953,7 @@ def test_run_input( return - def test_run_cwd( + def test_run_cwd__linux( self, os_ops_descr: OsOpsDescr, ): @@ -5916,6 +5961,7 @@ def test_run_cwd( assert isinstance(os_ops_descr.os_ops, OsOperations) RunConditions.skip_if_windows() + RunConditions.skip_if_darwin() os_ops = os_ops_descr.os_ops