blob: ea1b8855fef51177c4346406c84ef8e75f7218a4 [file] [log] [blame]
// Copyright 2018 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include <src/lib/fxl/logging.h>
#include <src/lib/fxl/strings/string_printf.h>
#include <string.h>
#include <virtio/balloon.h>
#include "guest_test.h"
#include "logger.h"
#include "src/lib/fxl/test/test_settings.h"
using ::testing::HasSubstr;
static constexpr char kVirtioRngUtil[] = "virtio_rng_test_util";
static constexpr size_t kVirtioConsoleMessageCount = 100;
static constexpr size_t kVirtioBalloonPageCount = 256;
class SingleCpuZirconEnclosedGuest : public ZirconEnclosedGuest {
zx_status_t LaunchInfo(
fuchsia::virtualization::LaunchInfo* launch_info) override {
launch_info->url = kZirconGuestUrl;
launch_info->args.push_back("--virtio-gpu=false");
launch_info->args.push_back("--cpus=1");
launch_info->args.push_back("--cmdline-add=kernel.serial=none");
return ZX_OK;
}
};
class SingleCpuDebianEnclosedGuest : public DebianEnclosedGuest {
zx_status_t LaunchInfo(
fuchsia::virtualization::LaunchInfo* launch_info) override {
launch_info->url = kDebianGuestUrl;
launch_info->args.push_back("--virtio-gpu=false");
launch_info->args.push_back("--cpus=1");
return ZX_OK;
}
};
using GuestTypes =
::testing::Types<ZirconEnclosedGuest, SingleCpuZirconEnclosedGuest,
DebianEnclosedGuest, SingleCpuDebianEnclosedGuest>;
TYPED_TEST_SUITE(GuestTest, GuestTypes);
TYPED_TEST(GuestTest, LaunchGuest) {
std::string result;
EXPECT_EQ(this->Execute({"echo", "test"}, &result), ZX_OK);
EXPECT_EQ(result, "test\n");
}
TYPED_TEST(GuestTest, VirtioRng) {
std::string result;
EXPECT_EQ(this->RunUtil(kVirtioRngUtil, {}, &result), ZX_OK);
EXPECT_THAT(result, HasSubstr("PASS"));
}
TYPED_TEST(GuestTest, VirtioConsole) {
// Test many small packets.
std::string result;
for (size_t i = 0; i != kVirtioConsoleMessageCount; ++i) {
EXPECT_EQ(this->Execute({"echo", "test"}, &result), ZX_OK);
EXPECT_EQ(result, "test\n");
}
// Test large packets. Note that we must keep the total length below 4096,
// which is the maximum line length for dash.
std::string test_data = "";
for (size_t i = 0; i != kVirtioConsoleMessageCount; ++i) {
test_data.append("Lorem ipsum dolor sit amet consectetur");
}
EXPECT_EQ(this->Execute({"echo", test_data.c_str()}, &result), ZX_OK);
test_data.append("\n");
EXPECT_EQ(result, test_data);
}
using VirtioBalloonGuestTest = GuestTest<DebianEnclosedGuest>;
TEST_F(VirtioBalloonGuestTest, VirtioBalloon) {
std::string result;
EXPECT_EQ(this->Execute({"echo", "test"}, &result), ZX_OK);
EXPECT_EQ(result, "test\n");
fuchsia::virtualization::BalloonControllerSyncPtr balloon_controller;
ConnectToBalloon(balloon_controller.NewRequest());
uint32_t initial_num_pages;
zx_status_t status = balloon_controller->GetNumPages(&initial_num_pages);
ASSERT_EQ(status, ZX_OK);
// Request an increase to the number of pages in the balloon.
status = balloon_controller->RequestNumPages(initial_num_pages +
kVirtioBalloonPageCount);
ASSERT_EQ(status, ZX_OK);
// Verify that the number of pages eventually equals the requested number. The
// guest may not respond to the request immediately so we call GetNumPages in
// a loop.
uint32_t num_pages;
while (true) {
status = balloon_controller->GetNumPages(&num_pages);
ASSERT_EQ(status, ZX_OK);
if (num_pages == initial_num_pages + kVirtioBalloonPageCount) {
break;
}
}
// Request a decrease to the number of pages in the balloon back to the
// initial value.
status = balloon_controller->RequestNumPages(initial_num_pages);
ASSERT_EQ(status, ZX_OK);
while (true) {
status = balloon_controller->GetNumPages(&num_pages);
ASSERT_EQ(status, ZX_OK);
if (num_pages == initial_num_pages) {
break;
}
}
}
// This test event listener dumps the guest's serial logs when a test fails.
class LoggerOutputListener : public ::testing::EmptyTestEventListener {
void OnTestEnd(const ::testing::TestInfo& info) override {
if (!info.result()->Failed()) {
return;
}
std::cout << "[----------] Begin guest output\n";
std::cout << Logger::Get().Buffer();
std::cout << "\n[----------] End guest output\n";
std::cout.flush();
}
};
int main(int argc, char** argv) {
if (!fxl::SetTestSettings(argc, argv)) {
return EXIT_FAILURE;
}
LoggerOutputListener listener;
testing::InitGoogleTest(&argc, argv);
testing::UnitTest::GetInstance()->listeners().Append(&listener);
int status = RUN_ALL_TESTS();
testing::UnitTest::GetInstance()->listeners().Release(&listener);
return status;
}