mirror of
https://github.com/flarum/framework.git
synced 2025-03-15 00:05:12 +08:00
test: Updates (#11)
This commit is contained in:
parent
b2d8f3dd5b
commit
1754313503
@ -9,18 +9,17 @@
|
||||
|
||||
namespace Flarum\PackageManager\Api\Controller;
|
||||
|
||||
use Flarum\Api\Controller\AbstractDeleteController;
|
||||
use Flarum\Bus\Dispatcher;
|
||||
use Flarum\Http\RequestUtil;
|
||||
use Illuminate\Support\Arr;
|
||||
use Flarum\PackageManager\Api\Serializer\ExtensionSerializer;
|
||||
use Laminas\Diactoros\Response\EmptyResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Flarum\PackageManager\Command\RemoveExtension;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class RemoveExtensionController extends AbstractDeleteController
|
||||
class RemoveExtensionController implements RequestHandlerInterface
|
||||
{
|
||||
public $serializer = ExtensionSerializer::class;
|
||||
|
||||
/**
|
||||
* @var Dispatcher
|
||||
*/
|
||||
@ -31,10 +30,7 @@ class RemoveExtensionController extends AbstractDeleteController
|
||||
$this->bus = $bus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Flarum\User\Exception\PermissionDeniedException
|
||||
*/
|
||||
protected function delete(ServerRequestInterface $request)
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
$actor = RequestUtil::getActor($request);
|
||||
$extensionId = Arr::get($request->getQueryParams(), 'id');
|
||||
@ -42,5 +38,7 @@ class RemoveExtensionController extends AbstractDeleteController
|
||||
$this->bus->dispatch(
|
||||
new RemoveExtension($actor, $extensionId)
|
||||
);
|
||||
|
||||
return new EmptyResponse();
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\PackageManager\Api\Serializer;
|
||||
|
||||
use Flarum\Api\Serializer\AbstractSerializer;
|
||||
use Flarum\Extension\Extension;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class ExtensionSerializer extends AbstractSerializer
|
||||
{
|
||||
protected $type = 'extensions';
|
||||
|
||||
public function getId($model)
|
||||
{
|
||||
return is_array($model) ? $model['id'] : $model->getId();
|
||||
}
|
||||
|
||||
protected function getDefaultAttributes($model)
|
||||
{
|
||||
if (is_array($model)) {
|
||||
return $model;
|
||||
}
|
||||
|
||||
if (! ($model instanceof Extension)) {
|
||||
throw new InvalidArgumentException(
|
||||
get_class($this).' can only serialize instances of '.Extension::class
|
||||
);
|
||||
}
|
||||
|
||||
return $model->toArray();
|
||||
}
|
||||
}
|
@ -24,9 +24,7 @@ class ExceptionHandler
|
||||
|
||||
protected function errorDetails(ComposerCommandFailedException $e): array
|
||||
{
|
||||
$details = [
|
||||
'output' => $e->getMessage(),
|
||||
];
|
||||
$details = [];
|
||||
|
||||
if ($guessedCause = $this->guessCause($e)) {
|
||||
$details['guessed_cause'] = $guessedCause;
|
||||
|
@ -1,5 +1,12 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\PackageManager\Settings;
|
||||
|
||||
interface JsonSetting
|
||||
|
@ -65,7 +65,13 @@ class LastUpdateRun implements JsonSetting
|
||||
|
||||
public function get(): array
|
||||
{
|
||||
return json_decode($this->settings->get(self::key()), true);
|
||||
$lastUpdateRun = json_decode($this->settings->get(self::key()), true);
|
||||
|
||||
if ($this->activeUpdate) {
|
||||
return $lastUpdateRun[$this->activeUpdate];
|
||||
}
|
||||
|
||||
return $lastUpdateRun;
|
||||
}
|
||||
|
||||
public static function key(): string
|
||||
|
@ -1,5 +1,12 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\PackageManager;
|
||||
|
||||
use Flarum\Foundation\AbstractValidator;
|
||||
|
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Flarum\PackageManager\Tests\integration;
|
||||
|
||||
trait ChangeComposerConfig
|
||||
{
|
||||
protected function setComposerConfig(array $requirements): void
|
||||
{
|
||||
$composerSetup = new SetupComposer($requirements);
|
||||
$composerSetup->run();
|
||||
|
||||
$this->composer('install');
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\PackageManager\Tests\integration;
|
||||
|
||||
use Flarum\Foundation\Paths;
|
||||
|
||||
trait DummyExtensions
|
||||
{
|
||||
protected function makeDummyExtensionCompatibleWith(string $name, string $coreVersions): void
|
||||
{
|
||||
$dirName = $this->tmpDir() . "/packages/" . str_replace('/', '-', $name);
|
||||
|
||||
if (! file_exists($dirName)) {
|
||||
mkdir($dirName);
|
||||
}
|
||||
|
||||
file_put_contents($dirName."/composer.json", json_encode([
|
||||
'name' => $name,
|
||||
'version' => '1.0.0',
|
||||
'require' => [
|
||||
'flarum/core' => $coreVersions
|
||||
],
|
||||
], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
}
|
||||
}
|
@ -1,7 +1,19 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\PackageManager\Tests\integration;
|
||||
|
||||
use FilesystemIterator;
|
||||
use Flarum\PackageManager\Composer\ComposerAdapter;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
|
||||
trait RefreshComposerSetup
|
||||
{
|
||||
public function tearDown(): void
|
||||
@ -9,10 +21,35 @@ trait RefreshComposerSetup
|
||||
$composerSetup = new SetupComposer();
|
||||
@unlink($this->tmpDir().'/composer.lock');
|
||||
|
||||
$this->deleteDummyExtensions();
|
||||
|
||||
$composerSetup->run();
|
||||
|
||||
$this->composer('install');
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
private function deleteDummyExtensions(): void
|
||||
{
|
||||
$dir = $this->tmpDir().'/packages';
|
||||
|
||||
$it = new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS);
|
||||
$files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
|
||||
|
||||
foreach($files as $file) {
|
||||
if ($file->isDir()){
|
||||
rmdir($file->getRealPath());
|
||||
} else {
|
||||
unlink($file->getRealPath());
|
||||
}
|
||||
}
|
||||
|
||||
rmdir($dir);
|
||||
}
|
||||
|
||||
protected function forgetComposerApp(): void
|
||||
{
|
||||
$this->app()->getContainer()->instance(ComposerAdapter::class, null);
|
||||
}
|
||||
}
|
||||
|
@ -15,20 +15,43 @@ class SetupComposer
|
||||
{
|
||||
use UsesTmpDir;
|
||||
|
||||
private $config = [
|
||||
'require' => [
|
||||
'flarum/core' => '1.0.0',
|
||||
'flarum/tags' => '1.0.3',
|
||||
'flarum/lang-english' => '*',
|
||||
],
|
||||
'config' => [
|
||||
'preferred-install' => 'dist',
|
||||
'sort-packages' => true,
|
||||
],
|
||||
'repositories' => [
|
||||
[
|
||||
'type' => 'path',
|
||||
'url' => __DIR__.'/../tmp/packages/*',
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
public function __construct(array $config = null)
|
||||
{
|
||||
$this->config = array_merge($this->config, $config ?? []);
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$filePath = $this->tmpDir().'/composer.json';
|
||||
$composerJson = $this->tmpDir().'/composer.json';
|
||||
$composerLock = $this->tmpDir().'/composer.lock';
|
||||
$packages = $this->tmpDir().'/packages';
|
||||
|
||||
file_put_contents($filePath, json_encode([
|
||||
'require' => [
|
||||
'flarum/core' => '1.0.0',
|
||||
'flarum/tags' => '1.0.3',
|
||||
'flarum/lang-english' => '*',
|
||||
],
|
||||
'config' => [
|
||||
'preferred-install' => 'dist',
|
||||
'sort-packages' => true,
|
||||
],
|
||||
], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
file_put_contents($composerJson, json_encode($this->config, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
|
||||
|
||||
if (! file_exists($packages)) {
|
||||
mkdir($packages);
|
||||
}
|
||||
|
||||
if (file_exists($composerLock)) {
|
||||
unlink($composerLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ namespace Flarum\PackageManager\Tests\integration;
|
||||
|
||||
use Flarum\Foundation\Paths;
|
||||
use Flarum\PackageManager\Composer\ComposerAdapter;
|
||||
use Flarum\PackageManager\Composer\ComposerJson;
|
||||
use Flarum\PackageManager\Extension\ExtensionUtils;
|
||||
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
|
||||
use Illuminate\Support\Arr;
|
||||
@ -27,7 +28,7 @@ class TestCase extends \Flarum\Testing\integration\TestCase
|
||||
|
||||
$this->extension('flarum-package-manager', 'flarum-tags');
|
||||
|
||||
$tmp = $this->tmpDir();
|
||||
$tmp = realpath($this->tmpDir());
|
||||
|
||||
$this->app()->getContainer()->instance('flarum.paths', new Paths([
|
||||
'base' => $tmp,
|
||||
@ -64,6 +65,14 @@ class TestCase extends \Flarum\Testing\integration\TestCase
|
||||
$this->assertExtension($id, false);
|
||||
}
|
||||
|
||||
protected function assertPackageVersion(string $packageName, string $version)
|
||||
{
|
||||
$composerJson = $this->app()->getContainer()->make(ComposerJson::class)->get();
|
||||
|
||||
$this->assertArrayHasKey($packageName, $composerJson['require'], "$packageName is not required.");
|
||||
$this->assertEquals($version, $composerJson['require'][$packageName], "Expected $packageName to be $version, found {$composerJson['require'][$packageName]} instead.");
|
||||
}
|
||||
|
||||
protected function requireExtension(string $package)
|
||||
{
|
||||
$this->composer("require $package");
|
||||
@ -81,10 +90,17 @@ class TestCase extends \Flarum\Testing\integration\TestCase
|
||||
$composer->run(new StringInput($command));
|
||||
}
|
||||
|
||||
protected function guessedCause(ResponseInterface $response): ?string
|
||||
protected function errorGuessedCause(ResponseInterface $response): ?string
|
||||
{
|
||||
$json = json_decode($response->getBody()->getContents(), true);
|
||||
$details = $this->errorDetails($response);
|
||||
|
||||
return $json['errors'] ? ($json['errors'][0]['guessed_cause'] ?? null) : null;
|
||||
return $details['guessed_cause'] ?? null;
|
||||
}
|
||||
|
||||
protected function errorDetails(ResponseInterface $response): array
|
||||
{
|
||||
$json = json_decode((string) $response->getBody(), true);
|
||||
|
||||
return $json['errors'] ? ($json['errors'][0] ?? []) : [];
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\PackageManager\Tests\integration\api;
|
||||
|
||||
use Flarum\PackageManager\Tests\integration\ChangeComposerConfig;
|
||||
use Flarum\PackageManager\Tests\integration\DummyExtensions;
|
||||
use Flarum\PackageManager\Tests\integration\RefreshComposerSetup;
|
||||
use Flarum\PackageManager\Tests\integration\TestCase;
|
||||
|
||||
class MajorUpdateTest extends TestCase
|
||||
{
|
||||
use RefreshComposerSetup, ChangeComposerConfig, DummyExtensions;
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function cannot_update_when_no_update_check_ran()
|
||||
{
|
||||
$this->makeDummyExtensionCompatibleWith("flarum/dummy-incompatible-extension", ">=0.1.0-beta.15 <=0.1.0-beta.16");
|
||||
$this->setComposerConfig([
|
||||
'require' => [
|
||||
'flarum/core' => '^0.1.0-beta.15',
|
||||
'flarum/tags' => '^0.1.0-beta.15',
|
||||
'flarum/dummy-incompatible-extension' => '^1.0.0'
|
||||
],
|
||||
'minimum-stability' => 'beta',
|
||||
]);
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('POST', '/api/package-manager/major-update', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals(409, $response->getStatusCode());
|
||||
$this->assertEquals('no_new_major_version', $this->errorDetails($response)['code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function can_update_when_major_update_available()
|
||||
{
|
||||
$this->makeDummyExtensionCompatibleWith("flarum/dummy-compatible-extension", "^0.1.0-beta.15 | ^1.0.0");
|
||||
$this->setComposerConfig([
|
||||
'require' => [
|
||||
'flarum/core' => '^0.1.0-beta.15',
|
||||
'flarum/tags' => '^0.1.0-beta.15',
|
||||
'flarum/dummy-compatible-extension' => '^1.0.0'
|
||||
],
|
||||
'minimum-stability' => 'beta',
|
||||
]);
|
||||
|
||||
$lastUpdateCheck = $this->send(
|
||||
$this->request('POST', '/api/package-manager/check-for-updates', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$this->forgetComposerApp();
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('POST', '/api/package-manager/major-update', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$newMinorCoreVersion = array_filter(
|
||||
json_decode((string) $lastUpdateCheck->getBody(), true)['updates']['installed'],
|
||||
function ($package) {
|
||||
return $package['name'] === 'flarum/core';
|
||||
}
|
||||
)[0]['latest-major'];
|
||||
|
||||
$this->assertEquals(204, $response->getStatusCode());
|
||||
$this->assertPackageVersion("flarum/core", str_replace('v', '^', $newMinorCoreVersion));
|
||||
$this->assertPackageVersion("flarum/tags", "*");
|
||||
$this->assertPackageVersion("flarum/dummy-compatible-extension", "*");
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function cannot_update_with_incompatible_extensions()
|
||||
{
|
||||
$this->makeDummyExtensionCompatibleWith("flarum/dummy-incompatible-extension-a", ">=0.1.0-beta.16 <0.1.0-beta.17");
|
||||
$this->makeDummyExtensionCompatibleWith("flarum/dummy-incompatible-extension-b", ">=0.1.0-beta.16 <=0.1.0-beta.17");
|
||||
$this->makeDummyExtensionCompatibleWith("flarum/dummy-incompatible-extension-c", "0.1.0-beta.16");
|
||||
$this->setComposerConfig([
|
||||
'require' => [
|
||||
'flarum/core' => '^0.1.0-beta.16',
|
||||
'flarum/tags' => '^0.1.0-beta.16',
|
||||
'flarum/dummy-incompatible-extension-a' => '^1.0.0',
|
||||
'flarum/dummy-incompatible-extension-b' => '^1.0.0',
|
||||
'flarum/dummy-incompatible-extension-c' => '^1.0.0',
|
||||
],
|
||||
'minimum-stability' => 'beta',
|
||||
]);
|
||||
|
||||
$this->send(
|
||||
$this->request('POST', '/api/package-manager/check-for-updates', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('POST', '/api/package-manager/major-update', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals(409, $response->getStatusCode());
|
||||
$this->assertEquals('extensions_incompatible_with_new_major', $this->errorDetails($response)['guessed_cause']);
|
||||
$this->assertEquals([
|
||||
'flarum/dummy-incompatible-extension-a',
|
||||
'flarum/dummy-incompatible-extension-b',
|
||||
'flarum/dummy-incompatible-extension-c'
|
||||
], $this->errorDetails($response)['incompatible_extensions']);
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* For detailed copyright and license information, please view the
|
||||
* LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\PackageManager\Tests\integration\api;
|
||||
|
||||
use Flarum\PackageManager\Event\FlarumUpdated;
|
||||
use Flarum\PackageManager\Settings\LastUpdateRun;
|
||||
use Flarum\PackageManager\Tests\integration\ChangeComposerConfig;
|
||||
use Flarum\PackageManager\Tests\integration\DummyExtensions;
|
||||
use Flarum\PackageManager\Tests\integration\RefreshComposerSetup;
|
||||
use Flarum\PackageManager\Tests\integration\TestCase;
|
||||
|
||||
class MinorUpdateTest extends TestCase
|
||||
{
|
||||
use RefreshComposerSetup, ChangeComposerConfig, DummyExtensions;
|
||||
|
||||
/**
|
||||
* @test--
|
||||
*/
|
||||
public function can_update_to_next_minor_version()
|
||||
{
|
||||
$this->makeDummyExtensionCompatibleWith("flarum/dummy-compatible-extension", "^1.0.0");
|
||||
$this->setComposerConfig([
|
||||
'require' => [
|
||||
// The only reason we don't set this to `^1.0.0` and let it update to latest minor,
|
||||
// is because migrations that run DDL queries might be introduced in future versions,
|
||||
// therefore breaking the test transaction.
|
||||
'flarum/core' => '>=1.0.0 <= 1.1.0',
|
||||
// We leave tags fixed to a version,
|
||||
// the update handler must be able to set it to `*`.
|
||||
'flarum/tags' => '1.0.3',
|
||||
'flarum/lang-english' => '*',
|
||||
'flarum/dummy-compatible-extension' => '^1.0.0'
|
||||
]
|
||||
]);
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('POST', '/api/package-manager/minor-update', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$this->assertEquals(204, $response->getStatusCode());
|
||||
$this->assertPackageVersion('flarum/tags', '*');
|
||||
$this->assertPackageVersion('flarum/dummy-compatible-extension', '*');
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function can_update_with_latest_ext_incompatible_with_latest_core()
|
||||
{
|
||||
$this->makeDummyExtensionCompatibleWith("flarum/dummy-extension", "1.0.0");
|
||||
$this->setComposerConfig([
|
||||
'require' => [
|
||||
'flarum/core' => '>=1.0.0 <=1.1.0',
|
||||
'flarum/tags' => '1.0.3',
|
||||
'flarum/lang-english' => '*',
|
||||
'flarum/dummy-extension' => '^1.0.0'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->send(
|
||||
$this->request('POST', '/api/package-manager/check-for-updates', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
$this->forgetComposerApp();
|
||||
|
||||
$response = $this->send(
|
||||
$this->request('POST', '/api/package-manager/minor-update', [
|
||||
'authenticatedAs' => 1,
|
||||
])
|
||||
);
|
||||
|
||||
/** @var LastUpdateRun $lastUpdateRun */
|
||||
$lastUpdateRun = $this->app()->getContainer()->make(LastUpdateRun::class);
|
||||
|
||||
$this->assertEquals(204, $response->getStatusCode());
|
||||
$this->assertPackageVersion("flarum/tags", "*");
|
||||
$this->assertPackageVersion("flarum/dummy-extension", "*");
|
||||
$this->assertEquals([
|
||||
'flarum/core',
|
||||
'flarum/lang-english',
|
||||
'flarum/tags'
|
||||
], $lastUpdateRun->for(FlarumUpdated::MINOR)->get()['limitedPackages']);
|
||||
}
|
||||
}
|
@ -100,7 +100,7 @@ class RequireExtensionTest extends TestCase
|
||||
);
|
||||
|
||||
$this->assertEquals(409, $response->getStatusCode());
|
||||
$this->assertEquals('extension_incompatible_with_instance', $this->guessedCause($response));
|
||||
$this->assertEquals('extension_incompatible_with_instance', $this->errorDetails($response)['guessed_cause']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,6 +120,6 @@ class RequireExtensionTest extends TestCase
|
||||
);
|
||||
|
||||
$this->assertEquals(409, $response->getStatusCode());
|
||||
$this->assertEquals('extension_incompatible_with_instance', $this->guessedCause($response));
|
||||
$this->assertEquals('extension_incompatible_with_instance', $this->errorDetails($response)['guessed_cause']);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user