diff --git a/flake.nix b/flake.nix index fa3d8d9..8d11c1d 100644 --- a/flake.nix +++ b/flake.nix @@ -34,15 +34,15 @@ devenv.shells.default = { languages.erlang.enable = true; - packages = [ kamid ]; - - env.ERL_FLAGS = '' - -kernel logger_level debug - -kernel logger '[ - {filters, log, [{no_progress, {fun logger_filters:progress/2, stop}}]} - ]' - -kernel shell_history enabled - ''; + packages = [ kamid pkgs._9pfs ]; + + # env.ERL_FLAGS = '' + # -kernel logger_level debug + # -kernel logger '[ + # {filters, log, [{no_progress, {fun logger_filters:progress/2, stop}}]} + # ]' + # -kernel shell_history enabled + # ''; }; }; }; diff --git a/rebar.config b/rebar.config index 1c06c6e..77bf8d3 100644 --- a/rebar.config +++ b/rebar.config @@ -9,10 +9,13 @@ {project_plugins, [ rebar3_ex_doc, - rebar3_proper + rebar3_proper, + covertool ]}. {profiles, [{test, [ {deps, [proper]}, {erl_opts, [nowarn_export_all]} ]}]}. + +{ct_opts, [{create_priv_dir, auto_per_run}]}. diff --git a/src/e9p_server.erl b/src/e9p_server.erl index 311fa41..7df0aff 100644 --- a/src/e9p_server.erl +++ b/src/e9p_server.erl @@ -8,8 +8,10 @@ -include_lib("kernel/include/logger.hrl"). --export([start_link/2, - setup_acceptor/3, +-export([start/2, + start_link/2]). + +-export([setup_acceptor/3, accept_loop/2, loop/1 ]). @@ -22,6 +24,9 @@ handler }). +start(Port, Handler) -> + proc_lib:start(?MODULE, setup_acceptor, [self(), Port, Handler]). + start_link(Port, Handler) -> proc_lib:start_link(?MODULE, setup_acceptor, [self(), Port, Handler]). diff --git a/test/e9p_sysfs_SUITE.erl b/test/e9p_sysfs_SUITE.erl new file mode 100644 index 0000000..9272c76 --- /dev/null +++ b/test/e9p_sysfs_SUITE.erl @@ -0,0 +1,146 @@ +% SPDX-FileCopyrightText: 2026 Ɓukasz Niemier <~@hauleth.dev> +% +% SPDX-License-Identifier: Apache-2.0 + +-module(e9p_sysfs_SUITE). + +-compile(export_all). + +-include_lib("stdlib/include/assert.hrl"). +-include_lib("common_test/include/ct.hrl"). + +all() -> [ + can_list_mount_content, + current_process_is_listed, + current_process_current_function, + system_info_atom_count, + applications_list, + application_info, + application_env + ]. + +init_per_suite(Config) -> + PrivDir = ?config(priv_dir, Config), + Path = filename:join(PrivDir, "sysfs"), + Port = 19999, + ok = file:make_dir(Path), + {ok, PID} = e9p_server:start(Port, {e9p_sysfs, []}), + ct:pal(Path), + ct:sleep(1000), + Cmd = io_lib:format("9pfs -p ~B localhost ~s", + [Port, Path]), + ct:pal(Cmd), + _Out = os:cmd(Cmd, #{ exception_on_failure => true }), + [{sysfs, PID}, {mount, Path} | Config]. + +end_per_suite(Config) -> + PID = ?config(sysfs, Config), + Mount = ?config(mount, Config), + os:cmd(["umount ", Mount], #{exception_on_failure => true}), + erlang:exit(PID, normal), + Config. + +can_list_mount_content(Config) -> + Mount = ?config(mount, Config), + ct:pal(Mount), + ?assertEqual([ + "applications", + "processes", + "system_info" + ], ls(Mount)). + +current_process_is_listed(Config) -> + Mount = ?config(mount, Config), + Path = filename:join([Mount, "processes", pid_to_list(self())]), + ?assertEqual([ + "current_function", + "dictionary", + "error_handler", + "garbage_collection", + "group_leader", + "heap_size", + "initial_call", + "links", + "message_queue_len", + "priority", + "reductions", + "stack_size", + "status", + "total_heap_size", + "trap_exit" + ], ls(Path)). + +current_process_current_function(Config) -> + Mount = ?config(mount, Config), + Path = filename:join([ + Mount, + "processes", + pid_to_list(self()), + "current_function" + ]), + {ok, Bin} = file:read_file(Path), + ?assertEqual(~"{gen,do_call,4}", Bin). + +system_info_atom_count(Config) -> + Mount = ?config(mount, Config), + Path = filename:join([ + Mount, + "system_info", + "atom_count" + ]), + {ok, Bin} = file:read_file(Path), + ?assertEqual(erlang:system_info(atom_count), binary_to_integer(Bin)). + +applications_list(Config) -> + Mount = ?config(mount, Config), + Path = filename:join([ + Mount, + "applications" + ]), + List = ls(Path), + Apps = lists:sort(lists:map(fun({AppName, _, _}) -> atom_to_list(AppName) end, + application:loaded_applications())), + ?assertEqual(Apps, List). + +application_info(Config) -> + Mount = ?config(mount, Config), + Path = filename:join([ + Mount, + "applications", + "kernel" + ]), + List = ls(Path), + ?assertEqual([ + "applications", + "description", + "env", + "id", + "included_applications", + "maxP", + "maxT", + "mod", + "modules", + "optional_applications", + "registered", + "start_phases", + "vsn" + ], List). + +application_env(Config) -> + Mount = ?config(mount, Config), + Path = filename:join([ + Mount, + "applications", + "kernel", + "env" + ]), + {ok, [Read]} = file:consult(Path), + Env = application:get_all_env(kernel), + ?assertEqual(Read, Env). + +%% Helpers + +ls(Path) -> + {ok, Files} = file:list_dir(Path), + % Remove `.fscache` added on macOS + lists:sort(Files) -- [".fscache"].