diff --git a/libmamba/include/mamba/core/output.hpp b/libmamba/include/mamba/core/output.hpp index f4b7b7d64f..0ef4ef010a 100644 --- a/libmamba/include/mamba/core/output.hpp +++ b/libmamba/include/mamba/core/output.hpp @@ -161,6 +161,25 @@ namespace mamba Console(const Context& context); ~Console(); + /** Utility to set `"success": false` on destruction of this object + when it's destructor is invoked while an exception is in flight. + + This helps avoiding situations where an exception that should be + considered a failure of the overall operation is thrown but + the json is still set with `"success": true`, while it should be `false`, + misleading the testing outputs. + */ + struct JSonFailureOnException + { + ~JSonFailureOnException() + { + if (std::uncaught_exceptions() > 0) + { + Console::instance().json_write({ { "success", false } }); + } + } + }; + private: void json_print(); diff --git a/libmamba/src/core/transaction.cpp b/libmamba/src/core/transaction.cpp index 41bf298717..14d2bfeaf8 100644 --- a/libmamba/src/core/transaction.cpp +++ b/libmamba/src/core/transaction.cpp @@ -367,6 +367,10 @@ namespace mamba bool MTransaction::execute(const Context& ctx, ChannelContext& channel_context, PrefixData& prefix) { + // If an exception is thrown in this function, we must consider the whole operation as a + // failure. + Console::JSonFailureOnException fail_json_on_exception; + // JSON output // back to the top level if any action was required if (!empty()) diff --git a/micromamba/tests/test_pkg_cache.py b/micromamba/tests/test_pkg_cache.py index 36ad0b9227..e48b820452 100644 --- a/micromamba/tests/test_pkg_cache.py +++ b/micromamba/tests/test_pkg_cache.py @@ -393,16 +393,15 @@ def test_no_writable_extracted_dir_corrupted(self, tmp_home, tmp_root_prefix, tm f"**{file_to_find_in_package}", recursive=True, root_dir=old_cache_dir ) for file in files: - (old_cache_dir / file).unlink() + file.unlink() helpers.recursive_chmod(tmp_cache, 0o500) os.environ["CONDA_PKGS_DIRS"] = f"{tmp_cache}" - # Mamba now handles corrupted extracted directories in read-only caches gracefully - # by extracting to a temporary location, so the operation should succeed - helpers.create( - "-n", "myenv", package_to_check_requirements(), "-vv", "--json", no_dry_run=True - ) + with pytest.raises(subprocess.CalledProcessError): + helpers.create( + "-n", "myenv", package_to_check_requirements(), "-vv", "--json", no_dry_run=True + ) def test_first_writable_extracted_dir_corrupted( self, tmp_home, tmp_root_prefix, tmp_cache, tmp_cache_alt