Quality of life improvements all around.
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed

This commit is contained in:
Jens True 2023-07-13 11:34:56 +00:00
parent 4645488b5d
commit 6ac9fd5575
14 changed files with 105 additions and 15 deletions

@ -1,6 +1,6 @@
{ {
"name": "furyfire/backupscript", "name": "furyfire/backupscript",
"description": "Wrapper for Rclone based backup", "description": "Wrapper for Rclone based backup with push notifications",
"homepage": "https://jcktrue.dk", "homepage": "https://jcktrue.dk",
"version": "0.1.0", "version": "0.1.0",
"require": { "require": {

2
composer.lock generated

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "7c0718c0e4c6eabc3fec9cc0dbf816e2", "content-hash": "545ed8a092dd0e7cb6c11837968dafc7",
"packages": [ "packages": [
{ {
"name": "dflydev/dot-access-data", "name": "dflydev/dot-access-data",

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace App; namespace App;
use Symfony\Component\Yaml\Yaml; use Symfony\Component\Yaml\Yaml;
@ -11,21 +13,17 @@ use League\Config\Configuration;
use Nette\Schema\Expect; use Nette\Schema\Expect;
/** /**
* Application class
*
* Mostly working as a register pattern for the logging and configuration. * Mostly working as a register pattern for the logging and configuration.
*
* @author Jens True <jens.chr.true@gmail.com>
* @license https://opensource.org/licenses/gpl-license.php GNU Public License
* @link https://jcktrue.dk
*/ */
class App class App
{ {
/// Logging instance
protected Logger $logger; protected Logger $logger;
/// Configuration singleton
protected Configuration $config; protected Configuration $config;
/** /**
* Create a new instance providing a config file * Create a new instance providing a config file.
* *
* @param string $configFile Relative or full path to YML config. * @param string $configFile Relative or full path to YML config.
* @SuppressWarnings(PHPMD.StaticAccess) * @SuppressWarnings(PHPMD.StaticAccess)

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace App; namespace App;
use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Attribute\AsCommand;
@ -28,6 +30,18 @@ class CommandBackup extends Command
); );
} }
/**
* Start the backup process.
*
* 1. Read the configuration file.
* 2. For each configured backup entry
* 1. Get the size of the source
* 2. Get the size of the destination
* 3. Perform the backup
* 4. Get the new size of the destination
* 5. Send push notifications.
* 3. Report final success
*/
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$sio = new SymfonyStyle($input, $output); $sio = new SymfonyStyle($input, $output);

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace App; namespace App;
use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Attribute\AsCommand;

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace App\Notification; namespace App\Notification;
use App\Notification\Ntfy; use App\Notification\Ntfy;

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace App\Notification; namespace App\Notification;
interface NotificationInterface interface NotificationInterface

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace App\Notification; namespace App\Notification;
use Ntfy\Server; use Ntfy\Server;

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace App\Rclone; namespace App\Rclone;
use Psr\Log\LoggerAwareTrait; use Psr\Log\LoggerAwareTrait;

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace App\Template; namespace App\Template;
use Twig\Environment; use Twig\Environment;

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace App\Template; namespace App\Template;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;

28
tests/AppTest.php Normal file

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace App\Tests;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;
use Psr\Log\LoggerInterface;
use App\App;
#[CoversClass(App::class)]
final class AppTest extends \PHPUnit\Framework\TestCase
{
public function testNonexistentConfigFile(): void
{
$this->expectException(\Exception::class);
new App('no_file');
$this->fail('Exception was not thrown');
}
public function testGoodConfig(): void
{
$app = new App('config.example.yml');
$this->assertEquals('output.log', $app->getConfig('log'));
$this->assertInstanceOf(LoggerInterface::class, $app->getLogger());
}
}

@ -23,15 +23,15 @@ final class RcloneTest extends TestCase
public function testRclonePath(): void public function testRclonePath(): void
{ {
$this->expectException(\Exception::class); $this->expectException(\Exception::class);
$rclone = new Rclone('invalid'); new Rclone('invalid');
$this->assertEquals('', $rclone->getVersion()); $this->fail('Exception was not thrown');
} }
public function testRcloneInvalidVersion(): void public function testRcloneInvalidVersion(): void
{ {
$this->expectException(\Exception::class); $this->expectException(\Exception::class);
$rclone = new Rclone('uname'); new Rclone('uname');
$this->assertEquals('', $rclone->getVersion()); $this->fail('Exception was not thrown');
} }
public function testRcloneValidVersion(): void public function testRcloneValidVersion(): void
@ -49,7 +49,7 @@ final class RcloneTest extends TestCase
$this->expectException(\Exception::class); $this->expectException(\Exception::class);
$this->expectExceptionMessage("ERROR"); $this->expectExceptionMessage("ERROR");
$size = $rclone->getSize('temp/bogus-source'); $size = $rclone->getSize('temp/bogus-source');
$this->assertEquals(0, $size); $this->fail('Exception was not thrown');
} }
public function testRcloneCopy(): void public function testRcloneCopy(): void
@ -65,6 +65,6 @@ final class RcloneTest extends TestCase
$this->expectException(\Exception::class); $this->expectException(\Exception::class);
$this->expectExceptionMessage("ERROR"); $this->expectExceptionMessage("ERROR");
$rclone->copy('temp/bogus-source', 'temp/bogus-destination'); $rclone->copy('temp/bogus-source', 'temp/bogus-destination');
$this->assertDirectoryDoesNotExist('temp/bogus-destination'); $this->fail('Exception was not thrown');
} }
} }

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Tests;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use App\Template\TwigExtension;
use Twig\TwigFilter;
final class TwigExtensionTest extends \PHPUnit\Framework\TestCase
{
public function testGetFilters(): void
{
$obj = new TwigExtension();
$filters = $obj->getFilters();
$this->assertContainsOnlyInstancesOf(TwigFilter::class, $filters);
}
public function testformatBytes(): void
{
$obj = new TwigExtension();
$this->assertEquals('1.00B', $obj->formatBytes(1, 2));
$this->assertEquals('2.00B', $obj->formatBytes(2, 2));
$this->assertEquals('10.00B', $obj->formatBytes(10, 2));
$this->assertEquals('0.98kB', $obj->formatBytes(1000, 2));
$this->assertEquals('1.00kB', $obj->formatBytes(1024, 2));
$this->assertEquals('512.00MB', $obj->formatBytes(1024 ** 3 / 2, 2));
$this->assertEquals('1.00GB', $obj->formatBytes(1024 ** 3 - 1, 2));
$this->assertEquals('1.00GB', $obj->formatBytes(1024 ** 3, 2));
$this->assertEquals('512.00GB', $obj->formatBytes(1024 ** 4 / 2, 2));
$this->assertEquals('1.00TB', $obj->formatBytes(1024 ** 4, 2));
}
}