├── .gitignore ├── .travis.yml ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── McCool │ └── DatabaseBackup │ │ ├── Archivers │ │ ├── ArchiverInterface.php │ │ └── GzipArchiver.php │ │ ├── BackupProcedure.php │ │ ├── Commands │ │ └── LaravelBackupCommand.php │ │ ├── Dumpers │ │ ├── DumperInterface.php │ │ └── MysqlDumper.php │ │ ├── Processors │ │ ├── ProcessorException.php │ │ ├── ProcessorInterface.php │ │ └── ShellProcessor.php │ │ ├── ServiceProviders │ │ └── LaravelServiceProvider.php │ │ └── Storers │ │ ├── S3Storer.php │ │ └── StorerInterface.php └── config │ └── config.php └── tests ├── .gitkeep ├── Archivers └── GzipArchiverTest.php ├── BackupProcedureTest.php ├── Commands └── LaravelBackupCommandTest.php ├── Dumpers └── MysqlDumperTest.php ├── Processors └── ShellProcessorTest.php ├── ServiceProviders └── LaravelServiceProviderTest.php └── Storers └── S3StorerTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store 5 | phpunit.php 6 | .idea 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | 8 | before_script: 9 | - curl -s http://getcomposer.org/installer | php 10 | - php composer.phar install --dev 11 | 12 | script: phpunit -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > This package is abandoned. This [Backup Manager](https://github.com/backup-manager) has fully replaced it. 2 | 3 | Database Backup 4 | =============== 5 | 6 | A framework-agnostic database backup package. 7 | 8 | **Drivers:** At this moment the package supports MySQL, gzip, and Amazon S3. However, it's modular and could be extended to support much more. 9 | 10 | **Frameworks:** This package doesn't require a framework, but a Laravel service provider and Artisan command are made available for convenience. 11 | 12 | Note: be aware that this package uses ```mysqldump``` for MySQL backups. 13 | 14 | # Example 15 | 16 | Laravel users can run the following command if they'd like to backup the db, gzip it, upload it to s3, and remove the local backup file: 17 | 18 | ```PHP 19 | php artisan db:backup --s3-bucket=whatever --s3-path=/this/is/optional/ --cleanup --gzip 20 | ``` 21 | 22 | Non-Laravel users can look at the Usage section below. 23 | 24 | # Requirements 25 | 26 | * 5.4 (would openly accept pull requests to lower to 5.3) 27 | 28 | # Installation 29 | 30 | ## Laravel 31 | 32 | 1. add to composer.json 33 | 34 | ```JSON 35 | "mccool/database-backup": "1.0.1" 36 | ``` 37 | 2. install dependency 38 | 39 | ```SHELL 40 | composer update 41 | ``` 42 | 3. install configuration file 43 | 44 | ```SHELL 45 | php artisan config:publish mccool/database-backup 46 | ``` 47 | 4. add service provider to config/app.php 48 | 49 | ```PHP 50 | 'McCool\DatabaseBackup\ServiceProviders\LaravelServiceProvider', 51 | ``` 52 | 5. add key / secret to the config file in ```app/config/packages/mccool/database-backup/aws.php``` 53 | 54 | ## Native PHP 55 | 56 | 1. add to composer.json 57 | 58 | ```JSON 59 | "mccool/database-backup": "dev-master" 60 | ``` 61 | 2. install dependency 62 | 63 | ```SHELL 64 | composer update 65 | ``` 66 | 3. make sure that your app requires the composer autoloader 67 | 68 | ```PHP 69 | require '../vendor/autoload.php'; 70 | ``` 71 | 72 | # Usage 73 | 74 | ## Laravel 75 | 76 | **Dump the database to app/storage/dumps/databasename_timestamp.sql** 77 | 78 | ```SHELL 79 | php artisan db:backup 80 | ``` 81 | 82 | **Store the database to backups/databasename_timestamp.sql** 83 | 84 | ```SHELL 85 | php artisan db:backup --local-path=backups 86 | ``` 87 | 88 | **Gzip the database.** 89 | 90 | ```SHELL 91 | php artisan db:backup --gzip 92 | ``` 93 | 94 | **Choose a database to dump other than the default (names are configured in Laravel's config/database.php).** 95 | 96 | ```SHELL 97 | php artisan db:backup --database=otherdatabaseconnection 98 | ``` 99 | 100 | **Choose a specific filename other than the default (default is 'Y-m-d_H-i-s' ). Note, do not include the file extension .sql, we will do that for you** 101 | 102 | ```SHELL 103 | php artisan db:backup --filename=my_project_backup 104 | ``` 105 | 106 | **Upload the backup to S3** 107 | 108 | ```SHELL 109 | php artisan db:backup --s3-bucket=whatever --s3-path=/this/is/optional/ 110 | ``` 111 | 112 | **Cleanup file when we're done** 113 | 114 | ```SHELL 115 | php artisan db:backup --s3-bucket=whatever --s3-path=/this/is/optional/ --cleanup 116 | ``` 117 | 118 | ## Native PHP 119 | 120 | ```PHP 121 | backup(); 131 | 132 | // dump the database to backup/test.sql and gzip it 133 | $shellProcessor = new McCool\DatabaseBackup\Processors\ShellProcessor(new Symfony\Component\Process\Process('')); 134 | $dumper = new McCool\DatabaseBackup\Dumpers\MysqlDumper($shellProcessor, 'localhost', 3306, 'username', 'password', 'test_db', 'backup/test.sql'); 135 | $archiver = new McCool\DatabaseBackup\Archivers\GzipArchiver($shellProcessor); 136 | 137 | $backup = new McCool\DatabaseBackup\BackupProcedure($dumper); 138 | $backup->setArchiver($archiver); 139 | 140 | $backup->backup(); 141 | 142 | // dump the database to backup/test.sql, gzip it, upload it to S3, and clean up after ourselves 143 | $shellProcessor = new McCool\DatabaseBackup\Processors\ShellProcessor(new Symfony\Component\Process\Process('')); 144 | $dumper = new McCool\DatabaseBackup\Dumpers\MysqlDumper($shellProcessor, 'localhost', 3306, 'username', 'password', 'test_db', 'backup/test.sql'); 145 | $archiver = new McCool\DatabaseBackup\Archivers\GzipArchiver($shellProcessor); 146 | $storer = new McCool\DatabaseBackup\Storers\S3Storer($awsKey, $awsSecret, 'us-east-1', $bucket, $s3Path); 147 | 148 | $backup = new McCool\DatabaseBackup\BackupProcedure($dumper); 149 | $backup->setArchiver($archiver); 150 | $backup->setStorer($storer); 151 | 152 | $backup->backup(); 153 | $backup->cleanup(); 154 | ``` 155 | 156 | # License 157 | 158 | MIT 159 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mccool/database-backup", 3 | "description": "A framework-agnostic driver-based database backup package with a Laravel add-on.", 4 | "license": "MIT", 5 | "authors": [{ 6 | "name": "Shawn McCool", 7 | "email": "shawn@heybigname.com" 8 | }], 9 | "require": { 10 | "php": ">=5.3.0", 11 | "aws/aws-sdk-php": "~2.4", 12 | "symfony/process": "~2.1" 13 | }, 14 | "require-dev": { 15 | "phpunit/phpunit": "~4.0", 16 | "mockery/mockery": "~0.9", 17 | "illuminate/support": "~4.1", 18 | "illuminate/container": "~4.1", 19 | "illuminate/console": "~4.1" 20 | }, 21 | "autoload": { 22 | "psr-0": { 23 | "McCool\\DatabaseBackup": "src/" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/McCool/DatabaseBackup/Archivers/ArchiverInterface.php: -------------------------------------------------------------------------------- 1 | processor = $processor; 31 | } 32 | 33 | /** 34 | * Sets the filename for the backup. 35 | * 36 | * When you provide the filename make sure you obsolete the 37 | * file extension as this gets added automatically. 38 | * 39 | * @param string $filename 40 | * @return void 41 | */ 42 | public function setInputFilename($filename) 43 | { 44 | $this->filename = $filename; 45 | } 46 | 47 | /** 48 | * Returns the filename for the backup. 49 | * 50 | * @return string 51 | */ 52 | public function getOutputFilename() 53 | { 54 | return $this->filename . '.gz'; 55 | } 56 | 57 | /** 58 | * Executes the backup command. 59 | * 60 | * @return void 61 | * @throws \McCool\DatabaseBackup\Processors\ProcessorException 62 | */ 63 | public function archive() 64 | { 65 | $this->processor->process($this->getCommand()); 66 | 67 | if ($this->processor->getErrors()) { 68 | throw new ProcessorException($this->processor->getErrors()); 69 | } 70 | } 71 | 72 | /** 73 | * Returns the backup command. 74 | * 75 | * @return string 76 | */ 77 | protected function getCommand() 78 | { 79 | return "gzip {$this->filename}"; 80 | } 81 | } -------------------------------------------------------------------------------- /src/McCool/DatabaseBackup/BackupProcedure.php: -------------------------------------------------------------------------------- 1 | dumper = $dumper; 46 | } 47 | 48 | /** 49 | * Executes the backup. 50 | * 51 | * @return void 52 | */ 53 | public function backup() 54 | { 55 | $this->dump(); 56 | $this->archive(); 57 | $this->store(); 58 | } 59 | 60 | /** 61 | * Inject an Archiver 62 | * 63 | * @param \McCool\DatabaseBackup\Archivers\ArchiverInterface $archiver 64 | * @return void 65 | */ 66 | public function setArchiver(ArchiverInterface $archiver) 67 | { 68 | $this->archiver = $archiver; 69 | } 70 | 71 | /** 72 | * Inject a Storer 73 | * 74 | * @param \McCool\DatabaseBackup\Storers\StorerInterface $storer 75 | * @return void 76 | */ 77 | public function setStorer(StorerInterface $storer) 78 | { 79 | $this->storer = $storer; 80 | } 81 | 82 | /** 83 | * Cleans up the working file. 84 | * 85 | * @return void 86 | */ 87 | public function cleanup() 88 | { 89 | if (file_exists($this->workingFile)) { 90 | unlink($this->workingFile); 91 | } 92 | } 93 | 94 | /** 95 | * Dumps the backup in the working file. 96 | * 97 | * @return void 98 | */ 99 | protected function dump() 100 | { 101 | $this->dumper->dump(); 102 | 103 | $this->workingFile = $this->dumper->getOutputFilename(); 104 | } 105 | 106 | /** 107 | * Gzips the working file. 108 | * 109 | * @return void 110 | */ 111 | protected function archive() 112 | { 113 | if ($this->archiver) { 114 | $this->archiver->setInputFilename($this->workingFile); 115 | $this->archiver->archive(); 116 | 117 | $this->workingFile = $this->archiver->getOutputFilename(); 118 | } 119 | } 120 | 121 | /** 122 | * Stores the working file into the storage provider. 123 | * 124 | * return void 125 | */ 126 | protected function store() 127 | { 128 | if ($this->storer) { 129 | $this->storer->setInputFilename($this->workingFile); 130 | 131 | $this->storer->store(); 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /src/McCool/DatabaseBackup/Commands/LaravelBackupCommand.php: -------------------------------------------------------------------------------- 1 | getDumper()); 35 | 36 | $archiver = $this->getArchiver(); 37 | $storer = $this->getStorer(); 38 | 39 | if ($archiver) { 40 | $backup->setArchiver($archiver); 41 | } 42 | 43 | if ($storer) { 44 | $backup->setStorer($storer); 45 | } 46 | 47 | $backup->backup(); 48 | 49 | if ($this->option('cleanup')) { 50 | $backup->cleanup(); 51 | } 52 | } 53 | 54 | /** 55 | * Get the console command arguments. 56 | * 57 | * @return array 58 | */ 59 | protected function getArguments() 60 | { 61 | return array(); 62 | } 63 | 64 | /** 65 | * Get the console command options. 66 | * 67 | * @return array 68 | */ 69 | protected function getOptions() 70 | { 71 | return array( 72 | array('database', null, InputOption::VALUE_OPTIONAL, 'The database connection to backup, uses the default if not specified.', null), 73 | array('local-path', null, InputOption::VALUE_OPTIONAL, 'The local storage path for the dump. Defaults to app/storage/dumps.', null), 74 | array('s3-bucket', null, InputOption::VALUE_OPTIONAL, 'Specify this option to upload to S3.', null), 75 | array('s3-path', null, InputOption::VALUE_OPTIONAL, 'Define the path on the S3 bucket to store the file.', null), 76 | array('filename', null, InputOption::VALUE_OPTIONAL, 'Define the filename to be used.', null), 77 | array('gzip', null, InputOption::VALUE_NONE, 'Gzip the backup.', null), 78 | array('cleanup', null, InputOption::VALUE_NONE, 'Remove the dump when the process finishes.', null), 79 | ); 80 | } 81 | 82 | /** 83 | * Returns a MysqlDumper instance. 84 | * 85 | * @return \McCool\DatabaseBackup\Dumpers\MysqlDumper 86 | */ 87 | protected function getDumper() 88 | { 89 | // laravel config 90 | $connections = $this->laravel['config']->get('database.connections'); 91 | $connection = $this->option('database') ?: $this->laravel['config']->get('database.default'); 92 | $conn = $connections[$connection]; 93 | 94 | // file path 95 | $storagePath = $this->laravel['path.storage']; 96 | $localPath = $this->option('local-path') ?: $storagePath . '/dumps'; 97 | $filename = $this->option('filename') ?: ($conn['database'] .'-'. date('Y-m-d_H-i-s') . '.sql'); 98 | $filePath = $localPath . '/'.$filename; 99 | 100 | // dumper config 101 | $config = [ 102 | 'host' => $conn['host'], 103 | 'port' => 3306, 104 | 'username' => $conn['username'], 105 | 'password' => $conn['password'], 106 | 'database' => $conn['database'], 107 | 'filePath' => $filePath, 108 | ]; 109 | 110 | return $this->laravel->make('databasebackup.dumpers.mysqldumper', $config); 111 | } 112 | 113 | /** 114 | * Returns the GzipArchiver instance. 115 | * 116 | * @return \McCool\DatabaseBackup\Archivers\GzipArchiver|null 117 | */ 118 | protected function getArchiver() 119 | { 120 | if ($this->option('gzip')) { 121 | return $this->laravel->make('databasebackup.archivers.gziparchiver'); 122 | } 123 | 124 | return null; 125 | } 126 | 127 | /** 128 | * Returns the S3Storer instance. 129 | * 130 | * return \McCool\DatabaseBackup\Storers\S3Storer|null 131 | */ 132 | protected function getStorer() 133 | { 134 | if ($this->option('s3-bucket')) { 135 | return $this->laravel->make('databasebackup.storers.s3storer', [ 136 | 's3-bucket' => $this->option('s3-bucket'), 137 | 's3-path' => $this->option('s3-path'), 138 | ]); 139 | } 140 | 141 | return null; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/McCool/DatabaseBackup/Dumpers/DumperInterface.php: -------------------------------------------------------------------------------- 1 | processor = $processor; 71 | $this->host = $host; 72 | $this->port = $port; 73 | $this->username = $username; 74 | $this->password = $password; 75 | $this->database = $database; 76 | $this->destinationPath = $destinationPath; 77 | } 78 | 79 | /** 80 | * Dumps the backup into the database. 81 | * 82 | * @return void. 83 | */ 84 | public function dump() 85 | { 86 | $this->process(); 87 | } 88 | 89 | /** 90 | * Returns the filename for the backup. 91 | * 92 | * @return string 93 | */ 94 | public function getOutputFilename() 95 | { 96 | return $this->destinationPath; 97 | } 98 | 99 | /** 100 | * Executes the process command. 101 | * 102 | * @return void 103 | * @throws \McCool\DatabaseBackup\Processors\ProcessorException 104 | */ 105 | protected function process() 106 | { 107 | $this->processor->process($this->getCommand()); 108 | 109 | if ($this->processor->getErrors() && ( ! ($this->processor->getErrors() != "Warning: Using a password on the command line interface can be insecure\n."))) { 110 | throw new ProcessorException($this->processor->getErrors()); 111 | } 112 | } 113 | 114 | /** 115 | * Returns the mysqldump command with arguments. 116 | * 117 | * @return string 118 | */ 119 | protected function getCommand() 120 | { 121 | return sprintf('mysqldump --host=%s --port=%s --user=%s --password=%s %s > %s', 122 | escapeshellarg($this->host), 123 | escapeshellarg($this->port), 124 | escapeshellarg($this->username), 125 | escapeshellarg($this->password), 126 | escapeshellarg($this->database), 127 | escapeshellarg($this->destinationPath) 128 | ); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/McCool/DatabaseBackup/Processors/ProcessorException.php: -------------------------------------------------------------------------------- 1 | process = $process; 17 | } 18 | 19 | /** 20 | * Executes the given command. 21 | * 22 | * @param string $command 23 | * @return void 24 | */ 25 | public function process($command) 26 | { 27 | $this->process->setCommandLine($command); 28 | $this->process->run(); 29 | } 30 | 31 | /** 32 | * Returns errors which happened during the command execution. 33 | * 34 | * @return string|null 35 | */ 36 | public function getErrors() 37 | { 38 | return $this->process->getErrorOutput(); 39 | } 40 | } -------------------------------------------------------------------------------- /src/McCool/DatabaseBackup/ServiceProviders/LaravelServiceProvider.php: -------------------------------------------------------------------------------- 1 | guessPackagePath() . '/..' ); 24 | $this->package('mccool/database-backup', 'database-backup', $path); 25 | } 26 | 27 | /** 28 | * Register the service provider. 29 | * 30 | * @return void 31 | */ 32 | public function register() 33 | { 34 | $this->app->bind('databasebackup.backupcommand', function($app) { 35 | return new LaravelBackupCommand(); 36 | }); 37 | $this->commands('databasebackup.backupcommand'); 38 | 39 | $this->app->bind('databasebackup.s3client', function($app) { 40 | return Aws::factory([ 41 | 'key' => $app['config']->get('database-backup::aws.key'), 42 | 'secret' => $app['config']->get('database-backup::aws.secret'), 43 | 'region' => $app['config']->get('database-backup::aws.region'), 44 | ])->get('s3'); 45 | }); 46 | 47 | $this->app->bind('databasebackup.archivers.gziparchiver', function($app) { 48 | return new GzipArchiver(new ShellProcessor(new Process(''))); 49 | }); 50 | 51 | $this->app->bind('databasebackup.processors.shellprocessor', function($app) { 52 | return new ShellProcessor(new Process('')); 53 | }); 54 | 55 | $this->app->bind('databasebackup.storers.s3storer', function($app, $params) { 56 | return new S3Storer($app->make('databasebackup.s3client'), $params['s3-bucket'], $params['s3-path']); 57 | }); 58 | 59 | $this->app->bind('databasebackup.dumpers.mysqldumper', function($app, $params) { 60 | return new MysqlDumper($app['databasebackup.processors.shellprocessor'], $params['host'], $params['port'], $params['username'], $params['password'], $params['database'], $params['filePath']); 61 | }); 62 | } 63 | } -------------------------------------------------------------------------------- /src/McCool/DatabaseBackup/Storers/S3Storer.php: -------------------------------------------------------------------------------- 1 | s3Client = $s3Client; 44 | $this->bucket = $bucket; 45 | $this->s3Path = $s3Path; 46 | } 47 | 48 | /** 49 | * Sets the filename for the backup. 50 | * 51 | * @param string $filename 52 | * @return void 53 | */ 54 | public function setInputFilename($filename) 55 | { 56 | $this->filename = $filename; 57 | } 58 | 59 | /** 60 | * Stores the backup to the given storage provider. 61 | * 62 | * @return void 63 | */ 64 | public function store() 65 | { 66 | $this->s3Client->putObject([ 67 | 'Bucket' => $this->bucket, 68 | 'Key' => $this->getS3Path() . $this->getFilename(), 69 | 'SourceFile' => $this->filename, 70 | 'ACL' => 'private', 71 | ]); 72 | } 73 | 74 | /** 75 | * Returns the S3 path. 76 | * 77 | * @return string 78 | */ 79 | protected function getS3Path() 80 | { 81 | if ( ! preg_match("/\/$/", $this->s3Path)) { 82 | return $this->s3Path . '/'; 83 | } 84 | 85 | return $this->s3Path; 86 | } 87 | 88 | /** 89 | * Returns the base backup filename. 90 | * 91 | * @return string 92 | */ 93 | protected function getFilename() 94 | { 95 | return basename($this->filename); 96 | } 97 | } -------------------------------------------------------------------------------- /src/McCool/DatabaseBackup/Storers/StorerInterface.php: -------------------------------------------------------------------------------- 1 | [ 19 | 'key' => '', 20 | 'secret' => '', 21 | 'region' => Aws\Common\Enum\Region::US_EAST_1, 22 | ], 23 | ]; -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ShawnMcCool/database-backup/bd5cca0fe9c49ed88276b5a86a8c9314bec5a3f0/tests/.gitkeep -------------------------------------------------------------------------------- /tests/Archivers/GzipArchiverTest.php: -------------------------------------------------------------------------------- 1 | shouldReceive('process')->with('gzip test.sql'); 16 | $processor->shouldReceive('getErrors')->andReturn(null); 17 | 18 | $archiver = new \McCool\DatabaseBackup\Archivers\GzipArchiver($processor); 19 | 20 | $archiver->setInputFilename('test.sql'); 21 | $archiver->archive(); 22 | 23 | $this->assertEquals('test.sql.gz', $archiver->getOutputFilename()); 24 | } 25 | 26 | /** 27 | * @expectedException McCool\DatabaseBackup\Processors\ProcessorException 28 | */ 29 | public function testThrowsExceptionOnError() 30 | { 31 | $processor = m::mock('McCool\DatabaseBackup\Processors\ProcessorInterface'); 32 | $processor->shouldReceive('process'); 33 | $processor->shouldReceive('getErrors')->andReturn(true); 34 | 35 | $archiver = new \McCool\DatabaseBackup\Archivers\GzipArchiver($processor); 36 | $archiver->archive(); 37 | } 38 | } -------------------------------------------------------------------------------- /tests/BackupProcedureTest.php: -------------------------------------------------------------------------------- 1 | shouldReceive('dump', 'getOutputFilename'); 17 | 18 | $backup = new BackupProcedure($dumper); 19 | $backup->backup(); 20 | } 21 | 22 | public function testArchivedDump() 23 | { 24 | $dumper = m::mock('McCool\DatabaseBackup\Dumpers\DumperInterface'); 25 | $dumper->shouldReceive('dump', 'getOutputFilename'); 26 | 27 | $archiver = m::mock('McCool\DatabaseBackup\Archivers\ArchiverInterface'); 28 | $archiver->shouldReceive('setInputFilename', 'archive', 'getOutputFilename'); 29 | 30 | $backup = new BackupProcedure($dumper); 31 | $backup->setArchiver($archiver); 32 | 33 | $backup->backup(); 34 | } 35 | 36 | public function testStoredDump() 37 | { 38 | $dumper = m::mock('McCool\DatabaseBackup\Dumpers\DumperInterface'); 39 | $dumper->shouldReceive('dump', 'getOutputFilename'); 40 | 41 | $storer = m::mock('McCool\DatabaseBackup\Storers\StorerInterface'); 42 | $storer->shouldReceive('setInputFilename', 'store'); 43 | 44 | $backup = new BackupProcedure($dumper); 45 | $backup->setStorer($storer); 46 | 47 | $backup->backup(); 48 | } 49 | 50 | public function testArchivedStoredDump() 51 | { 52 | $dumper = m::mock('McCool\DatabaseBackup\Dumpers\DumperInterface'); 53 | $dumper->shouldReceive('dump', 'getOutputFilename'); 54 | 55 | $archiver = m::mock('McCool\DatabaseBackup\Archivers\ArchiverInterface'); 56 | $archiver->shouldReceive('setInputFilename', 'archive', 'getOutputFilename'); 57 | 58 | $storer = m::mock('McCool\DatabaseBackup\Storers\StorerInterface'); 59 | $storer->shouldReceive('setInputFilename', 'store'); 60 | 61 | $backup = new BackupProcedure($dumper); 62 | $backup->setArchiver($archiver); 63 | $backup->setStorer($storer); 64 | 65 | $backup->backup(); 66 | } 67 | } -------------------------------------------------------------------------------- /tests/Commands/LaravelBackupCommandTest.php: -------------------------------------------------------------------------------- 1 | getCommand(); 18 | 19 | $this->assertInstanceOf('McCool\DatabaseBackup\Commands\LaravelBackupCommand', $command); 20 | } 21 | 22 | public function testCanDump() 23 | { 24 | $app = $this->getApp(); 25 | 26 | // ensure that dumper is called 27 | $dumper = m::mock('McCool\DatabaseBackup\Dumpers\MysqlDumper'); 28 | $dumper->shouldReceive('getOutputFilename'); 29 | $dumper->shouldReceive('dump')->once(); 30 | $app['databasebackup.dumpers.mysqldumper'] = $dumper; 31 | 32 | // prepare 33 | $command = $this->getCommand(); 34 | $command->setLaravel($app); 35 | 36 | // run 37 | $this->runCommand($command); 38 | } 39 | 40 | public function testCanChooseDbConfig() 41 | { 42 | 43 | } 44 | 45 | public function testGetDefaultDbConfig() 46 | { 47 | 48 | } 49 | 50 | public function testCanChangeLocalPath() 51 | { 52 | 53 | } 54 | 55 | public function testCanArchive() 56 | { 57 | $app = $this->getApp(); 58 | 59 | // ensure that dumper is called 60 | $dumper = m::mock('McCool\DatabaseBackup\Dumpers\DumperInterface'); 61 | $dumper->shouldReceive('getOutputFilename'); 62 | $dumper->shouldReceive('dump')->once(); 63 | $app['databasebackup.dumpers.mysqldumper'] = $dumper; 64 | 65 | // ensure that archiver is called 66 | $archiver = m::mock('McCool\DatabaseBackup\Archivers\ArchiverInterface'); 67 | $archiver->shouldReceive('getOutputFilename', 'setInputFilename'); 68 | $archiver->shouldReceive('archive')->once(); 69 | $app['databasebackup.archivers.gziparchiver'] = $archiver; 70 | 71 | // prepare 72 | $command = $this->getCommand(); 73 | $command->setLaravel($app); 74 | 75 | // run 76 | $this->runCommand($command, ['gzip' => true]); 77 | } 78 | 79 | public function testCanStore() 80 | { 81 | $app = $this->getApp(); 82 | 83 | // ensure that dumper is called 84 | $dumper = m::mock('McCool\DatabaseBackup\Dumpers\DumperInterface'); 85 | $dumper->shouldReceive('getOutputFilename'); 86 | $dumper->shouldReceive('dump')->once(); 87 | $app['databasebackup.dumpers.mysqldumper'] = $dumper; 88 | 89 | // ensure that storer is called 90 | $storer = m::mock('McCool\DatabaseBackup\Storers\StorerInterface'); 91 | $storer->shouldReceive('getOutputFilename', 'setInputFilename'); 92 | $storer->shouldReceive('store')->once(); 93 | $app['databasebackup.storers.s3storer'] = $storer; 94 | 95 | // prepare 96 | $command = $this->getCommand(); 97 | $command->setLaravel($app); 98 | 99 | // run 100 | $this->runCommand($command, ['s3-bucket' => 'bucket', 's3-path' => 'path']); 101 | } 102 | 103 | public function testCanCleanup() 104 | { 105 | } 106 | 107 | private function runCommand($command, $options = []) 108 | { 109 | $input = m::mock('Symfony\Component\Console\Input\InputInterface'); 110 | $input->shouldReceive('bind', 'isInteractive', 'validate'); 111 | 112 | $defaultOptions = [ 113 | 'database' => false, 114 | 'local-path' => false, 115 | 's3-bucket' => false, 116 | 'cleanup' => false, 117 | 'gzip' => false, 118 | ]; 119 | 120 | $options = array_merge($defaultOptions, $options); 121 | 122 | foreach ($options as $key => $value) { 123 | $input->shouldReceive('getOption')->with($key)->andReturn($value); 124 | } 125 | 126 | $output = m::mock('Symfony\Component\Console\Output\OutputInterface'); 127 | 128 | $command->run($input, $output); 129 | } 130 | 131 | private function getCommand($options = [], $arguments = []) 132 | { 133 | date_default_timezone_set('UTC'); 134 | 135 | $helperSet = new Symfony\Component\Console\Helper\HelperSet; 136 | 137 | $input = m::mock('Symfony\Component\Console\Input\InputDefinition'); 138 | $input->shouldReceive('getOptions')->andReturn($options); 139 | $input->shouldReceive('getArguments')->andReturn($arguments); 140 | 141 | $consoleApplication = m::mock('Symfony\Component\Console\Application'); 142 | $consoleApplication->shouldReceive('getHelperSet')->andReturn($helperSet); 143 | $consoleApplication->shouldReceive('getDefinition')->andReturn($input); 144 | 145 | $command = new LaravelBackupCommand; 146 | $command->setApplication($consoleApplication); 147 | 148 | return $command; 149 | } 150 | 151 | private function getApp() 152 | { 153 | $app = $this->getContainer(); 154 | 155 | // mock out laravel environment configuration 156 | $app['files'] = m::mock(); 157 | $app['files']->shouldReceive('isDirectory'); 158 | 159 | $app['events'] = m::mock(); 160 | $app['events']->shouldReceive('listen'); 161 | 162 | $app['config'] = m::mock(); 163 | $app['config']->shouldReceive('get'); 164 | 165 | $app['path'] = "path"; 166 | $app['path.storage'] = "storage path"; 167 | 168 | // register ioc bindings 169 | $provider = new LaravelServiceProvider($app); 170 | $provider->register(); 171 | 172 | return $app; 173 | } 174 | 175 | private function getContainer() 176 | { 177 | return new Container; 178 | } 179 | } -------------------------------------------------------------------------------- /tests/Dumpers/MysqlDumperTest.php: -------------------------------------------------------------------------------- 1 | shouldReceive('process')->with("mysqldump --host='localhost' --port='3306' --user='username' --password='password' 'db_name' > 'output.sql'"); 16 | $processor->shouldReceive('getErrors')->andReturn(null); 17 | 18 | $dumper = new \McCool\DatabaseBackup\Dumpers\MysqlDumper($processor, 'localhost', 3306, 'username', 'password', 'db_name', 'output.sql'); 19 | 20 | $dumper->dump(); 21 | 22 | $this->assertEquals('output.sql', $dumper->getOutputFilename()); 23 | } 24 | 25 | /** 26 | * @expectedException McCool\DatabaseBackup\Processors\ProcessorException 27 | */ 28 | public function testThrowsExceptionOnError() 29 | { 30 | $processor = m::mock('McCool\DatabaseBackup\Processors\ProcessorInterface'); 31 | $processor->shouldReceive('process'); 32 | $processor->shouldReceive('getErrors')->andReturn(true); 33 | 34 | $dumper = new \McCool\DatabaseBackup\Dumpers\MysqlDumper($processor, 'localhost', 3306, 'username', 'password', 'db_name', 'output.sql'); 35 | $dumper->dump(); 36 | } 37 | } -------------------------------------------------------------------------------- /tests/Processors/ShellProcessorTest.php: -------------------------------------------------------------------------------- 1 | shouldReceive('run', 'stop'); 18 | $process->shouldReceive('setCommandLine')->with('test command'); 19 | $process->shouldReceive('getErrorOutput')->andReturn('no errors'); 20 | 21 | $processor = new ShellProcessor($process); 22 | $processor->process('test command'); 23 | 24 | $this->assertEquals('no errors', $processor->getErrors()); 25 | } 26 | } -------------------------------------------------------------------------------- /tests/ServiceProviders/LaravelServiceProviderTest.php: -------------------------------------------------------------------------------- 1 | getContainer()); 17 | 18 | $this->assertInstanceOf('McCool\DatabaseBackup\ServiceProviders\LaravelServiceProvider', $provider); 19 | } 20 | 21 | public function testCanBoot() 22 | { 23 | $app = $this->getApp(); 24 | 25 | $provider = new LaravelServiceProvider($app); 26 | $provider->boot(); 27 | } 28 | 29 | public function testCanRegister() 30 | { 31 | $app = $this->getApp(); 32 | 33 | $provider = new LaravelServiceProvider($app); 34 | $provider->register(); 35 | } 36 | 37 | public function testCanCreateBackupCommand() 38 | { 39 | $app = $this->getApp(); 40 | 41 | $provider = new LaravelServiceProvider($app); 42 | $provider->register(); 43 | 44 | $this->assertInstanceOf('McCool\DatabaseBackup\Commands\LaravelBackupCommand', $app->make('databasebackup.backupcommand')); 45 | } 46 | 47 | public function testCanCreateS3Client() 48 | { 49 | $app = $this->getApp(); 50 | 51 | $provider = new LaravelServiceProvider($app); 52 | $provider->register(); 53 | 54 | $this->assertInstanceOf('Aws\S3\S3Client', $app->make('databasebackup.s3client')); 55 | } 56 | 57 | public function testCanCreateGzipArchiver() 58 | { 59 | $app = $this->getApp(); 60 | 61 | $provider = new LaravelServiceProvider($app); 62 | $provider->register(); 63 | 64 | $this->assertInstanceOf('McCool\DatabaseBackup\Archivers\GzipArchiver', $app->make('databasebackup.archivers.gziparchiver')); 65 | } 66 | 67 | public function testCanCreateShellProcessor() 68 | { 69 | $app = $this->getApp(); 70 | 71 | $provider = new LaravelServiceProvider($app); 72 | $provider->register(); 73 | 74 | $this->assertInstanceOf('McCool\DatabaseBackup\Processors\ShellProcessor', $app->make('databasebackup.processors.shellprocessor')); 75 | } 76 | 77 | public function testCanCreateS3Storer() 78 | { 79 | $app = $this->getApp(); 80 | 81 | $provider = new LaravelServiceProvider($app); 82 | $provider->register(); 83 | 84 | $s3Config = ['s3-bucket' => 'bucket', 's3-path' => 'path']; 85 | $this->assertInstanceOf('McCool\DatabaseBackup\Storers\S3Storer', $app->make('databasebackup.storers.s3storer', $s3Config)); 86 | } 87 | 88 | public function testCanCreateMysqlDumper() 89 | { 90 | $app = $this->getApp(); 91 | 92 | $provider = new LaravelServiceProvider($app); 93 | $provider->register(); 94 | 95 | $dumperConfig = [ 96 | 'host' => 'bucket', 97 | 'port' => 3306, 98 | 'username' => 'username', 99 | 'password' => 'password', 100 | 'database' => 'database', 101 | 'filePath' => 'filePath', 102 | ]; 103 | 104 | $this->assertInstanceOf('McCool\DatabaseBackup\Dumpers\MysqlDumper', $app->make('databasebackup.dumpers.mysqldumper', $dumperConfig)); 105 | } 106 | 107 | private function getApp() 108 | { 109 | $app = $this->getContainer(); 110 | 111 | $app['files'] = m::mock(); 112 | $app['files']->shouldReceive('isDirectory'); 113 | 114 | $app['events'] = m::mock(); 115 | $app['events']->shouldReceive('listen'); 116 | 117 | $app['config'] = m::mock(); 118 | $app['config']->shouldReceive('get'); 119 | 120 | $app['path'] = "path"; 121 | 122 | return $app; 123 | } 124 | 125 | private function getContainer() 126 | { 127 | return new Container; 128 | } 129 | } -------------------------------------------------------------------------------- /tests/Storers/S3StorerTest.php: -------------------------------------------------------------------------------- 1 | shouldReceive('putObject')->with([ 16 | 'Bucket' => 'bucket', 17 | 'Key' => 'path/iceking.sql.gz', 18 | 'SourceFile' => 'backups/iceking.sql.gz', 19 | 'ACL' => 'private', 20 | ]); 21 | 22 | $storer = new \McCool\DatabaseBackup\Storers\S3Storer($s3Client, 'bucket', 'path'); 23 | $storer->setInputFilename('backups/iceking.sql.gz'); 24 | $storer->store(); 25 | } 26 | } --------------------------------------------------------------------------------