diff --git a/.gitattributes b/.gitattributes index f2f51ddf..64ab6e0f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,4 +3,5 @@ /.travis.yml export-ignore /examples export-ignore /phpunit.xml.dist export-ignore +/phpunit.xml.legacy export-ignore /tests export-ignore diff --git a/.travis.yml b/.travis.yml index 56d2001f..d1d2b11e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: php # lock distro so new future defaults will not break the build dist: trusty -matrix: +jobs: include: - php: 5.3 dist: precise @@ -38,10 +38,9 @@ matrix: - os: osx - os: windows -sudo: false - install: - - composer install --no-interaction + - composer install script: - - vendor/bin/phpunit --coverage-text + - if [[ "$TRAVIS_PHP_VERSION" > "7.2" ]]; then vendor/bin/phpunit --coverage-text; fi + - if [[ "$TRAVIS_PHP_VERSION" < "7.3" ]]; then vendor/bin/phpunit --coverage-text -c phpunit.xml.legacy; fi diff --git a/composer.json b/composer.json index 58cf494d..f0f0b46e 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ }, "require-dev": { "clue/block-react": "^1.2", - "phpunit/phpunit": "^9.0 || ^5.7 || ^4.8.35", + "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35", "react/promise-stream": "^1.2" }, "autoload": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 0e947b87..fa88e7e0 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,15 +1,19 @@ - + + ./tests/ - - - + + ./src/ - - + + diff --git a/phpunit.xml.legacy b/phpunit.xml.legacy new file mode 100644 index 00000000..fbb43e85 --- /dev/null +++ b/phpunit.xml.legacy @@ -0,0 +1,18 @@ + + + + + + + ./tests/ + + + + + ./src/ + + + diff --git a/tests/HappyEyeBallsConnectionBuilderTest.php b/tests/HappyEyeBallsConnectionBuilderTest.php index 52e47ef4..e9b932ff 100644 --- a/tests/HappyEyeBallsConnectionBuilderTest.php +++ b/tests/HappyEyeBallsConnectionBuilderTest.php @@ -290,6 +290,47 @@ public function testConnectWillStartConnectingWithAttemptTimerWhenIpv6AndIpv4Res $deferred->reject(new \RuntimeException()); } + public function testConnectWillStartConnectingWithAlternatingIPv6AndIPv4WhenResolverReturnsMultipleIPAdresses() + { + $timer = $this->getMockBuilder('React\EventLoop\TimerInterface')->getMock(); + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + $loop->expects($this->once())->method('addTimer')->with(0.1, $this->anything())->willReturn($timer); + $loop->expects($this->once())->method('cancelTimer')->with($timer); + + $deferred = new Deferred(); + $connector = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock(); + $connector->expects($this->exactly(4))->method('connect')->withConsecutive( + array('tcp://[::1]:80?hostname=reactphp.org'), + array('tcp://127.0.0.1:80?hostname=reactphp.org'), + array('tcp://[::2]:80?hostname=reactphp.org'), + array('tcp://127.0.0.2:80?hostname=reactphp.org') + )->willReturnOnConsecutiveCalls( + $deferred->promise(), + $deferred->promise(), + $deferred->promise(), + new Promise(function () { }) + ); + + $resolver = $this->getMockBuilder('React\Dns\Resolver\ResolverInterface')->getMock(); + $resolver->expects($this->exactly(2))->method('resolveAll')->withConsecutive( + array('reactphp.org', Message::TYPE_AAAA), + array('reactphp.org', Message::TYPE_A) + )->willReturnOnConsecutiveCalls( + \React\Promise\resolve(array('::1', '::2')), + \React\Promise\resolve(array('127.0.0.1', '127.0.0.2')) + ); + + $uri = 'tcp://reactphp.org:80'; + $host = 'reactphp.org'; + $parts = parse_url($uri); + + $builder = new HappyEyeBallsConnectionBuilder($loop, $connector, $resolver, $uri, $host, $parts); + + $builder->connect(); + + $deferred->reject(new \RuntimeException()); + } + public function testConnectWillStartConnectingWithAttemptTimerWhenOnlyIpv6ResolvesAndWillStartNextConnectionAttemptWithoutAttemptTimerImmediatelyWhenFirstConnectionAttemptFails() { $timer = $this->getMockBuilder('React\EventLoop\TimerInterface')->getMock(); diff --git a/tests/HappyEyeBallsConnectorTest.php b/tests/HappyEyeBallsConnectorTest.php index 209c6aa1..2ed40b25 100644 --- a/tests/HappyEyeBallsConnectorTest.php +++ b/tests/HappyEyeBallsConnectorTest.php @@ -148,8 +148,13 @@ public function testIpv6ResolvesFirstSoIsTheFirstToConnect(array $ipv6, array $i { $deferred = new Deferred(); - $this->resolver->expects($this->at(0))->method('resolveAll')->with('google.com', Message::TYPE_AAAA)->will($this->returnValue(Promise\resolve($ipv6))); - $this->resolver->expects($this->at(1))->method('resolveAll')->with('google.com', Message::TYPE_A)->will($this->returnValue($deferred->promise())); + $this->resolver->expects($this->exactly(2))->method('resolveAll')->withConsecutive( + array('google.com', Message::TYPE_AAAA), + array('google.com', Message::TYPE_A) + )->willReturnOnConsecutiveCalls( + $this->returnValue(Promise\resolve($ipv6)), + $this->returnValue($deferred->promise()) + ); $this->tcp->expects($this->any())->method('connect')->with($this->stringContains(']:80/?hostname=google.com'))->will($this->returnValue(Promise\reject())); $this->connector->connect('scheme://google.com:80/?hostname=google.com'); @@ -168,8 +173,13 @@ public function testIpv6DoesntResolvesWhileIpv4DoesFirstSoIpv4Connects(array $ip { $deferred = new Deferred(); - $this->resolver->expects($this->at(0))->method('resolveAll')->with('google.com', Message::TYPE_AAAA)->will($this->returnValue($deferred->promise())); - $this->resolver->expects($this->at(1))->method('resolveAll')->with('google.com', Message::TYPE_A)->will($this->returnValue(Promise\resolve($ipv4))); + $this->resolver->expects($this->exactly(2))->method('resolveAll')->withConsecutive( + array('google.com', Message::TYPE_AAAA), + array('google.com', Message::TYPE_A) + )->willReturnOnConsecutiveCalls( + $this->returnValue($deferred->promise()), + $this->returnValue(Promise\resolve($ipv4)) + ); $this->tcp->expects($this->any())->method('connect')->with($this->stringContains(':80/?hostname=google.com'))->will($this->returnValue(Promise\reject())); $this->connector->connect('scheme://google.com:80/?hostname=google.com'); @@ -181,38 +191,6 @@ public function testIpv6DoesntResolvesWhileIpv4DoesFirstSoIpv4Connects(array $ip $this->loop->run(); } - /** - * @dataProvider provideIpvAddresses - */ - public function testAttemptsToConnectBothIpv6AndIpv4AddressesAlternatingIpv6AndIpv4AddressesWhenMoreThenOneIsResolvedPerFamily(array $ipv6, array $ipv4) - { - $this->resolver->expects($this->at(0))->method('resolveAll')->with('google.com', Message::TYPE_AAAA)->will($this->returnValue( - Promise\Timer\resolve(0.1, $this->loop)->then(function () use ($ipv6) { - return Promise\resolve($ipv6); - }) - )); - $this->resolver->expects($this->at(1))->method('resolveAll')->with('google.com', Message::TYPE_A)->will($this->returnValue( - Promise\Timer\resolve(0.1, $this->loop)->then(function () use ($ipv4) { - return Promise\resolve($ipv4); - }) - )); - - $i = 0; - while (count($ipv6) > 0 || count($ipv4) > 0) { - if (count($ipv6) > 0) { - $this->tcp->expects($this->at($i++))->method('connect')->with($this->equalTo('scheme://[' . array_shift($ipv6) . ']:80/?hostname=google.com'))->will($this->returnValue(Promise\reject())); - } - if (count($ipv4) > 0) { - $this->tcp->expects($this->at($i++))->method('connect')->with($this->equalTo('scheme://' . array_shift($ipv4) . ':80/?hostname=google.com'))->will($this->returnValue(Promise\reject())); - } - } - - - $this->connector->connect('scheme://google.com:80/?hostname=google.com'); - - $this->loop->run(); - } - public function testRejectsImmediatelyIfUriIsInvalid() { $this->resolver->expects($this->never())->method('resolveAll'); @@ -297,8 +275,13 @@ public function testCancelDuringTcpConnectionCancelsTcpConnectionIfGivenIp() */ public function testShouldConnectOverIpv4WhenIpv6LookupFails(array $ipv6, array $ipv4) { - $this->resolver->expects($this->at(0))->method('resolveAll')->with($this->equalTo('example.com'), Message::TYPE_AAAA)->willReturn(Promise\reject(new \Exception('failure'))); - $this->resolver->expects($this->at(1))->method('resolveAll')->with($this->equalTo('example.com'), Message::TYPE_A)->willReturn(Promise\resolve($ipv4)); + $this->resolver->expects($this->exactly(2))->method('resolveAll')->withConsecutive( + array($this->equalTo('example.com'), Message::TYPE_AAAA), + array($this->equalTo('example.com'), Message::TYPE_A) + )->willReturnOnConsecutiveCalls( + Promise\reject(new \Exception('failure')), + Promise\resolve($ipv4) + ); $this->tcp->expects($this->exactly(1))->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=example.com'))->willReturn(Promise\resolve($this->connection)); $promise = $this->connector->connect('example.com:80');; @@ -316,8 +299,13 @@ public function testShouldConnectOverIpv6WhenIpv4LookupFails(array $ipv6, array $ipv6[] = '1:2:3:4'; } - $this->resolver->expects($this->at(0))->method('resolveAll')->with($this->equalTo('example.com'), Message::TYPE_AAAA)->willReturn(Promise\resolve($ipv6)); - $this->resolver->expects($this->at(1))->method('resolveAll')->with($this->equalTo('example.com'), Message::TYPE_A)->willReturn(Promise\reject(new \Exception('failure'))); + $this->resolver->expects($this->exactly(2))->method('resolveAll')->withConsecutive( + array($this->equalTo('example.com'), Message::TYPE_AAAA), + array($this->equalTo('example.com'), Message::TYPE_A) + )->willReturnOnConsecutiveCalls( + Promise\resolve($ipv6), + Promise\reject(new \Exception('failure')) + ); $this->tcp->expects($this->exactly(1))->method('connect')->with($this->equalTo('[1:2:3:4]:80?hostname=example.com'))->willReturn(Promise\resolve($this->connection)); $promise = $this->connector->connect('example.com:80');;