1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 
4 #include "TestEndpointBridgeMain.h"
5 
6 #include "base/task.h"
7 #include "IPDLUnitTests.h"      // fail etc.
8 #include "IPDLUnitTestSubprocess.h"
9 
10 using namespace std;
11 
12 namespace mozilla {
13 namespace _ipdltest {
14 
15 
16 //-----------------------------------------------------------------------------
17 // main process
18 void
Main()19 TestEndpointBridgeMainParent::Main()
20 {
21   if (!SendStart()) {
22     fail("sending Start");
23   }
24 }
25 
26 bool
RecvBridged(Endpoint<PTestEndpointBridgeMainSubParent> && endpoint)27 TestEndpointBridgeMainParent::RecvBridged(Endpoint<PTestEndpointBridgeMainSubParent>&& endpoint)
28 {
29   TestEndpointBridgeMainSubParent* a = new TestEndpointBridgeMainSubParent();
30   if (!endpoint.Bind(a)) {
31     fail("Bind failed");
32   }
33   return true;
34 }
35 
36 void
ActorDestroy(ActorDestroyReason why)37 TestEndpointBridgeMainParent::ActorDestroy(ActorDestroyReason why)
38 {
39   if (NormalShutdown != why) {
40     fail("unexpected destruction!");
41   }
42   passed("ok");
43   QuitParent();
44 }
45 
46 bool
RecvHello()47 TestEndpointBridgeMainSubParent::RecvHello()
48 {
49   return SendHi();
50 }
51 
52 bool
RecvHelloSync()53 TestEndpointBridgeMainSubParent::RecvHelloSync()
54 {
55   return true;
56 }
57 
58 bool
AnswerHelloRpc()59 TestEndpointBridgeMainSubParent::AnswerHelloRpc()
60 {
61   return CallHiRpc();
62 }
63 
64 void
ActorDestroy(ActorDestroyReason why)65 TestEndpointBridgeMainSubParent::ActorDestroy(ActorDestroyReason why)
66 {
67   if (NormalShutdown != why) {
68     fail("unexpected destruction!");
69   }
70 
71   // ActorDestroy() is just a callback from IPDL-generated code,
72   // which needs the top-level actor (this) to stay alive a little
73   // longer so other things can be cleaned up.
74   MessageLoop::current()->PostTask(
75     do_AddRef(new DeleteTask<TestEndpointBridgeMainSubParent>(this)));
76 }
77 
78 //-----------------------------------------------------------------------------
79 // sub process --- child of main
80 TestEndpointBridgeMainChild* gEndpointBridgeMainChild;
81 
TestEndpointBridgeMainChild()82 TestEndpointBridgeMainChild::TestEndpointBridgeMainChild()
83  : mSubprocess(nullptr)
84 {
85   gEndpointBridgeMainChild = this;
86 }
87 
88 bool
RecvStart()89 TestEndpointBridgeMainChild::RecvStart()
90 {
91   vector<string> subsubArgs;
92   subsubArgs.push_back("TestEndpointBridgeSub");
93 
94   mSubprocess = new IPDLUnitTestSubprocess();
95   if (!mSubprocess->SyncLaunch(subsubArgs)) {
96     fail("problem launching subprocess");
97   }
98 
99   IPC::Channel* transport = mSubprocess->GetChannel();
100   if (!transport) {
101     fail("no transport");
102   }
103 
104   TestEndpointBridgeSubParent* bsp = new TestEndpointBridgeSubParent();
105   bsp->Open(transport, base::GetProcId(mSubprocess->GetChildProcessHandle()));
106 
107   bsp->Main();
108   return true;
109 }
110 
111 void
ActorDestroy(ActorDestroyReason why)112 TestEndpointBridgeMainChild::ActorDestroy(ActorDestroyReason why)
113 {
114   if (NormalShutdown != why) {
115     fail("unexpected destruction!");
116   }
117   // NB: this is kosher because QuitChild() joins with the IO thread
118   XRE_GetIOMessageLoop()->PostTask(
119     do_AddRef(new DeleteTask<IPDLUnitTestSubprocess>(mSubprocess)));
120   QuitChild();
121 }
122 
123 void
Main()124 TestEndpointBridgeSubParent::Main()
125 {
126   if (!SendPing()) {
127     fail("sending Ping");
128   }
129 }
130 
131 bool
RecvBridgeEm()132 TestEndpointBridgeSubParent::RecvBridgeEm()
133 {
134   Endpoint<PTestEndpointBridgeMainSubParent> parent;
135   Endpoint<PTestEndpointBridgeMainSubChild> child;
136   nsresult rv;
137   rv = PTestEndpointBridgeMainSub::CreateEndpoints(
138     gEndpointBridgeMainChild->OtherPid(), OtherPid(),
139     &parent, &child);
140   if (NS_FAILED(rv)) {
141     fail("opening PTestEndpointOpensOpened");
142   }
143 
144   if (!gEndpointBridgeMainChild->SendBridged(mozilla::Move(parent))) {
145     fail("SendBridge failed for parent");
146   }
147   if (!SendBridged(mozilla::Move(child))) {
148     fail("SendBridge failed for child");
149   }
150 
151   return true;
152 }
153 
154 void
ActorDestroy(ActorDestroyReason why)155 TestEndpointBridgeSubParent::ActorDestroy(ActorDestroyReason why)
156 {
157   if (NormalShutdown != why) {
158     fail("unexpected destruction!");
159   }
160   gEndpointBridgeMainChild->Close();
161 
162   // ActorDestroy() is just a callback from IPDL-generated code,
163   // which needs the top-level actor (this) to stay alive a little
164   // longer so other things can be cleaned up.
165   MessageLoop::current()->PostTask(
166     do_AddRef(new DeleteTask<TestEndpointBridgeSubParent>(this)));
167 }
168 
169 //-----------------------------------------------------------------------------
170 // subsub process --- child of sub
171 
172 static TestEndpointBridgeSubChild* gBridgeSubChild;
173 
TestEndpointBridgeSubChild()174 TestEndpointBridgeSubChild::TestEndpointBridgeSubChild()
175 {
176     gBridgeSubChild = this;
177 }
178 
179 bool
RecvPing()180 TestEndpointBridgeSubChild::RecvPing()
181 {
182   if (!SendBridgeEm()) {
183     fail("sending BridgeEm");
184   }
185   return true;
186 }
187 
188 bool
RecvBridged(Endpoint<PTestEndpointBridgeMainSubChild> && endpoint)189 TestEndpointBridgeSubChild::RecvBridged(Endpoint<PTestEndpointBridgeMainSubChild>&& endpoint)
190 {
191   TestEndpointBridgeMainSubChild* a = new TestEndpointBridgeMainSubChild();
192 
193   if (!endpoint.Bind(a)) {
194     fail("failed to Bind");
195   }
196 
197   if (!a->SendHello()) {
198     fail("sending Hello");
199   }
200 
201   return true;
202 }
203 
204 void
ActorDestroy(ActorDestroyReason why)205 TestEndpointBridgeSubChild::ActorDestroy(ActorDestroyReason why)
206 {
207   if (NormalShutdown != why) {
208     fail("unexpected destruction!");
209   }
210   QuitChild();
211 }
212 
213 bool
RecvHi()214 TestEndpointBridgeMainSubChild::RecvHi()
215 {
216   if (!SendHelloSync()) {
217     fail("sending HelloSync");
218   }
219   if (!CallHelloRpc()) {
220     fail("calling HelloRpc");
221   }
222   if (!mGotHi) {
223     fail("didn't answer HiRpc");
224   }
225 
226   // Need to close the channel without message-processing frames on
227   // the C++ stack
228   MessageLoop::current()->PostTask(
229     NewNonOwningRunnableMethod(this, &TestEndpointBridgeMainSubChild::Close));
230   return true;
231 }
232 
233 bool
AnswerHiRpc()234 TestEndpointBridgeMainSubChild::AnswerHiRpc()
235 {
236   mGotHi = true;              // d00d
237   return true;
238 }
239 
240 void
ActorDestroy(ActorDestroyReason why)241 TestEndpointBridgeMainSubChild::ActorDestroy(ActorDestroyReason why)
242 {
243   if (NormalShutdown != why) {
244     fail("unexpected destruction!");
245   }
246 
247   gBridgeSubChild->Close();
248 
249   // ActorDestroy() is just a callback from IPDL-generated code,
250   // which needs the top-level actor (this) to stay alive a little
251   // longer so other things can be cleaned up.
252   MessageLoop::current()->PostTask(
253     do_AddRef(new DeleteTask<TestEndpointBridgeMainSubChild>(this)));
254 }
255 
256 } // namespace mozilla
257 } // namespace _ipdltest
258