2017-06-01 10:56:34 -04:00
< ? php
/**
2024-05-10 09:09:14 -04:00
* SPDX - FileCopyrightText : 2018 - 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX - FileCopyrightText : 2016 ownCloud , Inc .
* SPDX - License - Identifier : AGPL - 3.0 - or - later
2017-06-01 10:56:34 -04:00
*/
namespace Test\DB ;
2018-07-18 04:42:32 -04:00
use Doctrine\DBAL\Schema\Column ;
use Doctrine\DBAL\Schema\ForeignKeyConstraint ;
use Doctrine\DBAL\Schema\Index ;
2017-06-01 10:56:34 -04:00
use Doctrine\DBAL\Schema\Schema ;
2018-10-10 04:45:10 -04:00
use Doctrine\DBAL\Schema\SchemaException ;
2018-07-18 04:42:32 -04:00
use Doctrine\DBAL\Schema\Sequence ;
use Doctrine\DBAL\Schema\Table ;
2020-11-11 08:34:24 -05:00
use Doctrine\DBAL\Types\Type ;
2017-06-01 10:56:34 -04:00
use OC\DB\Connection ;
use OC\DB\MigrationService ;
2017-06-09 10:45:12 -04:00
use OC\DB\SchemaWrapper ;
2024-07-29 07:14:29 -04:00
use OC\Migration\MetadataManager ;
2025-07-31 09:14:48 -04:00
use OCP\App\AppPathNotFoundException ;
2024-07-29 07:14:29 -04:00
use OCP\App\IAppManager ;
2017-06-01 10:56:34 -04:00
use OCP\IDBConnection ;
2024-07-29 07:14:29 -04:00
use OCP\Migration\Attributes\AddColumn ;
use OCP\Migration\Attributes\AddIndex ;
use OCP\Migration\Attributes\ColumnType ;
use OCP\Migration\Attributes\CreateTable ;
use OCP\Migration\Attributes\DropColumn ;
use OCP\Migration\Attributes\DropIndex ;
use OCP\Migration\Attributes\DropTable ;
use OCP\Migration\Attributes\IndexType ;
use OCP\Migration\Attributes\ModifyColumn ;
2017-06-09 10:45:12 -04:00
use OCP\Migration\IMigrationStep ;
2024-07-29 07:14:29 -04:00
use OCP\Server ;
use PHPUnit\Framework\MockObject\MockObject ;
2017-06-01 10:56:34 -04:00
/**
* Class MigrationsTest
*
* @ package Test\DB
*/
class MigrationsTest extends \Test\TestCase {
2024-07-29 07:14:29 -04:00
private MigrationService | MockObject $migrationService ;
private MockObject | IDBConnection $db ;
private IAppManager $appManager ;
2017-06-01 10:56:34 -04:00
2019-11-27 09:27:18 -05:00
protected function setUp () : void {
2017-06-01 10:56:34 -04:00
parent :: setUp ();
$this -> db = $this -> createMock ( Connection :: class );
$this -> db -> expects ( $this -> any ()) -> method ( 'getPrefix' ) -> willReturn ( 'test_oc_' );
$this -> migrationService = new MigrationService ( 'testing' , $this -> db );
2024-07-29 07:14:29 -04:00
$this -> appManager = Server :: get ( IAppManager :: class );
2017-06-01 10:56:34 -04:00
}
2024-09-15 16:32:31 -04:00
public function testGetters () : void {
2017-06-01 10:56:34 -04:00
$this -> assertEquals ( 'testing' , $this -> migrationService -> getApp ());
2017-06-09 10:45:12 -04:00
$this -> assertEquals ( \OC :: $SERVERROOT . '/apps/testing/lib/Migration' , $this -> migrationService -> getMigrationsDirectory ());
$this -> assertEquals ( 'OCA\Testing\Migration' , $this -> migrationService -> getMigrationsNamespace ());
2017-06-01 10:56:34 -04:00
$this -> assertEquals ( 'test_oc_migrations' , $this -> migrationService -> getMigrationsTableName ());
}
2024-09-15 16:32:31 -04:00
public function testCore () : void {
2017-06-01 10:56:34 -04:00
$this -> migrationService = new MigrationService ( 'core' , $this -> db );
$this -> assertEquals ( 'core' , $this -> migrationService -> getApp ());
$this -> assertEquals ( \OC :: $SERVERROOT . '/core/Migrations' , $this -> migrationService -> getMigrationsDirectory ());
2017-07-05 09:46:25 -04:00
$this -> assertEquals ( 'OC\Core\Migrations' , $this -> migrationService -> getMigrationsNamespace ());
2017-06-01 10:56:34 -04:00
$this -> assertEquals ( 'test_oc_migrations' , $this -> migrationService -> getMigrationsTableName ());
}
2019-12-05 08:38:28 -05:00
2024-09-15 16:32:31 -04:00
public function testExecuteUnknownStep () : void {
2019-11-27 09:27:18 -05:00
$this -> expectException ( \InvalidArgumentException :: class );
$this -> expectExceptionMessage ( 'Version 20170130180000 is unknown.' );
2017-06-01 10:56:34 -04:00
$this -> migrationService -> executeStep ( '20170130180000' );
}
2019-12-05 08:38:28 -05:00
2024-09-15 16:32:31 -04:00
public function testUnknownApp () : void {
2025-07-31 09:14:48 -04:00
$this -> expectException ( AppPathNotFoundException :: class );
$this -> expectExceptionMessage ( 'Could not find path for unknown_bloody_app' );
2019-11-27 09:27:18 -05:00
2025-07-31 09:14:48 -04:00
$migrationService = new MigrationService ( 'unknown_bloody_app' , $this -> db );
2017-06-01 10:56:34 -04:00
}
2019-12-05 08:38:28 -05:00
2024-09-15 16:32:31 -04:00
public function testExecuteStepWithUnknownClass () : void {
2019-11-27 09:27:18 -05:00
$this -> expectException ( \Exception :: class );
$this -> expectExceptionMessage ( 'Migration step \'X\' is unknown' );
2017-06-01 10:56:34 -04:00
$this -> migrationService = $this -> getMockBuilder ( MigrationService :: class )
2025-04-30 02:29:47 -04:00
-> onlyMethods ([ 'findMigrations' ])
2017-06-01 10:56:34 -04:00
-> setConstructorArgs ([ 'testing' , $this -> db ])
-> getMock ();
$this -> migrationService -> expects ( $this -> any ()) -> method ( 'findMigrations' ) -> willReturn (
[ '20170130180000' => 'X' , '20170130180001' => 'Y' , '20170130180002' => 'Z' , '20170130180003' => 'A' ]
);
$this -> migrationService -> executeStep ( '20170130180000' );
}
2024-09-15 16:32:31 -04:00
public function testExecuteStepWithSchemaChange () : void {
2017-06-01 10:56:34 -04:00
$schema = $this -> createMock ( Schema :: class );
2017-06-09 10:45:12 -04:00
$this -> db -> expects ( $this -> any ())
-> method ( 'createSchema' )
-> willReturn ( $schema );
$this -> db -> expects ( $this -> once ())
-> method ( 'migrateToSchema' );
2018-07-18 04:42:32 -04:00
$wrappedSchema = $this -> createMock ( Schema :: class );
2023-07-21 06:17:36 -04:00
$wrappedSchema -> expects ( $this -> exactly ( 2 ))
2018-07-18 04:42:32 -04:00
-> method ( 'getTables' )
-> willReturn ([]);
2023-07-21 06:17:36 -04:00
$wrappedSchema -> expects ( $this -> exactly ( 2 ))
2018-07-18 04:42:32 -04:00
-> method ( 'getSequences' )
2018-10-10 04:45:10 -04:00
-> willReturn ([]);
2018-07-18 04:42:32 -04:00
2017-06-09 10:45:12 -04:00
$schemaResult = $this -> createMock ( SchemaWrapper :: class );
$schemaResult -> expects ( $this -> once ())
-> method ( 'getWrappedSchema' )
2018-07-18 04:42:32 -04:00
-> willReturn ( $wrappedSchema );
2017-06-09 10:45:12 -04:00
$step = $this -> createMock ( IMigrationStep :: class );
2022-06-20 04:53:06 -04:00
$step -> expects ( $this -> once ())
2017-06-09 10:45:12 -04:00
-> method ( 'preSchemaChange' );
2022-06-20 04:53:06 -04:00
$step -> expects ( $this -> once ())
2017-06-09 10:45:12 -04:00
-> method ( 'changeSchema' )
-> willReturn ( $schemaResult );
2022-06-20 04:53:06 -04:00
$step -> expects ( $this -> once ())
2017-06-09 10:45:12 -04:00
-> method ( 'postSchemaChange' );
2017-06-01 10:56:34 -04:00
$this -> migrationService = $this -> getMockBuilder ( MigrationService :: class )
2025-04-30 02:29:47 -04:00
-> onlyMethods ([ 'createInstance' ])
2017-06-01 10:56:34 -04:00
-> setConstructorArgs ([ 'testing' , $this -> db ])
-> getMock ();
2017-06-09 10:45:12 -04:00
$this -> migrationService -> expects ( $this -> any ())
-> method ( 'createInstance' )
-> with ( '20170130180000' )
-> willReturn ( $step );
2017-06-01 10:56:34 -04:00
$this -> migrationService -> executeStep ( '20170130180000' );
}
2024-09-15 16:32:31 -04:00
public function testExecuteStepWithoutSchemaChange () : void {
2017-06-09 10:45:12 -04:00
$schema = $this -> createMock ( Schema :: class );
$this -> db -> expects ( $this -> any ())
-> method ( 'createSchema' )
-> willReturn ( $schema );
$this -> db -> expects ( $this -> never ())
-> method ( 'migrateToSchema' );
$step = $this -> createMock ( IMigrationStep :: class );
2022-06-20 04:53:06 -04:00
$step -> expects ( $this -> once ())
2017-06-09 10:45:12 -04:00
-> method ( 'preSchemaChange' );
2022-06-20 04:53:06 -04:00
$step -> expects ( $this -> once ())
2017-06-09 10:45:12 -04:00
-> method ( 'changeSchema' )
-> willReturn ( null );
2022-06-20 04:53:06 -04:00
$step -> expects ( $this -> once ())
2017-06-09 10:45:12 -04:00
-> method ( 'postSchemaChange' );
2017-06-01 10:56:34 -04:00
$this -> migrationService = $this -> getMockBuilder ( MigrationService :: class )
2025-04-30 02:29:47 -04:00
-> onlyMethods ([ 'createInstance' ])
2017-06-01 10:56:34 -04:00
-> setConstructorArgs ([ 'testing' , $this -> db ])
-> getMock ();
2017-06-09 10:45:12 -04:00
$this -> migrationService -> expects ( $this -> any ())
-> method ( 'createInstance' )
-> with ( '20170130180000' )
-> willReturn ( $step );
2017-06-01 10:56:34 -04:00
$this -> migrationService -> executeStep ( '20170130180000' );
}
2025-05-13 04:10:13 -04:00
public static function dataGetMigration () : array {
2017-06-09 10:45:12 -04:00
return [
[ 'current' , '20170130180001' ],
[ 'prev' , '20170130180000' ],
[ 'next' , '20170130180002' ],
[ 'latest' , '20170130180003' ],
];
}
/**
* @ param string $alias
* @ param string $expected
*/
2025-06-30 10:56:59 -04:00
#[\PHPUnit\Framework\Attributes\DataProvider('dataGetMigration')]
2024-09-15 16:32:31 -04:00
public function testGetMigration ( $alias , $expected ) : void {
2017-06-01 10:56:34 -04:00
$this -> migrationService = $this -> getMockBuilder ( MigrationService :: class )
2025-04-30 02:29:47 -04:00
-> onlyMethods ([ 'getMigratedVersions' , 'findMigrations' ])
2017-06-01 10:56:34 -04:00
-> setConstructorArgs ([ 'testing' , $this -> db ])
-> getMock ();
$this -> migrationService -> expects ( $this -> any ()) -> method ( 'getMigratedVersions' ) -> willReturn (
[ '20170130180000' , '20170130180001' ]
);
$this -> migrationService -> expects ( $this -> any ()) -> method ( 'findMigrations' ) -> willReturn (
[ '20170130180000' => 'X' , '20170130180001' => 'Y' , '20170130180002' => 'Z' , '20170130180003' => 'A' ]
);
$this -> assertEquals (
[ '20170130180000' , '20170130180001' , '20170130180002' , '20170130180003' ],
$this -> migrationService -> getAvailableVersions ());
2017-06-09 10:45:12 -04:00
$migration = $this -> migrationService -> getMigration ( $alias );
$this -> assertEquals ( $expected , $migration );
2017-06-01 10:56:34 -04:00
}
2024-09-15 16:32:31 -04:00
public function testMigrate () : void {
2017-06-01 10:56:34 -04:00
$this -> migrationService = $this -> getMockBuilder ( MigrationService :: class )
2025-04-30 02:29:47 -04:00
-> onlyMethods ([ 'getMigratedVersions' , 'findMigrations' , 'executeStep' ])
2017-06-01 10:56:34 -04:00
-> setConstructorArgs ([ 'testing' , $this -> db ])
-> getMock ();
2025-04-30 02:29:47 -04:00
$this -> migrationService -> method ( 'getMigratedVersions' )
-> willReturn (
[ '20170130180000' , '20170130180001' ]
);
$this -> migrationService -> method ( 'findMigrations' )
-> willReturn (
[ '20170130180000' => 'X' , '20170130180001' => 'Y' , '20170130180002' => 'Z' , '20170130180003' => 'A' ]
);
2017-06-01 10:56:34 -04:00
$this -> assertEquals (
[ '20170130180000' , '20170130180001' , '20170130180002' , '20170130180003' ],
2025-04-30 02:29:47 -04:00
$this -> migrationService -> getAvailableVersions ()
);
2017-06-01 10:56:34 -04:00
2025-04-30 02:29:47 -04:00
$calls = [
[ '20170130180002' , false ],
[ '20170130180003' , false ],
];
$this -> migrationService -> expects ( $this -> exactly ( 2 ))
-> method ( 'executeStep' )
2025-06-12 12:31:58 -04:00
-> willReturnCallback ( function () use ( & $calls ) : void {
2025-04-30 02:29:47 -04:00
$expected = array_shift ( $calls );
$this -> assertEquals ( $expected , func_get_args ());
});
2017-06-01 10:56:34 -04:00
$this -> migrationService -> migrate ();
}
2018-07-18 04:42:32 -04:00
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsValid () : void {
2018-07-18 04:42:32 -04:00
$column = $this -> createMock ( Column :: class );
$column -> expects ( $this -> once ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$index = $this -> createMock ( Index :: class );
$index -> expects ( $this -> once ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$foreignKey = $this -> createMock ( ForeignKeyConstraint :: class );
$foreignKey -> expects ( $this -> once ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$table = $this -> createMock ( Table :: class );
2018-10-10 04:45:10 -04:00
$table -> expects ( $this -> atLeastOnce ())
2018-07-18 04:42:32 -04:00
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$sequence = $this -> createMock ( Sequence :: class );
2018-10-10 04:45:10 -04:00
$sequence -> expects ( $this -> atLeastOnce ())
2018-07-18 04:42:32 -04:00
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
2022-03-10 08:04:04 -05:00
$primaryKey = $this -> createMock ( Index :: class );
2022-11-14 10:14:35 -05:00
$primaryKey -> expects ( $this -> once ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
2022-03-10 08:04:04 -05:00
2018-07-18 04:42:32 -04:00
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([ $column ]);
$table -> expects ( $this -> once ())
-> method ( 'getIndexes' )
-> willReturn ([ $index ]);
$table -> expects ( $this -> once ())
-> method ( 'getForeignKeys' )
-> willReturn ([ $foreignKey ]);
$table -> expects ( $this -> once ())
-> method ( 'getPrimaryKey' )
2022-03-10 08:04:04 -05:00
-> willReturn ( $primaryKey );
2018-07-18 04:42:32 -04:00
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
$schema -> expects ( $this -> once ())
-> method ( 'getSequences' )
-> willReturn ([ $sequence ]);
2018-10-10 04:45:10 -04:00
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2018-07-18 04:42:32 -04:00
}
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsValidWithPrimaryKey () : void {
2018-07-18 04:42:32 -04:00
$index = $this -> createMock ( Index :: class );
2018-07-19 04:28:52 -04:00
$index -> expects ( $this -> any ())
2018-07-18 04:42:32 -04:00
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$table = $this -> createMock ( Table :: class );
2018-07-19 04:28:52 -04:00
$table -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 26 ));
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getIndexes' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getForeignKeys' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getPrimaryKey' )
-> willReturn ( $index );
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
$schema -> expects ( $this -> once ())
-> method ( 'getSequences' )
-> willReturn ([]);
2018-10-10 04:45:10 -04:00
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2018-07-19 04:28:52 -04:00
}
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsValidWithPrimaryKeyDefault () : void {
2018-07-19 04:28:52 -04:00
$defaultName = 'PRIMARY' ;
2024-07-01 10:59:47 -04:00
if ( $this -> db -> getDatabaseProvider () === IDBConnection :: PLATFORM_POSTGRES ) {
2018-07-19 04:28:52 -04:00
$defaultName = \str_repeat ( 'a' , 26 ) . '_' . \str_repeat ( 'b' , 30 ) . '_seq' ;
2024-07-01 10:59:47 -04:00
} elseif ( $this -> db -> getDatabaseProvider () === IDBConnection :: PLATFORM_ORACLE ) {
2018-07-19 04:28:52 -04:00
$defaultName = \str_repeat ( 'a' , 26 ) . '_seq' ;
}
$index = $this -> createMock ( Index :: class );
$index -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( $defaultName );
$index -> expects ( $this -> any ())
-> method ( 'getColumns' )
-> willReturn ([ \str_repeat ( 'b' , 30 )]);
$table = $this -> createMock ( Table :: class );
$table -> expects ( $this -> any ())
2018-07-18 04:42:32 -04:00
-> method ( 'getName' )
2019-12-05 08:38:28 -05:00
-> willReturn ( \str_repeat ( 'a' , 25 ));
2018-07-18 04:42:32 -04:00
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getIndexes' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getForeignKeys' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getPrimaryKey' )
-> willReturn ( $index );
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
$schema -> expects ( $this -> once ())
-> method ( 'getSequences' )
-> willReturn ([]);
2018-10-10 04:45:10 -04:00
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2018-07-18 04:42:32 -04:00
}
2019-12-05 08:38:28 -05:00
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsTooLongTableName () : void {
2019-11-27 09:27:18 -05:00
$this -> expectException ( \InvalidArgumentException :: class );
2018-07-18 04:42:32 -04:00
$table = $this -> createMock ( Table :: class );
$table -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 31 ));
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
2018-10-10 04:45:10 -04:00
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2018-07-18 04:42:32 -04:00
}
2019-12-05 08:38:28 -05:00
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsTooLongPrimaryWithDefault () : void {
2019-11-27 09:27:18 -05:00
$this -> expectException ( \InvalidArgumentException :: class );
2018-07-19 04:28:52 -04:00
$defaultName = 'PRIMARY' ;
2024-07-01 10:59:47 -04:00
if ( $this -> db -> getDatabaseProvider () === IDBConnection :: PLATFORM_POSTGRES ) {
2018-07-19 04:28:52 -04:00
$defaultName = \str_repeat ( 'a' , 27 ) . '_' . \str_repeat ( 'b' , 30 ) . '_seq' ;
2024-07-01 10:59:47 -04:00
} elseif ( $this -> db -> getDatabaseProvider () === IDBConnection :: PLATFORM_ORACLE ) {
2018-07-19 04:28:52 -04:00
$defaultName = \str_repeat ( 'a' , 27 ) . '_seq' ;
}
2018-07-18 04:42:32 -04:00
$index = $this -> createMock ( Index :: class );
$index -> expects ( $this -> any ())
-> method ( 'getName' )
2018-07-19 04:28:52 -04:00
-> willReturn ( $defaultName );
$index -> expects ( $this -> any ())
-> method ( 'getColumns' )
-> willReturn ([ \str_repeat ( 'b' , 30 )]);
2018-07-18 04:42:32 -04:00
$table = $this -> createMock ( Table :: class );
$table -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 27 ));
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getIndexes' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getForeignKeys' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getPrimaryKey' )
-> willReturn ( $index );
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
2018-10-10 04:45:10 -04:00
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2018-07-18 04:42:32 -04:00
}
2019-12-05 08:38:28 -05:00
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsTooLongPrimaryWithName () : void {
2019-11-27 09:27:18 -05:00
$this -> expectException ( \InvalidArgumentException :: class );
2018-07-18 04:42:32 -04:00
$index = $this -> createMock ( Index :: class );
$index -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 31 ));
$table = $this -> createMock ( Table :: class );
$table -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 26 ));
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getIndexes' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getForeignKeys' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getPrimaryKey' )
-> willReturn ( $index );
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
2018-10-10 04:45:10 -04:00
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2018-07-18 04:42:32 -04:00
}
2019-12-05 08:38:28 -05:00
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsTooLongColumnName () : void {
2019-11-27 09:27:18 -05:00
$this -> expectException ( \InvalidArgumentException :: class );
2018-07-18 04:42:32 -04:00
$column = $this -> createMock ( Column :: class );
$column -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 31 ));
$table = $this -> createMock ( Table :: class );
$table -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([ $column ]);
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
2018-10-10 04:45:10 -04:00
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2018-07-18 04:42:32 -04:00
}
2019-12-05 08:38:28 -05:00
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsTooLongIndexName () : void {
2019-11-27 09:27:18 -05:00
$this -> expectException ( \InvalidArgumentException :: class );
2018-07-18 04:42:32 -04:00
$index = $this -> createMock ( Index :: class );
$index -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 31 ));
$table = $this -> createMock ( Table :: class );
$table -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getIndexes' )
-> willReturn ([ $index ]);
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
2018-10-10 04:45:10 -04:00
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2018-07-18 04:42:32 -04:00
}
2019-12-05 08:38:28 -05:00
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsTooLongForeignKeyName () : void {
2019-11-27 09:27:18 -05:00
$this -> expectException ( \InvalidArgumentException :: class );
2018-07-18 04:42:32 -04:00
$foreignKey = $this -> createMock ( ForeignKeyConstraint :: class );
$foreignKey -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 31 ));
$table = $this -> createMock ( Table :: class );
$table -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getIndexes' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getForeignKeys' )
-> willReturn ([ $foreignKey ]);
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
2018-10-10 04:45:10 -04:00
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2022-03-10 08:04:04 -05:00
}
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsNoPrimaryKey () : void {
2022-03-22 12:07:48 -04:00
$this -> markTestSkipped ( 'Test disabled for now due to multiple reasons, see https://github.com/nextcloud/server/pull/31580#issuecomment-1069182234 for details.' );
2022-03-10 08:04:04 -05:00
$this -> expectException ( \InvalidArgumentException :: class );
$table = $this -> createMock ( Table :: class );
$table -> expects ( $this -> atLeastOnce ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getIndexes' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getForeignKeys' )
-> willReturn ([]);
$table -> expects ( $this -> once ())
-> method ( 'getPrimaryKey' )
-> willReturn ( null );
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
$schema -> expects ( $this -> once ())
-> method ( 'getSequences' )
-> willReturn ([]);
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2018-07-18 04:42:32 -04:00
}
2019-12-05 08:38:28 -05:00
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsTooLongSequenceName () : void {
2019-11-27 09:27:18 -05:00
$this -> expectException ( \InvalidArgumentException :: class );
2018-07-18 04:42:32 -04:00
$sequence = $this -> createMock ( Sequence :: class );
$sequence -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 31 ));
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([]);
$schema -> expects ( $this -> once ())
-> method ( 'getSequences' )
-> willReturn ([ $sequence ]);
2018-10-10 04:45:10 -04:00
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2018-07-18 04:42:32 -04:00
}
2020-11-11 08:34:24 -05:00
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsBooleanNotNull () : void {
2020-11-11 08:34:24 -05:00
$this -> expectException ( \InvalidArgumentException :: class );
$column = $this -> createMock ( Column :: class );
$column -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( 'aaaa' );
$column -> expects ( $this -> any ())
-> method ( 'getType' )
-> willReturn ( Type :: getType ( 'boolean' ));
$column -> expects ( $this -> any ())
-> method ( 'getNotnull' )
-> willReturn ( true );
$table = $this -> createMock ( Table :: class );
$table -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([ $column ]);
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
2020-11-11 08:40:26 -05:00
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
2020-11-11 08:34:24 -05:00
}
2022-03-23 10:04:18 -04:00
2024-09-15 16:32:31 -04:00
public function testEnsureOracleConstraintsStringLength4000 () : void {
2022-03-23 10:04:18 -04:00
$this -> expectException ( \InvalidArgumentException :: class );
$column = $this -> createMock ( Column :: class );
$column -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( 'aaaa' );
$column -> expects ( $this -> any ())
-> method ( 'getType' )
-> willReturn ( Type :: getType ( 'string' ));
$column -> expects ( $this -> any ())
-> method ( 'getLength' )
-> willReturn ( 4001 );
$table = $this -> createMock ( Table :: class );
$table -> expects ( $this -> any ())
-> method ( 'getName' )
-> willReturn ( \str_repeat ( 'a' , 30 ));
$table -> expects ( $this -> once ())
-> method ( 'getColumns' )
-> willReturn ([ $column ]);
$schema = $this -> createMock ( Schema :: class );
$schema -> expects ( $this -> once ())
-> method ( 'getTables' )
-> willReturn ([ $table ]);
$sourceSchema = $this -> createMock ( Schema :: class );
$sourceSchema -> expects ( $this -> any ())
-> method ( 'getTable' )
-> willThrowException ( new SchemaException ());
$sourceSchema -> expects ( $this -> any ())
-> method ( 'hasSequence' )
-> willReturn ( false );
self :: invokePrivate ( $this -> migrationService , 'ensureOracleConstraints' , [ $sourceSchema , $schema , 3 ]);
}
2024-07-29 07:14:29 -04:00
2024-09-15 16:32:31 -04:00
public function testExtractMigrationAttributes () : void {
2024-07-29 07:14:29 -04:00
$metadataManager = Server :: get ( MetadataManager :: class );
$this -> appManager -> loadApp ( 'testing' );
$this -> assertEquals ( $this -> getMigrationMetadata (), json_decode ( json_encode ( $metadataManager -> extractMigrationAttributes ( 'testing' )), true ));
$this -> appManager -> disableApp ( 'testing' );
}
2024-09-15 16:32:31 -04:00
public function testDeserializeMigrationMetadata () : void {
2024-07-29 07:14:29 -04:00
$metadataManager = Server :: get ( MetadataManager :: class );
$this -> assertEquals (
[
'core' => [],
'apps' => [
'testing' => [
'30000Date20240102030405' => [
new DropTable ( 'old_table' ),
new CreateTable ( 'new_table' ,
description : 'Table is used to store things, but also to get more things' ,
notes : [ 'this is a notice' , 'and another one, if really needed' ]
),
new AddColumn ( 'my_table' ),
new AddColumn ( 'my_table' , 'another_field' ),
new AddColumn ( 'other_table' , 'last_one' , ColumnType :: DATE ),
new AddIndex ( 'my_table' ),
new AddIndex ( 'my_table' , IndexType :: PRIMARY ),
new DropColumn ( 'other_table' ),
new DropColumn ( 'other_table' , 'old_column' ,
description : 'field is not used anymore and replaced by \'last_one\''
),
new DropIndex ( 'other_table' ),
new ModifyColumn ( 'other_table' ),
new ModifyColumn ( 'other_table' , 'this_field' ),
new ModifyColumn ( 'other_table' , 'this_field' , ColumnType :: BIGINT )
]
]
]
],
$metadataManager -> getMigrationsAttributesFromReleaseMetadata (
[
'core' => [],
'apps' => [ 'testing' => $this -> getMigrationMetadata ()]
]
)
);
}
private function getMigrationMetadata () : array {
return [
'30000Date20240102030405' => [
[
'class' => 'OCP\\Migration\\Attributes\\DropTable' ,
'table' => 'old_table' ,
'description' => '' ,
'notes' => [],
'columns' => []
],
[
'class' => 'OCP\\Migration\\Attributes\\CreateTable' ,
'table' => 'new_table' ,
'description' => 'Table is used to store things, but also to get more things' ,
2025-06-30 09:04:05 -04:00
'notes' => [
'this is a notice' ,
'and another one, if really needed'
],
2024-07-29 07:14:29 -04:00
'columns' => []
],
[
'class' => 'OCP\\Migration\\Attributes\\AddColumn' ,
'table' => 'my_table' ,
'description' => '' ,
'notes' => [],
'name' => '' ,
'type' => ''
],
[
'class' => 'OCP\\Migration\\Attributes\\AddColumn' ,
'table' => 'my_table' ,
'description' => '' ,
'notes' => [],
'name' => 'another_field' ,
'type' => ''
],
[
'class' => 'OCP\\Migration\\Attributes\\AddColumn' ,
'table' => 'other_table' ,
'description' => '' ,
'notes' => [],
'name' => 'last_one' ,
'type' => 'date'
],
[
'class' => 'OCP\\Migration\\Attributes\\AddIndex' ,
'table' => 'my_table' ,
'description' => '' ,
'notes' => [],
'type' => ''
],
[
'class' => 'OCP\\Migration\\Attributes\\AddIndex' ,
'table' => 'my_table' ,
'description' => '' ,
'notes' => [],
'type' => 'primary'
],
[
'class' => 'OCP\\Migration\\Attributes\\DropColumn' ,
'table' => 'other_table' ,
'description' => '' ,
'notes' => [],
'name' => '' ,
'type' => ''
],
[
'class' => 'OCP\\Migration\\Attributes\\DropColumn' ,
'table' => 'other_table' ,
'description' => 'field is not used anymore and replaced by \'last_one\'' ,
'notes' => [],
'name' => 'old_column' ,
'type' => ''
],
[
'class' => 'OCP\\Migration\\Attributes\\DropIndex' ,
'table' => 'other_table' ,
'description' => '' ,
'notes' => [],
'type' => ''
],
[
'class' => 'OCP\\Migration\\Attributes\\ModifyColumn' ,
'table' => 'other_table' ,
'description' => '' ,
'notes' => [],
'name' => '' ,
'type' => ''
],
[
'class' => 'OCP\\Migration\\Attributes\\ModifyColumn' ,
'table' => 'other_table' ,
'description' => '' ,
'notes' => [],
'name' => 'this_field' ,
'type' => ''
],
[
'class' => 'OCP\\Migration\\Attributes\\ModifyColumn' ,
'table' => 'other_table' ,
'description' => '' ,
'notes' => [],
'name' => 'this_field' ,
'type' => 'bigint'
],
]
];
}
2017-06-01 10:56:34 -04:00
}