Merge pull request #6650 from owncloud/migration_unit_tests
User migration fix, and basic unit test
This commit is contained in:
commit
a573fe7d76
|
@ -44,7 +44,7 @@ class OC_DB {
|
|||
/**
|
||||
* @var \OC\DB\Connection $connection
|
||||
*/
|
||||
static private $connection; //the prefered connection to use, only Doctrine
|
||||
static private $connection; //the preferred connection to use, only Doctrine
|
||||
|
||||
static private $prefix=null;
|
||||
static private $type=null;
|
||||
|
|
|
@ -35,12 +35,8 @@ class OC_Migrate{
|
|||
static private $zip=false;
|
||||
// Stores the type of export
|
||||
static private $exporttype=false;
|
||||
// Array of temp files to be deleted after zip creation
|
||||
static private $tmpfiles=array();
|
||||
// Holds the db object
|
||||
static private $MDB2=false;
|
||||
// Schema db object
|
||||
static private $schema=false;
|
||||
static private $migration_database=false;
|
||||
// Path to the sqlite db
|
||||
static private $dbpath=false;
|
||||
// Holds the path to the zip file
|
||||
|
@ -131,7 +127,7 @@ class OC_Migrate{
|
|||
if( !self::connectDB() ) {
|
||||
return json_encode( array( 'success' => false ) );
|
||||
}
|
||||
self::$content = new OC_Migration_Content( self::$zip, self::$MDB2 );
|
||||
self::$content = new OC_Migration_Content( self::$zip, self::$migration_database );
|
||||
// Export the app info
|
||||
$exportdata = self::exportAppData();
|
||||
// Add the data dir to the zip
|
||||
|
@ -257,7 +253,7 @@ class OC_Migrate{
|
|||
$userfolder = $extractpath . $json->exporteduser;
|
||||
$newuserfolder = $datadir . '/' . self::$uid;
|
||||
foreach(scandir($userfolder) as $file){
|
||||
if($file !== '.' && $file !== '..' && is_dir($file)) {
|
||||
if($file !== '.' && $file !== '..' && is_dir($userfolder.'/'.$file)) {
|
||||
$file = str_replace(array('/', '\\'), '', $file);
|
||||
|
||||
// Then copy the folder over
|
||||
|
@ -358,24 +354,6 @@ class OC_Migrate{
|
|||
return $to;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief connects to a MDB2 database scheme
|
||||
* @returns bool
|
||||
*/
|
||||
static private function connectScheme() {
|
||||
// We need a mdb2 database connection
|
||||
self::$MDB2->loadModule( 'Manager' );
|
||||
self::$MDB2->loadModule( 'Reverse' );
|
||||
|
||||
// Connect if this did not happen before
|
||||
if( !self::$schema ) {
|
||||
require_once 'MDB2/Schema.php';
|
||||
self::$schema=MDB2_Schema::factory( self::$MDB2 );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief creates a migration.db in the users data dir with their app data in
|
||||
* @return bool whether operation was successfull
|
||||
|
@ -463,47 +441,18 @@ class OC_Migrate{
|
|||
return false;
|
||||
}
|
||||
// Already connected
|
||||
if(!self::$MDB2) {
|
||||
require_once 'MDB2.php';
|
||||
|
||||
if(!self::$migration_database) {
|
||||
$datadir = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" );
|
||||
|
||||
// DB type
|
||||
if( class_exists( 'SQLite3' ) ) {
|
||||
$dbtype = 'sqlite3';
|
||||
} else if( is_callable( 'sqlite_open' ) ) {
|
||||
$dbtype = 'sqlite';
|
||||
} else {
|
||||
OC_Log::write( 'migration', 'SQLite not found', OC_Log::ERROR );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prepare options array
|
||||
$options = array(
|
||||
'portability' => MDB2_PORTABILITY_ALL & (!MDB2_PORTABILITY_FIX_CASE),
|
||||
'log_line_break' => '<br>',
|
||||
'idxname_format' => '%s',
|
||||
'debug' => true,
|
||||
'quote_identifier' => true
|
||||
);
|
||||
$dsn = array(
|
||||
'phptype' => $dbtype,
|
||||
'database' => self::$dbpath,
|
||||
'mode' => '0644'
|
||||
$connectionParams = array(
|
||||
'path' => self::$dbpath,
|
||||
'driver' => 'pdo_sqlite',
|
||||
);
|
||||
$connectionParams['adapter'] = '\OC\DB\AdapterSqlite';
|
||||
$connectionParams['wrapperClass'] = 'OC\DB\Connection';
|
||||
$connectionParams['tablePrefix'] = '';
|
||||
|
||||
// Try to establish connection
|
||||
self::$MDB2 = MDB2::factory( $dsn, $options );
|
||||
// Die if we could not connect
|
||||
if( PEAR::isError( self::$MDB2 ) ) {
|
||||
die( self::$MDB2->getMessage() );
|
||||
OC_Log::write( 'migration', 'Failed to create/connect to migration.db', OC_Log::FATAL );
|
||||
OC_Log::write( 'migration', self::$MDB2->getUserInfo(), OC_Log::FATAL );
|
||||
OC_Log::write( 'migration', self::$MDB2->getMessage(), OC_Log::FATAL );
|
||||
return false;
|
||||
}
|
||||
// We always, really always want associative arrays
|
||||
self::$MDB2->setFetchMode(MDB2_FETCHMODE_ASSOC);
|
||||
self::$migration_database = \Doctrine\DBAL\DriverManager::getConnection($connectionParams);
|
||||
}
|
||||
return true;
|
||||
|
||||
|
@ -515,10 +464,7 @@ class OC_Migrate{
|
|||
* @return bool whether the operation was successful
|
||||
*/
|
||||
static private function createAppTables( $appid ) {
|
||||
|
||||
if( !self::connectScheme() ) {
|
||||
return false;
|
||||
}
|
||||
$schema_manager = new OC\DB\MDB2SchemaManager(self::$migration_database);
|
||||
|
||||
// There is a database.xml file
|
||||
$content = file_get_contents(OC_App::getAppPath($appid) . '/appinfo/database.xml' );
|
||||
|
@ -538,29 +484,16 @@ class OC_Migrate{
|
|||
file_put_contents( $file2, $content );
|
||||
|
||||
// Try to create tables
|
||||
$definition = self::$schema->parseDatabaseDefinitionFile( $file2 );
|
||||
|
||||
try {
|
||||
$schema_manager->createDbFromStructure($file2);
|
||||
} catch(Exception $e) {
|
||||
unlink( $file2 );
|
||||
|
||||
// Die in case something went wrong
|
||||
if( $definition instanceof MDB2_Schema_Error ) {
|
||||
OC_Log::write( 'migration', 'Failed to parse database.xml for: '.$appid, OC_Log::FATAL );
|
||||
OC_Log::write( 'migration', $definition->getMessage().': '.$definition->getUserInfo(), OC_Log::FATAL );
|
||||
return false;
|
||||
}
|
||||
|
||||
$definition['overwrite'] = true;
|
||||
|
||||
$ret = self::$schema->createDatabase( $definition );
|
||||
|
||||
// Die in case something went wrong
|
||||
if( $ret instanceof MDB2_Error ) {
|
||||
OC_Log::write( 'migration', 'Failed to create tables for: '.$appid, OC_Log::FATAL );
|
||||
OC_Log::write( 'migration', $ret->getMessage().': '.$ret->getUserInfo(), OC_Log::FATAL );
|
||||
OC_Log::write( 'migration', $e->getMessage(), OC_Log::FATAL );
|
||||
return false;
|
||||
}
|
||||
return $tables;
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -646,7 +579,7 @@ class OC_Migrate{
|
|||
if( !self::connectDB( $db ) ) {
|
||||
return false;
|
||||
}
|
||||
$content = new OC_Migration_Content( self::$zip, self::$MDB2 );
|
||||
$content = new OC_Migration_Content( self::$zip, self::$migration_database );
|
||||
$provider->setData( self::$uid, $content, $info );
|
||||
// Then do the import
|
||||
if( !$appsstatus[$id] = $provider->import( $info->apps->$id, $importinfo ) ) {
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
class OC_Migration_Content{
|
||||
|
||||
private $zip=false;
|
||||
// Holds the MDB2 object
|
||||
// Holds the database object
|
||||
private $db=null;
|
||||
// Holds an array of tmpfiles to delete after zip creation
|
||||
private $tmpfiles=array();
|
||||
|
@ -35,7 +35,7 @@ class OC_Migration_Content{
|
|||
/**
|
||||
* @brief sets up the
|
||||
* @param $zip ZipArchive object
|
||||
* @param optional $db a MDB2 database object (required for exporttype user)
|
||||
* @param optional $db a database object (required for exporttype user)
|
||||
* @return bool
|
||||
*/
|
||||
public function __construct( $zip, $db=null ) {
|
||||
|
@ -63,19 +63,11 @@ class OC_Migration_Content{
|
|||
|
||||
// Optimize the query
|
||||
$query = $this->db->prepare( $query );
|
||||
$query = new OC_DB_StatementWrapper($query, false);
|
||||
|
||||
// Die if we have an error (error means: bad query, not 0 results!)
|
||||
if( PEAR::isError( $query ) ) {
|
||||
$entry = 'DB Error: "'.$query->getMessage().'"<br />';
|
||||
$entry .= 'Offending command was: '.$query.'<br />';
|
||||
OC_Log::write( 'migration', $entry, OC_Log::FATAL );
|
||||
return false;
|
||||
} else {
|
||||
return $query;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief processes the db query
|
||||
* @param $query the query to process
|
||||
|
@ -156,11 +148,6 @@ class OC_Migration_Content{
|
|||
$sql .= $valuessql . " )";
|
||||
// Make the query
|
||||
$query = $this->prepare( $sql );
|
||||
if( !$query ) {
|
||||
OC_Log::write( 'migration', 'Invalid sql produced: '.$sql, OC_Log::FATAL );
|
||||
return false;
|
||||
exit();
|
||||
} else {
|
||||
$query->execute( $values );
|
||||
// Do we need to return some values?
|
||||
if( array_key_exists( 'idcol', $options ) ) {
|
||||
|
@ -170,7 +157,6 @@ class OC_Migration_Content{
|
|||
// Take a guess and return the first field :)
|
||||
$return[] = reset($row);
|
||||
}
|
||||
}
|
||||
$fields = '';
|
||||
$values = '';
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2014 Tom Needham <tom@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
class Test_Migrate extends PHPUnit_Framework_TestCase {
|
||||
|
||||
public $users;
|
||||
public $tmpfiles = array();
|
||||
|
||||
/**
|
||||
* @brief Generates a test user and sets up their file system
|
||||
* @return string the test users id
|
||||
*/
|
||||
public function generateUser() {
|
||||
$username = uniqid();
|
||||
\OC_User::createUser($username, 'password');
|
||||
\OC_Util::tearDownFS();
|
||||
\OC_User::setUserId('');
|
||||
\OC\Files\Filesystem::tearDown();
|
||||
\OC_Util::setupFS($username);
|
||||
$this->users[] = $username;
|
||||
return $username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief validates an export for a user
|
||||
* @brief checks for existence of export_info.json and file folder
|
||||
* @param string $exportedUser the user that was exported
|
||||
* @param string $path the path to the .zip export
|
||||
*/
|
||||
public function validateUserExport($exportedBy, $exportedUser, $path) {
|
||||
$this->assertTrue(file_exists($path));
|
||||
// Extract
|
||||
$extract = get_temp_dir() . '/oc_import_' . uniqid();
|
||||
//mkdir($extract);
|
||||
$this->tmpfiles[] = $extract;
|
||||
$zip = new ZipArchive;
|
||||
$zip->open($path);
|
||||
$zip->extractTo($extract);
|
||||
$zip->close();
|
||||
$this->assertTrue(file_exists($extract.'/export_info.json'));
|
||||
$exportInfo = file_get_contents($extract.'/export_info.json');
|
||||
$exportInfo = json_decode($exportInfo);
|
||||
$this->assertNotNull($exportInfo);
|
||||
$this->assertEquals($exportedUser, $exportInfo->exporteduser);
|
||||
$this->assertEquals($exportedBy, $exportInfo->exportedby);
|
||||
$this->assertTrue(file_exists($extract.'/'.$exportedUser.'/files'));
|
||||
}
|
||||
|
||||
public function testUserSelfExport() {
|
||||
// Create a user
|
||||
$user = $this->generateUser();
|
||||
\OC_User::setUserId($user);
|
||||
$export = \OC_Migrate::export($user);
|
||||
// Check it succeeded and exists
|
||||
$this->assertTrue(json_decode($export)->success);
|
||||
// Validate the export
|
||||
$this->validateUserExport($user, $user, json_decode($export)->data);
|
||||
}
|
||||
|
||||
public function testUserOtherExport() {
|
||||
$user = $this->generateUser();
|
||||
$user2 = $this->generateUser();
|
||||
\OC_User::setUserId($user2);
|
||||
$export = \OC_Migrate::export($user);
|
||||
// Check it succeeded and exists
|
||||
$this->assertTrue(json_decode($export)->success);
|
||||
// Validate the export
|
||||
$this->validateUserExport($user2, $user, json_decode($export)->data);
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
$u = new OC_User();
|
||||
foreach($this->users as $user) {
|
||||
$u->deleteUser($user);
|
||||
}
|
||||
foreach($this->tmpfiles as $file) {
|
||||
\OC_Helper::rmdirr($file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue