OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "ppapi/tests/test_transport.h" | |
6 | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
9 | |
10 #include <list> | |
11 #include <map> | |
12 | |
13 #include "ppapi/c/dev/ppb_testing_dev.h" | |
14 #include "ppapi/c/pp_errors.h" | |
15 #include "ppapi/c/pp_macros.h" | |
16 #include "ppapi/cpp/dev/transport_dev.h" | |
17 #include "ppapi/cpp/instance.h" | |
18 #include "ppapi/cpp/module.h" | |
19 #include "ppapi/cpp/var.h" | |
20 #include "ppapi/tests/test_utils.h" | |
21 #include "ppapi/tests/testing_instance.h" | |
22 #include "ppapi/utility/completion_callback_factory.h" | |
23 | |
24 REGISTER_TEST_CASE(Transport); | |
25 | |
26 namespace { | |
27 | |
28 const char kTestChannelName[] = "test"; | |
29 const int kReadBufferSize = 65536; | |
30 | |
31 class StreamReader { | |
32 public: | |
33 StreamReader(pp::Transport_Dev* transport, | |
34 int expected_size, | |
35 pp::CompletionCallback done_callback) | |
36 : expected_size_(expected_size), | |
37 done_callback_(done_callback), | |
38 PP_ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)), | |
39 transport_(transport), | |
40 received_size_(0) { | |
41 Read(); | |
42 } | |
43 | |
44 const std::list<std::vector<char> >& received() { return received_; } | |
45 std::list<std::string> errors() { return errors_; } | |
46 | |
47 private: | |
48 void Read() { | |
49 while (true) { | |
50 buffer_.resize(kReadBufferSize); | |
51 int result = transport_->Recv( | |
52 &buffer_[0], buffer_.size(), | |
53 callback_factory_.NewOptionalCallback(&StreamReader::OnReadFinished)); | |
54 if (result > 0) | |
55 DidFinishRead(result); | |
56 else | |
57 break; | |
58 } | |
59 } | |
60 | |
61 void OnReadFinished(int result) { | |
62 DidFinishRead(result); | |
63 if (result > 0) | |
64 Read(); | |
65 } | |
66 | |
67 void DidFinishRead(int result) { | |
68 if (result > 0) { | |
69 if (result > static_cast<int>(buffer_.size())) { | |
70 errors_.push_back(TestCase::MakeFailureMessage( | |
71 __FILE__, __LINE__, | |
72 "Recv() returned value that is bigger than the buffer.")); | |
73 } | |
74 buffer_.resize(result); | |
75 received_.push_back(buffer_); | |
76 received_size_ += buffer_.size(); | |
77 if (received_size_ >= expected_size_) | |
78 done_callback_.Run(0); | |
79 } | |
80 } | |
81 | |
82 int expected_size_; | |
83 pp::CompletionCallback done_callback_; | |
84 pp::CompletionCallbackFactory<StreamReader> callback_factory_; | |
85 pp::Transport_Dev* transport_; | |
86 std::vector<char> buffer_; | |
87 std::list<std::vector<char> > received_; | |
88 int received_size_; | |
89 std::list<std::string> errors_; | |
90 }; | |
91 | |
92 } // namespace | |
93 | |
94 TestTransport::~TestTransport() { | |
95 delete transport1_; | |
96 delete transport2_; | |
97 } | |
98 | |
99 bool TestTransport::Init() { | |
100 transport_interface_ = static_cast<const PPB_Transport_Dev*>( | |
101 pp::Module::Get()->GetBrowserInterface(PPB_TRANSPORT_DEV_INTERFACE)); | |
102 return transport_interface_ && CheckTestingInterface(); | |
103 } | |
104 | |
105 void TestTransport::RunTests(const std::string& filter) { | |
106 RUN_TEST(Create, filter); | |
107 RUN_TEST_FORCEASYNC_AND_NOT(Connect, filter); | |
108 RUN_TEST(SetProperty, filter); | |
109 RUN_TEST_FORCEASYNC_AND_NOT(SendDataUdp, filter); | |
110 RUN_TEST_FORCEASYNC_AND_NOT(SendDataTcp, filter); | |
111 RUN_TEST_FORCEASYNC_AND_NOT(ConnectAndCloseUdp, filter); | |
112 RUN_TEST_FORCEASYNC_AND_NOT(ConnectAndCloseTcp, filter); | |
113 } | |
114 | |
115 std::string TestTransport::InitTargets(PP_TransportType type) { | |
116 transport1_ = new pp::Transport_Dev(instance_, kTestChannelName, type); | |
117 transport2_ = new pp::Transport_Dev(instance_, kTestChannelName, type); | |
118 | |
119 ASSERT_NE(NULL, transport1_); | |
120 ASSERT_NE(NULL, transport2_); | |
121 | |
122 PASS(); | |
123 } | |
124 | |
125 std::string TestTransport::Connect() { | |
126 TestCompletionCallback connect_cb1(instance_->pp_instance()); | |
127 TestCompletionCallback connect_cb2(instance_->pp_instance()); | |
128 ASSERT_EQ(transport1_->Connect(connect_cb1), PP_OK_COMPLETIONPENDING); | |
129 ASSERT_EQ(transport2_->Connect(connect_cb2), PP_OK_COMPLETIONPENDING); | |
130 | |
131 pp::Var address1; | |
132 pp::Var address2; | |
133 TestCompletionCallback next_address_cb1(instance_->pp_instance()); | |
134 TestCompletionCallback next_address_cb2(instance_->pp_instance()); | |
135 ASSERT_EQ(transport1_->GetNextAddress(&address1, next_address_cb1), | |
136 PP_OK_COMPLETIONPENDING); | |
137 ASSERT_EQ(transport2_->GetNextAddress(&address2, next_address_cb2), | |
138 PP_OK_COMPLETIONPENDING); | |
139 ASSERT_EQ(next_address_cb1.WaitForResult(), PP_OK); | |
140 ASSERT_EQ(next_address_cb2.WaitForResult(), PP_OK); | |
141 ASSERT_EQ(transport1_->GetNextAddress(&address1, next_address_cb1), PP_OK); | |
142 ASSERT_EQ(transport2_->GetNextAddress(&address2, next_address_cb2), PP_OK); | |
143 | |
144 ASSERT_EQ(transport1_->ReceiveRemoteAddress(address2), PP_OK); | |
145 ASSERT_EQ(transport2_->ReceiveRemoteAddress(address1), PP_OK); | |
146 | |
147 | |
148 ASSERT_EQ(connect_cb1.WaitForResult(), PP_OK); | |
149 ASSERT_EQ(connect_cb2.WaitForResult(), PP_OK); | |
150 | |
151 ASSERT_TRUE(transport1_->IsWritable()); | |
152 ASSERT_TRUE(transport2_->IsWritable()); | |
153 | |
154 PASS(); | |
155 } | |
156 | |
157 std::string TestTransport::Clean() { | |
158 delete transport1_; | |
159 transport1_ = NULL; | |
160 delete transport2_; | |
161 transport2_ = NULL; | |
162 | |
163 PASS(); | |
164 } | |
165 | |
166 std::string TestTransport::TestCreate() { | |
167 ASSERT_SUBTEST_SUCCESS(InitTargets(PP_TRANSPORTTYPE_DATAGRAM)); | |
168 | |
169 Clean(); | |
170 | |
171 PASS(); | |
172 } | |
173 | |
174 std::string TestTransport::TestSetProperty() { | |
175 ASSERT_SUBTEST_SUCCESS(InitTargets(PP_TRANSPORTTYPE_STREAM)); | |
176 | |
177 // Try settings STUN and Relay properties. | |
178 ASSERT_EQ(transport1_->SetProperty( | |
179 PP_TRANSPORTPROPERTY_STUN_SERVER, | |
180 pp::Var("stun.example.com:19302")), PP_OK); | |
181 | |
182 ASSERT_EQ(transport1_->SetProperty( | |
183 PP_TRANSPORTPROPERTY_RELAY_SERVER, | |
184 pp::Var("ralay.example.com:80")), PP_OK); | |
185 | |
186 ASSERT_EQ(transport1_->SetProperty( | |
187 PP_TRANSPORTPROPERTY_RELAY_USERNAME, | |
188 pp::Var("USERNAME")), PP_OK); | |
189 ASSERT_EQ(transport1_->SetProperty( | |
190 PP_TRANSPORTPROPERTY_RELAY_PASSWORD, | |
191 pp::Var("PASSWORD")), PP_OK); | |
192 | |
193 // Try changing TCP window size. | |
194 ASSERT_EQ(transport1_->SetProperty(PP_TRANSPORTPROPERTY_TCP_RECEIVE_WINDOW, | |
195 pp::Var(65536)), PP_OK); | |
196 ASSERT_EQ(transport1_->SetProperty(PP_TRANSPORTPROPERTY_TCP_RECEIVE_WINDOW, | |
197 pp::Var(10000000)), PP_ERROR_BADARGUMENT); | |
198 | |
199 ASSERT_EQ(transport1_->SetProperty(PP_TRANSPORTPROPERTY_TCP_SEND_WINDOW, | |
200 pp::Var(65536)), PP_OK); | |
201 ASSERT_EQ(transport1_->SetProperty(PP_TRANSPORTPROPERTY_TCP_SEND_WINDOW, | |
202 pp::Var(10000000)), PP_ERROR_BADARGUMENT); | |
203 | |
204 ASSERT_EQ(transport1_->SetProperty(PP_TRANSPORTPROPERTY_TCP_NO_DELAY, | |
205 pp::Var(true)), PP_OK); | |
206 | |
207 ASSERT_EQ(transport1_->SetProperty(PP_TRANSPORTPROPERTY_TCP_ACK_DELAY, | |
208 pp::Var(10)), PP_OK); | |
209 ASSERT_EQ(transport1_->SetProperty(PP_TRANSPORTPROPERTY_TCP_ACK_DELAY, | |
210 pp::Var(10000)), PP_ERROR_BADARGUMENT); | |
211 | |
212 TestCompletionCallback connect_cb(instance_->pp_instance()); | |
213 ASSERT_EQ(transport1_->Connect(connect_cb), PP_OK_COMPLETIONPENDING); | |
214 | |
215 // SetProperty() should fail after we've connected. | |
216 ASSERT_EQ(transport1_->SetProperty( | |
217 PP_TRANSPORTPROPERTY_STUN_SERVER, | |
218 pp::Var("stun.example.com:31323")), PP_ERROR_FAILED); | |
219 | |
220 Clean(); | |
221 ASSERT_EQ(connect_cb.WaitForResult(), PP_ERROR_ABORTED); | |
222 | |
223 PASS(); | |
224 } | |
225 | |
226 std::string TestTransport::TestConnect() { | |
227 ASSERT_SUBTEST_SUCCESS(InitTargets(PP_TRANSPORTTYPE_DATAGRAM)); | |
228 ASSERT_SUBTEST_SUCCESS(Connect()); | |
229 | |
230 Clean(); | |
231 | |
232 PASS(); | |
233 } | |
234 | |
235 // Creating datagram connection and try sending data over it. Verify | |
236 // that at least some packets are received (some packets may be lost). | |
237 std::string TestTransport::TestSendDataUdp() { | |
238 ASSERT_SUBTEST_SUCCESS(InitTargets(PP_TRANSPORTTYPE_DATAGRAM)); | |
239 ASSERT_SUBTEST_SUCCESS(Connect()); | |
240 | |
241 const int kNumPackets = 100; | |
242 const int kSendBufferSize = 1200; | |
243 const int kUdpWaitTimeMs = 1000; // 1 second. | |
244 | |
245 TestCompletionCallback done_cb(instance_->pp_instance()); | |
246 StreamReader reader(transport1_, kSendBufferSize * kNumPackets, done_cb); | |
247 | |
248 std::map<int, std::vector<char> > sent_packets; | |
249 for (int i = 0; i < kNumPackets; ++i) { | |
250 std::vector<char> send_buffer(kSendBufferSize); | |
251 for (size_t j = 0; j < send_buffer.size(); ++j) { | |
252 send_buffer[j] = rand() % 256; | |
253 } | |
254 // Put packet index in the beginning. | |
255 memcpy(&send_buffer[0], &i, sizeof(i)); | |
256 | |
257 TestCompletionCallback send_cb(instance_->pp_instance(), force_async_); | |
258 int32_t result = transport2_->Send(&send_buffer[0], send_buffer.size(), | |
259 send_cb); | |
260 if (force_async_) { | |
261 ASSERT_EQ(result, PP_OK_COMPLETIONPENDING); | |
262 ASSERT_EQ(send_cb.WaitForResult(), static_cast<int>(send_buffer.size())); | |
263 } else { | |
264 ASSERT_EQ(result, static_cast<int>(send_buffer.size())); | |
265 } | |
266 sent_packets[i] = send_buffer; | |
267 } | |
268 | |
269 // Limit waiting time. | |
270 TestCompletionCallback timeout_cb(instance_->pp_instance()); | |
271 pp::Module::Get()->core()->CallOnMainThread(kUdpWaitTimeMs, timeout_cb); | |
272 ASSERT_EQ(timeout_cb.WaitForResult(), PP_OK); | |
273 | |
274 ASSERT_TRUE(reader.errors().size() == 0); | |
275 ASSERT_TRUE(reader.received().size() > 0); | |
276 for (std::list<std::vector<char> >::const_iterator it = | |
277 reader.received().begin(); it != reader.received().end(); ++it) { | |
278 int index; | |
279 memcpy(&index, &(*it)[0], sizeof(index)); | |
280 ASSERT_TRUE(sent_packets[index] == *it); | |
281 } | |
282 | |
283 Clean(); | |
284 | |
285 PASS(); | |
286 } | |
287 | |
288 // Creating reliable (TCP-like) connection and try sending data over | |
289 // it. Verify that all data is received correctly. | |
290 std::string TestTransport::TestSendDataTcp() { | |
291 ASSERT_SUBTEST_SUCCESS(InitTargets(PP_TRANSPORTTYPE_STREAM)); | |
292 ASSERT_SUBTEST_SUCCESS(Connect()); | |
293 | |
294 const int kTcpSendSize = 100000; | |
295 | |
296 TestCompletionCallback done_cb(instance_->pp_instance()); | |
297 StreamReader reader(transport1_, kTcpSendSize, done_cb); | |
298 | |
299 std::vector<char> send_buffer(kTcpSendSize); | |
300 for (size_t j = 0; j < send_buffer.size(); ++j) { | |
301 send_buffer[j] = rand() % 256; | |
302 } | |
303 | |
304 int pos = 0; | |
305 while (pos < static_cast<int>(send_buffer.size())) { | |
306 TestCompletionCallback send_cb(instance_->pp_instance(), force_async_); | |
307 int result = transport2_->Send( | |
308 &send_buffer[0] + pos, send_buffer.size() - pos, send_cb); | |
309 if (force_async_) | |
310 ASSERT_EQ(result, PP_OK_COMPLETIONPENDING); | |
311 if (result == PP_OK_COMPLETIONPENDING) | |
312 result = send_cb.WaitForResult(); | |
313 ASSERT_TRUE(result > 0); | |
314 pos += result; | |
315 } | |
316 | |
317 ASSERT_EQ(done_cb.WaitForResult(), PP_OK); | |
318 | |
319 ASSERT_TRUE(reader.errors().size() == 0); | |
320 | |
321 std::vector<char> received_data; | |
322 for (std::list<std::vector<char> >::const_iterator it = | |
323 reader.received().begin(); it != reader.received().end(); ++it) { | |
324 received_data.insert(received_data.end(), it->begin(), it->end()); | |
325 } | |
326 ASSERT_EQ(send_buffer, received_data); | |
327 | |
328 Clean(); | |
329 | |
330 PASS(); | |
331 } | |
332 | |
333 std::string TestTransport::TestConnectAndCloseUdp() { | |
334 ASSERT_SUBTEST_SUCCESS(InitTargets(PP_TRANSPORTTYPE_DATAGRAM)); | |
335 ASSERT_SUBTEST_SUCCESS(Connect()); | |
336 | |
337 std::vector<char> recv_buffer(kReadBufferSize); | |
338 TestCompletionCallback recv_cb(instance_->pp_instance()); | |
339 ASSERT_EQ( | |
340 transport1_->Recv(&recv_buffer[0], recv_buffer.size(), recv_cb), | |
341 PP_OK_COMPLETIONPENDING); | |
342 | |
343 // Close the transport and verify that callback is aborted. | |
344 ASSERT_EQ(transport1_->Close(), PP_OK); | |
345 | |
346 ASSERT_EQ(recv_cb.run_count(), 1); | |
347 ASSERT_EQ(recv_cb.result(), PP_ERROR_ABORTED); | |
348 | |
349 Clean(); | |
350 | |
351 PASS(); | |
352 } | |
353 | |
354 std::string TestTransport::TestConnectAndCloseTcp() { | |
355 ASSERT_SUBTEST_SUCCESS(InitTargets(PP_TRANSPORTTYPE_STREAM)); | |
356 ASSERT_SUBTEST_SUCCESS(Connect()); | |
357 | |
358 std::vector<char> recv_buffer(kReadBufferSize); | |
359 TestCompletionCallback recv_cb(instance_->pp_instance()); | |
360 ASSERT_EQ( | |
361 transport1_->Recv(&recv_buffer[0], recv_buffer.size(), recv_cb), | |
362 PP_OK_COMPLETIONPENDING); | |
363 | |
364 // Close the transport and verify that callback is aborted. | |
365 ASSERT_EQ(transport1_->Close(), PP_OK); | |
366 | |
367 ASSERT_EQ(recv_cb.run_count(), 1); | |
368 ASSERT_EQ(recv_cb.result(), PP_ERROR_ABORTED); | |
369 | |
370 Clean(); | |
371 | |
372 PASS(); | |
373 } | |
OLD | NEW |