Server.php 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. <?php
  2. /**
  3. * Hoa
  4. *
  5. *
  6. * @license
  7. *
  8. * New BSD License
  9. *
  10. * Copyright © 2007-2017, Hoa community. All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions are met:
  14. * * Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * * Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. * * Neither the name of the Hoa nor the names of its contributors may be
  20. * used to endorse or promote products derived from this software without
  21. * specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  24. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
  27. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  30. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  31. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  32. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. namespace Hoa\Socket\Test\Unit;
  36. use Hoa\Socket\Server as SUT;
  37. use Hoa\Stream;
  38. use Hoa\Test;
  39. /**
  40. * Class \Hoa\Socket\Test\Unit\Server.
  41. *
  42. * Test suite for the server object.
  43. *
  44. * @copyright Copyright © 2007-2017 Hoa community
  45. * @license New BSD License
  46. */
  47. class Server extends Test\Unit\Suite
  48. {
  49. public function case_is_a_connection()
  50. {
  51. $this
  52. ->given($this->mockGenerator->orphanize('__construct'))
  53. ->when($result = new \Mock\Hoa\Socket\Server())
  54. ->then
  55. ->object($result)
  56. ->isInstanceOf('Hoa\Socket\Connection');
  57. }
  58. public function case_constructor()
  59. {
  60. $this
  61. ->given(
  62. $socket = 'tcp://hoa-project.net:80',
  63. $timeout = 42,
  64. $flag = SUT::BIND,
  65. $context = 'foo'
  66. )
  67. ->when($result = new SUT($socket, $timeout, $flag, $context))
  68. ->then
  69. ->let($_socket = $result->getSocket())
  70. ->object($_socket)
  71. ->isInstanceOf('Hoa\Socket\Socket')
  72. ->integer($_socket->getAddressType())
  73. ->isEqualTo($_socket::ADDRESS_DOMAIN)
  74. ->string($_socket->getTransport())
  75. ->isEqualTo('tcp')
  76. ->string($_socket->getAddress())
  77. ->isEqualTo('hoa-project.net')
  78. ->integer($_socket->getPort())
  79. ->isEqualTo(80)
  80. ->boolean($_socket->isSecured())
  81. ->isFalse()
  82. ->integer($result->getTimeout())
  83. ->isEqualTo($timeout)
  84. ->integer($result->getFlag())
  85. ->isEqualTo($flag | SUT::LISTEN)
  86. ->string($result->getContext())
  87. ->isEqualTo($context);
  88. }
  89. public function case_constructor_no_flag_with_tcp()
  90. {
  91. $this
  92. ->given(
  93. $socket = 'tcp://hoa-project.net:80',
  94. $timeout = 42
  95. )
  96. ->when($result = new SUT($socket, $timeout))
  97. ->then
  98. ->let($_socket = $result->getSocket())
  99. ->string($_socket->getTransport())
  100. ->isEqualTo('tcp')
  101. ->integer($result->getFlag())
  102. ->isEqualTo(SUT::BIND | SUT::LISTEN);
  103. }
  104. public function case_constructor_no_flag_with_udp()
  105. {
  106. $this
  107. ->given(
  108. $socket = 'udp://hoa-project.net:80',
  109. $timeout = 42
  110. )
  111. ->when($result = new SUT($socket, $timeout))
  112. ->then
  113. ->let($_socket = $result->getSocket())
  114. ->string($_socket->getTransport())
  115. ->isEqualTo('udp')
  116. ->integer($result->getFlag())
  117. ->isEqualTo(SUT::BIND);
  118. }
  119. public function case_constructor_with_flag_and_tcp()
  120. {
  121. $this
  122. ->given(
  123. $socket = 'tcp://hoa-project.net:80',
  124. $timeout = 42,
  125. $flag = SUT::BIND
  126. )
  127. ->when($result = new SUT($socket, $timeout, $flag))
  128. ->then
  129. ->let($_socket = $result->getSocket())
  130. ->string($_socket->getTransport())
  131. ->isEqualTo('tcp')
  132. ->integer($result->getFlag())
  133. ->isEqualTo(SUT::BIND | SUT::LISTEN);
  134. }
  135. public function case_constructor_with_flag_and_udp()
  136. {
  137. $this
  138. ->given(
  139. $socket = 'udp://hoa-project.net:80',
  140. $timeout = 42,
  141. $flag = SUT::BIND
  142. )
  143. ->when($result = new SUT($socket, $timeout, $flag))
  144. ->then
  145. ->let($_socket = $result->getSocket())
  146. ->string($_socket->getTransport())
  147. ->isEqualTo('udp')
  148. ->integer($result->getFlag())
  149. ->isEqualTo($flag);
  150. }
  151. public function case_constructor_with_flag_and_udp_listen_not_allowed()
  152. {
  153. $this
  154. ->given(
  155. $socket = 'udp://hoa-project.net:80',
  156. $timeout = 42,
  157. $flag = SUT::LISTEN
  158. )
  159. ->exception(function () use ($socket, $timeout, $flag) {
  160. new SUT($socket, $timeout, $flag);
  161. })
  162. ->isInstanceOf('Hoa\Socket\Exception');
  163. }
  164. public function case_open_cannot_join()
  165. {
  166. $self = $this;
  167. $this
  168. ->given(
  169. $this->mockGenerator->orphanize('__construct'),
  170. $server = new \Mock\Hoa\Socket\Server(),
  171. $streamName = 'foobar',
  172. $flag = SUT::BIND | SUT::LISTEN,
  173. $this->calling($server)->getFlag = $flag,
  174. $this->function->stream_socket_server = function ($_streamName, &$_errno, &$_errstr, $_flag) use ($self, &$called, $streamName, $flag) {
  175. $called = true;
  176. $_errno = 0;
  177. $self
  178. ->string($_streamName)
  179. ->isEqualTo($streamName)
  180. ->integer($_flag)
  181. ->isEqualTo($flag);
  182. return false;
  183. }
  184. )
  185. ->exception(function () use ($self, $server, $streamName) {
  186. $self->invoke($server)->_open($streamName);
  187. })
  188. ->isInstanceOf('Hoa\Socket\Exception')
  189. ->hasCode(1)
  190. ->boolean($called)
  191. ->isTrue();
  192. }
  193. public function case_open()
  194. {
  195. $self = $this;
  196. $this
  197. ->given(
  198. $this->mockGenerator->orphanize('__construct'),
  199. $server = new \Mock\Hoa\Socket\Server(),
  200. $streamName = 'foobar',
  201. $flag = SUT::BIND | SUT::LISTEN,
  202. $oldMasters = $this->invoke($server)->getMasters(),
  203. $oldServers = $this->invoke($server)->getServers(),
  204. $oldStack = $this->invoke($server)->getStack(),
  205. $this->calling($server)->getFlag = $flag,
  206. $this->function->stream_socket_server = function ($_streamName, &$_errno, &$_errstr, $_flag) use ($self, &$called, $streamName, $flag) {
  207. $called = true;
  208. $self
  209. ->string($_streamName)
  210. ->isEqualTo($streamName)
  211. ->integer($_flag)
  212. ->isEqualTo($flag);
  213. return fopen(__FILE__, 'r');
  214. }
  215. )
  216. ->when($result = $this->invoke($server)->_open($streamName))
  217. ->then
  218. ->resource($result)
  219. ->let($masters = $this->invoke($server)->getMasters())
  220. ->integer(count($masters))
  221. ->isEqualTo(count($oldMasters) + 1)
  222. ->isEqualTo(1)
  223. ->array($masters)
  224. ->resource($masters[0])
  225. ->isIdenticalTo($result)
  226. ->let($servers = $this->invoke($server)->getServers())
  227. ->integer(count($servers))
  228. ->isEqualTo(count($oldServers) + 1)
  229. ->isEqualTo(1)
  230. ->array($servers)
  231. ->object($servers[0])
  232. ->isIdenticalTo($server)
  233. ->let($stack = $this->invoke($server)->getStack())
  234. ->integer(count($stack))
  235. ->isEqualTo(count($oldStack) + 1)
  236. ->isEqualTo(1)
  237. ->array($stack)
  238. ->resource($stack[0])
  239. ->isIdenticalTo($result);
  240. }
  241. public function case_open_with_context()
  242. {
  243. $self = $this;
  244. $this
  245. ->given(
  246. $this->mockGenerator->orphanize('__construct'),
  247. $server = new \Mock\Hoa\Socket\Server(),
  248. $streamName = 'foobar',
  249. $context = Stream\Context::getInstance('foo'),
  250. $flag = SUT::BIND | SUT::LISTEN,
  251. $oldMasters = $this->invoke($server)->getMasters(),
  252. $oldServers = $this->invoke($server)->getServers(),
  253. $oldStack = $this->invoke($server)->getStack(),
  254. $this->calling($server)->getFlag = $flag,
  255. $this->function->stream_socket_server = function ($_streamName, &$_errno, &$_errstr, $_flag, $_context) use ($self, &$called, $streamName, $flag, $context) {
  256. $called = true;
  257. $self
  258. ->string($_streamName)
  259. ->isEqualTo($streamName)
  260. ->integer($_flag)
  261. ->isEqualTo($flag)
  262. ->resource($_context)
  263. ->isStreamContext()
  264. ->isIdenticalTo($context->getContext());
  265. return fopen(__FILE__, 'r');
  266. }
  267. )
  268. ->when($result = $this->invoke($server)->_open($streamName, $context))
  269. ->then
  270. ->resource($result)
  271. ->let($masters = $this->invoke($server)->getMasters())
  272. ->integer(count($masters))
  273. ->isEqualTo(count($oldMasters) + 1)
  274. ->isEqualTo(1)
  275. ->array($masters)
  276. ->resource($masters[0])
  277. ->isIdenticalTo($result)
  278. ->let($servers = $this->invoke($server)->getServers())
  279. ->integer(count($servers))
  280. ->isEqualTo(count($oldServers) + 1)
  281. ->isEqualTo(1)
  282. ->array($servers)
  283. ->object($servers[0])
  284. ->isIdenticalTo($server)
  285. ->let($stack = $this->invoke($server)->getStack())
  286. ->integer(count($stack))
  287. ->isEqualTo(count($oldStack) + 1)
  288. ->isEqualTo(1)
  289. ->array($stack)
  290. ->resource($stack[0])
  291. ->isIdenticalTo($result);
  292. }
  293. public function case_connect_timed_out()
  294. {
  295. $self = $this;
  296. $this
  297. ->given(
  298. $this->mockGenerator->orphanize('__construct'),
  299. $streamName = 'tcp://hoa-project.net:80',
  300. $server = new SUT($streamName),
  301. $this->function->stream_socket_server = fopen(__FILE__, 'r'),
  302. $master = $this->invoke($server)->_open($streamName),
  303. $this->function->stream_socket_accept = function ($_master) use ($self, &$called, $master) {
  304. $called = true;
  305. $self
  306. ->resource($_master)
  307. ->isEqualTo($master);
  308. return false;
  309. }
  310. )
  311. ->exception(function () use ($server) {
  312. $server->connect();
  313. })
  314. ->isInstanceOf('Hoa\Socket\Exception')
  315. ->boolean($called)
  316. ->isTrue();
  317. }
  318. public function case_connect()
  319. {
  320. $self = $this;
  321. $this
  322. ->given(
  323. $this->mockGenerator->orphanize('__construct'),
  324. $streamName = 'tcp://hoa-project.net:80',
  325. $server = new SUT($streamName),
  326. $this->function->stream_socket_server = fopen(__FILE__, 'r'),
  327. $master = $this->invoke($server)->_open($streamName),
  328. $this->function->stream_socket_accept = function ($_master) use ($self, &$called, $master, &$client) {
  329. $called = true;
  330. $self
  331. ->resource($_master)
  332. ->isEqualTo($master);
  333. return $client = fopen(__FILE__, 'r');
  334. }
  335. )
  336. ->when($result = $server->connect())
  337. ->then
  338. ->object($result)
  339. ->isIdenticalTo($server)
  340. ->boolean($called)
  341. ->isTrue()
  342. ->resource($server->getStream())
  343. ->isIdenticalTo($client);
  344. }
  345. public function case_connect_and_wait()
  346. {
  347. $self = $this;
  348. $this
  349. ->given(
  350. $this->mockGenerator->orphanize('__construct'),
  351. $streamName = 'tcp://hoa-project.net:80',
  352. $server = new SUT($streamName),
  353. $this->function->stream_socket_server = fopen(__FILE__, 'r'),
  354. $master = $this->invoke($server)->_open($streamName),
  355. $this->function->stream_socket_accept = function () use (&$called) {
  356. $called = true;
  357. return false;
  358. }
  359. )
  360. ->when($result = $server->connectAndWait())
  361. ->then
  362. ->object($result)
  363. ->isIdenticalTo($server)
  364. ->variable($called)
  365. ->isNotEqualTo(true);
  366. }
  367. public function case_select_not_a_master()
  368. {
  369. $self = $this;
  370. $this
  371. ->given(
  372. $this->mockGenerator->orphanize('__construct'),
  373. $server = new \Mock\Hoa\Socket\Server(),
  374. $stack = ['foo'],
  375. $timeout = 42,
  376. $oldIteratorValues = $this->invoke($server)->getIteratorValues(),
  377. $this->calling($server)->getTimeout = $timeout,
  378. $this->function->stream_select = function (&$_read, &$_write, &$_except, $_timeout, $_ttimeout) use ($self, &$called, $stack, $timeout) {
  379. $called = true;
  380. $self
  381. ->array($_read)
  382. ->variable($_write)
  383. ->isNull()
  384. ->variable($_except)
  385. ->isNull()
  386. ->integer($_timeout)
  387. ->isEqualTo($timeout)
  388. ->integer($_ttimeout)
  389. ->isZero();
  390. $_read = $stack;
  391. return;
  392. },
  393. $this->function->in_array = false
  394. )
  395. ->when($result = $server->select())
  396. ->then
  397. ->object($result)
  398. ->isIdenticalTo($server)
  399. ->boolean($called)
  400. ->isTrue()
  401. ->let($iteratorValues = $this->invoke($server)->getIteratorValues())
  402. ->integer(count($iteratorValues))
  403. ->isEqualTo(count($oldIteratorValues) + 1);
  404. }
  405. public function case_select_timed_out()
  406. {
  407. $self = $this;
  408. $this
  409. ->given(
  410. $this->mockGenerator->orphanize('__construct'),
  411. $server = new \Mock\Hoa\Socket\Server(),
  412. $stack = ['foo'],
  413. $timeout = 42,
  414. $this->calling($server)->getTimeout = $timeout,
  415. $this->function->stream_select = function (&$_read, &$_write, &$_except, $_timeout, $_ttimeout) use ($self, &$called0, $stack, $timeout) {
  416. $called0 = true;
  417. $self
  418. ->array($_read)
  419. ->variable($_write)
  420. ->isNull()
  421. ->variable($_except)
  422. ->isNull()
  423. ->integer($_timeout)
  424. ->isEqualTo($timeout)
  425. ->integer($_ttimeout)
  426. ->isZero();
  427. $_read = $stack;
  428. return;
  429. },
  430. $this->function->in_array = true,
  431. $this->function->stream_socket_accept = function () use (&$called1) {
  432. $called1 = true;
  433. return false;
  434. }
  435. )
  436. ->exception(function () use ($server) {
  437. $server->select();
  438. })
  439. ->isInstanceOf('Hoa\Socket\Exception')
  440. ->boolean($called0)
  441. ->isTrue()
  442. ->boolean($called1)
  443. ->isTrue();
  444. }
  445. public function case_consider_client()
  446. {
  447. $this->_case_consider_client(false);
  448. }
  449. public function case_consider_disconnected_client()
  450. {
  451. $this->_case_consider_client(true);
  452. }
  453. protected function _case_consider_client($disconnected)
  454. {
  455. $this
  456. ->given(
  457. $this->mockGenerator->orphanize('__construct'),
  458. $server = new \Mock\Hoa\Socket\Server(),
  459. $this->mockGenerator->orphanize('__construct'),
  460. $other = new \Mock\Hoa\Socket\Client(),
  461. $oldMasters = $this->invoke($server)->getMasters(),
  462. $oldServers = $this->invoke($server)->getServers(),
  463. $oldStack = $this->invoke($server)->getStack(),
  464. $this->calling($other)->isDisconnected = $disconnected,
  465. $this->calling($other)->connect = function () use (&$called) {
  466. $called = true;
  467. }
  468. )
  469. ->when($result = $server->consider($other))
  470. ->then
  471. ->object($result)
  472. ->isIdenticalTo($server)
  473. ->let($masters = $this->invoke($server)->getMasters())
  474. ->integer(count($masters))
  475. ->isEqualTo(count($oldMasters))
  476. ->let($servers = $this->invoke($server)->getServers())
  477. ->integer(count($servers))
  478. ->isEqualTo(count($oldServers))
  479. ->let($stack = $this->invoke($server)->getStack())
  480. ->integer(count($stack))
  481. ->isEqualTo(count($oldStack) + 1)
  482. ->variable($called)
  483. ->isEqualTo($disconnected ?: null);
  484. }
  485. public function case_consider()
  486. {
  487. $this->_case_consider(false);
  488. }
  489. public function case_consider_disconnected_other()
  490. {
  491. $this->_case_consider(true);
  492. }
  493. protected function _case_consider($disconnected)
  494. {
  495. $this
  496. ->given(
  497. $this->mockGenerator->orphanize('__construct'),
  498. $server = new \Mock\Hoa\Socket\Server(),
  499. $this->mockGenerator->orphanize('__construct'),
  500. $other = new \Mock\Hoa\Socket\Server(),
  501. $oldMasters = $this->invoke($server)->getMasters(),
  502. $oldServers = $this->invoke($server)->getServers(),
  503. $oldStack = $this->invoke($server)->getStack(),
  504. $this->calling($other)->isDisconnected = $disconnected,
  505. $this->calling($other)->connectAndWait = function () use (&$called) {
  506. $called = true;
  507. }
  508. )
  509. ->when($result = $server->consider($other))
  510. ->then
  511. ->object($result)
  512. ->isIdenticalTo($server)
  513. ->let($masters = $this->invoke($server)->getMasters())
  514. ->integer(count($masters))
  515. ->isEqualTo(count($oldMasters) + 1)
  516. ->let($servers = $this->invoke($server)->getServers())
  517. ->integer(count($servers))
  518. ->isEqualTo(count($oldServers) + 1)
  519. ->let($stack = $this->invoke($server)->getStack())
  520. ->integer(count($stack))
  521. ->isEqualTo(count($oldStack) + 1)
  522. ->variable($called)
  523. ->isEqualTo($disconnected ?: null);
  524. }
  525. public function case_is()
  526. {
  527. $this
  528. ->given(
  529. $this->mockGenerator->orphanize('__construct'),
  530. $connection = new \Mock\Hoa\Socket\Connection()
  531. )
  532. ->_case_is($connection, $connection)
  533. ->isTrue();
  534. }
  535. public function case_is_not()
  536. {
  537. $this
  538. ->given(
  539. $this->mockGenerator->orphanize('__construct'),
  540. $nodeConnection = new \Mock\Hoa\Socket\Connection(),
  541. $connection = clone $nodeConnection
  542. )
  543. ->_case_is($nodeConnection, $connection)
  544. ->isFalse();
  545. }
  546. protected function _case_is($nodeConnection, $connection)
  547. {
  548. return
  549. $this
  550. ->given(
  551. $this->mockGenerator->orphanize('__construct'),
  552. $server = new \Mock\Hoa\Socket\Server(),
  553. $this->mockGenerator->orphanize('__construct'),
  554. $node = new \Mock\Hoa\Socket\Node(),
  555. $this->calling($server)->getCurrentNode = $node,
  556. $this->calling($node)->getConnection = $nodeConnection
  557. )
  558. ->when($result = $server->is($connection))
  559. ->then
  560. ->boolean($result);
  561. }
  562. public function case_is_binding()
  563. {
  564. $this
  565. ->_case_flag_is(SUT::BIND, 'isBinding');
  566. }
  567. public function case_is_Listening()
  568. {
  569. $this
  570. ->_case_flag_is(SUT::LISTEN, 'isListening');
  571. }
  572. protected function _case_flag_is($flag, $method)
  573. {
  574. return
  575. $this
  576. ->given(
  577. $socket = 'tcp://hoa-project.net:80',
  578. $timeout = 42
  579. )
  580. ->when($result = new SUT($socket, $timeout, $flag))
  581. ->then
  582. ->boolean($result->$method())
  583. ->isTrue();
  584. }
  585. }