Refactor plugin system (part 8)
This commit is contained in:
parent
85a67a5332
commit
3594b7abf8
@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Exception;
|
||||
use App\Services\Plugin;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Services\PluginManager;
|
||||
@ -30,11 +31,10 @@ class MarketController extends Controller
|
||||
$this->guzzle = $guzzle;
|
||||
}
|
||||
|
||||
public function marketData()
|
||||
public function marketData(PluginManager $manager)
|
||||
{
|
||||
$plugins = collect($this->getAllAvailablePlugins())->map(function ($item) {
|
||||
$plugin = plugin($item['name']);
|
||||
$manager = app('plugins');
|
||||
$plugins = collect($this->getAllAvailablePlugins())->map(function ($item) use ($manager) {
|
||||
$plugin = $manager->get($item['name']);
|
||||
|
||||
if ($plugin) {
|
||||
$item['enabled'] = $plugin->isEnabled();
|
||||
@ -48,9 +48,8 @@ class MarketController extends Controller
|
||||
unset($item['require']);
|
||||
|
||||
$item['dependencies'] = [
|
||||
'isRequirementsSatisfied' => $manager->isRequirementsSatisfied($requirements),
|
||||
'requirements' => $requirements,
|
||||
'unsatisfiedRequirements' => $manager->getUnsatisfiedRequirements($requirements),
|
||||
'all' => $requirements,
|
||||
'unsatisfied' => $manager->getUnsatisfied(new Plugin('', $item)),
|
||||
];
|
||||
|
||||
return $item;
|
||||
@ -59,13 +58,13 @@ class MarketController extends Controller
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
public function checkUpdates()
|
||||
public function checkUpdates(PluginManager $manager)
|
||||
{
|
||||
$pluginsHaveUpdate = collect($this->getAllAvailablePlugins())->filter(function ($item) {
|
||||
$plugin = plugin($item['name']);
|
||||
|
||||
return $plugin && Comparator::greaterThan($item['version'], $plugin->version);
|
||||
});
|
||||
$pluginsHaveUpdate = collect($this->getAllAvailablePlugins())
|
||||
->filter(function ($item) use ($manager) {
|
||||
$plugin = $manager->get($item['name']);
|
||||
return $plugin && Comparator::greaterThan($item['version'], $plugin->version);
|
||||
});
|
||||
|
||||
return json([
|
||||
'available' => $pluginsHaveUpdate->isNotEmpty(),
|
||||
@ -98,7 +97,7 @@ class MarketController extends Controller
|
||||
|
||||
protected function getPluginMetadata($name)
|
||||
{
|
||||
return collect($this->getAllAvailablePlugins())->where('name', $name)->first();
|
||||
return collect($this->getAllAvailablePlugins())->firstWhere('name', $name);
|
||||
}
|
||||
|
||||
protected function getAllAvailablePlugins()
|
||||
|
@ -115,31 +115,4 @@ trait GeneratesFakePlugins
|
||||
|
||||
file_put_contents("$plugin_dir/bootstrap.php", "<?php return function () { return '{$info['name']}'; };");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a fake zip archive of given plugin.
|
||||
*
|
||||
* @param array $info Plugin information.
|
||||
* @return string File path of generated zip archive.
|
||||
*/
|
||||
protected function generateFakePluginArchive($info)
|
||||
{
|
||||
$name = Arr::get($info, 'name');
|
||||
$version = Arr::get($info, 'version');
|
||||
$zipPath = storage_path("testing/{$name}_{$version}.zip");
|
||||
|
||||
if (file_exists($zipPath)) {
|
||||
unlink($zipPath);
|
||||
}
|
||||
|
||||
$zip = new ZipArchive();
|
||||
$zip->open($zipPath, ZipArchive::CREATE);
|
||||
$zip->addEmptyDir($name);
|
||||
$zip->addFromString("$name/package.json", json_encode(
|
||||
$this->generateFakePlguinInfo($info)
|
||||
));
|
||||
$zip->close();
|
||||
|
||||
return $zipPath;
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,17 @@
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use App\Services\Plugin;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use App\Services\PluginManager;
|
||||
use App\Services\PackageManager;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Tests\Concerns\MocksGuzzleClient;
|
||||
use Tests\Concerns\GeneratesFakePlugins;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
|
||||
class MarketControllerTest extends TestCase
|
||||
{
|
||||
use MocksGuzzleClient;
|
||||
use GeneratesFakePlugins;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
@ -26,7 +25,10 @@ class MarketControllerTest extends TestCase
|
||||
$this->setupGuzzleClientMock();
|
||||
|
||||
// Try to download a non-existent plugin
|
||||
$this->appendToGuzzleQueue(200, [], $this->generateFakePluginsRegistry());
|
||||
$this->appendToGuzzleQueue(200, [], json_encode([
|
||||
'version' => 1,
|
||||
'packages' => [],
|
||||
]));
|
||||
$this->postJson('/admin/plugins/market/download', [
|
||||
'name' => 'non-existent-plugin',
|
||||
])->assertJson([
|
||||
@ -35,17 +37,36 @@ class MarketControllerTest extends TestCase
|
||||
]);
|
||||
|
||||
// Download
|
||||
$fakeRegistry = $this->generateFakePluginsRegistry('fake-test-download', '0.0.1');
|
||||
$fakeRegistry = json_encode(['packages' => [
|
||||
[
|
||||
'name' => 'fake',
|
||||
'version' => '0.0.0',
|
||||
'dist' => ['url' => 'http://nowhere.test/', 'shasum' => 'deadbeef'],
|
||||
],
|
||||
]]);
|
||||
$this->appendToGuzzleQueue([new Response(200, [], $fakeRegistry)]);
|
||||
app()->instance(PackageManager::class, new Concerns\FakePackageManager(null, true));
|
||||
$this->mock(PackageManager::class, function ($mock) {
|
||||
$mock->shouldReceive('download')
|
||||
->withArgs(['http://nowhere.test/', storage_path('packages/fake_0.0.0.zip'), 'deadbeef'])
|
||||
->once()
|
||||
->andThrow(new \Exception());
|
||||
});
|
||||
$this->postJson('/admin/plugins/market/download', [
|
||||
'name' => 'fake-test-download',
|
||||
'name' => 'fake',
|
||||
])->assertJson(['code' => 1]);
|
||||
|
||||
$this->appendToGuzzleQueue([new Response(200, [], $fakeRegistry)]);
|
||||
app()->bind(PackageManager::class, Concerns\FakePackageManager::class);
|
||||
$this->mock(PackageManager::class, function ($mock) {
|
||||
$mock->shouldReceive('download')
|
||||
->withArgs(['http://nowhere.test/', storage_path('packages/fake_0.0.0.zip'), 'deadbeef'])
|
||||
->once()
|
||||
->andReturnSelf();
|
||||
$mock->shouldReceive('extract')
|
||||
->with(base_path('plugins'))
|
||||
->once();
|
||||
});
|
||||
$this->postJson('/admin/plugins/market/download', [
|
||||
'name' => 'fake-test-download',
|
||||
'name' => 'fake',
|
||||
])->assertJson(['code' => 0, 'message' => trans('admin.plugins.market.install-success')]);
|
||||
}
|
||||
|
||||
@ -53,20 +74,30 @@ class MarketControllerTest extends TestCase
|
||||
{
|
||||
$this->setupGuzzleClientMock();
|
||||
|
||||
$fakeRegistry = json_encode(['packages' => [
|
||||
[
|
||||
'name' => 'fake',
|
||||
'version' => '0.0.1',
|
||||
'dist' => ['url' => 'http://nowhere.test/', 'shasum' => 'deadbeef'],
|
||||
],
|
||||
]]);
|
||||
|
||||
// Not installed
|
||||
$this->appendToGuzzleQueue(200, [], $this->generateFakePluginsRegistry('fake-test-update', '0.0.1'));
|
||||
$this->appendToGuzzleQueue(200, [], $fakeRegistry);
|
||||
$this->getJson('/admin/plugins/market/check')
|
||||
->assertJson([
|
||||
'available' => false,
|
||||
'plugins' => [],
|
||||
]);
|
||||
|
||||
// Generate fake plugin and refresh plugin manager
|
||||
$this->generateFakePlugin(['name' => 'fake-test-update', 'version' => '0.0.1']);
|
||||
$this->app->singleton('plugins', \App\Services\PluginManager::class);
|
||||
|
||||
$this->mock(PluginManager::class, function ($mock) {
|
||||
$mock->shouldReceive('get')
|
||||
->with('fake')
|
||||
->twice()
|
||||
->andReturn(new Plugin('', ['name' => 'fake', 'version' => '0.0.1']));
|
||||
});
|
||||
// Plugin up-to-date
|
||||
$this->appendToGuzzleQueue(200, [], $this->generateFakePluginsRegistry('fake-test-update', '0.0.1'));
|
||||
$this->appendToGuzzleQueue(200, [], $fakeRegistry);
|
||||
$this->getJson('/admin/plugins/market/check')
|
||||
->assertJson([
|
||||
'available' => false,
|
||||
@ -74,30 +105,64 @@ class MarketControllerTest extends TestCase
|
||||
]);
|
||||
|
||||
// New version available
|
||||
$this->appendToGuzzleQueue(200, [], $this->generateFakePluginsRegistry('fake-test-update', '2.3.3'));
|
||||
$fakeRegistry = json_encode(['packages' => [
|
||||
[
|
||||
'name' => 'fake',
|
||||
'version' => '2.3.3',
|
||||
'dist' => ['url' => 'http://nowhere.test/', 'shasum' => 'deadbeef'],
|
||||
],
|
||||
]]);
|
||||
$this->appendToGuzzleQueue(200, [], $fakeRegistry);
|
||||
$this->getJson('/admin/plugins/market/check')
|
||||
->assertJson([
|
||||
'available' => true,
|
||||
'plugins' => [[
|
||||
'name' => 'fake-test-update',
|
||||
'name' => 'fake',
|
||||
]],
|
||||
]);
|
||||
}
|
||||
|
||||
public function testMarketData()
|
||||
{
|
||||
$registry = $this->generateFakePluginsRegistry();
|
||||
$package = json_decode($registry, true)['packages'][0];
|
||||
$this->generateFakePlugin($package);
|
||||
$this->setupGuzzleClientMock([
|
||||
new RequestException('Connection Error', new Request('POST', 'whatever')),
|
||||
new Response(200, [], $registry),
|
||||
new Response(200, [], json_encode(array_merge(json_decode($registry, true), ['version' => 0]))),
|
||||
new Response(200, [], json_encode(['version' => 1, 'packages' => [
|
||||
[
|
||||
'name' => 'fake1',
|
||||
'title' => 'Fake',
|
||||
'version' => '1.0.0',
|
||||
'description' => '',
|
||||
'author' => '',
|
||||
'dist' => [],
|
||||
'require' => [],
|
||||
],
|
||||
[
|
||||
'name' => 'fake2',
|
||||
'title' => 'Fake',
|
||||
'version' => '0.0.0',
|
||||
'description' => '',
|
||||
'author' => '',
|
||||
'dist' => [],
|
||||
'require' => [],
|
||||
],
|
||||
]])),
|
||||
new Response(200, [], json_encode(['version' => 0])),
|
||||
]);
|
||||
|
||||
// Expected an exception, but unable to be asserted.
|
||||
$this->getJson('/admin/plugins/market-data');
|
||||
|
||||
$this->mock(PluginManager::class, function ($mock) {
|
||||
$mock->shouldReceive('get')
|
||||
->with('fake1')
|
||||
->once()
|
||||
->andReturn(new Plugin('', ['name' => 'fake1', 'version' => '0.0.1']));
|
||||
$mock->shouldReceive('get')
|
||||
->with('fake2')
|
||||
->once()
|
||||
->andReturn(null);
|
||||
$mock->shouldReceive('getUnsatisfied')->twice();
|
||||
});
|
||||
$this->getJson('/admin/plugins/market-data')
|
||||
->assertJsonStructure([
|
||||
[
|
||||
@ -112,20 +177,7 @@ class MarketControllerTest extends TestCase
|
||||
],
|
||||
]);
|
||||
|
||||
File::deleteDirectory(config('plugins.directory').DIRECTORY_SEPARATOR.$package['name']);
|
||||
|
||||
$this
|
||||
->getJson('/admin/plugins/market-data')
|
||||
$this->getJson('/admin/plugins/market-data')
|
||||
->assertJson(['message' => 'Only version 1 of market registry is accepted.']);
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
// Clean fake plugins
|
||||
File::deleteDirectory(config('plugins.directory').DIRECTORY_SEPARATOR.'fake-test-download');
|
||||
File::deleteDirectory(config('plugins.directory').DIRECTORY_SEPARATOR.'fake-test-update');
|
||||
File::delete(config('plugins.directory').DIRECTORY_SEPARATOR.'whatever');
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,11 @@ namespace Tests;
|
||||
|
||||
use App\Services\Plugin;
|
||||
use App\Services\PluginManager;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Tests\Concerns\GeneratesFakePlugins;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
|
||||
class PluginControllerTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
use GeneratesFakePlugins;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user