Add Libssh mockable singleton (MP_LIBSSH) and route all libssh calls through it#4978
Add Libssh mockable singleton (MP_LIBSSH) and route all libssh calls through it#4978Copilot wants to merge 7 commits into
Conversation
|
@copilot I want you to also re-route the libssh calls in unique_ptr deleters. Add the changes in a separate commit. |
Done in a separate commit. All libssh/libsftp functions used as
The |
|
@copilot The new singleton is not compiling because the code is not being compiled with the WITH_SERVER flag. I would like you to, within the src/ssh/CMakeLists.txt, to create a base libssh target (choose a different name) that is imported by all ssh_target, sftp_client and sftp_server in src/sshfs_mount/CMakeLists.txt. This libssh target needs to have the macro definition and access libssh code. Re-organize the CMake targets to accomplish this while doing the minimal changes possible. |
Done in 7d53a93. I extracted
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4978 +/- ##
==========================================
+ Coverage 87.77% 87.83% +0.06%
==========================================
Files 273 274 +1
Lines 14682 14902 +220
==========================================
+ Hits 12886 13087 +201
- Misses 1796 1815 +19 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@copilot, now rebase the PR. Keep the changes from main while applying the changes to the libssh calls that you made. |
Done in f71fad0. The branch now incorporates the latest Note on mechanics: this environment can only push fast-forward updates (no force-push), so I integrated Key conflict resolutions (main heavily refactored the SSH layer in the meantime):
I verified the merged tree is byte-identical to a clean rebase of the four commits onto current |
|
@copilot I want you to remove the functions that are currently unused in the singleton. Remove them from the mocks as well. |
I checked every method in the singleton against the production sources and they all currently have at least one caller — so I want to confirm scope before removing anything, since dropping a used method would break the build. Breakdown of the 93 methods:
If your tooling flagged that second group as unused, that's the macro indirection hiding the references rather than them actually being dead. Could you point me at the specific functions you're seeing as unused (or a list)? I'll remove exactly those from both the singleton and |
There was a problem hiding this comment.
Pull request overview
This PR introduces a mockable multipass::Libssh singleton (MP_LIBSSH) that centralizes all libssh/libsftp entry points behind a virtual interface, and reroutes SSH/SFTP call sites (including smart-pointer deleters) to use it so unit tests can mock libssh usage.
Changes:
- Add
multipass::Libsshwrapper +MP_LIBSSHaccessor and route all libssh/libsftp calls through it (includingunique_ptrdeleters andthrow_on_errorcall sites). - Update build targets so SSH/SFTP components link against a shared
libssh_wrapper(and_testvariant). - Add a gmock-based
MockLibsshand a small smoke-test suite validating the wrapper against the real libssh.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
include/multipass/ssh/libssh.h |
Declares the mockable Libssh singleton interface (MP_LIBSSH) with 1:1 virtual methods for libssh/libsftp. |
src/ssh/libssh.cpp |
Implements Libssh by forwarding each virtual method to the corresponding ::ssh_* / ::sftp_* symbol (plus sftp_reply_version). |
src/ssh/CMakeLists.txt |
Introduces libssh_wrapper / libssh_wrapper_test and links SSH/SFTP targets against the wrapper. |
src/ssh/libssh_scope_guard.cpp |
Routes init/finalize through MP_LIBSSH. |
include/multipass/ssh/throw_on_error.h |
Uses MP_LIBSSH.ssh_get_error() so error retrieval can be mocked. |
include/multipass/ssh/sftp_utils.h |
Updates MP_SFTP_UNIQUE_PTR to allocate and delete via MP_LIBSSH; adds raw-deleter variant for free. |
src/ssh/plain_ssh_session.cpp |
Reroutes session lifecycle and option/auth/connect calls through MP_LIBSSH. |
src/ssh/plain_ssh_process.cpp |
Reroutes channel/event/callback calls through MP_LIBSSH (macro init exception documented). |
src/ssh/ssh_client.cpp |
Reroutes channel/event/connector and exec/shell operations through MP_LIBSSH. |
src/ssh/ssh_client_key_provider.cpp |
Reroutes key import/free through MP_LIBSSH. |
src/ssh/openssh_key_provider.cpp |
Reroutes key generation/import/export/free through MP_LIBSSH. |
src/ssh/sftp_client.cpp |
Reroutes SFTP init and read/write/stat/mkdir/etc through MP_LIBSSH. |
src/ssh/sftp_dir_iterator.cpp |
Reroutes eof/error handling calls through MP_LIBSSH. |
src/ssh/sftp_utils.cpp |
Reroutes mkdir and error retrieval calls through MP_LIBSSH. |
src/sshfs_mount/sftp_server.h |
Adjusts unique_ptr deleter type to support routing server session teardown via singleton. |
src/sshfs_mount/sftp_server.cpp |
Reroutes all server-side sftp/libssh calls through MP_LIBSSH, including message lifecycle and handle management. |
src/sshfs_mount/CMakeLists.txt |
Links sshfs_mount targets against the appropriate wrapper library. |
src/platform/console/windows_console.cpp |
Reroutes channel/session socket and IO operations through MP_LIBSSH. |
src/platform/console/unix_console.cpp |
Reroutes PTY sizing operations through MP_LIBSSH. |
src/platform/backends/hyperv/hyperv_virtual_machine.cpp |
Reroutes ssh_get_fd() access through MP_LIBSSH. |
tests/unit/mock_libssh.h |
Adds gmock MockLibssh matching the wrapper interface. |
tests/unit/test_libssh.cpp |
Adds smoke tests calling real libssh via MP_LIBSSH. |
tests/unit/CMakeLists.txt |
Adds the new test and applies premock compile defines to libssh_wrapper_test. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
f830cf5 to
aa85de1
Compare
aa85de1 to
32a53a7
Compare
66c2fcd to
38ce442
Compare
38ce442 to
d0ab56e
Compare
d0ab56e to
f48eb1e
Compare
Description
Introduces a thin, mockable wrapper around libssh —
multipass::Libssh(accessed viaMP_LIBSSH) — modelled onMP_UTILS/MP_FILEOPS/MP_PLATFORM, so SSH/SFTP code paths become unit-testable without a real libssh. Every libssh/libsftp call site insrc/andinclude/(includingunique_ptrdeleters) is rerouted through the singleton.include/multipass/ssh/libssh.hdeclares one virtual per wrapped libssh entry point;src/ssh/libssh.cppforwards 1:1 to::ssh_xxx/::sftp_xxx. Non-coverage:ssh_callbacks_init(a header-only init macro, not a library call).libssh.cppis built once into dedicated base targetslibssh_wrapper/libssh_wrapper_test(compiled withWITH_SERVER, required by thesftp_server_*family).ssh_common,sftp_client,ssh_client, andsshfs_mount(plus their*_testvariants) link the wrapper. The*_testvariant additionally getsc_mock_definesso existing PREMOCK tests keep intercepting calls now routed through the singleton.MP_LIBSSH.throw_on_errorsites that previously took a libssh function pointer now take a small lambda calling the singleton.unique_ptrdeleter rerouting — raw function-pointer deleters (ssh_free,ssh_channel_free,ssh_event_free,ssh_connector_free,sftp_server_free,sftp_client_message_free,ssh_string_free) become non-capturing lambdas that forward to the singleton and decay to the existingvoid (*)(...)deleter types, so public type aliases are unchanged.MP_SFTP_UNIQUE_PTRroutes its deleter throughMP_LIBSSHwhile preserving itsstd::functiondeleter type so the returned smart pointers stay interchangeable with the public aliases (SFTPDirUPtr,SFTPAttributesUPtr, …); the lone non-libssh deleter (free, used bysftp_readlink) is kept raw via a newMP_SFTP_UNIQUE_PTR_RAW.tests/unit/mock_libssh.h: header-onlyMockLibssh : public Libsshwith oneMOCK_METHODper virtual, closed withMP_MOCK_SINGLETON_BOILERPLATE. Matches theMockFileOps/MockUtilsshape.tests/unit/test_libssh.cppexercises real libssh throughMP_LIBSSHto validate the wrapper's basic assumptions:ssh_init/ssh_finalizesucceed,ssh_event_new/ssh_event_freeround-trip, and an RSA key can be generated, exported to base64, and freed. Only entry points outsidec_mock_defines.cmakeare used, so calls reach the real library rather than premock shims.Out of scope: existing PREMOCK shims (
mock_ssh.h,mock_sftp.h,mock_sftpserver.h) and their tests are untouched; migrating them ontoMockLibsshis the follow-up step.Example pattern at a call site:
Example pattern at a deleter:
Testing
libssh_wrapper_testcarriesc_mock_definesso PREMOCK keeps working). Newtest_libssh.cppadds three smoke tests against real libssh throughMP_LIBSSH.libssh.cppis built intolibssh_wrapperand linked byssh_common/sftp_client/ssh_client/sshfs_mount.grepconfirms no remaining directssh_*/sftp_*library calls (including deleters) insrc/orinclude/outsidesrc/ssh/libssh.cppand the documented exceptions.MP_SFTP_UNIQUE_PTRpreserving thestd::functiondeleter type sounique_ptr::swapstill compiles).libssh.cppfails to compile withoutWITH_SERVER(onsftp_server_*) and compiles with it.test_libssh.cppagainst the system libssh via an equivalent standalone program.Screenshots (if applicable)
Checklist
Additional Notes
Step 4 (migrate PREMOCK-based SSH/SFTP tests to
MockLibssh) is intentionally deferred — flagging it here so reviewers know the new mock is added but not yet adopted. A separate reviewer request to prune "unused" singleton methods was investigated and a clarification was posted on the thread: all 93 methods are currently referenced (82 directly viaMP_LIBSSH.<name>(...), the remaining 11 reached only throughMP_SFTP_UNIQUE_PTR/MP_SFTP_UNIQUE_PTR_RAWmacros), plus a few methods used exclusively fromwindows_console.cpp— awaiting the reviewer's specific list before removing anything.