PK       ! ­      RESTBagOStuffTest.phpnu ŐIwś´        <?php

use Wikimedia\Http\MultiHttpClient;
use Wikimedia\ObjectCache\BagOStuff;
use Wikimedia\ObjectCache\RESTBagOStuff;

/**
 * @group BagOStuff
 *
 * @covers \Wikimedia\ObjectCache\RESTBagOStuff
 */
class RESTBagOStuffTest extends \MediaWikiUnitTestCase {

	/**
	 * @var MultiHttpClient
	 */
	private $client;
	/**
	 * @var RESTBagOStuff
	 */
	private $bag;

	protected function setUp(): void {
		parent::setUp();
		$this->client =
			$this->getMockBuilder( MultiHttpClient::class )
				->setConstructorArgs( [ [] ] )
				->onlyMethods( [ 'run' ] )
				->getMock();
		$this->bag = new RESTBagOStuff( [ 'client' => $this->client, 'url' => 'http://test/rest/' ] );
	}

	/**
	 * @dataProvider dataGet
	 */
	public function testGet( $serializationType, $hmacKey, $data ) {
		$classReflect = new ReflectionClass( RESTBagOStuff::class );

		$serializationTypeReflect = $classReflect->getProperty( 'serializationType' );
		$serializationTypeReflect->setAccessible( true );
		$serializationTypeReflect->setValue( $this->bag, $serializationType );

		$hmacKeyReflect = $classReflect->getProperty( 'hmacKey' );
		$hmacKeyReflect->setAccessible( true );
		$hmacKeyReflect->setValue( $this->bag, $hmacKey );

		$this->client->expects( $this->once() )->method( 'run' )->with( [
			'method' => 'GET',
			'url' => 'http://test/rest/42xyz42',
			'headers' => []
			// [ $rcode, $rdesc, $rhdrs, $rbody, $rerr ]
		] )->willReturn( [ 200, 'OK', [], $data, 0 ] );
		$result = $this->bag->get( '42xyz42' );
		$this->assertEquals( 'somedata', $result );
	}

	public static function dataGet() {
		// Make sure the defaults are last, so the $bag is left as expected for the next test
		return [
			[ 'JSON', '12345', 'JSON.Us1wli82zEJ6DNQnCG//w+MShOFrdx9wCdfTUhPPA2w=."somedata"' ],
			[ 'JSON', '', 'JSON.."somedata"' ],
			[ 'PHP', '12345', 'PHP.t2EKhUF4l65kZqWhoAnKW8ZPzekDYfrDxTkQcVmGsuM=.s:8:"somedata";' ],
			[ 'PHP', '', 'PHP..s:8:"somedata";' ],
		];
	}

	public function testGetNotExist() {
		$this->client->expects( $this->once() )->method( 'run' )->with( [
			'method' => 'GET',
			'url' => 'http://test/rest/42xyz42',
			'headers' => []
			// [ $rcode, $rdesc, $rhdrs, $rbody, $rerr ]
		] )->willReturn( [ 404, 'Not found', [], 'Nothing to see here', 0 ] );
		$result = $this->bag->get( '42xyz42' );
		$this->assertFalse( $result );
	}

	public function testGetBadClient() {
		$this->client->expects( $this->once() )->method( 'run' )->with( [
			'method' => 'GET',
			'url' => 'http://test/rest/42xyz42',
			'headers' => []
			// [ $rcode, $rdesc, $rhdrs, $rbody, $rerr ]
		] )->willReturn( [ 0, '', [], '', 'cURL has failed you today' ] );
		$result = $this->bag->get( '42xyz42' );
		$this->assertFalse( $result );
		$this->assertEquals( BagOStuff::ERR_UNREACHABLE, $this->bag->getLastError() );
	}

	public function testGetBadServer() {
		$this->client->expects( $this->once() )->method( 'run' )->with( [
			'method' => 'GET',
			'url' => 'http://test/rest/42xyz42',
			'headers' => []
			// [ $rcode, $rdesc, $rhdrs, $rbody, $rerr ]
		] )->willReturn( [ 500, 'Too busy', [], 'Server is too busy', '' ] );
		$result = $this->bag->get( '42xyz42' );
		$this->assertFalse( $result );
		$this->assertEquals( BagOStuff::ERR_UNEXPECTED, $this->bag->getLastError() );
	}

	/**
	 * @dataProvider dataGet
	 */
	public function testPut( $serializationType, $hmacKey, $data ) {
		$classReflect = new ReflectionClass( RESTBagOStuff::class );

		$serializationTypeReflect = $classReflect->getProperty( 'serializationType' );
		$serializationTypeReflect->setAccessible( true );
		$serializationTypeReflect->setValue( $this->bag, $serializationType );

		$hmacKeyReflect = $classReflect->getProperty( 'hmacKey' );
		$hmacKeyReflect->setAccessible( true );
		$hmacKeyReflect->setValue( $this->bag, $hmacKey );

		$this->client->expects( $this->once() )->method( 'run' )->with( [
			'method' => 'PUT',
			'url' => 'http://test/rest/42xyz42',
			'body' => $data,
			'headers' => []
			// [ $rcode, $rdesc, $rhdrs, $rbody, $rerr ]
		] )->willReturn( [ 200, 'OK', [], 'Done', 0 ] );
		$result = $this->bag->set( '42xyz42', 'somedata' );
		$this->assertTrue( $result );
	}

	public function testDelete() {
		$this->client->expects( $this->once() )->method( 'run' )->with( [
			'method' => 'DELETE',
			'url' => 'http://test/rest/42xyz42',
			'headers' => []
			// [ $rcode, $rdesc, $rhdrs, $rbody, $rerr ]
		] )->willReturn( [ 200, 'OK', [], 'Done', 0 ] );
		$result = $this->bag->delete( '42xyz42' );
		$this->assertTrue( $result );
	}
}
PK       ! l'Pˇ  ˇ    RedisBagOStuffTest.phpnu ŐIwś´        <?php

use Wikimedia\ObjectCache\RedisBagOStuff;
use Wikimedia\TestingAccessWrapper;

/**
 * @covers \Wikimedia\ObjectCache\RedisBagOStuff
 * @group BagOStuff
 */
class RedisBagOStuffTest extends MediaWikiUnitTestCase {

	/** @var RedisBagOStuff */
	private $cache;

	protected function setUp(): void {
		parent::setUp();

		$cache = $this->createMock( RedisBagOStuff::class );
		$this->cache = TestingAccessWrapper::newFromObject( $cache );
	}

	/**
	 * @dataProvider unserializeProvider
	 */
	public function testUnserialize( $expected, $input, $message ) {
		$actual = $this->cache->unserialize( $input );
		$this->assertSame( $expected, $actual, $message );
	}

	public static function unserializeProvider() {
		return [
			[
				-1,
				'-1',
				'String representation of \'-1\'',
			],
			[
				0,
				'0',
				'String representation of \'0\'',
			],
			[
				1,
				'1',
				'String representation of \'1\'',
			],
			[
				-1.0,
				'd:-1;',
				'Serialized negative double',
			],
			[
				'foo',
				's:3:"foo";',
				'Serialized string',
			]
		];
	}

	/**
	 * @dataProvider serializeProvider
	 */
	public function testSerialize( $expected, $input, $message ) {
		$actual = $this->cache->serialize( $input );
		$this->assertSame( $expected, $actual, $message );
	}

	public function serializeProvider() {
		return [
			[
				-1,
				-1,
				'-1 as integer',
			],
			[
				0,
				0,
				'0 as integer',
			],
			[
				1,
				1,
				'1 as integer',
			],
			[
				'd:-1;',
				-1.0,
				'Negative double',
			],
			[
				's:3:"2.1";',
				'2.1',
				'Decimal string',
			],
			[
				's:1:"1";',
				'1',
				'String representation of 1',
			],
			[
				's:3:"foo";',
				'foo',
				'String',
			],
		];
	}
}
PK       ! Ěż;  ;    MemcachedBagOStuffTest.phpnu ŐIwś´        <?php

use Wikimedia\ObjectCache\MemcachedBagOStuff;
use Wikimedia\ObjectCache\MemcachedPhpBagOStuff;

/**
 * @covers \Wikimedia\ObjectCache\MemcachedBagOStuff
 * @group BagOStuff
 */
class MemcachedBagOStuffTest extends \MediaWikiUnitTestCase {
	/** @var MemcachedBagOStuff */
	private $cache;

	protected function setUp(): void {
		parent::setUp();
		$this->cache = new MemcachedPhpBagOStuff( [ 'keyspace' => 'test', 'servers' => [] ] );
	}

	public function testKeyNormalization() {
		$this->assertEquals(
			'test:vanilla',
			$this->cache->makeKey( 'vanilla' )
		);

		$this->assertEquals(
			'test:punctuation_marks_are_ok:!@$^&*()',
			$this->cache->makeKey( 'punctuation_marks_are_ok', '!@$^&*()' )
		);

		$this->assertEquals(
			'test:but_spaces:hashes%23:and%0Anewlines:are_not',
			$this->cache->makeKey( 'but spaces', 'hashes#', "and\nnewlines", 'are_not' )
		);

		$this->assertEquals(
			'test:this:key:contains:%F0%9D%95%9E%F0%9D%95%A6%F0%9D%95%9D%F0%9D%95%A5%F0%9' .
				'D%95%9A%F0%9D%95%93%F0%9D%95%AA%F0%9D%95%A5%F0%9D%95%96:characters',
			$this->cache->makeKey( 'this', 'key', 'contains', 'đđŚđđĽđđđŞđĽđ', 'characters' )
		);

		$this->assertEquals(
			'test:this:key:contains:#c118f92685a635cb843039de50014c9c',
			$this->cache->makeKey( 'this', 'key', 'contains', 'đĽđ đ  đđđđŞ đđŚđđĽđđđŞđĽđ đđđđŁđđđĽđđŁđ¤' )
		);

		$this->assertEquals(
			'test:BagOStuff-long-key:##dc89dcb43b28614da27660240af478b5',
			$this->cache->makeKey( 'đđ§đđ', 'đđ', 'đ¨đ', 'đđťđ', 'đđđđ',
				'đđŁđđŚđđđđĽ', 'đĽđđđ¤', 'đđđŞ', 'đ¨đ đŚđđ', 'đ¤đĽđđđ', 'đđ', 'đĽđ đ ', 'đđ đđ' )
		);

		$this->assertEquals(
			'test:%23%235820ad1d105aa4dc698585c39df73e19',
			$this->cache->makeKey( '##5820ad1d105aa4dc698585c39df73e19' )
		);

		$this->assertEquals(
			'test:percent_is_escaped:!@$%25^&*()',
			$this->cache->makeKey( 'percent_is_escaped', '!@$%^&*()' )
		);

		$this->assertEquals(
			'test:colon_is_escaped:!@$%3A^&*()',
			$this->cache->makeKey( 'colon_is_escaped', '!@$:^&*()' )
		);

		$this->assertEquals(
			'test:long_key_part_hashed:#0244f7b1811d982dd932dd7de01465ac',
			$this->cache->makeKey( 'long_key_part_hashed', str_repeat( 'y', 500 ) )
		);
	}

	/**
	 * @dataProvider validKeyProvider
	 */
	public function testValidateKeyEncoding( $key ) {
		$this->assertSame( $key, $this->cache->validateKeyEncoding( $key ) );
	}

	public static function validKeyProvider() {
		return [
			'empty' => [ '' ],
			'digits' => [ '09' ],
			'letters' => [ 'AZaz' ],
			'ASCII special characters' => [ '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' ],
		];
	}

	/**
	 * @dataProvider invalidKeyProvider
	 */
	public function testValidateKeyEncodingThrowsException( $key ) {
		$this->expectException( Exception::class );
		$this->cache->validateKeyEncoding( $key );
	}

	public static function invalidKeyProvider() {
		return [
			[ "\x00" ],
			[ ' ' ],
			[ "\x1F" ],
			[ "\x7F" ],
			[ "\x80" ],
			[ "\xFF" ],
		];
	}
}
PK       ! dßćy  y    ObjectCacheFactoryTest.phpnu ŐIwś´        <?php

use MediaWiki\Config\ServiceOptions;
use MediaWiki\Logger\NullSpi;
use Wikimedia\ObjectCache\HashBagOStuff;
use Wikimedia\Stats\StatsFactory;

/**
 * @covers ObjectCacheFactory
 */
class ObjectCacheFactoryTest extends MediaWikiUnitTestCase {
	private function newObjectCacheFactory() {
		return new ObjectCacheFactory(
			$this->createMock( ServiceOptions::class ),
			StatsFactory::newNull(),
			new NullSpi(),
			static function () {
			},
			'testWikiId'
		);
	}

	public function testNewObjectCacheFactory() {
		$this->assertInstanceOf(
			ObjectCacheFactory::class,
			$this->newObjectCacheFactory()
		);
	}

	public function testNewFromParams() {
		$factory = $this->newObjectCacheFactory();

		$objCache = $factory->newFromParams( [
			'class' => HashBagOStuff::class,
			'args' => [ 'foo', 'bar' ],
		] );

		$this->assertInstanceOf( HashBagOStuff::class, $objCache );
	}
}
PK       ! 	ň<ą	  ą	    SqlBagOStuffTest.phpnu ŐIwś´        <?php

/**
 * @covers \SqlBagOStuff
 * @group BagOStuff
 */
class SqlBagOStuffTest extends MediaWikiUnitTestCase {
	public static function provideMakeKey() {
		yield [ 'local', 'first', [ 'second', 'third' ],
			'local:first:second:third' ];
		yield [ 'local with spaces', 'first:first', [ 'second:second' ],
			'local_with_spaces:first%3Afirst:second%3Asecond' ];
		$longA = str_repeat( 'a', 128 );
		$longB = str_repeat( 'b', 128 );
		$longC = str_repeat( 'c', 128 );
		yield [ 'global fairly long', 'first', [ $longA, $longB ],
			'global_fairly_long:first:' . $longA . ':#73045f89f89b1604b62a6ae1ab4d4133' ];
		yield [ 'global really long', 'first', [ $longA, $longB, $longC ],
			'global_really_long:BagOStuff-long-key:##99f6adc828cfb6c892501f20153bd028' ];
	}

	/**
	 * @param string $keyspace
	 * @param string $class
	 * @param array $components
	 * @param string $expected
	 * @dataProvider SqlBagOStuffTest::provideMakeKey
	 */
	public function testMakeKey(
		string $keyspace,
		string $class,
		array $components,
		string $expected
	) {
		$cache = new SqlBagOStuff( [
			'keyspace' => $keyspace,
			'servers' => []
		] );
		$this->assertSame( $expected, $cache->makeKey( $class, ...$components ) );
	}

	public function testSisterKeys() {
		$cache = new SqlBagOStuff( [
			'keyspace' => 'test',
			'servers' => [ 'pc1' => [], 'pc2' => [], 'pc3' => [], 'pc4' => [], 'pc5' => [], 'pc6' => [] ],
			'shards' => 30
		] );
		$cacheObj = \Wikimedia\TestingAccessWrapper::newFromObject( $cache );

		[ $indexFirstKey, $tableNameFirstKey ] = $cacheObj->getKeyLocation( 'Test123' );
		[ $indexSecondKey, $tableNameSecondKey ] = $cacheObj->getKeyLocation( 'Test133' );
		$this->assertNotEquals( $indexFirstKey, $indexSecondKey );
		$this->assertNotEquals( $tableNameFirstKey, $tableNameSecondKey );

		[ $indexFirstKey, $tableNameFirstKey ] = $cacheObj->getKeyLocation( 'Test123|#|12345' );
		[ $indexSecondKey, $tableNameSecondKey ] = $cacheObj->getKeyLocation( 'Test123|#|54321' );
		$this->assertSame( $indexFirstKey, $indexSecondKey );
		$this->assertSame( $tableNameFirstKey, $tableNameSecondKey );

		[ $indexFirstKey, $tableNameFirstKey ] = $cacheObj->getKeyLocation(
			$cache->makeKey( 'Test123', '|#|', '12345' )
		);
		[ $indexSecondKey, $tableNameSecondKey ] = $cacheObj->getKeyLocation(
			$cache->makeKey( 'Test123', '|#|', '54321' )
		);
		$this->assertSame( $indexFirstKey, $indexSecondKey );
		$this->assertSame( $tableNameFirstKey, $tableNameSecondKey );
	}
}
PK         ! ­                    RESTBagOStuffTest.phpnu ŐIwś´        PK         ! l'Pˇ  ˇ              ä  RedisBagOStuffTest.phpnu ŐIwś´        PK         ! Ěż;  ;              á  MemcachedBagOStuffTest.phpnu ŐIwś´        PK         ! dßćy  y              f%  ObjectCacheFactoryTest.phpnu ŐIwś´        PK         ! 	ň<ą	  ą	              ))  SqlBagOStuffTest.phpnu ŐIwś´        PK      ł  3    