mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/Vector.git
synced 2024-11-11 16:59:09 +00:00
Validate the value of VectorWebABTestEnrollment
The generation of JavaScript will throw a RuntimeException making it obvious when an invalid A/B test has been setup. Bug: T297662 Change-Id: I75b0e923463bf52f8fc5b5c6b7f9baf586053154
This commit is contained in:
parent
0cbf9c61d9
commit
64ee622c73
|
@ -7,6 +7,7 @@ use HTMLForm;
|
|||
use MediaWiki\MediaWikiServices;
|
||||
use OutputPage;
|
||||
use ResourceLoaderContext;
|
||||
use RuntimeException;
|
||||
use Skin;
|
||||
use SkinTemplate;
|
||||
use SkinVector;
|
||||
|
@ -23,6 +24,41 @@ use Vector\HTMLForm\Fields\HTMLLegacySkinVersionField;
|
|||
* @internal
|
||||
*/
|
||||
class Hooks {
|
||||
/**
|
||||
* @param Config $config
|
||||
* @return array
|
||||
*/
|
||||
private static function getActiveABTest( $config ) {
|
||||
$ab = $config->get(
|
||||
Constants::CONFIG_STICKY_HEADER_TREATMENT_AB_TEST_ENROLLMENT
|
||||
);
|
||||
if ( count( $ab ) === 0 ) {
|
||||
// If array is empty then no experiment and need to validate.
|
||||
return $ab;
|
||||
}
|
||||
if ( !array_key_exists( 'buckets', $ab ) ) {
|
||||
throw new RuntimeException( 'Invalid VectorWebABTestEnrollment value: Must contain buckets key.' );
|
||||
}
|
||||
if ( !array_key_exists( 'unsampled', $ab['buckets'] ) ) {
|
||||
throw new RuntimeException( 'Invalid VectorWebABTestEnrollment value: Must define an `unsampled` bucket.' );
|
||||
} else {
|
||||
// check bucket values.
|
||||
foreach ( $ab['buckets'] as $bucketName => $bucketDefinition ) {
|
||||
if ( !is_array( $bucketDefinition ) ) {
|
||||
throw new RuntimeException( 'Invalid VectorWebABTestEnrollment value: Buckets should be arrays' );
|
||||
}
|
||||
$samplingRate = $bucketDefinition['samplingRate'];
|
||||
if ( is_string( $samplingRate ) ) {
|
||||
throw new RuntimeException(
|
||||
'Invalid VectorWebABTestEnrollment value: Sampling rate should be number between 0 and 1.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes config variables to Vector (modern) ResourceLoader module.
|
||||
* @param ResourceLoaderContext $context
|
||||
|
@ -35,9 +71,7 @@ class Hooks {
|
|||
) {
|
||||
return [
|
||||
'wgVectorSearchHost' => $config->get( 'VectorSearchHost' ),
|
||||
'wgVectorWebABTestEnrollment' => $config->get(
|
||||
Constants::CONFIG_STICKY_HEADER_TREATMENT_AB_TEST_ENROLLMENT
|
||||
),
|
||||
'wgVectorWebABTestEnrollment' => self::getActiveABTest( $config ),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,123 @@ class VectorHooksTest extends MediaWikiIntegrationTestCase {
|
|||
];
|
||||
}
|
||||
|
||||
public function provideGetVectorResourceLoaderConfig() {
|
||||
return [
|
||||
[
|
||||
[
|
||||
'VectorWebABTestEnrollment' => [],
|
||||
'VectorSearchHost' => 'en.wikipedia.org'
|
||||
],
|
||||
[
|
||||
'wgVectorSearchHost' => 'en.wikipedia.org',
|
||||
'wgVectorWebABTestEnrollment' => [],
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'VectorWebABTestEnrollment' => [
|
||||
'name' => 'vector.sticky_header',
|
||||
'enabled' => true,
|
||||
'buckets' => [
|
||||
'unsampled' => [
|
||||
'samplingRate' => 1,
|
||||
],
|
||||
'control' => [
|
||||
'samplingRate' => 0
|
||||
],
|
||||
'stickyHeaderEnabled' => [
|
||||
'samplingRate' => 0
|
||||
],
|
||||
'stickyHeaderDisabled' => [
|
||||
'samplingRate' => 0
|
||||
],
|
||||
],
|
||||
],
|
||||
'VectorSearchHost' => 'en.wikipedia.org'
|
||||
],
|
||||
[
|
||||
'wgVectorSearchHost' => 'en.wikipedia.org',
|
||||
'wgVectorWebABTestEnrollment' => [
|
||||
'name' => 'vector.sticky_header',
|
||||
'enabled' => true,
|
||||
'buckets' => [
|
||||
'unsampled' => [
|
||||
'samplingRate' => 1,
|
||||
],
|
||||
'control' => [
|
||||
'samplingRate' => 0
|
||||
],
|
||||
'stickyHeaderEnabled' => [
|
||||
'samplingRate' => 0
|
||||
],
|
||||
'stickyHeaderDisabled' => [
|
||||
'samplingRate' => 0
|
||||
],
|
||||
],
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function provideGetVectorResourceLoaderConfigWithExceptions() {
|
||||
return [
|
||||
# Bad experiment (no buckets)
|
||||
[
|
||||
[
|
||||
'VectorSearchHost' => 'en.wikipedia.org',
|
||||
'VectorWebABTestEnrollment' => [
|
||||
'name' => 'vector.sticky_header',
|
||||
'enabled' => true,
|
||||
],
|
||||
]
|
||||
],
|
||||
# Bad experiment (no unsampled bucket)
|
||||
[
|
||||
[
|
||||
'VectorSearchHost' => 'en.wikipedia.org',
|
||||
'VectorWebABTestEnrollment' => [
|
||||
'name' => 'vector.sticky_header',
|
||||
'enabled' => true,
|
||||
'buckets' => [
|
||||
'a' => [
|
||||
'samplingRate' => 0
|
||||
],
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
# Bad experiment (wrong format)
|
||||
[
|
||||
[
|
||||
'VectorSearchHost' => 'en.wikipedia.org',
|
||||
'VectorWebABTestEnrollment' => [
|
||||
'name' => 'vector.sticky_header',
|
||||
'enabled' => true,
|
||||
'buckets' => [
|
||||
'unsampled' => 1,
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
# Bad experiment (samplingRate defined as string)
|
||||
[
|
||||
[
|
||||
'VectorSearchHost' => 'en.wikipedia.org',
|
||||
'VectorWebABTestEnrollment' => [
|
||||
'name' => 'vector.sticky_header',
|
||||
'enabled' => true,
|
||||
'buckets' => [
|
||||
'unsampled' => [
|
||||
'samplingRate' => '1'
|
||||
],
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::shouldDisableMaxWidth
|
||||
*/
|
||||
|
@ -220,6 +337,36 @@ class VectorHooksTest extends MediaWikiIntegrationTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getVectorResourceLoaderConfig
|
||||
* @dataProvider provideGetVectorResourceLoaderConfig
|
||||
*/
|
||||
public function testGetVectorResourceLoaderConfig( $configData, $expected ) {
|
||||
$config = new HashConfig( $configData );
|
||||
$vectorConfig = Hooks::getVectorResourceLoaderConfig(
|
||||
$this->createMock( ResourceLoaderContext::class ),
|
||||
$config
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
$vectorConfig,
|
||||
$expected
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getVectorResourceLoaderConfig
|
||||
* @dataProvider provideGetVectorResourceLoaderConfigWithExceptions
|
||||
*/
|
||||
public function testGetVectorResourceLoaderConfigWithExceptions( $configData ) {
|
||||
$config = new HashConfig( $configData );
|
||||
$this->expectException( RuntimeException::class );
|
||||
$vectorConfig = Hooks::getVectorResourceLoaderConfig(
|
||||
$this->createMock( ResourceLoaderContext::class ),
|
||||
$config
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::onGetPreferences
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue