Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 15 additions & 21 deletions src/Console/FetchDataFromOzu.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
namespace Code16\OzuClient\Console;

use Code16\OzuClient\Client;
use Code16\OzuClient\Support\ZipExtractor;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Cache;
use Symfony\Component\Process\Process;
use ZipArchive;
use Illuminate\Support\Facades\Process;

use function Laravel\Prompts\confirm;

Expand Down Expand Up @@ -102,21 +102,19 @@ private function importDatabase(): bool
$this->info('🛠 Importing Ozu database...');
$config = config('database.connections.mysql');

$process = Process::fromShellCommandline(sprintf(
'mysql -h%s -P%s -u%s %s < %s',
$config['host'],
$config['port'],
$config['username'],
$config['database'],
$this->databaseDumpPath
));

$process->setEnv(['MYSQL_PWD' => $config['password']]);
$process->run();

if (!$process->isSuccessful()) {
$result = Process::env(['MYSQL_PWD' => $config['password']])
->run(sprintf(
'mysql -h%s -P%s -u%s %s < %s',
$config['host'],
$config['port'],
$config['username'],
$config['database'],
$this->databaseDumpPath
));

if (!$result->successful()) {
$this->error('❌ Error importing the database:');
$this->error($process->getErrorOutput());
$this->error($result->errorOutput());

return false;
}
Expand Down Expand Up @@ -147,11 +145,7 @@ private function extractAssets(): bool
$this->info('📦 Extracting Ozu assets...');

try {
$zip = new ZipArchive();
if ($zip->open($this->assetsZipPath) === true) {
$zip->extractTo($this->assetsExtractPath);
$zip->close();

if (app(ZipExtractor::class)->extract($this->assetsZipPath, $this->assetsExtractPath)) {
return true;
}

Expand Down
21 changes: 21 additions & 0 deletions src/Support/ZipExtractor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Code16\OzuClient\Support;

use ZipArchive;

class ZipExtractor
{
public function extract(string $zipPath, string $extractPath): bool
{
$zip = new ZipArchive();
if ($zip->open($zipPath) === true) {
$zip->extractTo($extractPath);
$zip->close();

return true;
}

return false;
}
}
157 changes: 157 additions & 0 deletions tests/Console/FetchDataFromOzuTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?php

namespace Code16\OzuClient\Tests\Console;

use Code16\OzuClient\Client;
use Code16\OzuClient\Console\FetchDataFromOzu;
use Code16\OzuClient\Support\ZipExtractor;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Storage;

it('fetches database and assets from Ozu', function () {
Storage::fake('local');
Http::fake([
'*/api/v1/websites/database' => Http::response('SQL DUMP', 200),
'*/api/v1/websites/assets' => Http::response('ZIP CONTENT', 200),
'*/api/v1/settings/fetch' => Http::response(['key' => 'value'], 200),
'*/api/v1/website' => Http::response(['key' => 'test-website'], 200),
]);

config([
'ozu-client.api_host' => 'https://ozu.test',
'ozu-client.api_version' => 'v1',
'ozu-client.website_key' => 'test-website',
'database.connections.mysql' => [
'host' => '127.0.0.1',
'port' => '3306',
'username' => 'root',
'database' => 'forge',
'password' => '',
],
]);

// Mock Artisan::call('db:wipe')
// We can't easily mock Artisan facade here because it's final in Testbench
// But we can check if it was called if we really need to.
// For now let's just let it be or use a partial mock if possible.

// Mock Process for mysql import
Process::fake([
'mysql *' => Process::result('', '', 0),
]);

// Mock ZipExtractor
$this->mock(ZipExtractor::class, function ($mock) {
$mock->shouldReceive('extract')->once()->andReturn(true);
});

$this->artisan('ozu:import', ['--force' => true])
->expectsOutput('⬇️ Downloading Ozu database...')
->expectsOutput('🧹 Wiping local database...')
->expectsOutput('🛠 Importing Ozu database...')
->expectsOutput('✅ Database imported successfully.')
->expectsOutput('⬇️ Downloading Ozu assets...')
->expectsOutput('📦 Extracting Ozu assets...')
->expectsOutput('✅ Ozu data successfully imported.')
->assertExitCode(FetchDataFromOzu::SUCCESS);
});

it('can skip assets import', function () {
Storage::fake('local');
Http::fake([
'*/api/v1/websites/database' => Http::response('SQL DUMP', 200),
'*/api/v1/website' => Http::response(['key' => 'test-website'], 200),
]);

config([
'ozu-client.api_host' => 'https://ozu.test',
'ozu-client.api_version' => 'v1',
'ozu-client.website_key' => 'test-website',
'database.connections.mysql' => [
'host' => '127.0.0.1',
'port' => '3306',
'username' => 'root',
'database' => 'forge',
'password' => '',
],
]);

Process::fake([
'mysql *' => Process::result('', '', 0),
]);

$this->artisan('ozu:import', ['--force' => true, '--withoutAssets' => true])
->expectsOutput('⬇️ Downloading Ozu database...')
->expectsOutput('🧹 Wiping local database...')
->expectsOutput('🛠 Importing Ozu database...')
->expectsOutput('✅ Database imported successfully.')
->doesntExpectOutput('⬇️ Downloading Ozu assets...')
->expectsOutput('✅ Ozu data successfully imported.')
->assertExitCode(FetchDataFromOzu::SUCCESS);
});

it('handles database download failure', function () {
Storage::fake('local');

$this->mock(Client::class, function ($mock) {
$mock->shouldReceive('downloadOzuDatabase')->once()->andReturn(null);
});

$this->artisan('ozu:import', ['--force' => true])
->expectsOutput('⬇️ Downloading Ozu database...')
->expectsOutput('❌ Failed to download the Ozu database.')
->assertExitCode(FetchDataFromOzu::FAILURE);
});

it('asks for confirmation when force option is not present', function () {
Storage::fake('local');
Http::fake([
'*/api/v1/website' => Http::response(['key' => 'test-website'], 200),
]);

$this->artisan('ozu:import')
->expectsConfirmation('Are you sure you want to continue? This cannot be undone.', 'no')
->assertExitCode(FetchDataFromOzu::SUCCESS);
});

it('handles asset extraction failure', function () {
Storage::fake('local');
Http::fake([
'*/api/v1/websites/database' => Http::response('SQL DUMP', 200),
'*/api/v1/websites/assets' => Http::response('ZIP CONTENT', 200),
'*/api/v1/website' => Http::response(['key' => 'test-website'], 200),
]);

config([
'ozu-client.api_host' => 'https://ozu.test',
'ozu-client.api_version' => 'v1',
'ozu-client.website_key' => 'test-website',
'database.connections.mysql' => [
'host' => '127.0.0.1',
'port' => '3306',
'username' => 'root',
'database' => 'forge',
'password' => '',
],
]);

Process::fake([
'mysql *' => Process::result('', '', 0),
]);

$this->mock(ZipExtractor::class, function ($mock) {
$mock->shouldReceive('extract')->once()->andReturn(false);
});

$this->artisan('ozu:import', ['--force' => true])
->expectsOutput('⬇️ Downloading Ozu database...')
->expectsOutput('🧹 Wiping local database...')
->expectsOutput('🛠 Importing Ozu database...')
->expectsOutput('✅ Database imported successfully.')
->expectsOutput('⬇️ Downloading Ozu assets...')
->expectsOutput('📦 Extracting Ozu assets...')
->expectsOutput('❌ Failed to open the zip file.')
->assertExitCode(FetchDataFromOzu::FAILURE);
});