<?php
+use Wikimedia\TestingAccessWrapper;
+
class EtcConfigTest extends PHPUnit_Framework_TestCase {
private function createConfigMock( array $options = [] ) {
$this->assertSame( 'from-cache-expired', $mock->get( 'known' ) );
}
+
+ public static function provideFetchFromServer() {
+ return [
+ '200 OK - Success' => [
+ 'http' => [
+ 'code' => 200,
+ 'reason' => 'OK',
+ 'headers' => [],
+ 'body' => json_encode( [ 'node' => [ 'nodes' => [
+ [
+ 'key' => '/example/foo',
+ 'value' => json_encode( [ 'val' => true ] )
+ ],
+ ] ] ] ),
+ 'error' => '',
+ ],
+ 'expect' => [
+ [ 'foo' => true ], // data
+ null,
+ false // retry
+ ],
+ ],
+ '200 OK - Skip dir' => [
+ 'http' => [
+ 'code' => 200,
+ 'reason' => 'OK',
+ 'headers' => [],
+ 'body' => json_encode( [ 'node' => [ 'nodes' => [
+ [
+ 'key' => '/example/foo',
+ 'value' => json_encode( [ 'val' => true ] )
+ ],
+ [
+ 'key' => '/example/sub',
+ 'dir' => true
+ ],
+ [
+ 'key' => '/example/bar',
+ 'value' => json_encode( [ 'val' => false ] )
+ ],
+ ] ] ] ),
+ 'error' => '',
+ ],
+ 'expect' => [
+ [ 'foo' => true, 'bar' => false ], // data
+ null,
+ false // retry
+ ],
+ ],
+ '200 OK - Bad value' => [
+ 'http' => [
+ 'code' => 200,
+ 'reason' => 'OK',
+ 'headers' => [],
+ 'body' => json_encode( [ 'node' => [ 'nodes' => [
+ [
+ 'key' => '/example/foo',
+ 'value' => ';"broken{value'
+ ]
+ ] ] ] ),
+ 'error' => '',
+ ],
+ 'expect' => [
+ null, // data
+ "Failed to parse value for 'foo'.",
+ false // retry
+ ],
+ ],
+ '200 OK - Empty node list' => [
+ 'http' => [
+ 'code' => 200,
+ 'reason' => 'OK',
+ 'headers' => [],
+ 'body' => '{"node":{"nodes":[]}}',
+ 'error' => '',
+ ],
+ 'expect' => [
+ [], // data
+ null,
+ false // retry
+ ],
+ ],
+ '200 OK - Invalid JSON' => [
+ 'http' => [
+ 'code' => 200,
+ 'reason' => 'OK',
+ 'headers' => [ 'content-length' => 0 ],
+ 'body' => '',
+ 'error' => '(curl error: no status set)',
+ ],
+ 'expect' => [
+ null, // data
+ "Unexpected JSON response; missing 'nodes' list.",
+ false // retry
+ ],
+ ],
+ '404 Not Found' => [
+ 'http' => [
+ 'code' => 404,
+ 'reason' => 'Not Found',
+ 'headers' => [ 'content-length' => 0 ],
+ 'body' => '',
+ 'error' => '',
+ ],
+ 'expect' => [
+ null, // data
+ 'HTTP 404 (Not Found)',
+ false // retry
+ ],
+ ],
+ '400 Bad Request - custom error' => [
+ 'http' => [
+ 'code' => 400,
+ 'reason' => 'Bad Request',
+ 'headers' => [ 'content-length' => 0 ],
+ 'body' => '',
+ 'error' => 'No good reason',
+ ],
+ 'expect' => [
+ null, // data
+ 'No good reason',
+ true // retry
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @covers EtcdConfig::fetchAllFromEtcdServer
+ * @covers EtcdConfig::unserialize
+ * @dataProvider provideFetchFromServer
+ */
+ public function testFetchFromServer( array $httpResponse, array $expected ) {
+ $http = $this->getMockBuilder( MultiHttpClient::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $http->expects( $this->once() )->method( 'run' )
+ ->willReturn( array_values( $httpResponse ) );
+
+ $conf = $this->getMockBuilder( EtcdConfig::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+ // Access for protected member and method
+ $conf = TestingAccessWrapper::newFromObject( $conf );
+ $conf->http = $http;
+
+ $this->assertSame(
+ $expected,
+ $conf->fetchAllFromEtcdServer( 'etcd-tcp.example.net' )
+ );
+ }
}