|
2 | 2 | import tempfile |
3 | 3 |
|
4 | 4 | from ...platform import acl_get, acl_set |
| 5 | +from ...platform import fdatasync, sync_dir |
5 | 6 | from .platform_test import skipif_not_darwin, skipif_fakeroot_detected, skipif_acls_not_working |
6 | 7 |
|
7 | 8 | # Set module-level skips |
@@ -46,3 +47,65 @@ def test_extended_acl(): |
46 | 47 | b"group:ABCDEFAB-CDEF-ABCD-EFAB-CDEF00000000::0:allow:read" |
47 | 48 | in get_acl(file2.name, numeric_ids=True)["acl_extended"] |
48 | 49 | ) |
| 50 | + |
| 51 | + |
| 52 | +def test_fdatasync_uses_f_fullfsync(monkeypatch): |
| 53 | + """Verify fcntl F_FULLFSYNC is called.""" |
| 54 | + import fcntl as fcntl_mod |
| 55 | + from ...platform import darwin |
| 56 | + |
| 57 | + calls = [] |
| 58 | + original_fcntl = fcntl_mod.fcntl |
| 59 | + |
| 60 | + def mock_fcntl(fd, cmd, *args): |
| 61 | + calls.append((fd, cmd)) |
| 62 | + return original_fcntl(fd, cmd, *args) |
| 63 | + |
| 64 | + monkeypatch.setattr(fcntl_mod, "fcntl", mock_fcntl) |
| 65 | + |
| 66 | + with tempfile.NamedTemporaryFile() as tmp: |
| 67 | + tmp.write(b"test data") |
| 68 | + tmp.flush() |
| 69 | + darwin.fdatasync(tmp.fileno()) |
| 70 | + |
| 71 | + assert any(cmd == fcntl_mod.F_FULLFSYNC for _, cmd in calls), "fdatasync should call fcntl with F_FULLFSYNC" |
| 72 | + |
| 73 | + |
| 74 | +def test_fdatasync_falls_back_to_fsync(monkeypatch): |
| 75 | + """Verify os.fsync fallback when F_FULLFSYNC fails.""" |
| 76 | + import fcntl as fcntl_mod |
| 77 | + from ...platform import darwin |
| 78 | + |
| 79 | + fsync_calls = [] |
| 80 | + |
| 81 | + def mock_fcntl(fd, cmd, *args): |
| 82 | + if cmd == fcntl_mod.F_FULLFSYNC: |
| 83 | + raise OSError("F_FULLFSYNC not supported") |
| 84 | + return 0 |
| 85 | + |
| 86 | + def mock_fsync(fd): |
| 87 | + fsync_calls.append(fd) |
| 88 | + |
| 89 | + monkeypatch.setattr(fcntl_mod, "fcntl", mock_fcntl) |
| 90 | + monkeypatch.setattr(os, "fsync", mock_fsync) |
| 91 | + |
| 92 | + with tempfile.NamedTemporaryFile() as tmp: |
| 93 | + tmp.write(b"test data") |
| 94 | + tmp.flush() |
| 95 | + darwin.fdatasync(tmp.fileno()) |
| 96 | + |
| 97 | + assert len(fsync_calls) == 1, "Should fall back to os.fsync when F_FULLFSYNC fails" |
| 98 | + |
| 99 | + |
| 100 | +def test_fdatasync_basic(): |
| 101 | + """Integration: fdatasync completes on a real file without error.""" |
| 102 | + with tempfile.NamedTemporaryFile() as tmp: |
| 103 | + tmp.write(b"test data for fdatasync") |
| 104 | + tmp.flush() |
| 105 | + fdatasync(tmp.fileno()) |
| 106 | + |
| 107 | + |
| 108 | +def test_sync_dir_basic(): |
| 109 | + """Integration: sync_dir completes on a real directory without error.""" |
| 110 | + with tempfile.TemporaryDirectory() as tmpdir: |
| 111 | + sync_dir(tmpdir) |
0 commit comments