PageRenderTime 150ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/tests/http/agent-destroyed-socket.t

https://github.com/mamod/Rum
Unknown | 112 lines | 93 code | 19 blank | 0 comment | 0 complexity | 759d49b591cfb1ffdaf43ddb519ca83f MD5 | raw file
  1. use Rum;
  2. use Test::More;
  3. use Data::Dumper;
  4. my $common = Require('../common');
  5. my $assert = Require('assert');
  6. my $http = Require('http');
  7. sub debug {
  8. print @_, "\n";
  9. }
  10. my $server = $http->createServer( sub {
  11. my ($this, $req, $res) = @_;
  12. $res->writeHead(200, {'Content-Type' => 'text/plain'});
  13. $res->end("Hello World\n");
  14. })->listen($common->{PORT});
  15. my $agent = $http->{Agent}->new({maxSockets => 1});
  16. $agent->on('free', sub {
  17. my ($this, $socket, $host, $port) = @_;
  18. debug('freeing socket. destroyed? ', $socket->{destroyed});
  19. });
  20. my $requestOptions = {
  21. agent => $agent,
  22. host => 'localhost',
  23. port => $common->{PORT},
  24. path => '/'
  25. };
  26. my $request2;
  27. my $request1; $request1 = $http->get($requestOptions, sub {
  28. my ($this, $response) = @_;
  29. #assert request2 is queued in the agent
  30. my $key = $agent->getName($requestOptions);
  31. ok(@{$agent->{requests}->{$key}} == 1);
  32. debug('got response1');
  33. $request1->{socket}->on('close', sub {
  34. debug('request1 socket closed');
  35. });
  36. $response->pipe(process->stdout);
  37. $response->on('end', sub {
  38. debug('response1 done');
  39. #/////////////////////////////////
  40. #//
  41. #// THE IMPORTANT PART
  42. #//
  43. #// It is possible for the socket to get destroyed and other work
  44. #// to run before the 'close' event fires because it happens on
  45. #// nextTick. This example is contrived because it destroys the
  46. #// socket manually at just the right time, but at Voxer we have
  47. #// seen cases where the socket is destroyed by non-user code
  48. #// then handed out again by an agent *before* the 'close' event
  49. #// is triggered.
  50. $request1->{socket}->destroy();
  51. $response->once('close', sub {
  52. #assert request2 was removed from the queue
  53. ok(!$agent->{requests}->{$key});
  54. debug("waiting for request2.onSocket's nextTick");
  55. process->nextTick( sub {
  56. #assert that the same socket was not assigned to request2,
  57. #since it was destroyed.
  58. ok($request1->{socket} != $request2->{socket});
  59. ok(!$request2->{socket}->{destroyed}, 'the socket is destroyed');
  60. });
  61. });
  62. });
  63. });
  64. my $gotClose = 0;
  65. my $gotResponseEnd = 0;
  66. $request2 = $http->get($requestOptions, sub {
  67. my ($this, $response) = @_;
  68. ok(!$request2->{socket}->{destroyed});
  69. ok($request1->{socket}->{destroyed});
  70. # assert not reusing the same socket, since it was destroyed.
  71. ok($request1->{socket} != $request2->{socket});
  72. debug('got response2');
  73. $request2->{socket}->on('close', sub {
  74. debug('request2 socket closed');
  75. $gotClose = 1;
  76. done();
  77. });
  78. $response->pipe(process->stdout);
  79. $response->on('end', sub {
  80. debug('response2 done');
  81. $gotResponseEnd = 1;
  82. done();
  83. });
  84. });
  85. sub done {
  86. if ($gotResponseEnd && $gotClose) {
  87. $server->close();
  88. }
  89. }
  90. process->on('exit', sub {
  91. done_testing();
  92. });
  93. 1;