summaryrefslogtreecommitdiffstats
path: root/ipc/ipdl/test/gtest/TestEndpointOpens.cpp
blob: 50dab06058ae54f541bc7a9a9923408469d6955c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * Test Endpoint usage.
 */

#include "gtest/gtest.h"

#include "mozilla/_ipdltest/IPDLUnitTest.h"
#include "mozilla/_ipdltest/PTestEndpointOpensChild.h"
#include "mozilla/_ipdltest/PTestEndpointOpensParent.h"
#include "mozilla/_ipdltest/PTestEndpointOpensOpenedChild.h"
#include "mozilla/_ipdltest/PTestEndpointOpensOpenedParent.h"

#include <memory>

using namespace mozilla::ipc;

namespace mozilla::_ipdltest {

class TestEndpointOpensOpenedParent : public PTestEndpointOpensOpenedParent {
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestEndpointOpensOpenedParent, override)
 private:
  IPCResult RecvHello() final override {
    EXPECT_FALSE(NS_IsMainThread());
    if (!SendHi()) {
      return IPC_TEST_FAIL(this);
    }
    return IPC_OK();
  }

  IPCResult RecvHelloSync() final override {
    EXPECT_FALSE(NS_IsMainThread());
    return IPC_OK();
  }

  void ActorDestroy(ActorDestroyReason why) final override {
    EXPECT_FALSE(NS_IsMainThread());
  }

  ~TestEndpointOpensOpenedParent() = default;
};

class TestEndpointOpensChild : public PTestEndpointOpensChild {
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestEndpointOpensChild, override)
 private:
  IPCResult RecvStart() final override;

  ~TestEndpointOpensChild() = default;
};

class TestEndpointOpensOpenedChild : public PTestEndpointOpensOpenedChild {
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestEndpointOpensOpenedChild, override)

  explicit TestEndpointOpensOpenedChild(TestEndpointOpensChild* opensChild)
      : mOpensChild(opensChild) {}

 private:
  IPCResult RecvHi() final override {
    EXPECT_FALSE(NS_IsMainThread());

    EXPECT_TRUE(SendHelloSync());

    Close();
    return IPC_OK();
  }

  void ActorDestroy(ActorDestroyReason why) final override {
    EXPECT_FALSE(NS_IsMainThread());

    // Kick off main-thread shutdown.
    NS_DispatchToMainThread(NewRunnableMethod("ipc::IToplevelProtocol::Close",
                                              mOpensChild,
                                              &TestEndpointOpensChild::Close));
  }

  ~TestEndpointOpensOpenedChild() = default;

  TestEndpointOpensChild* mOpensChild;
};

class TestEndpointOpensParent : public PTestEndpointOpensParent {
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TestEndpointOpensParent, override)
 private:
  IPCResult RecvStartSubprotocol(
      Endpoint<PTestEndpointOpensOpenedParent>&& endpoint) final override {
    nsCOMPtr<nsISerialEventTarget> eventTarget;
    auto rv = NS_CreateBackgroundTaskQueue("ParentThread",
                                           getter_AddRefs(eventTarget));
    if (NS_FAILED(rv)) {
      ADD_FAILURE() << "creating background task queue for child";
      return IPC_TEST_FAIL(this);
    }

    eventTarget->Dispatch(NS_NewRunnableFunction(
        "OpenParent", [endpoint{std::move(endpoint)}]() mutable {
          EXPECT_FALSE(NS_IsMainThread());

          // Open the actor on the off-main thread to park it there.
          // Messages will be delivered to this thread's message loop
          // instead of the main thread's.
          auto actor = MakeRefPtr<TestEndpointOpensOpenedParent>();
          ASSERT_TRUE(endpoint.Bind(actor));
        }));

    return IPC_OK();
  }

  ~TestEndpointOpensParent() = default;
};

IPCResult TestEndpointOpensChild::RecvStart() {
  Endpoint<PTestEndpointOpensOpenedParent> parent;
  Endpoint<PTestEndpointOpensOpenedChild> child;
  nsresult rv;
  rv = PTestEndpointOpensOpened::CreateEndpoints(
      OtherPidMaybeInvalid(), base::GetCurrentProcId(), &parent, &child);
  if (NS_FAILED(rv)) {
    ADD_FAILURE() << "opening PTestEndpointOpensOpened";
    return IPC_TEST_FAIL(this);
  }

  nsCOMPtr<nsISerialEventTarget> childEventTarget;
  rv = NS_CreateBackgroundTaskQueue("ChildThread",
                                    getter_AddRefs(childEventTarget));
  if (NS_FAILED(rv)) {
    ADD_FAILURE() << "creating background task queue for child";
    return IPC_TEST_FAIL(this);
  }

  auto actor = MakeRefPtr<TestEndpointOpensOpenedChild>(this);
  childEventTarget->Dispatch(NS_NewRunnableFunction(
      "OpenChild",
      [actor{std::move(actor)}, endpoint{std::move(child)}]() mutable {
        EXPECT_FALSE(NS_IsMainThread());

        // Open the actor on the off-main thread to park it there.
        // Messages will be delivered to this thread's message loop
        // instead of the main thread's.
        ASSERT_TRUE(endpoint.Bind(actor));

        // Kick off the unit tests
        ASSERT_TRUE(actor->SendHello());
      }));

  EXPECT_TRUE(SendStartSubprotocol(std::move(parent)));

  return IPC_OK();
}

IPDL_TEST_ON(CROSSPROCESS, TestEndpointOpens) {
  EXPECT_TRUE(mActor->SendStart());
}

}  // namespace mozilla::_ipdltest