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