nextcloud/tests/Core/Command/App/UpdateTest.php
Côme Chilliet 9d5d2cd367
fix: Simulate upgrade failure from code changes
Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
2025-10-02 14:24:13 +02:00

154 lines
4.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace Tests\Core\Command\App;
use OC\Core\Command\App\Update;
use OC\Installer;
use OCP\App\IAppManager;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Test\TestCase;
class UpdateTest extends TestCase {
private IAppManager&MockObject $appManager;
private Installer&MockObject $installer;
private LoggerInterface&MockObject $logger;
private InputInterface&MockObject $inputInterface;
private OutputInterface&MockObject $outputInterface;
protected Update $command;
protected function setUp(): void {
parent::setUp();
$this->appManager = $this->createMock(IAppManager::class);
$this->installer = $this->createMock(Installer::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->inputInterface = $this->createMock(InputInterface::class);
$this->outputInterface = $this->createMock(OutputInterface::class);
$this->command = new Update(
$this->appManager,
$this->installer,
$this->logger,
);
}
public function testAppUpdateNoUpdatesFound(): void {
$this->inputInterface->expects(self::once())
->method('getArgument')
->with('app-id')
->willReturn('fakeid');
$this->outputInterface->expects(self::once())
->method('writeln')
->with('fakeid is up-to-date or no updates could be found');
$this->assertEquals(0, self::invokePrivate($this->command, 'execute', [$this->inputInterface, $this->outputInterface]));
}
public function testAppUpdate(): void {
$this->inputInterface->expects(self::once())
->method('getArgument')
->with('app-id')
->willReturn('fakeid');
$this->inputInterface->expects(self::any())
->method('getOption')
->willReturnMap([
['allow-unstable', false],
['showonly', false],
]);
$this->installer->expects(self::once())
->method('isUpdateAvailable')
->willReturn('fakeversion');
$this->installer->expects(self::once())
->method('updateAppstoreApp')
->with('fakeid', false)
->willReturn(true);
$output = [];
$this->outputInterface->expects(self::any())
->method('writeln')
->willReturnCallback(
function (string $line) use (&$output) {
$output[] = $line;
}
);
$this->assertEquals(0, self::invokePrivate($this->command, 'execute', [$this->inputInterface, $this->outputInterface]));
$this->assertEquals(
[
'fakeid new version available: fakeversion',
'fakeid updated',
],
$output
);
}
public function testAppUpdateWithNewMethod(): void {
// First create new apps path
$apps_dirname = \sha1(\random_bytes(4));
$new_apps_path = \sys_get_temp_dir() . '/' . $apps_dirname;
// Create an app within that path
mkdir($new_apps_path . '/test_app/lib', recursive:true);
file_put_contents(
$new_apps_path . '/test_app/lib/MyClass.php',
'<?php namespace OCA\FakeApp; class MyClass { public function __construct(private string $oldParam) {} }'
);
// Add the app path
\OC::$APPSROOTS[] = [
'path' => $new_apps_path,
// 'url' => '/apptest',
'writable' => false,
];
// Load the class as if as the app had been booted
require_once($new_apps_path . '/test_app/lib/MyClass.php');
$object = new \OCA\FakeApp\MyClass('oldParam');
// Now, lets update the app
$this->inputInterface->expects(self::once())
->method('getArgument')
->with('app-id')
->willReturn('test_app');
$this->inputInterface->expects(self::any())
->method('getOption')
->willReturnMap([
['allow-unstable', false],
['showonly', false],
]);
$this->installer->expects(self::once())
->method('isUpdateAvailable')
->willReturn('2.0.0');
$this->installer->expects(self::once())
->method('updateAppstoreApp')
->willReturnCallback(
function (string $appid, bool $allowUnstable) use ($new_apps_path): bool {
file_put_contents(
$new_apps_path . '/test_app/lib/MyClass.php',
'<?php namespace OCA\FakeApp; class MyClass { public function __construct() {} }'
);
file_put_contents(
$new_apps_path . '/test_app/lib/MyMigration.php',
'<?php require_once __DIR__."/MyClass.php"; $object = new \OCA\FakeApp\MyClass(); // no param needed now'
);
require_once $new_apps_path . '/test_app/lib/MyMigration.php';
return true;
}
);
$this->assertEquals(0, self::invokePrivate($this->command, 'execute', [$this->inputInterface, $this->outputInterface]));
}
}