Skip to content

Commit

Permalink
Merge pull request #3826 from canonical/fix-console-creation-logic
Browse files Browse the repository at this point in the history
Fix console creation
  • Loading branch information
sharder996 authored Dec 17, 2024
2 parents 1f46465 + 5d97600 commit da34898
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 31 deletions.
3 changes: 0 additions & 3 deletions include/multipass/console.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@

namespace multipass
{
class Terminal;

class Console : private DisabledCopyMove
{
public:
Expand All @@ -47,7 +45,6 @@ class Console : private DisabledCopyMove
virtual void write_console() = 0;
virtual void exit_console() = 0;

static UPtr make_console(ssh_channel channel, Terminal* term);
static void setup_environment();

protected:
Expand Down
6 changes: 6 additions & 0 deletions include/multipass/terminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
#define MULTIPASS_TERMINAL_H

#include <istream>
#include <libssh/libssh.h>
#include <memory>
#include <ostream>
#include <string>

namespace multipass
{
class Console;

class Terminal
{
public:
Expand All @@ -44,6 +47,9 @@ class Terminal

using UPtr = std::unique_ptr<Terminal>;
static UPtr make_terminal();

using ConsolePtr = std::unique_ptr<Console>;
virtual ConsolePtr make_console(ssh_channel channel) = 0;
};
} // namespace multipass

Expand Down
2 changes: 1 addition & 1 deletion src/client/cli/cmd/exec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ mp::ReturnCode cmd::Exec::exec_success(const mp::SSHInfoReply& reply, const std:

try
{
auto console_creator = [&term](auto channel) { return Console::make_console(channel, term); };
auto console_creator = [&term](auto channel) { return term->make_console(channel); };
mp::SSHClient ssh_client{host, port, username, priv_key_blob, console_creator};

std::vector<std::vector<std::string>> all_args;
Expand Down
2 changes: 1 addition & 1 deletion src/client/cli/cmd/shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ mp::ReturnCode cmd::Shell::run(mp::ArgParser* parser)

try
{
auto console_creator = [this](auto channel) { return Console::make_console(channel, term); };
auto console_creator = [this](auto channel) { return term->make_console(channel); };
mp::SSHClient ssh_client{host, port, username, priv_key_blob, console_creator};
ssh_client.connect();
}
Expand Down
5 changes: 0 additions & 5 deletions src/platform/console/console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@

namespace mp = multipass;

mp::Console::UPtr mp::Console::make_console(ssh_channel channel, Terminal* term)
{
return std::make_unique<UnixConsole>(channel, static_cast<UnixTerminal*>(term));
}

void mp::Console::setup_environment()
{
UnixConsole::setup_environment();
Expand Down
7 changes: 7 additions & 0 deletions src/platform/console/unix_terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <termios.h>
#include <unistd.h>

#include "unix_console.h"

namespace mp = multipass;

int mp::UnixTerminal::cin_fd() const
Expand Down Expand Up @@ -56,3 +58,8 @@ void mp::UnixTerminal::set_cin_echo(const bool enable)

tcsetattr(cin_fd(), TCSANOW, &tty);
}

mp::UnixTerminal::ConsolePtr mp::UnixTerminal::make_console(ssh_channel channel)
{
return std::make_unique<UnixConsole>(channel, this);
}
2 changes: 2 additions & 0 deletions src/platform/console/unix_terminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class UnixTerminal : public Terminal
bool cout_is_live() const override;

void set_cin_echo(const bool enable) override;

ConsolePtr make_console(ssh_channel channel) override;
};
} // namespace multipass

Expand Down
1 change: 1 addition & 0 deletions tests/mock_terminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct MockTerminal : public Terminal
MOCK_METHOD(bool, cin_is_live, (), (const, override));
MOCK_METHOD(bool, cout_is_live, (), (const, override));
MOCK_METHOD(void, set_cin_echo, (const bool), (override));
MOCK_METHOD(ConsolePtr, make_console, (ssh_channel), (override));
};
} // namespace test
} // namespace multipass
Expand Down
7 changes: 7 additions & 0 deletions tests/stub_terminal.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

#include <multipass/terminal.h>

#include "stub_console.h"

namespace multipass
{
namespace test
Expand Down Expand Up @@ -61,6 +63,11 @@ class StubTerminal : public multipass::Terminal
{
}

ConsolePtr make_console(ssh_channel channel) override
{
return std::make_unique<StubConsole>();
}

private:
std::ostream &cout_stream;
std::ostream& cerr_stream;
Expand Down
65 changes: 44 additions & 21 deletions tests/test_cli_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,29 @@ auto make_info_function(const std::string& source_path = "", const std::string&
return info_function;
}

mp::SSHInfo make_ssh_info(const std::string& host = "222.222.222.222",
int port = 22,
const std::string& priv_key = mpt::fake_key_data,
const std::string& username = "user")
{
mp::SSHInfo ssh_info;

ssh_info.set_host(host);
ssh_info.set_port(port);
ssh_info.set_priv_key_base64(priv_key);
ssh_info.set_username(username);

return ssh_info;
}

mp::SSHInfoReply make_fake_ssh_info_response(const std::string& instance_name)
{
mp::SSHInfoReply response;
(*response.mutable_ssh_info())[instance_name] = make_ssh_info();

return response;
}

typedef std::vector<std::pair<std::string, mp::AliasDefinition>> AliasesVector;

const std::string csv_header{"Alias,Instance,Command,Working directory,Context\n"};
Expand Down Expand Up @@ -743,6 +766,27 @@ TEST_F(Client, shell_cmd_no_args_targets_petenv)
EXPECT_THAT(send_command({"shell"}), Eq(mp::ReturnCode::Ok));
}

TEST_F(Client, shell_cmd_creates_console)
{
EXPECT_CALL(mock_daemon, ssh_info)
.WillOnce([](auto, grpc::ServerReaderWriter<mp::SSHInfoReply, mp::SSHInfoRequest>* server) {
server->Write(make_fake_ssh_info_response("fake-instance"));
return grpc::Status{};
});

std::string error_string = "attempted to create console";
std::stringstream cerr_stream;

mpt::MockTerminal term{};
EXPECT_CALL(term, cin()).WillRepeatedly(ReturnRef(trash_stream));
EXPECT_CALL(term, cout()).WillRepeatedly(ReturnRef(trash_stream));
EXPECT_CALL(term, cerr()).WillRepeatedly(ReturnRef(cerr_stream));
EXPECT_CALL(term, make_console(_)).WillOnce(Throw(std::runtime_error(error_string)));

EXPECT_EQ(setup_client_and_run({"shell"}, term), mp::ReturnCode::CommandFail);
EXPECT_THAT(cerr_stream.str(), HasSubstr(error_string));
}

TEST_F(Client, shell_cmd_considers_configured_petenv)
{
const auto custom_petenv = "jarjar binks";
Expand Down Expand Up @@ -1545,27 +1589,6 @@ TEST_F(Client, exec_cmd_fails_on_other_absent_instance)
Eq(mp::ReturnCode::CommandFail));
}

mp::SSHInfo make_ssh_info(const std::string& host = "222.222.222.222", int port = 22,
const std::string& priv_key = mpt::fake_key_data, const std::string& username = "user")
{
mp::SSHInfo ssh_info;

ssh_info.set_host(host);
ssh_info.set_port(port);
ssh_info.set_priv_key_base64(priv_key);
ssh_info.set_username(username);

return ssh_info;
}

mp::SSHInfoReply make_fake_ssh_info_response(const std::string& instance_name)
{
mp::SSHInfoReply response;
(*response.mutable_ssh_info())[instance_name] = make_ssh_info();

return response;
}

struct SSHClientReturnTest : Client, WithParamInterface<int>
{
};
Expand Down
14 changes: 14 additions & 0 deletions tests/unix/test_unix_terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "mock_libc_functions.h"

#include <src/platform/console/unix_console.h>
#include <src/platform/console/unix_terminal.h>

#include <tuple>
Expand Down Expand Up @@ -110,3 +111,16 @@ TEST_F(TestUnixTerminal, unsetsEchoOnTerminal)

unix_terminal.set_cin_echo(false);
}

TEST_F(TestUnixTerminal, make_console_makes_unix_console)
{
// force is_live() to return false so UnixConsole ctor doesn't break
REPLACE(fileno, [this](auto) { return fake_fd; });
REPLACE(isatty, [this](auto fd) {
EXPECT_EQ(fd, fake_fd);
return 0;
});

auto console = unix_terminal.make_console(nullptr);
EXPECT_NE(dynamic_cast<multipass::UnixConsole*>(console.get()), nullptr);
}

0 comments on commit da34898

Please sign in to comment.