Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: net/tools/quic/quic_simple_server_session_test.cc

Issue 1662083003: Change server push unit tests of quic toy server session to make tests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@Final_0203
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/tools/quic/quic_simple_server_session.h" 5 #include "net/tools/quic/quic_simple_server_session.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/macros.h" 9 #include "base/macros.h"
10 #include "base/strings/string_number_conversions.h" 10 #include "base/strings/string_number_conversions.h"
(...skipping 13 matching lines...) Expand all
24 #include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h" 24 #include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h"
25 #include "net/quic/test_tools/quic_test_utils.h" 25 #include "net/quic/test_tools/quic_test_utils.h"
26 #include "net/test/gtest_util.h" 26 #include "net/test/gtest_util.h"
27 #include "net/tools/quic/quic_simple_server_stream.h" 27 #include "net/tools/quic/quic_simple_server_stream.h"
28 #include "net/tools/quic/test_tools/mock_quic_server_session_visitor.h" 28 #include "net/tools/quic/test_tools/mock_quic_server_session_visitor.h"
29 #include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h" 29 #include "net/tools/quic/test_tools/quic_in_memory_cache_peer.h"
30 #include "testing/gmock/include/gmock/gmock.h" 30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h" 31 #include "testing/gtest/include/gtest/gtest.h"
32 32
33 using net::test::CryptoTestUtils; 33 using net::test::CryptoTestUtils;
34 using net::test::GenerateBody;
34 using net::test::MockConnection; 35 using net::test::MockConnection;
35 using net::test::MockConnectionHelper; 36 using net::test::MockConnectionHelper;
36 using net::test::QuicConfigPeer; 37 using net::test::QuicConfigPeer;
37 using net::test::QuicConnectionPeer; 38 using net::test::QuicConnectionPeer;
38 using net::test::QuicSpdyStreamPeer; 39 using net::test::QuicSpdyStreamPeer;
39 using net::test::QuicSentPacketManagerPeer; 40 using net::test::QuicSentPacketManagerPeer;
40 using net::test::QuicSessionPeer; 41 using net::test::QuicSessionPeer;
41 using net::test::QuicSpdySessionPeer; 42 using net::test::QuicSpdySessionPeer;
42 using net::test::QuicSustainedBandwidthRecorderPeer; 43 using net::test::QuicSustainedBandwidthRecorderPeer;
43 using net::test::SupportedVersions; 44 using net::test::SupportedVersions;
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 QuicRandom::GetInstance(), &clock, 170 QuicRandom::GetInstance(), &clock,
170 QuicCryptoServerConfig::ConfigOptions())); 171 QuicCryptoServerConfig::ConfigOptions()));
171 session_->Initialize(); 172 session_->Initialize();
172 visitor_ = QuicConnectionPeer::GetVisitor(connection_); 173 visitor_ = QuicConnectionPeer::GetVisitor(connection_);
173 headers_stream_ = new MockQuicHeadersStream(session_.get()); 174 headers_stream_ = new MockQuicHeadersStream(session_.get());
174 QuicSpdySessionPeer::SetHeadersStream(session_.get(), headers_stream_); 175 QuicSpdySessionPeer::SetHeadersStream(session_.get(), headers_stream_);
175 // TODO(jri): Remove this line once tests pass. 176 // TODO(jri): Remove this line once tests pass.
176 FLAGS_quic_cede_correctly = false; 177 FLAGS_quic_cede_correctly = false;
177 } 178 }
178 179
179 // Given |num_resources|, create this number of fake push resources and push
180 // them by sending PUSH_PROMISE for all and sending push responses for as much
181 // as possible(limited by kMaxStreamsForTest).
182 // If |num_resources| > kMaxStreamsForTest, the left over will be queued.
183 void PromisePushResources(size_t num_resources) {
184 // Assume encryption already established.
185 MockQuicCryptoServerStream* crypto_stream =
186 new MockQuicCryptoServerStream(&crypto_config_, session_.get());
187 crypto_stream->set_encryption_established(true);
188 QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
189
190 QuicInMemoryCachePeer::ResetForTests();
191
192 string request_url = "mail.google.com/";
193 SpdyHeaderBlock request_headers;
194 string resource_host = "www.google.com";
195 string partial_push_resource_path = "/server_push_src";
196 string partial_push_response_body =
197 "Push resource body " + partial_push_resource_path;
198 list<QuicInMemoryCache::ServerPushInfo> push_resources;
199 string scheme = "http";
200 for (unsigned int i = 1; i <= num_resources; ++i) {
201 string path = partial_push_resource_path + base::UintToString(i);
202 string url = scheme + "://" + resource_host + path;
203 GURL resource_url = GURL(url);
204 string body = partial_push_response_body + base::UintToString(i);
205 SpdyHeaderBlock response_headers;
206 QuicInMemoryCache::GetInstance()->AddSimpleResponse(resource_host, path,
207 200, body);
208 push_resources.push_back(QuicInMemoryCache::ServerPushInfo(
209 resource_url, response_headers, kDefaultPriority, body));
210 // PUSH_PROMISED are sent for all the resources.
211 EXPECT_CALL(*headers_stream_,
212 WritePushPromise(kClientDataStreamId1, i * 2, _, nullptr));
213 if (i <= kMaxStreamsForTest) {
214 // |kMaxStreamsForTest| promised responses should be sent.
215 EXPECT_CALL(*headers_stream_,
216 WriteHeaders(i * 2, _, false, kDefaultPriority, nullptr));
217 // Mock that SendStreamData() returns less than supposed to send to keep
218 // the stream open.
219 EXPECT_CALL(*connection_, SendStreamData(i * 2, _, 0, true, _, nullptr))
220 .WillOnce(Return(QuicConsumedData(0, false)));
221 }
222 }
223 session_->PromisePushResources(request_url, push_resources,
224 kClientDataStreamId1, request_headers);
225 }
226
227 StrictMock<MockQuicServerSessionVisitor> owner_; 180 StrictMock<MockQuicServerSessionVisitor> owner_;
228 MockConnectionHelper helper_; 181 MockConnectionHelper helper_;
229 StrictMock<MockConnectionWithSendStreamData>* connection_; 182 StrictMock<MockConnectionWithSendStreamData>* connection_;
230 QuicConfig config_; 183 QuicConfig config_;
231 QuicCryptoServerConfig crypto_config_; 184 QuicCryptoServerConfig crypto_config_;
232 scoped_ptr<QuicSimpleServerSession> session_; 185 scoped_ptr<QuicSimpleServerSession> session_;
233 scoped_ptr<CryptoHandshakeMessage> handshake_message_; 186 scoped_ptr<CryptoHandshakeMessage> handshake_message_;
234 QuicConnectionVisitorInterface* visitor_; 187 QuicConnectionVisitorInterface* visitor_;
235 MockQuicHeadersStream* headers_stream_; 188 MockQuicHeadersStream* headers_stream_;
236 }; 189 };
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 } 349 }
397 350
398 TEST_P(QuicSimpleServerSessionTest, OnStreamFrameWithEvenStreamId) { 351 TEST_P(QuicSimpleServerSessionTest, OnStreamFrameWithEvenStreamId) {
399 QuicStreamFrame frame(2, false, 0, StringPiece()); 352 QuicStreamFrame frame(2, false, 0, StringPiece());
400 EXPECT_CALL(*connection_, SendConnectionCloseWithDetails( 353 EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(
401 QUIC_INVALID_STREAM_ID, 354 QUIC_INVALID_STREAM_ID,
402 "Client sent data on server push stream")); 355 "Client sent data on server push stream"));
403 session_->OnStreamFrame(frame); 356 session_->OnStreamFrame(frame);
404 } 357 }
405 358
406 TEST_P(QuicSimpleServerSessionTest, TestPromisePushResources) { 359 TEST_P(QuicSimpleServerSessionTest, GetEvenIncomingError) {
360 // Tests that calling GetOrCreateDynamicStream() on an outgoing stream not
361 // promised yet should result close connection.
362 EXPECT_CALL(*connection_,
363 SendConnectionCloseWithDetails(QUIC_INVALID_STREAM_ID,
364 "Data for nonexistent stream"));
365 EXPECT_EQ(nullptr,
366 QuicSessionPeer::GetOrCreateDynamicStream(session_.get(), 4));
367 }
368
369 // In order to test the case where server push stream creation goes beyond
370 // limit, server push streams need to be hanging there instead of
371 // immediately closing after sending back response.
372 // To achieve this goal, this class resets flow control windows so that large
373 // responses will not be sent fully in order to prevent push streams from being
374 // closed immediately.
375 // Also adjust connection-level flow control window to ensure a large response
376 // can cause stream-level flow control blocked but not connection-level.
377 class QuicSimpleServerSessionServerPushTest
378 : public QuicSimpleServerSessionTest {
379 protected:
380 const size_t kStreamFlowControlWindowSize = 32 * 1024; // 32KB.
381
382 QuicSimpleServerSessionServerPushTest() : QuicSimpleServerSessionTest() {
383 // This flag has to be true for negotiation of max number of outgoing
384 // streams to work correctly.
385 FLAGS_quic_different_max_num_open_streams = true;
386
387 config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest);
388
389 // Reset stream level flow control window to be 32KB.
390 QuicConfigPeer::SetReceivedInitialStreamFlowControlWindow(
391 &config_, kStreamFlowControlWindowSize);
392 // Reset connection level flow control window to be 1.5 MB which is large
393 // enough that it won't block any stream to write before stream level flow
394 // control blocks it.
395 QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
396 &config_, kInitialSessionFlowControlWindowForTest);
397
398 connection_ = new StrictMock<MockConnectionWithSendStreamData>(
399 &helper_, Perspective::IS_SERVER, SupportedVersions(GetParam()));
400 session_.reset(new QuicSimpleServerSession(config_, connection_, &owner_,
401 &crypto_config_));
402 session_->Initialize();
403 // Needed to make new session flow control window work.
404 session_->OnConfigNegotiated();
405
406 visitor_ = QuicConnectionPeer::GetVisitor(connection_);
407 headers_stream_ = new MockQuicHeadersStream(session_.get());
408 QuicSpdySessionPeer::SetHeadersStream(session_.get(), headers_stream_);
409
410 // Assume encryption already established.
411 MockQuicCryptoServerStream* crypto_stream =
412 new MockQuicCryptoServerStream(&crypto_config_, session_.get());
413 crypto_stream->set_encryption_established(true);
414 QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream);
415 }
416
417 // Given |num_resources|, create this number of fake push resources and push
418 // them by sending PUSH_PROMISE for all and sending push responses for as much
419 // as possible(limited by kMaxStreamsForTest).
420 // If |num_resources| > kMaxStreamsForTest, the left over will be queued.
421 void PromisePushResources(size_t num_resources) {
422 // To prevent push streams from being closed the response need to be larger
423 // than stream flow control window so stream won't send the full body.
424 size_t body_size = 2 * kStreamFlowControlWindowSize; // 64KB.
425
426 config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest);
427
428 QuicInMemoryCachePeer::ResetForTests();
429
430 string request_url = "mail.google.com/";
431 SpdyHeaderBlock request_headers;
432 string resource_host = "www.google.com";
433 string partial_push_resource_path = "/server_push_src";
434 list<QuicInMemoryCache::ServerPushInfo> push_resources;
435 string scheme = "http";
436 for (unsigned int i = 1; i <= num_resources; ++i) {
437 QuicStreamId stream_id = i * 2;
438 string path = partial_push_resource_path + base::UintToString(i);
439 string url = scheme + "://" + resource_host + path;
440 GURL resource_url = GURL(url);
441 string body;
442 GenerateBody(&body, body_size);
443 SpdyHeaderBlock response_headers;
444 QuicInMemoryCache::GetInstance()->AddSimpleResponse(resource_host, path,
445 200, body);
446 push_resources.push_back(QuicInMemoryCache::ServerPushInfo(
447 resource_url, response_headers, kDefaultPriority, body));
448 // PUSH_PROMISED are sent for all the resources.
449 EXPECT_CALL(*headers_stream_, WritePushPromise(kClientDataStreamId1,
450 stream_id, _, nullptr));
451 if (i <= kMaxStreamsForTest) {
452 // |kMaxStreamsForTest| promised responses should be sent.
453 EXPECT_CALL(*headers_stream_, WriteHeaders(stream_id, _, false,
454 kDefaultPriority, nullptr));
455 // Since flow control window is smaller than response body, not the
456 // whole body will be sent.
457 EXPECT_CALL(*connection_,
458 SendStreamData(stream_id, _, 0, false, _, nullptr))
459 .WillOnce(
460 Return(QuicConsumedData(kStreamFlowControlWindowSize, false)));
461 EXPECT_CALL(*connection_, SendBlocked(stream_id));
462 }
463 }
464 session_->PromisePushResources(request_url, push_resources,
465 kClientDataStreamId1, request_headers);
466 }
467 };
468
469 INSTANTIATE_TEST_CASE_P(Tests,
470 QuicSimpleServerSessionServerPushTest,
471 ::testing::ValuesIn(QuicSupportedVersions()));
472
473 TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
407 // Tests that given more than kMaxOpenStreamForTest resources, all their 474 // Tests that given more than kMaxOpenStreamForTest resources, all their
408 // PUSH_PROMISE's will be sent out and only |kMaxOpenStreamForTest| streams 475 // PUSH_PROMISE's will be sent out and only |kMaxOpenStreamForTest| streams
409 // will be opened and send push response. 476 // will be opened and send push response.
410 size_t num_resources = kMaxStreamsForTest + 5; 477 size_t num_resources = kMaxStreamsForTest + 5;
411 PromisePushResources(num_resources); 478 PromisePushResources(num_resources);
412 EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams()); 479 EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
413 } 480 }
414 481
415 TEST_P(QuicSimpleServerSessionTest, 482 TEST_P(QuicSimpleServerSessionServerPushTest,
416 HandlePromisedPushRequestsAfterStreamDraining) { 483 HandlePromisedPushRequestsAfterStreamDraining) {
417 // Tests that after promised stream queued up, when an opened stream is marked 484 // Tests that after promised stream queued up, when an opened stream is marked
418 // draining, a queued promised stream will become open and send push response. 485 // draining, a queued promised stream will become open and send push response.
419 size_t num_resources = kMaxStreamsForTest + 1; 486 size_t num_resources = kMaxStreamsForTest + 1;
420 PromisePushResources(num_resources); 487 PromisePushResources(num_resources);
421 QuicStreamId next_out_going_stream_id = num_resources * 2; 488 QuicStreamId next_out_going_stream_id = num_resources * 2;
422 489
423 // After an open stream is marked draining, a new stream is expected to be 490 // After an open stream is marked draining, a new stream is expected to be
424 // created and a response sent on the stream. 491 // created and a response sent on the stream.
425 EXPECT_CALL(*headers_stream_, WriteHeaders(next_out_going_stream_id, _, false, 492 EXPECT_CALL(*headers_stream_, WriteHeaders(next_out_going_stream_id, _, false,
426 kDefaultPriority, nullptr)); 493 kDefaultPriority, nullptr));
427 EXPECT_CALL(*connection_, 494 EXPECT_CALL(*connection_,
428 SendStreamData(next_out_going_stream_id, _, 0, true, _, nullptr)) 495 SendStreamData(next_out_going_stream_id, _, 0, false, _, nullptr))
429 .WillOnce(Return(QuicConsumedData(0, false))); 496 .WillOnce(Return(QuicConsumedData(kStreamFlowControlWindowSize, false)));
497 EXPECT_CALL(*connection_, SendBlocked(next_out_going_stream_id));
430 session_->StreamDraining(2); 498 session_->StreamDraining(2);
431 // Number of open outgoing streams should still be the same, because a new 499 // Number of open outgoing streams should still be the same, because a new
432 // stream is opened. And the queue should be empty. 500 // stream is opened. And the queue should be empty.
433 EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams()); 501 EXPECT_EQ(kMaxStreamsForTest, session_->GetNumOpenOutgoingStreams());
434 } 502 }
435 503
436 TEST_P(QuicSimpleServerSessionTest, GetEvenIncomingError) { 504 TEST_P(QuicSimpleServerSessionServerPushTest,
437 // Tests that calling GetOrCreateDynamicStream() on an outgoing stream not 505 ResetPromisedStreamToCancelServerPush) {
438 // promised yet should result close connection.
439 EXPECT_CALL(*connection_,
440 SendConnectionCloseWithDetails(QUIC_INVALID_STREAM_ID,
441 "Data for nonexistent stream"));
442 EXPECT_EQ(nullptr,
443 QuicSessionPeer::GetOrCreateDynamicStream(session_.get(), 4));
444 }
445
446 TEST_P(QuicSimpleServerSessionTest, ResetPromisedStreamToCancelServerPush) {
447 // Tests that after all resources are promised, a RST frame from client can 506 // Tests that after all resources are promised, a RST frame from client can
448 // prevent a promised resource to be send out. 507 // prevent a promised resource to be send out.
449 508
450 // Having two extra resources to be send later. One of them will be reset, so 509 // Having two extra resources to be send later. One of them will be reset, so
451 // when opened stream become close, only one will become open. 510 // when opened stream become close, only one will become open.
452 size_t num_resources = kMaxStreamsForTest + 2; 511 size_t num_resources = kMaxStreamsForTest + 2;
453 PromisePushResources(num_resources); 512 PromisePushResources(num_resources);
454 513
455 // Reset the last stream in the queue. It should be marked cancelled. 514 // Reset the last stream in the queue. It should be marked cancelled.
456 QuicStreamId stream_got_reset = num_resources * 2; 515 QuicStreamId stream_got_reset = num_resources * 2;
457 QuicRstStreamFrame rst(stream_got_reset, QUIC_STREAM_CANCELLED, 0); 516 QuicRstStreamFrame rst(stream_got_reset, QUIC_STREAM_CANCELLED, 0);
458 EXPECT_CALL(*connection_, 517 EXPECT_CALL(*connection_,
459 SendRstStream(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT, 0)); 518 SendRstStream(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT, 0));
460 visitor_->OnRstStream(rst); 519 visitor_->OnRstStream(rst);
461 520
462 // When the first 2 streams becomes draining, the two queued up stream could 521 // When the first 2 streams becomes draining, the two queued up stream could
463 // be created. But since one of them was marked cancelled due to RST frame, 522 // be created. But since one of them was marked cancelled due to RST frame,
464 // only one queued resource will be sent out. 523 // only one queued resource will be sent out.
465 QuicStreamId stream_not_reset = (kMaxStreamsForTest + 1) * 2; 524 QuicStreamId stream_not_reset = (kMaxStreamsForTest + 1) * 2;
466 InSequence s; 525 InSequence s;
467 EXPECT_CALL(*headers_stream_, WriteHeaders(stream_not_reset, _, false, 526 EXPECT_CALL(*headers_stream_, WriteHeaders(stream_not_reset, _, false,
468 kDefaultPriority, nullptr)); 527 kDefaultPriority, nullptr));
469 EXPECT_CALL(*connection_, 528 EXPECT_CALL(*connection_,
470 SendStreamData(stream_not_reset, _, 0, true, _, nullptr)) 529 SendStreamData(stream_not_reset, _, 0, false, _, nullptr))
471 .WillOnce(Return(QuicConsumedData(0, false))); 530 .WillOnce(Return(QuicConsumedData(kStreamFlowControlWindowSize, false)));
531 EXPECT_CALL(*connection_, SendBlocked(stream_not_reset));
472 EXPECT_CALL(*headers_stream_, WriteHeaders(stream_got_reset, _, false, 532 EXPECT_CALL(*headers_stream_, WriteHeaders(stream_got_reset, _, false,
473 kDefaultPriority, nullptr)) 533 kDefaultPriority, nullptr))
474 .Times(0); 534 .Times(0);
475 535
476 session_->StreamDraining(2); 536 session_->StreamDraining(2);
477 session_->StreamDraining(4); 537 session_->StreamDraining(4);
478 } 538 }
479 539
480 TEST_P(QuicSimpleServerSessionTest, CloseStreamToHandleMorePromisedStream) { 540 TEST_P(QuicSimpleServerSessionServerPushTest,
541 CloseStreamToHandleMorePromisedStream) {
481 // Tests that closing a open outgoing stream can trigger a promised resource 542 // Tests that closing a open outgoing stream can trigger a promised resource
482 // in the queue to be send out. 543 // in the queue to be send out.
483 size_t num_resources = kMaxStreamsForTest + 1; 544 size_t num_resources = kMaxStreamsForTest + 1;
484 PromisePushResources(num_resources); 545 PromisePushResources(num_resources);
485 QuicStreamId stream_to_open = num_resources * 2; 546 QuicStreamId stream_to_open = num_resources * 2;
486 547
487 // Resetting 1st open stream will close the stream and give space for extra 548 // Resetting 1st open stream will close the stream and give space for extra
488 // stream to be opened. 549 // stream to be opened.
489 QuicStreamId stream_got_reset = 2; 550 QuicStreamId stream_got_reset = 2;
490 EXPECT_CALL(*connection_, 551 EXPECT_CALL(*connection_,
491 SendRstStream(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT, _)); 552 SendRstStream(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT, _));
492 EXPECT_CALL(*headers_stream_, WriteHeaders(stream_to_open, _, false, 553 EXPECT_CALL(*headers_stream_, WriteHeaders(stream_to_open, _, false,
493 kDefaultPriority, nullptr)); 554 kDefaultPriority, nullptr));
494 EXPECT_CALL(*connection_, 555 EXPECT_CALL(*connection_,
495 SendStreamData(stream_to_open, _, 0, true, _, nullptr)) 556 SendStreamData(stream_to_open, _, 0, false, _, nullptr))
496 .WillOnce(Return(QuicConsumedData(0, false))); 557 .WillOnce(Return(QuicConsumedData(kStreamFlowControlWindowSize, false)));
497 558
559 EXPECT_CALL(*connection_, SendBlocked(stream_to_open));
498 QuicRstStreamFrame rst(stream_got_reset, QUIC_STREAM_CANCELLED, 0); 560 QuicRstStreamFrame rst(stream_got_reset, QUIC_STREAM_CANCELLED, 0);
499 visitor_->OnRstStream(rst); 561 visitor_->OnRstStream(rst);
500 } 562 }
501 563
502 } // namespace 564 } // namespace
503 } // namespace test 565 } // namespace test
504 } // namespace net 566 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698