Merge "Fix 'Tags' padding to keep it farther from the edge and document the source...
[lhc/web/wiklou.git] / tests / phpunit / includes / Storage / SqlBlobStoreTest.php
1 <?php
2
3 namespace MediaWiki\Tests\Storage;
4
5 use InvalidArgumentException;
6 use Language;
7 use MediaWiki\MediaWikiServices;
8 use MediaWiki\Storage\SqlBlobStore;
9 use MediaWikiTestCase;
10 use stdClass;
11 use TitleValue;
12
13 /**
14 * @covers \MediaWiki\Storage\SqlBlobStore
15 * @group Database
16 */
17 class SqlBlobStoreTest extends MediaWikiTestCase {
18
19 /**
20 * @return SqlBlobStore
21 */
22 public function getBlobStore( $legacyEncoding = false, $compressRevisions = false ) {
23 $services = MediaWikiServices::getInstance();
24
25 $store = new SqlBlobStore(
26 $services->getDBLoadBalancer(),
27 $services->getMainWANObjectCache()
28 );
29
30 if ( $compressRevisions ) {
31 $store->setCompressBlobs( $compressRevisions );
32 }
33 if ( $legacyEncoding ) {
34 $store->setLegacyEncoding( $legacyEncoding, Language::factory( 'en' ) );
35 }
36
37 return $store;
38 }
39
40 /**
41 * @covers \MediaWiki\Storage\SqlBlobStore::getCompressBlobs()
42 * @covers \MediaWiki\Storage\SqlBlobStore::setCompressBlobs()
43 */
44 public function testGetSetCompressRevisions() {
45 $store = $this->getBlobStore();
46 $this->assertFalse( $store->getCompressBlobs() );
47 $store->setCompressBlobs( true );
48 $this->assertTrue( $store->getCompressBlobs() );
49 }
50
51 /**
52 * @covers \MediaWiki\Storage\SqlBlobStore::getLegacyEncoding()
53 * @covers \MediaWiki\Storage\SqlBlobStore::getLegacyEncodingConversionLang()
54 * @covers \MediaWiki\Storage\SqlBlobStore::setLegacyEncoding()
55 */
56 public function testGetSetLegacyEncoding() {
57 $store = $this->getBlobStore();
58 $this->assertFalse( $store->getLegacyEncoding() );
59 $this->assertNull( $store->getLegacyEncodingConversionLang() );
60 $en = Language::factory( 'en' );
61 $store->setLegacyEncoding( 'foo', $en );
62 $this->assertSame( 'foo', $store->getLegacyEncoding() );
63 $this->assertSame( $en, $store->getLegacyEncodingConversionLang() );
64 }
65
66 /**
67 * @covers \MediaWiki\Storage\SqlBlobStore::getCacheExpiry()
68 * @covers \MediaWiki\Storage\SqlBlobStore::setCacheExpiry()
69 */
70 public function testGetSetCacheExpiry() {
71 $store = $this->getBlobStore();
72 $this->assertSame( 604800, $store->getCacheExpiry() );
73 $store->setCacheExpiry( 12 );
74 $this->assertSame( 12, $store->getCacheExpiry() );
75 }
76
77 /**
78 * @covers \MediaWiki\Storage\SqlBlobStore::getUseExternalStore()
79 * @covers \MediaWiki\Storage\SqlBlobStore::setUseExternalStore()
80 */
81 public function testGetSetUseExternalStore() {
82 $store = $this->getBlobStore();
83 $this->assertFalse( $store->getUseExternalStore() );
84 $store->setUseExternalStore( true );
85 $this->assertTrue( $store->getUseExternalStore() );
86 }
87
88 public function provideDecompress() {
89 yield '(no legacy encoding), empty in empty out' => [ false, '', [], '' ];
90 yield '(no legacy encoding), empty in empty out' => [ false, 'A', [], 'A' ];
91 yield '(no legacy encoding), error flag -> false' => [ false, 'X', [ 'error' ], false ];
92 yield '(no legacy encoding), string in with gzip flag returns string' => [
93 // gzip string below generated with gzdeflate( 'AAAABBAAA' )
94 false, "sttttr\002\022\000", [ 'gzip' ], 'AAAABBAAA',
95 ];
96 yield '(no legacy encoding), string in with object flag returns false' => [
97 // gzip string below generated with serialize( 'JOJO' )
98 false, "s:4:\"JOJO\";", [ 'object' ], false,
99 ];
100 yield '(no legacy encoding), serialized object in with object flag returns string' => [
101 false,
102 // Using a TitleValue object as it has a getText method (which is needed)
103 serialize( new TitleValue( 0, 'HHJJDDFF' ) ),
104 [ 'object' ],
105 'HHJJDDFF',
106 ];
107 yield '(no legacy encoding), serialized object in with object & gzip flag returns string' => [
108 false,
109 // Using a TitleValue object as it has a getText method (which is needed)
110 gzdeflate( serialize( new TitleValue( 0, '8219JJJ840' ) ) ),
111 [ 'object', 'gzip' ],
112 '8219JJJ840',
113 ];
114 yield '(ISO-8859-1 encoding), string in string out' => [
115 'ISO-8859-1',
116 iconv( 'utf-8', 'ISO-8859-1', "1®Àþ1" ),
117 [],
118 '1®Àþ1',
119 ];
120 yield '(ISO-8859-1 encoding), serialized object in with gzip flags returns string' => [
121 'ISO-8859-1',
122 gzdeflate( iconv( 'utf-8', 'ISO-8859-1', "4®Àþ4" ) ),
123 [ 'gzip' ],
124 '4®Àþ4',
125 ];
126 yield '(ISO-8859-1 encoding), serialized object in with object flags returns string' => [
127 'ISO-8859-1',
128 serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "3®Àþ3" ) ) ),
129 [ 'object' ],
130 '3®Àþ3',
131 ];
132 yield '(ISO-8859-1 encoding), serialized object in with object & gzip flags returns string' => [
133 'ISO-8859-1',
134 gzdeflate( serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
135 [ 'gzip', 'object' ],
136 '2®Àþ2',
137 ];
138 yield 'T184749 (windows-1252 encoding), string in string out' => [
139 'windows-1252',
140 iconv( 'utf-8', 'windows-1252', "sammansättningar" ),
141 [],
142 'sammansättningar',
143 ];
144 yield 'T184749 (windows-1252 encoding), string in string out with gzip' => [
145 'windows-1252',
146 gzdeflate( iconv( 'utf-8', 'windows-1252', "sammansättningar" ) ),
147 [ 'gzip' ],
148 'sammansättningar',
149 ];
150 }
151
152 /**
153 * @dataProvider provideDecompress
154 * @covers \MediaWiki\Storage\SqlBlobStore::decompressData
155 *
156 * @param string|bool $legacyEncoding
157 * @param mixed $data
158 * @param array $flags
159 * @param mixed $expected
160 */
161 public function testDecompressData( $legacyEncoding, $data, $flags, $expected ) {
162 $store = $this->getBlobStore( $legacyEncoding );
163 $this->assertSame(
164 $expected,
165 $store->decompressData( $data, $flags )
166 );
167 }
168
169 /**
170 * @covers \MediaWiki\Storage\SqlBlobStore::decompressData
171 */
172 public function testDecompressData_InvalidArgumentException() {
173 $store = $this->getBlobStore();
174
175 $this->setExpectedException( InvalidArgumentException::class );
176 $store->decompressData( false, [] );
177 }
178
179 /**
180 * @covers \MediaWiki\Storage\SqlBlobStore::compressData
181 */
182 public function testCompressRevisionTextUtf8() {
183 $store = $this->getBlobStore();
184 $row = new stdClass;
185 $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
186 $row->old_flags = $store->compressData( $row->old_text );
187 $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
188 "Flags should contain 'utf-8'" );
189 $this->assertFalse( false !== strpos( $row->old_flags, 'gzip' ),
190 "Flags should not contain 'gzip'" );
191 $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
192 $row->old_text, "Direct check" );
193 }
194
195 /**
196 * @covers \MediaWiki\Storage\SqlBlobStore::compressData
197 */
198 public function testCompressRevisionTextUtf8Gzip() {
199 $store = $this->getBlobStore( false, true );
200 $this->checkPHPExtension( 'zlib' );
201
202 $row = new stdClass;
203 $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
204 $row->old_flags = $store->compressData( $row->old_text );
205 $this->assertTrue( false !== strpos( $row->old_flags, 'utf-8' ),
206 "Flags should contain 'utf-8'" );
207 $this->assertTrue( false !== strpos( $row->old_flags, 'gzip' ),
208 "Flags should contain 'gzip'" );
209 $this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
210 gzinflate( $row->old_text ), "Direct check" );
211 }
212
213 public function provideBlobs() {
214 yield [ '' ];
215 yield [ 'someText' ];
216 yield [ "sammansättningar" ];
217 }
218
219 /**
220 * @dataProvider provideBlobs
221 * @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
222 * @covers \MediaWiki\Storage\SqlBlobStore::getBlob
223 */
224 public function testSimpleStoreGetBlobSimpleRoundtrip( $blob ) {
225 $store = $this->getBlobStore();
226 $address = $store->storeBlob( $blob );
227 $this->assertSame( $blob, $store->getBlob( $address ) );
228 }
229
230 /**
231 * @dataProvider provideBlobs
232 * @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
233 * @covers \MediaWiki\Storage\SqlBlobStore::getBlob
234 */
235 public function testSimpleStoreGetBlobSimpleRoundtripWindowsLegacyEncoding( $blob ) {
236 $store = $this->getBlobStore( 'windows-1252' );
237 $address = $store->storeBlob( $blob );
238 $this->assertSame( $blob, $store->getBlob( $address ) );
239 }
240
241 /**
242 * @dataProvider provideBlobs
243 * @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
244 * @covers \MediaWiki\Storage\SqlBlobStore::getBlob
245 */
246 public function testSimpleStoreGetBlobSimpleRoundtripWindowsLegacyEncodingGzip( $blob ) {
247 $store = $this->getBlobStore( 'windows-1252', true );
248 $address = $store->storeBlob( $blob );
249 $this->assertSame( $blob, $store->getBlob( $address ) );
250 }
251
252 public function provideGetTextIdFromAddress() {
253 yield [ 'tt:17', 17 ];
254 yield [ 'xy:17', null ];
255 yield [ 'xy:xyzzy', null ];
256 }
257
258 /**
259 * @dataProvider provideGetTextIdFromAddress
260 */
261 public function testGetTextIdFromAddress( $address, $textId ) {
262 $store = $this->getBlobStore();
263 $this->assertSame( $textId, $store->getTextIdFromAddress( $address ) );
264 }
265
266 public function provideGetTextIdFromAddressInvalidArgumentException() {
267 yield [ 'tt:-17' ];
268 yield [ 'tt:xy' ];
269 yield [ 'tt:0' ];
270 yield [ 'tt:' ];
271 yield [ 'xy' ];
272 yield [ '' ];
273 }
274
275 /**
276 * @dataProvider provideGetTextIdFromAddressInvalidArgumentException
277 */
278 public function testGetTextIdFromAddressInvalidArgumentException( $address ) {
279 $this->setExpectedException( InvalidArgumentException::class );
280 $store = $this->getBlobStore();
281 $store->getTextIdFromAddress( $address );
282 }
283
284 public function testMakeAddressFromTextId() {
285 $this->assertSame( 'tt:17', SqlBlobStore::makeAddressFromTextId( 17 ) );
286 }
287
288 }