Skip to content

Commit

Permalink
Enable elasticsearch for new wikis
Browse files Browse the repository at this point in the history
This adds wwExtEnableElasticSearch to new wikis and dispatches a job to
initialize the index and enable the feature.

Lexeme and Wikibase terms end up in the same index so we do not need to
take this into consideration.
  • Loading branch information
toban committed Aug 17, 2021
1 parent 36c480b commit d57042c
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 28 deletions.
15 changes: 8 additions & 7 deletions app/Http/Controllers/WikiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,13 @@ public function create(Request $request): \Illuminate\Http\Response
'value' => Str::random(64),
]);

// Enable elasticsearch for new wikis by default
// Create elasticsearch setting to be updated once ElasticSearch has been initialized
// T285541
// WikiSetting::create([
// 'wiki_id' => $wiki->id,
// 'name' => 'wwExtEnableElasticSearch',
// 'value' => true,
// ]);
WikiSetting::create([
'wiki_id' => $wiki->id,
'name' => 'wwExtEnableElasticSearch',
'value' => false,
]);

// Also track the domain forever in your domains table
$wikiDomain = WikiDomain::create([
Expand Down Expand Up @@ -117,7 +117,8 @@ public function create(Request $request): \Illuminate\Http\Response
$this->dispatch(new ProvisionWikiDbJob(null, null, 10));
$this->dispatch(new ProvisionQueryserviceNamespaceJob(null, 10));

// $this->dispatch(new ElasticSearchIndexInit($wiki->domain));
// dispatch elasticsearch init job to enable the feature
$this->dispatch(new ElasticSearchIndexInit($wiki->domain, $wiki->id));

$res['success'] = true;
$res['message'] = 'Success!';
Expand Down
88 changes: 67 additions & 21 deletions app/Jobs/ElasticSearchIndexInit.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@

namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use App\WikiSetting;
use App\Http\Curl\CurlRequest;
use App\Http\Curl\HttpRequest;

class ElasticSearchIndexInit extends Job implements ShouldBeUnique
{
private $wikiDomain;
private $wikiId;

private $request;

/**
* @return void
*/
public function __construct($wikiDomain)
public function __construct( string $wikiDomain, int $wikiId, HttpRequest $request = null )
{
$this->wikiDomain = $wikiDomain;
$this->wikiId = $wikiId;
$this->request = $request ?? new CurlRequest();
}

/**
Expand All @@ -30,31 +38,44 @@ public function uniqueId()
*/
public function handle()
{
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => getenv('PLATFORM_MW_BACKEND_HOST').'/w/api.php?action=wbstackElasticSearchInit&format=json',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'content-type: application/x-www-form-urlencoded',
'host: '.$this->wikiDomain,
],
]);

$rawResponse = curl_exec($curl);
$err = curl_error($curl);
$setting = WikiSetting::where([ 'wiki_id' => $this->wikiId, 'name' => WikiSetting::wwExtEnableElasticSearch, ])->first();

// job got triggered but no setting in database
if ( $setting === null ) {
$this->fail(
new \RuntimeException('wbstackElasticSearchInit call for '.$this->wikiDomain.' was triggered but not setting available.')
);

return;
}

$this->request->setOptions(
[
CURLOPT_URL => getenv('PLATFORM_MW_BACKEND_HOST').'/w/api.php?action=wbstackElasticSearchInit&format=json',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => [
'content-type: application/x-www-form-urlencoded',
'host: '.$this->wikiDomain,
]
]
);

$rawResponse = $this->request->execute();
$err = $this->request->error();

if ($err) {
$this->fail(
new \RuntimeException('curl error for '.$this->wikiDomain.': '.$err)
);

return; //safegaurd
return;
}

curl_close($curl);
$this->request->close();

$response = json_decode($rawResponse, true);

Expand All @@ -63,15 +84,40 @@ public function handle()
new \RuntimeException('wbstackElasticSearchInit call for '.$this->wikiDomain.'. No wbstackElasticSearchInit key in response: '.$rawResponse)
);

return; //safegaurd
return;
}

if ($response['wbstackElasticSearchInit']['success'] == 0) {
$this->fail(
new \RuntimeException('wbstackElasticSearchInit call for '.$this->wikiDomain.' was not successful:'.$rawResponse)
);

return; //safegaurd
return;
}

$output = $response['wbstackElasticSearchInit']['output'];

$newlyCreated = "\tCreating index...ok"; // occurs a couple of times when newly created
$updated = "\t\tValidating {$this->wikiDomain}_general alias...ok"; // occurs on a successful update run

$enableElasticSearchFeature = false;

if ( in_array( $newlyCreated, $output ) ) {

// newly created index succeeded, turn on the wiki setting
$enableElasticSearchFeature = true;

} else if ( in_array( $updated, $output ) ) {

// script ran and update was successful, make sure feature is enabled
$enableElasticSearchFeature = true;
}

$setting->update(
[
'value' => $enableElasticSearchFeature
]
);

}
}
1 change: 1 addition & 0 deletions app/WikiSetting.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class WikiSetting extends Model

public const wwExtEnableElasticSearch = 'wwExtEnableElasticSearch';
public const wwExtEnableWikibaseLexeme = 'wwExtEnableWikibaseLexeme';
public const wgSecretKey = 'wgSecretKey';

/**
* The attributes that are mass assignable.
Expand Down
115 changes: 115 additions & 0 deletions tests/Jobs/ElasticSearchIndexInitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

namespace Tests\Jobs;

use App\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use App\Jobs\ElasticSearchIndexInit;
use App\Http\Curl\HttpRequest;
use App\WikiManager;
use App\WikiSetting;
use App\Wiki;

class ElasticSearchIndexInitTest extends TestCase
{
use DatabaseTransactions;

private $wiki;
private $user;

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

$this->user = User::factory()->create(['verified' => true]);
$this->wiki = Wiki::factory()->create();
WikiManager::factory()->create(['wiki_id' => $this->wiki->id, 'user_id' => $this->user->id]);
WikiSetting::factory()->create(
[
'wiki_id' => $this->wiki->id,
'name' => WikiSetting::wwExtEnableElasticSearch,
'value' => false
]
);
}

public function testSuccess()
{
$mockResponse = [
'warnings' => [],
'wbstackElasticSearchInit' => [
"success" => 1,
"output" => [
"\tCreating index...ok" // successfully created some index
]
]
];
$request = $this->createMock(HttpRequest::class);
$request->method('execute')->willReturn(json_encode($mockResponse));

$job = new ElasticSearchIndexInit($this->wiki->domain, $this->wiki->id, $request);
$job->handle();

// feature should get enabled
$this->assertSame(
1,
WikiSetting::where( ['wiki_id' => $this->wiki->id, 'name' => WikiSetting::wwExtEnableElasticSearch, 'value' => true])->count()
);
}

public function testUpdate()
{
$mockResponse = [
'warnings' => [],
'wbstackElasticSearchInit' => [
"success" => 1,
"output" => [
"\t\tValidating {$this->wiki->domain}_general alias...ok"
]
]
];
$request = $this->createMock(HttpRequest::class);
$request->method('execute')->willReturn(json_encode($mockResponse));

$job = new ElasticSearchIndexInit($this->wiki->domain, $this->wiki->id, $request);
$job->handle();

// feature should get enabled
$this->assertSame(
1,
WikiSetting::where( ['wiki_id' => $this->wiki->id, 'name' => WikiSetting::wwExtEnableElasticSearch, 'value' => true])->count()
);
}

public function testFailure()
{
$mockResponse = [
'warnings' => [],
'wbstackElasticSearchInit' => [
"success" => 0,
"output" => []
]
];
$request = $this->createMock(HttpRequest::class);
$request->method('execute')->willReturn(json_encode($mockResponse));

$job = new ElasticSearchIndexInit($this->wiki->domain, $this->wiki->id, $request);
$job->handle();

// feature should not get enabled
$this->assertSame(
0,
WikiSetting::where( ['wiki_id' => $this->wiki->id, 'name' => WikiSetting::wwExtEnableElasticSearch, 'value' => true])->count()
);
}

public function testJobTriggeredButNoSetting()
{
WikiSetting::where( ['wiki_id' => $this->wiki->id, 'name' => WikiSetting::wwExtEnableElasticSearch ])->first()->delete();
$request = $this->createMock(HttpRequest::class);
$request->expects( $this->never() )->method('execute');

$job = new ElasticSearchIndexInit($this->wiki->domain, $this->wiki->id, $request);
$job->handle();
}
}
51 changes: 51 additions & 0 deletions tests/Routes/Wiki/CreateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,61 @@

use Tests\Routes\Traits\OptionsRequestAllowed;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use App\User;
use Illuminate\Support\Facades\Queue;
use App\Jobs\ElasticSearchIndexInit;
use App\Jobs\ProvisionWikiDbJob;
use App\Jobs\MediawikiInit;
use App\WikiSetting;

class CreateTest extends TestCase
{
protected $route = 'wiki/create';

use OptionsRequestAllowed;
use DatabaseTransactions;

public function testWikiCreateDispatchesSomeJobs()
{
Queue::fake();

$user = User::factory()->create(['verified' => true]);
Queue::assertNothingPushed();

$response = $this->actingAs($user, 'api')
->json(
'POST',
$this->route,
[
'domain' => 'derp.com',
'sitename' => 'merp',
'username' => 'AdminBoss'
]
);

$response->assertStatus(200)
->assertJsonPath('data.domain', 'derp.com')
->assertJsonPath('data.name', null)
->assertJsonPath('success', true );

Queue::assertPushed( ProvisionWikiDbJob::class, 1);
Queue::assertPushed( MediawikiInit::class, 1);
Queue::assertPushed( ElasticSearchIndexInit::class, 1);

$id = $response->original['data']['id'];

$this->assertSame(
1,
WikiSetting::where( [ 'name' => WikiSetting::wgSecretKey, 'wiki_id' => $id ] )->count()
);

// will get flipped by the job
$this->assertSame(
1,
WikiSetting::where( [ 'name' => WikiSetting::wwExtEnableElasticSearch, 'value' => false, 'wiki_id' => $id ] )->count()
);


}
}

0 comments on commit d57042c

Please sign in to comment.