libfuse/test/test_custom_io.py
Tofik Sonono 50c74e6459
Support application-defined I/O functions for FUSE fd
The io for FUSE requests and responses can now be further customized by allowing to write custom functions for reading/writing the responses. This includes overriding the splice io.

The reason for this addition is that having a custom file descriptor is not sufficient to allow custom io. Different types of file descriptor require different mechanisms of io interaction. For example, some file descriptor communication has boundaries (SOCK_DGRAM, EOF, etc...), while other types of fd:s might be unbounded (SOCK_STREAMS, ...). For unbounded communication, you have to read the header of the FUSE request first, and then read the remaining packet data. Furthermore, the one read call does not necessarily return all the data expected, requiring further
calls in a loop.
2023-01-10 10:04:35 +00:00

82 lines
2.1 KiB
Python

#!/usr/bin/env python3
if __name__ == '__main__':
import sys
import pytest
sys.exit(pytest.main([__file__] + sys.argv[1:]))
import os
import socket
import struct
import subprocess
import sys
import time
from os.path import join as pjoin
import pytest
from util import base_cmdline, basename
FUSE_OP_INIT = 26
FUSE_MAJOR_VERSION = 7
FUSE_MINOR_VERSION = 38
fuse_in_header_fmt = '<IIQQIIII'
fuse_out_header_fmt = '<IiQ'
fuse_init_in_fmt = '<IIIII44x'
fuse_init_out_fmt = '<IIIIHHIIHHI28x'
def sock_recvall(sock: socket.socket, bufsize: int) -> bytes:
buf = bytes()
while len(buf) < bufsize:
buf += sock.recv(bufsize - len(buf))
return buf
def tst_init(sock: socket.socket):
unique_req = 10
dummy_init_req_header = struct.pack(
fuse_in_header_fmt, struct.calcsize(fuse_in_header_fmt) +
struct.calcsize(fuse_init_in_fmt), FUSE_OP_INIT, unique_req, 0, 0, 0,
0, 0)
dummy_init_req_payload = struct.pack(
fuse_init_in_fmt, FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION, 0, 0, 0)
dummy_init_req = dummy_init_req_header + dummy_init_req_payload
sock.sendall(dummy_init_req)
response_header = sock_recvall(sock, struct.calcsize(fuse_out_header_fmt))
packet_len, _, unique_res = struct.unpack(
fuse_out_header_fmt, response_header)
assert unique_res == unique_req
response_payload = sock_recvall(sock, packet_len - len(response_header))
response_payload = struct.unpack(fuse_init_out_fmt, response_payload)
assert response_payload[0] == FUSE_MAJOR_VERSION
def test_hello_uds(output_checker):
cmdline = base_cmdline + [pjoin(basename, 'example', 'hello_ll_uds')]
print(cmdline)
uds_process = subprocess.Popen(cmdline, stdout=output_checker.fd,
stderr=output_checker.fd)
time.sleep(1)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.settimeout(1)
sock.connect("/tmp/libfuse-hello-ll.sock")
tst_init(sock)
sock.close()
uds_process.terminate()
try:
uds_process.wait(1)
except subprocess.TimeoutExpired:
uds_process.kill()
os.remove("/tmp/libfuse-hello-ll.sock")