blob: 45cbe66ac1bf445c9c58b146f471a8a43588e221 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/bringup/bin/virtcon/session-manager.h"
#include <fuchsia/hardware/pty/llcpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <memory>
#include <zxtest/zxtest.h>
#include "src/bringup/bin/virtcon/vc.h"
// These are necessary because vc-device.cc calls these functions and they need to be
// mocked out for testing. Ideally these files can be refactored to follow C++ patterns.
bool is_primary_bound() { return false; }
bool g_vc_owns_display = false;
void vc_gfx_invalidate_status(vc_gfx_t* gfx) {}
void vc_gfx_invalidate_all(vc_gfx_t* gfx, vc_t* vc) {}
void vc_gfx_invalidate(vc_gfx_t* gfx, vc_t* vc, unsigned x, unsigned y, unsigned w, unsigned h) {}
void vc_gfx_draw_char(vc_gfx_t* gfx, vc_t* vc, vc_char_t ch, unsigned x, unsigned y, bool invert) {}
void vc_attach_to_main_display(vc_t* vc) {}
void vc_toggle_framebuffer() {}
TEST(VirtconSessionManager, LifeTimeTest) {
async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
virtcon::SessionManager sessions(loop.dispatcher(), false, &color_schemes[kDefaultColorScheme]);
auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
ASSERT_EQ(ZX_OK, endpoints.status_value());
auto [local, remote] = *std::move(endpoints);
ASSERT_EQ(ZX_OK, sessions.CreateSession(std::move(remote)).status_value());
loop.Shutdown();
}
TEST(VirtconSessionManager, TestWriting) {
async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
virtcon::SessionManager sessions(loop.dispatcher(), false, &color_schemes[kDefaultColorScheme]);
auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
ASSERT_EQ(ZX_OK, endpoints.status_value());
auto [local, remote] = *std::move(endpoints);
vc_t* session = nullptr;
{
auto response = sessions.CreateSession(std::move(remote));
ASSERT_EQ(ZX_OK, response.status_value());
session = std::move(response.value());
}
auto pty = fidl::Client(std::move(local), loop.dispatcher());
char output[] = "Testing!";
auto result = pty->Write_Sync(
fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(output), sizeof(output)));
ASSERT_EQ(result.status(), ZX_OK);
ASSERT_EQ(result->s, ZX_OK);
ASSERT_EQ(result->actual, sizeof(output));
loop.RunUntilIdle();
// Check characters up to -1 since text_buf isn't null terminated.
for (size_t i = 0; i < sizeof(output) - 1; i++) {
ASSERT_EQ(vc_char_get_char(session->text_buf[i]), output[i], "index %ld : %c != %c", i,
vc_char_get_char(session->text_buf[i]), output[i]);
}
loop.Shutdown();
}
TEST(VirtconSessionManager, TestWritingMultipleClients) {
async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
virtcon::SessionManager sessions(loop.dispatcher(), false, &color_schemes[kDefaultColorScheme]);
auto endpoints1 = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
ASSERT_EQ(ZX_OK, endpoints1.status_value());
auto [local1, remote1] = *std::move(endpoints1);
vc_t* session_one = nullptr;
{
auto response = sessions.CreateSession(std::move(remote1));
ASSERT_EQ(ZX_OK, response.status_value());
session_one = std::move(response.value());
}
auto pty_one = fidl::Client(std::move(local1), loop.dispatcher());
auto endpoints2 = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
ASSERT_EQ(ZX_OK, endpoints2.status_value());
auto [local2, remote2] = *std::move(endpoints2);
vc_t* session_two = nullptr;
{
auto response = sessions.CreateSession(std::move(remote2));
ASSERT_EQ(ZX_OK, response.status_value());
session_two = std::move(response.value());
}
auto pty_two = fidl::Client(std::move(local2), loop.dispatcher());
// Write pty_one.
char output_one[] = "Testing One!";
{
auto result = pty_one->Write_Sync(fidl::VectorView<uint8_t>::FromExternal(
reinterpret_cast<uint8_t*>(output_one), sizeof(output_one)));
ASSERT_EQ(result.status(), ZX_OK);
ASSERT_EQ(result->s, ZX_OK);
ASSERT_EQ(result->actual, sizeof(output_one));
}
// Write pty_two.
char output_two[] = "Testing One!";
{
auto result = pty_two->Write_Sync(fidl::VectorView<uint8_t>::FromExternal(
reinterpret_cast<uint8_t*>(output_two), sizeof(output_two)));
ASSERT_EQ(result.status(), ZX_OK);
ASSERT_EQ(result->s, ZX_OK);
ASSERT_EQ(result->actual, sizeof(output_two));
}
loop.RunUntilIdle();
// Check output_one.
// Check characters up to -1 since text_buf isn't null terminated.
for (size_t i = 0; i < sizeof(output_one) - 1; i++) {
ASSERT_EQ(vc_char_get_char(session_one->text_buf[i]), output_one[i], "index %ld : %c != %c", i,
vc_char_get_char(session_one->text_buf[i]), output_one[i]);
}
// Check output_two.
// Check characters up to -1 since text_buf isn't null terminated.
for (size_t i = 0; i < sizeof(output_two) - 1; i++) {
ASSERT_EQ(vc_char_get_char(session_two->text_buf[i]), output_two[i], "index %ld : %c != %c", i,
vc_char_get_char(session_two->text_buf[i]), output_two[i]);
}
loop.Shutdown();
}
// Test that the log stays active with keep-log-visible.
TEST(VirtconSessionManager, KeepLogVisibleSessionStaysActive) {
async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
zx::debuglog fake_log;
ASSERT_EQ(log_start(loop.dispatcher(), std::move(fake_log), &color_schemes[kDefaultColorScheme]),
0);
virtcon::SessionManager sessions(loop.dispatcher(), true, &color_schemes[kDefaultColorScheme]);
// Create the first session and check that it's not active.
auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
ASSERT_EQ(ZX_OK, endpoints.status_value());
auto [local_one, remote] = *std::move(endpoints);
vc_t* vc_one;
{
auto result = sessions.CreateSession(std::move(remote));
ASSERT_TRUE(result.is_ok());
vc_one = std::move(result.value());
}
ASSERT_TRUE(g_log_vc->active);
ASSERT_FALSE(vc_one->active);
log_delete_vc(g_log_vc);
loop.Shutdown();
}
// Test that when we aren't keeping the log visible that the second session we create becomes
// the active one.
TEST(VirtconSessionManager, DontKeepLogVisibleSessionActivity) {
async::Loop loop = async::Loop(&kAsyncLoopConfigNeverAttachToThread);
zx::debuglog fake_log;
ASSERT_EQ(log_start(loop.dispatcher(), std::move(fake_log), &color_schemes[kDefaultColorScheme]),
0);
virtcon::SessionManager sessions(loop.dispatcher(), false, &color_schemes[kDefaultColorScheme]);
// Create the first session and check that it's active.
auto endpoints_one = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
ASSERT_EQ(ZX_OK, endpoints_one.status_value());
auto [local_one, remote_one] = *std::move(endpoints_one);
vc_t* vc_one;
{
auto result = sessions.CreateSession(std::move(remote_one));
ASSERT_TRUE(result.is_ok());
vc_one = std::move(result.value());
}
ASSERT_FALSE(g_log_vc->active);
ASSERT_TRUE(vc_one->active);
// Create the second session and check that it's not active.
auto endpoints_two = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
ASSERT_EQ(ZX_OK, endpoints_two.status_value());
auto [local_two, remote_two] = *std::move(endpoints_two);
vc_t* vc_two;
{
auto result = sessions.CreateSession(std::move(remote_two));
ASSERT_TRUE(result.is_ok());
vc_two = std::move(result.value());
}
ASSERT_FALSE(g_log_vc->active);
ASSERT_TRUE(vc_one->active);
ASSERT_FALSE(vc_two->active);
log_delete_vc(g_log_vc);
loop.Shutdown();
}