chromium/mojo/core/invitation_unittest.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "mojo/public/c/system/invitation.h"

#include <cstdint>
#include <cstring>
#include <optional>
#include <string>
#include <string_view>

#include "base/base_paths.h"
#include "base/base_switches.h"
#include "base/check_op.h"
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/shared_memory_mapping.h"
#include "base/memory/writable_shared_memory_region.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/process/process.h"
#include "base/run_loop.h"
#include "base/synchronization/lock.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/multiprocess_test.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "mojo/buildflags.h"
#include "mojo/core/embedder/embedder.h"
#include "mojo/core/ipcz_api.h"
#include "mojo/core/test/mojo_test_base.h"
#include "mojo/core/test/test_switches.h"
#include "mojo/public/cpp/platform/named_platform_channel.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/system/platform_handle.h"

#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
#include "mojo/core/core.h"
#include "mojo/core/node_controller.h"
#endif

#if BUILDFLAG(MOJO_USE_APPLE_CHANNEL)
#include "base/mac/mach_port_rendezvous.h"
#endif

namespace mojo {
namespace core {
namespace {

const char kSecondaryChannelHandleSwitch[] =;

// TODO(crbug.com/40900578): Flaky on Tsan.
#if defined(THREAD_SANITIZER)
#define MAYBE_InvitationTest
#else
#define MAYBE_InvitationTest
#endif
class MAYBE_InvitationTest : public test::MojoTestBase {};

void PrepareToPassRemoteEndpoint(PlatformChannel* channel,
                                 base::LaunchOptions* options,
                                 base::CommandLine* command_line,
                                 std::string_view switch_name = {}

TEST_F(MAYBE_InvitationTest, Create) {}

TEST_F(MAYBE_InvitationTest, InvalidArguments) {}

TEST_F(MAYBE_InvitationTest, AttachAndExtractLocally) {}

TEST_F(MAYBE_InvitationTest, ClosedInvitationClosesAttachments) {}

TEST_F(MAYBE_InvitationTest, AttachNameInUse) {}

// static
base::Process MAYBE_InvitationTest::LaunchChildTestClient(
    const std::string& test_client_name,
    MojoHandle* primordial_pipes,
    size_t num_primordial_pipes,
    MojoSendInvitationFlags send_flags,
    MojoProcessErrorHandler error_handler,
    uintptr_t error_handler_context,
    base::CommandLine* custom_command_line,
    base::LaunchOptions* custom_launch_options) {}

// static
void MAYBE_InvitationTest::SendInvitationToClient(
    PlatformHandle endpoint_handle,
    base::ProcessHandle process,
    MojoHandle* primordial_pipes,
    size_t num_primordial_pipes,
    MojoSendInvitationFlags flags,
    MojoProcessErrorHandler error_handler,
    uintptr_t error_handler_context,
    std::string_view isolated_invitation_name) {}

class TestClientBase : public MAYBE_InvitationTest {};

#define DEFINE_TEST_CLIENT(name)

const std::string kTestMessage1 =;
const std::string kTestMessage2 =;
const std::string kTestMessage3 =;
const std::string kTestMessage4 =;

TEST_F(MAYBE_InvitationTest, SendInvitation) {}

DEFINE_TEST_CLIENT(SendInvitationClient) {}

TEST_F(MAYBE_InvitationTest, SendInvitationMultiplePipes) {}

DEFINE_TEST_CLIENT(SendInvitationMultiplePipesClient) {}

const char kErrorMessage[] =;
const char kDisconnectMessage[] =;

class RemoteProcessState {};

void TestProcessErrorHandler(uintptr_t context,
                             const MojoProcessErrorDetails* details) {}

TEST_F(MAYBE_InvitationTest, ProcessErrors) {}

DEFINE_TEST_CLIENT(ProcessErrorsClient) {}

#if BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)
// Temporary removed support for reinvitation for non-isolated connections.
TEST_F(MAYBE_InvitationTest, DISABLED_Reinvitation) {
  // The gist of this test is that a process should be able to accept an
  // invitation, lose its connection to the process network, and then accept a
  // new invitation to re-establish communication.

  // We pass an extra PlatformChannel endpoint to the child process which it
  // will use to accept a secondary invitation after we sever its first
  // connection.
  PlatformChannel secondary_channel;
  auto command_line = base::GetMultiProcessTestChildBaseCommandLine();
  base::LaunchOptions launch_options;
  PrepareToPassRemoteEndpoint(&secondary_channel, &launch_options,
                              &command_line, kSecondaryChannelHandleSwitch);

  MojoHandle pipe;
  base::Process child_process = LaunchChildTestClient(
      "ReinvitationClient", &pipe, 1, MOJO_SEND_INVITATION_FLAG_NONE, nullptr,
      0, &command_line, &launch_options);
  secondary_channel.RemoteProcessLaunchAttempted();

  // Synchronize end-to-end communication first to ensure the process connection
  // is fully established.
  WriteMessage(pipe, kTestMessage1);
  EXPECT_EQ(kTestMessage2, ReadMessage(pipe));

  // Force-disconnect the child process.
  Core::Get()->GetNodeController()->ForceDisconnectProcessForTesting(
      child_process.Pid());

  // The above disconnection should force pipe closure eventually.
  WaitForSignals(pipe, MOJO_HANDLE_SIGNAL_PEER_CLOSED);
  MojoClose(pipe);

  // Now use our secondary channel to send a new invitation to the same process.
  // It should be able to accept the new invitation and re-establish
  // communication.
  mojo::OutgoingInvitation new_invitation;
  auto new_pipe = new_invitation.AttachMessagePipe(0);
  mojo::OutgoingInvitation::Send(std::move(new_invitation),
                                 child_process.Handle(),
                                 secondary_channel.TakeLocalEndpoint());

  WriteMessage(new_pipe.get().value(), kTestMessage3);
  EXPECT_EQ(kTestMessage4, ReadMessage(new_pipe.get().value()));
  WriteMessage(new_pipe.get().value(), kDisconnectMessage);

  WaitForProcessToTerminate(child_process);
}
#endif  // BUILDFLAG(MOJO_SUPPORT_LEGACY_CORE)

DEFINE_TEST_CLIENT(ReinvitationClient) {}

TEST_F(MAYBE_InvitationTest, SendIsolatedInvitation) {}

DEFINE_TEST_CLIENT(SendIsolatedInvitationClient) {}

TEST_F(MAYBE_InvitationTest, SendMultipleIsolatedInvitations) {}

DEFINE_TEST_CLIENT(SendMultipleIsolatedInvitationsClient) {}

TEST_F(MAYBE_InvitationTest, SendIsolatedInvitationWithDuplicateName) {}

TEST_F(MAYBE_InvitationTest, SendIsolatedInvitationToSelf) {}

TEST_F(MAYBE_InvitationTest, BrokenInvitationTransportBreaksAttachedPipe) {}

TEST_F(MAYBE_InvitationTest,
       BrokenIsolatedInvitationTransportBreaksAttachedPipe) {}

DEFINE_TEST_CLIENT(BrokenTransportClient) {
  // No-op. Exit immediately without accepting any invitation.
}

TEST_F(MAYBE_InvitationTest, NonBrokerToNonBroker) {}

DEFINE_TEST_CLIENT(NonBrokerToNonBrokerHost) {}

DEFINE_TEST_CLIENT(NonBrokerToNonBrokerClient) {}

TEST_F(MAYBE_InvitationTest, MultiBrokerNetwork) {}

MojoHandle CreateMemory(std::string_view contents) {}

std::string ReadMemory(MojoHandle handle) {}

constexpr size_t kNumMultiBrokerMessageIterations =;

DEFINE_TEST_CLIENT(SecondaryBroker) {}

DEFINE_TEST_CLIENT(MultiBrokerNetworkClient) {}

}  // namespace
}  // namespace core
}  // namespace mojo