def test_file_access_options(tmpdir):
    """
    Standard file access options are available, and work as expected.
    """
    storage = FileSystemStorage(location=str(tmpdir))

    assert not storage.exists("storage_test")

    f = storage.open("storage_test", "w")
    f.write("storage contents")
    f.close()

    assert storage.exists("storage_test")

    f = storage.open("storage_test", "r")
    assert f.read() == "storage contents"
    f.close()

    storage.delete("storage_test")
    assert not storage.exists("storage_test")
def test_remove_race_handling(tmpdir, monkeypatch):
    """
    File storage should be robust against file removal race conditions.
    """
    real_remove = os.remove

    # Monkey-patch os.remove, to simulate a normal call, a raced call,
    # and an error.
    def fake_remove(path):
        if path == os.path.join(str(tmpdir), "normal.file"):
            real_remove(path)
        elif path == os.path.join(str(tmpdir), "raced.file"):
            real_remove(path)
            raise OSError(errno.ENOENT, "simulated ENOENT")
        elif path == os.path.join(str(tmpdir), "error.file"):
            raise OSError(errno.EACCES, "simulated EACCES")
        else:
            pytest.fail("unexpected argument %r" % path)

    monkeypatch.setattr(os, "remove", fake_remove)

    storage = FileSystemStorage(location=str(tmpdir))

    storage.save("normal.file", io.StringIO("delete normally"))
    storage.delete("normal.file")

    assert not storage.exists("normal.file")

    storage.save("raced.file", io.StringIO("delete with race"))
    storage.delete("raced.file")

    assert not storage.exists("normal.file")

    # Check that OSErrors aside from ENOENT are still raised.
    storage.save("error.file", io.StringIO("delete with error"))

    with pytest.raises(OSError):
        storage.delete("error.file")