blob: 05b906add4a084814d7cb218c203dd83de946bbe [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 <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/sys/cpp/file_descriptor.h>
#include <lib/sys/cpp/testing/test_with_environment.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <fstream>
#include <string>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "src/lib/files/file.h"
#include "src/lib/files/scoped_temp_dir.h"
namespace intl_wisdom {
using fuchsia::sys::ComponentControllerPtr;
using fuchsia::sys::LaunchInfo;
using sys::testing::TestWithEnvironment;
// The C++ version of the wisdom client-server example.
constexpr char kIntlWisdomClientPackage[] =
"fuchsia-pkg://fuchsia.com/intl_wisdom#meta/intl_wisdom_client.cmx";
// The Rust version of the wisdom client-server example.
constexpr char kIntlWisdomClientRustPackage[] =
"fuchsia-pkg://fuchsia.com/intl_wisdom_rust#meta/intl_wisdom_client_rust.cmx";
// Integration test for IntlWisdomClient and IntlWisdomServer.
//
// Starts a client, which starts a server and asks it for wisdom. Compares the
// entire STDOUT output of the client (including the server's response) to an
// expected output file.
class IntlWisdomTest : public TestWithEnvironment {
protected:
void SetUp() override {
TestWithEnvironment::SetUp();
OpenNewOutFiles();
}
void TearDown() override {
CloseOutFiles();
TestWithEnvironment::TearDown();
}
void OpenNewOutFiles() {
ASSERT_TRUE(temp_dir_.NewTempFile(&out_file_path_));
out_file_ = std::fopen(out_file_path_.c_str(), "w");
ASSERT_TRUE(temp_dir_.NewTempFile(&err_file_path_));
err_file_ = std::fopen(err_file_path_.c_str(), "w");
}
void CloseOutFiles() {
if (out_file_ != nullptr) {
std::fclose(out_file_);
}
if (err_file_ != nullptr) {
std::fclose(err_file_);
}
}
// Read the contents of the file at |path| into |contents|.
static void ReadFile(const std::string& path, std::string& contents) {
ASSERT_TRUE(files::ReadFileToString(path, &contents)) << "Could not read file " << path;
}
ComponentControllerPtr LaunchClientWithServer(const std::string& url) {
LaunchInfo launch_info{
.url = url,
.out = sys::CloneFileDescriptor(fileno(out_file_)),
.err = sys::CloneFileDescriptor(fileno(err_file_)),
.arguments = std::vector<std::string>({
"--timestamp=2018-11-01T12:34:56Z",
"--timezone=America/Los_Angeles",
}),
};
ComponentControllerPtr controller;
CreateComponentInCurrentEnvironment(std::move(launch_info), controller.NewRequest());
return controller;
}
const std::string& out_file_path() const { return out_file_path_; }
const std::string& err_file_path() const { return err_file_path_; }
// Syncs the files used for recording stdout and stderr.
void SyncWrites() {
fsync(fileno(out_file_));
fsync(fileno(err_file_));
}
void RunWisdomClientAndServer(const std::string& package_url) {
std::string expected_output;
IntlWisdomTest::ReadFile("/pkg/data/golden-output.txt", expected_output);
ComponentControllerPtr controller = LaunchClientWithServer(package_url);
ASSERT_TRUE(RunComponentUntilTerminated(std::move(controller), nullptr));
// Ensures that the data we just wrote is available for subsequent reading
// in the assertions. Not doing so can result in assertions not seeing
// the just-written content.
SyncWrites();
std::string actual_output;
ReadFile(out_file_path(), actual_output);
std::string stderr_output;
ReadFile(err_file_path(), stderr_output);
ASSERT_EQ(actual_output, expected_output) << "stdout:\n"
<< actual_output << "\n:stderr:\n"
<< stderr_output;
}
private:
files::ScopedTempDir temp_dir_;
std::string out_file_path_;
std::string err_file_path_;
FILE* out_file_ = nullptr;
FILE* err_file_ = nullptr;
};
TEST_F(IntlWisdomTest, RunWisdomClientAndServerCPP) {
RunWisdomClientAndServer(kIntlWisdomClientPackage);
}
TEST_F(IntlWisdomTest, RunWisdomClientAndServerRust) {
RunWisdomClientAndServer(kIntlWisdomClientRustPackage);
}
} // namespace intl_wisdom