3use Wikimedia\TestingAccessWrapper;
8 return $this->getMockBuilder( EtcdConfig::class )
10 'host' =>
'etcd-tcp.example.net',
14 ->setMethods( [
'fetchAllFromEtcd' ] )
20 $mock->expects( $this->once() )->method(
'fetchAllFromEtcd' )
36 $this->assertSame(
true, $config->has(
'known' ) );
47 $this->assertSame(
'value', $config->get(
'known' ) );
57 $this->assertSame(
false, $config->has(
'unknown' ) );
67 $this->setExpectedException( ConfigException::class );
68 $config->get(
'unknown' );
75 $cache = $this->getMockBuilder( HashBagOStuff::class )
76 ->setMethods( [
'get' ] )
78 $cache->expects( $this->once() )->method(
'get' )
80 'config' => [
'known' =>
'from-cache' ],
85 $this->assertSame(
'from-cache', $config->get(
'known' ) );
93 'class' => HashBagOStuff::class
95 $config->expects( $this->once() )->method(
'fetchAllFromEtcd' )
97 [
'known' =>
'from-fetch' ],
102 $this->assertSame(
'from-fetch', $config->get(
'known' ) );
152 $cache = $this->getMockBuilder( HashBagOStuff::class )
153 ->setMethods( [
'get',
'lock' ] )
156 $cache->expects( $this->once() )->method(
'get' )
157 ->willReturn(
false );
159 $cache->expects( $this->once() )->method(
'lock' )
160 ->willReturn(
true );
166 $mock->expects( $this->once() )->method(
'fetchAllFromEtcd' )
167 ->willReturn( [ [
'known' =>
'from-fetch' ],
null,
false ] );
169 $this->assertSame(
'from-fetch', $mock->get(
'known' ) );
177 $cache = $this->getMockBuilder( HashBagOStuff::class )
178 ->setMethods( [
'get',
'lock' ] )
181 $cache->expects( $this->once() )->method(
'get' )
182 ->willReturn(
false );
184 $cache->expects( $this->once() )->method(
'lock' )
185 ->willReturn(
true );
191 $mock->expects( $this->once() )->method(
'fetchAllFromEtcd' )
192 ->willReturn( [
null,
'Fake error',
false ] );
194 $this->setExpectedException( ConfigException::class );
203 $cache = $this->getMockBuilder( HashBagOStuff::class )
204 ->setMethods( [
'get',
'lock' ] )
206 $cache->expects( $this->exactly( 2 ) )->method(
'get' )
207 ->will( $this->onConsecutiveCalls(
212 'config' => [
'known' =>
'from-cache' ],
217 $cache->expects( $this->once() )->method(
'lock' )
218 ->willReturn(
false );
224 $mock->expects( $this->never() )->method(
'fetchAllFromEtcd' );
226 $this->assertSame(
'from-cache', $mock->get(
'known' ) );
234 $cache = $this->getMockBuilder( HashBagOStuff::class )
235 ->setMethods( [
'get',
'lock' ] )
237 $cache->expects( $this->once() )->method(
'get' )
240 'config' => [
'known' =>
'from-cache' ],
243 $cache->expects( $this->never() )->method(
'lock' );
249 $mock->expects( $this->never() )->method(
'fetchAllFromEtcd' );
251 $this->assertSame(
'from-cache', $mock->get(
'known' ) );
259 $cache = $this->getMockBuilder( HashBagOStuff::class )
260 ->setMethods( [
'get',
'lock' ] )
262 $cache->expects( $this->once() )->method(
'get' )
265 'config' => [
'known' =>
'from-cache' ],
268 $cache->expects( $this->never() )->method(
'lock' );
274 $mock->expects( $this->never() )->method(
'fetchAllFromEtcd' );
276 $this->assertSame(
'from-cache', $mock->get(
'known' ),
'Cache hit' );
277 $this->assertSame(
'from-cache', $mock->get(
'known' ),
'Process cache hit' );
285 $cache = $this->getMockBuilder( HashBagOStuff::class )
286 ->setMethods( [
'get',
'lock' ] )
288 $cache->expects( $this->once() )->method(
'get' )->willReturn(
291 'config' => [
'known' =>
'from-cache-expired' ],
296 $cache->expects( $this->once() )->method(
'lock' )
297 ->willReturn(
true );
303 $mock->expects( $this->once() )->method(
'fetchAllFromEtcd' )
304 ->willReturn( [ [
'known' =>
'from-fetch' ],
null,
false ] );
306 $this->assertSame(
'from-fetch', $mock->get(
'known' ) );
314 $cache = $this->getMockBuilder( HashBagOStuff::class )
315 ->setMethods( [
'get',
'lock' ] )
317 $cache->expects( $this->once() )->method(
'get' )->willReturn(
320 'config' => [
'known' =>
'from-cache-expired' ],
325 $cache->expects( $this->once() )->method(
'lock' )
326 ->willReturn(
true );
332 $mock->expects( $this->once() )->method(
'fetchAllFromEtcd' )
333 ->willReturn( [
null,
'Fake failure',
true ] );
335 $this->assertSame(
'from-cache-expired', $mock->get(
'known' ) );
343 $cache = $this->getMockBuilder( HashBagOStuff::class )
344 ->setMethods( [
'get',
'lock' ] )
346 $cache->expects( $this->once() )->method(
'get' )
349 'config' => [
'known' =>
'from-cache-expired' ],
353 $cache->expects( $this->once() )->method(
'lock' )
354 ->willReturn(
false );
360 $mock->expects( $this->never() )->method(
'fetchAllFromEtcd' );
362 $this->assertSame(
'from-cache-expired', $mock->get(
'known' ) );
367 '200 OK - Success' => [
372 'body' => json_encode( [
'node' => [
'nodes' => [
374 'key' =>
'/example/foo',
375 'value' => json_encode( [
'val' =>
true ] )
386 '200 OK - Empty dir' => [
391 'body' => json_encode( [
'node' => [
'nodes' => [
393 'key' =>
'/example/foo',
394 'value' => json_encode( [
'val' =>
true ] )
397 'key' =>
'/example/sub',
402 'key' =>
'/example/bar',
403 'value' => json_encode( [
'val' =>
false ] )
409 [
'foo' =>
true,
'bar' =>
false ],
414 '200 OK - Recursive' => [
419 'body' => json_encode( [
'node' => [
'nodes' => [
421 'key' =>
'/example/a',
426 'value' => json_encode( [
'val' =>
true ] ),
430 'value' => json_encode( [
'val' =>
false ] ),
438 [
'a/b' =>
true,
'a/c' =>
false ],
443 '200 OK - Missing nodes at second level' => [
448 'body' => json_encode( [
'node' => [
'nodes' => [
450 'key' =>
'/example/a',
458 "Unexpected JSON response in dir 'a'; missing 'nodes' list.",
462 '200 OK - Correctly encoded garbage response' => [
467 'body' => json_encode( [
'foo' =>
'bar' ] ),
472 "Unexpected JSON response: Missing or invalid node at top level.",
476 '200 OK - Bad value' => [
481 'body' => json_encode( [
'node' => [
'nodes' => [
483 'key' =>
'/example/foo',
484 'value' =>
';"broken{value'
491 "Failed to parse value for 'foo'.",
495 '200 OK - Empty node list' => [
500 'body' =>
'{"node":{"nodes":[]}}',
509 '200 OK - Invalid JSON' => [
513 'headers' => [
'content-length' => 0 ],
515 'error' =>
'(curl error: no status set)',
519 "Error unserializing JSON response.",
526 'reason' =>
'Not Found',
527 'headers' => [
'content-length' => 0 ],
533 'HTTP 404 (Not Found)',
537 '400 Bad Request - custom error' => [
540 'reason' =>
'Bad Request',
541 'headers' => [
'content-length' => 0 ],
543 'error' =>
'No good reason',
563 $http = $this->getMockBuilder( MultiHttpClient::class )
564 ->disableOriginalConstructor()
566 $http->expects( $this->once() )->method(
'run' )
567 ->willReturn( array_values( $httpResponse ) );
569 $conf = $this->getMockBuilder( EtcdConfig::class )
570 ->disableOriginalConstructor()
573 $conf = TestingAccessWrapper::newFromObject( $conf );
578 $conf->fetchAllFromEtcdServer(
'etcd-tcp.example.net' )
createConfigMock(array $options=[])
testLoadCacheMiss()
Test matrix.
testLoadProcessCacheHit()
EtcdConfig::load.
testLoadCacheMissWithoutLock()
EtcdConfig::load.
testConstructCacheObj()
EtcdConfig::__construct.
testLoadCacheExpiredNoLock()
EtcdConfig::load.
createSimpleConfigMock(array $config)
testLoadCacheExpiredLockFetchSucceeded()
EtcdConfig::load.
testConstructCacheSpec()
EtcdConfig::__construct.
testGetUnknown()
EtcdConfig::get.
testLoadCacheExpiredLockFetchFails()
EtcdConfig::load.
testFetchFromServer(array $httpResponse, array $expected)
EtcdConfig::fetchAllFromEtcdServer EtcdConfig::unserialize EtcdConfig::parseResponse EtcdConfig::pars...
testHasUnknown()
EtcdConfig::has.
testGetKnown()
EtcdConfig::__construct EtcdConfig::get.
testHasKnown()
EtcdConfig::has.
static provideFetchFromServer()
testLoadCacheHit()
EtcdConfig::load.
testLoadCacheMissBackendError()
EtcdConfig::load.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
processing should stop and the error should be shown to the user * false