blob: 729aba9206add75dbfbb8377d52ea9494764dde3 [file] [log] [blame]
// Copyright 2022 The Chromium OS 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 "mojo_service_manager/daemon/daemon_test_helper.h"
#include <errno.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <cstdlib>
#include <string>
#include <utility>
#include <base/check_op.h>
#include <base/files/file_util.h>
#include <base/posix/eintr_wrapper.h>
#include <base/test/bind.h>
#include <base/test/test_timeouts.h>
#include <base/threading/platform_thread.h>
#include <base/timer/elapsed_timer.h>
#include <mojo/core/embedder/embedder.h>
#include <mojo/public/cpp/bindings/remote.h>
#include <mojo/public/cpp/platform/platform_channel.h>
#include <mojo/public/cpp/system/invitation.h>
#include "mojo_service_manager/daemon/daemon.h"
#include "mojo_service_manager/daemon/mojo_test_environment.h"
namespace {
namespace mojo_service_manager = chromeos::mojo_service_manager;
namespace mojom = mojo_service_manager::mojom;
bool WaitForSocketReady(const base::FilePath& socket_path) {
for (base::ElapsedTimer t; t.Elapsed() < TestTimeouts::action_timeout();
base::PlatformThread::Sleep(base::Milliseconds(1))) {
if (base::PathExists(socket_path))
return true;
}
return false;
}
base::ScopedFD ConnectToSocket(const base::FilePath& socket_path) {
if (!WaitForSocketReady(socket_path))
return base::ScopedFD{};
base::ScopedFD sock{socket(AF_UNIX, SOCK_STREAM, 0)};
if (!sock.is_valid()) {
LOG(ERROR) << "Failed to create socket";
return base::ScopedFD{};
}
struct sockaddr_un unix_addr {
.sun_family = AF_UNIX,
};
constexpr size_t kMaxSize =
sizeof(unix_addr.sun_path) - /*NULL-terminator*/ 1;
CHECK_LE(socket_path.value().size(), kMaxSize);
strncpy(unix_addr.sun_path, socket_path.value().c_str(), kMaxSize);
int rc = HANDLE_EINTR(connect(sock.get(),
reinterpret_cast<const sockaddr*>(&unix_addr),
sizeof(unix_addr)));
if (rc == -1 && errno != EISCONN) {
LOG(ERROR) << "Failed to connect to socket";
return base::ScopedFD{};
}
return sock;
}
mojo::Remote<mojom::ServiceManager> ConnectToMojoServiceManager(
base::ScopedFD peer) {
CHECK(peer.is_valid());
auto invitation = mojo::IncomingInvitation::Accept(
mojo::PlatformChannelEndpoint(mojo::PlatformHandle(std::move(peer))));
mojo::ScopedMessagePipeHandle pipe = invitation.ExtractMessagePipe(
mojo_service_manager::kMojoInvitationPipeName);
return mojo::Remote<mojom::ServiceManager>{
mojo::PendingRemote<mojom::ServiceManager>(std::move(pipe), 0u)};
}
} // namespace
int main(int argc, char** argv) {
base::CommandLine::Init(argc, argv);
TestTimeouts::Initialize();
mojo::core::Init();
mojo_service_manager::MojoTaskEnvironment env;
mojo::Remote<mojom::ServiceManager> mojo_service_manager =
ConnectToMojoServiceManager(ConnectToSocket(
base::FilePath{mojo_service_manager::kTestSocketName}));
CHECK(mojo_service_manager.is_connected());
mojo_service_manager::DaemonTestHelperResult result =
mojo_service_manager::DaemonTestHelperResult::kConnectSuccessfully;
mojo_service_manager.set_disconnect_with_reason_handler(
base::BindLambdaForTesting([&](uint32_t error,
const std::string& message) {
CHECK_EQ(error,
static_cast<uint32_t>(mojom::ErrorCode::kUnexpectedOsError));
result =
mojo_service_manager::DaemonTestHelperResult::kResetWithOsError;
}));
// Make sure the state is updated.
mojo_service_manager.FlushForTesting();
return static_cast<int>(result);
}