Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

198 lines
6.4 KiB
Python

# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
#
# SPDX-License-Identifier: MIT
"""Tests for hipfile.file.FileHandle."""
# pylint: disable=missing-function-docstring,redefined-outer-name,protected-access
# pylint: disable=import-error # hipfile not installed in lint env; extension faked
import errno
import os
from unittest import mock
import pytest
import hipfile.file
from hipfile.enums import FileHandleType, OpError
from hipfile.error import HipFileException
from hipfile.file import FileHandle
_SUCCESS = (OpError.SUCCESS, 0)
_FAILURE = (OpError.HANDLE_ALREADY_REGISTERED, 0)
_FAKE_FD = 11
_FAKE_HANDLE = 0xF11E
# --- handle_type setter guards --------------------------------------------
def test_handle_type_rejects_non_member():
fh = FileHandle("/tmp/x", os.O_RDONLY)
with pytest.raises(ValueError):
fh.handle_type = 9999
def test_handle_type_rejects_win32():
fh = FileHandle("/tmp/x", os.O_RDONLY)
with pytest.raises(NotImplementedError):
fh.handle_type = FileHandleType.OPAQUE_WIN32
def test_handle_type_rejects_change_while_open():
fh = FileHandle("/tmp/x", os.O_RDONLY)
fh._handle = _FAKE_HANDLE # simulate an open handle
with pytest.raises(RuntimeError):
fh.handle_type = FileHandleType.USERSPACE_FS
# --- open -----------------------------------------------------------------
def test_open_registers_and_stores_handle():
fh = FileHandle("/tmp/x", os.O_RDONLY)
with mock.patch.object(
hipfile.file.os, "open", return_value=_FAKE_FD
), mock.patch.object(
hipfile.file,
"hipFileHandleRegister",
autospec=True,
return_value=(_FAKE_HANDLE, _SUCCESS),
) as register:
fh.open()
assert fh.handle == _FAKE_HANDLE
register.assert_called_once_with(_FAKE_FD, FileHandleType.OPAQUE_FD)
def test_open_closes_fd_when_registration_fails():
fh = FileHandle("/tmp/x", os.O_RDONLY)
with mock.patch.object(
hipfile.file.os, "open", return_value=_FAKE_FD
), mock.patch.object(hipfile.file.os, "close") as os_close, mock.patch.object(
hipfile.file,
"hipFileHandleRegister",
autospec=True,
return_value=(0, _FAILURE),
):
with pytest.raises(HipFileException):
fh.open()
os_close.assert_called_once_with(_FAKE_FD)
assert fh.handle is None
def test_open_raises_when_already_open():
fh = FileHandle("/tmp/x", os.O_RDONLY)
fh._handle = _FAKE_HANDLE
with pytest.raises(RuntimeError):
fh.open()
# --- close ----------------------------------------------------------------
def test_close_deregisters_and_closes():
fh = FileHandle("/tmp/x", os.O_RDONLY)
fh._handle = _FAKE_HANDLE
fh._fd = _FAKE_FD
with mock.patch.object(
hipfile.file, "hipFileHandleDeregister", autospec=True
) as dereg, mock.patch.object(hipfile.file.os, "close") as os_close:
fh.close()
dereg.assert_called_once_with(_FAKE_HANDLE)
os_close.assert_called_once_with(_FAKE_FD)
assert fh.handle is None
assert fh._fd is None
def test_close_on_never_opened_is_noop():
fh = FileHandle("/tmp/x", os.O_RDONLY)
with mock.patch.object(
hipfile.file, "hipFileHandleDeregister", autospec=True
) as dereg, mock.patch.object(hipfile.file.os, "close") as os_close:
fh.close()
dereg.assert_not_called()
os_close.assert_not_called()
def test_close_is_idempotent_after_open():
fh = FileHandle("/tmp/x", os.O_RDONLY)
fh._handle = _FAKE_HANDLE
fh._fd = _FAKE_FD
with mock.patch.object(
hipfile.file, "hipFileHandleDeregister", autospec=True
) as dereg, mock.patch.object(hipfile.file.os, "close") as os_close:
fh.close()
fh.close()
# Cleanup runs exactly once despite the repeated call.
dereg.assert_called_once_with(_FAKE_HANDLE)
os_close.assert_called_once_with(_FAKE_FD)
# --- read / write ---------------------------------------------------------
def _open_handle():
fh = FileHandle("/tmp/x", os.O_RDONLY)
fh._handle = _FAKE_HANDLE
return fh
@pytest.mark.parametrize("method", ["read", "write"])
def test_io_raises_when_not_open(method, fake_buffer):
fh = FileHandle("/tmp/x", os.O_RDONLY)
with pytest.raises(RuntimeError):
getattr(fh, method)(fake_buffer, 64, 0, 0)
@pytest.mark.parametrize("method", ["read", "write"])
def test_io_success_returns_bytecount(method, fake_buffer):
fh = _open_handle()
wrapper = "hipFileRead" if method == "read" else "hipFileWrite"
with mock.patch.object(
hipfile.file, wrapper, autospec=True, return_value=(64, 0)
) as io_call:
result = getattr(fh, method)(fake_buffer, 64, 8, 16)
assert result == 64
io_call.assert_called_once_with(_FAKE_HANDLE, fake_buffer.ptr, 64, 8, 16)
@pytest.mark.parametrize("method", ["read", "write"])
def test_io_system_error_raises_oserror(method, fake_buffer):
fh = _open_handle()
wrapper = "hipFileRead" if method == "read" else "hipFileWrite"
with mock.patch.object(
hipfile.file, wrapper, autospec=True, return_value=(-1, errno.EIO)
):
with pytest.raises(OSError) as excinfo:
getattr(fh, method)(fake_buffer, 64, 0, 0)
assert excinfo.value.errno == errno.EIO
@pytest.mark.parametrize("method", ["read", "write"])
def test_io_hipfile_error_raises_exception(method, fake_buffer):
fh = _open_handle()
wrapper = "hipFileRead" if method == "read" else "hipFileWrite"
# result < -1 encodes a negated hipFileOpError_t with extra_err == 0.
op_err = OpError.INVALID_VALUE
with mock.patch.object(
hipfile.file, wrapper, autospec=True, return_value=(-int(op_err), 0)
):
with pytest.raises(HipFileException) as excinfo:
getattr(fh, method)(fake_buffer, 64, 0, 0)
assert excinfo.value.hipfile_err == op_err
assert excinfo.value.hip_err == 0
@pytest.mark.parametrize("method", ["read", "write"])
def test_io_hip_driver_error_carries_hip_err(method, fake_buffer):
fh = _open_handle()
wrapper = "hipFileRead" if method == "read" else "hipFileWrite"
op_err = OpError.HIP_DRIVER_ERROR
with mock.patch.object(
hipfile.file, wrapper, autospec=True, return_value=(-int(op_err), 99)
):
with pytest.raises(HipFileException) as excinfo:
getattr(fh, method)(fake_buffer, 64, 0, 0)
assert excinfo.value.hipfile_err == op_err
assert excinfo.value.hip_err == 99