Skip to content

Commit

Permalink
Merge pull request #198 from Icinga/integrate-tests
Browse files Browse the repository at this point in the history
Integrate unit tests
  • Loading branch information
yhabteab authored Sep 18, 2023
2 parents 47afc99 + 9a41166 commit 88d1d69
Show file tree
Hide file tree
Showing 8 changed files with 382 additions and 0 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,43 @@ jobs:
- name: PHPStan
if: ${{ ! cancelled() }}
uses: php-actions/phpstan@v3

test:
name: Unit tests with PHP ${{ matrix.php }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}

env:
phpunit-version: 8.5

strategy:
fail-fast: false
matrix:
php: [ '7.2', '7.3', '7.4', '8.0', '8.1', '8.2' ]
os: ['ubuntu-latest']

steps:
- name: Checkout code base
uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: phpunit:${{ matrix.phpunit-version || env.phpunit-version }}
extensions: gmp

- name: Setup Icinga Web 2
run: |
git clone --depth 1 https://github.com/Icinga/icingaweb2.git _icingaweb2
ln -s `pwd` _icingaweb2/modules/x509
- name: Setup Libraries
run: |
mkdir _libraries
git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-library.git _libraries/ipl
git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-thirdparty.git _libraries/vendor
- name: PHPUnit
env:
ICINGAWEB_LIBDIR: _libraries
run: phpunit --verbose --bootstrap _icingaweb2/test/php/bootstrap.php
16 changes: 16 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
>
<testsuites>
<testsuite name="Icinga Certificate Monitoring PHP Unit Tests">
<directory suffix="Test.php">test/php</directory>
</testsuite>
</testsuites>
</phpunit>
30 changes: 30 additions & 0 deletions test/php/Lib/TestModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/* Icinga Web 2 X.509 Module | (c) 2023 Icinga GmbH | GPLv2 */

namespace Tests\Icinga\Module\X509\Lib;

use ipl\Orm\Model;
use ipl\Sql\Expression;

class TestModel extends Model
{
public const EXPRESSION = 'CASE WHEN 1 THEN YES ELSE NO';

public function getTableName()
{
return 'test';
}

public function getKeyName()
{
return 'id';
}

public function getColumns()
{
return [
'duration' => new Expression(static::EXPRESSION)
];
}
}
44 changes: 44 additions & 0 deletions test/php/library/X509/Common/JobUtilsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

/* Icinga Web 2 X.509 Module | (c) 2023 Icinga GmbH | GPLv2 */

namespace Tests\Icinga\Modules\X509\Common;

use Icinga\Module\X509\Common\JobUtils;
use PHPUnit\Framework\TestCase;

class JobUtilsTest extends TestCase
{
use JobUtils;

public function testGetCidrs()
{
$cidrs = $this->parseCIDRs('10.211.55.30/24,127.0.0.1/8,192.168.178.1/28');

$this->assertCount(3, $cidrs);
$this->assertCount(2, $cidrs['10.211.55.30/24']);

$this->assertSame('10.211.55.30', $cidrs['10.211.55.30/24'][0]);
$this->assertSame('24', $cidrs['10.211.55.30/24'][1]);
}

public function testGetPorts()
{
$ports = $this->parsePorts('5665,3306,6379,8000-9000');

$this->assertCount(4, $ports);
$this->assertCount(2, $ports[3]);

$this->assertSame('8000', $ports[3][0]);
$this->assertSame('9000', $ports[3][1]);
}

public function testGetExcludes()
{
$excludes = $this->parseExcludes('icinga.com,netways.de');

$this->assertCount(2, $excludes);
$this->assertArrayHasKey('icinga.com', $excludes);
$this->assertArrayHasKey('netways.de', $excludes);
}
}
53 changes: 53 additions & 0 deletions test/php/library/X509/JobTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace Tests\Icinga\Modules\X509;

use Icinga\Module\X509\Job;
use PHPUnit\Framework\TestCase;

class JobTest extends TestCase
{
public function testBinaryTransformsHumanReadableIPToItsPaddedVersionCorrectly()
{
$this->assertSame('0000000000000000000000000ad33720', bin2hex(Job::binary('10.211.55.32')));
$this->assertSame(
'2a0104a00004210208a951031cba4915',
bin2hex(Job::binary('2a01:4a0:4:2102:8a9:5103:1cba:4915'))
);
}

public function testIsIPV6()
{
$this->assertTrue(Job::isIPV6('::1'), 'Job::isIPV6() could not determine valid IPv6 as an IPv6');
$this->assertFalse(Job::isIPV6('10.211.54.35'), 'Job::isIPV6() could determines IPv4 as an IPv6');
}

public function testAddrToNumberUndViceVersa()
{
$this->assertSame('10.211.55.32', Job::numberToAddr(Job::addrToNumber('10.211.55.32'), false));

$this->assertSame('::1', Job::numberToAddr(Job::addrToNumber('::1')));
$this->assertSame(
'2a01:4a0:4:2102:8a9:5103:1cba:4915',
Job::numberToAddr(Job::addrToNumber('2a01:4a0:4:2102:8a9:5103:1cba:4915'))
);
}

public function testIsAddrInsideCidr()
{
$this->assertTrue(Job::isAddrInside(Job::addrToNumber('10.211.55.31'), '10.211.55.30', 24));
$this->assertFalse(Job::isAddrInside(Job::addrToNumber('10.211.54.35'), '10.211.55.30', 24));

$this->assertTrue(
Job::isAddrInside(Job::addrToNumber('2001:db8:abcd:0012::1'), '2001:db8:abcd:0012::', 64)
);
$this->assertTrue(
Job::isAddrInside(Job::addrToNumber('2001:db8:abcd:0012:ffff::1'), '2001:db8:abcd:0012::', 64)
);

$this->assertFalse(Job::isAddrInside(Job::addrToNumber('2001:db8:abcd::1'), '2001:db8:abcd:0012::', 64));
$this->assertFalse(
Job::isAddrInside(Job::addrToNumber('2001:db8:abcd:0011::'), '2001:db8:abcd:0012::', 64)
);
}
}
69 changes: 69 additions & 0 deletions test/php/library/X509/Model/Behavior/DERBase64Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/* Icinga Web 2 X.509 Module | (c) 2023 Icinga GmbH | GPLv2 */

namespace Tests\Icinga\Modules\X509\Model\Behavior;

use Icinga\Module\X509\Model\Behavior\DERBase64;
use PHPUnit\Framework\TestCase;

class DERBase64Test extends TestCase
{
protected const COLUMN = 'cert';

protected const CERT = <<<'EOD'
-----BEGIN CERTIFICATE-----
MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEA6QnU5eXu9ugwYsR3
LcHVZwpag+GlLzASRmQXoaWFTVVTsdnxYqFTs4+/raVtN0/GUtXX8YTN95VE1y/H
pwyTgQIDAQABAkEA3EtX/9BB+xR5kRSKWS4QTyzhbiRj49y8meBK2ps/DV8bP4nE
E6VadMSpWFIjuUKZ+D8rdI/7BNUPmgS7Gtk4BQIhAPd3u0fiFje2PWNye9mZX3f+
zbeAKXXrpWEGpNvi72wPAiEA8RK9fNLOBFUXsPtcGsQZD4DhthLfgTMbA/iGLC8i
t28CIDpKRJ3o/ky/K3SaSdv2iYtNRI2draZuDDVviDOXH8g3AiEAlFvAGW1yM+Ba
MCTAzggYlB3wyihbPBvDaHItwEtRxikCIQC2GzXRVDW6rbDJyX1Zhd/l7EC6heib
LErnxieVVzJglw==
-----END CERTIFICATE-----
EOD;

protected const CERT_BASE64_HEX = <<<'EOD'
30820156020100300d06092a864886f70d0101010500048201403082013c020100024100e909d
4e5e5eef6e83062c4772dc1d5670a5a83e1a52f3012466417a1a5854d5553b1d9f162a153b38fb
fada56d374fc652d5d7f184cdf79544d72fc7a70c93810203010001024100dc4b57ffd041fb1479
91148a592e104f2ce16e2463e3dcbc99e04ada9b3f0d5f1b3f89c413a55a74c4a9585223b94299f8
3f2b748ffb04d50f9a04bb1ad93805022100f777bb47e21637b63d63727bd9995f77fecdb7802975e
ba56106a4dbe2ef6c0f022100f112bd7cd2ce045517b0fb5c1ac4190f80e1b612df81331b03f8862c2
f22b76f02203a4a449de8fe4cbf2b749a49dbf6898b4d448d9dada66e0c356f8833971fc83702210094
5bc0196d7233e05a3024c0ce0818941df0ca285b3c1bc368722dc04b51c629022100b61b35d15435baa
db0c9c97d5985dfe5ec40ba85e89b2c4ae7c6279557326097
EOD;

public function testFromDbReturnsNullWhenNullIsPassed()
{
$this->assertNull($this->behavior()->retrieveProperty(null, static::COLUMN));
}

public function testFromDBTransformsPemToDer()
{
$this->assertSame(
static::CERT,
$this->behavior()->retrieveProperty(hex2bin(str_replace("\n", '', static::CERT_BASE64_HEX)), static::COLUMN)
);
}

public function testToDbReturnsNullWhenNullIsPassed()
{
$this->assertNull($this->behavior()->persistProperty(null, static::COLUMN));
}

public function testToDbTransformsDerToPem()
{
$this->assertSame(
hex2bin(str_replace("\n", '', static::CERT_BASE64_HEX)),
$this->behavior()->persistProperty(static::CERT, static::COLUMN)
);
}

protected function behavior(): DERBase64
{
return new DERBase64(['cert']);
}
}
38 changes: 38 additions & 0 deletions test/php/library/X509/Model/Behavior/ExpressionInjectorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

/* Icinga Web 2 X.509 Module | (c) 2023 Icinga GmbH | GPLv2 */

namespace Tests\Icinga\Modules\X509\Model\Behavior;

use Icinga\Module\X509\Model\Behavior\ExpressionInjector;
use ipl\Orm\Query;
use ipl\Sql\Connection;
use ipl\Stdlib\Filter\Equal;
use PHPUnit\Framework\TestCase;
use Tests\Icinga\Module\X509\Lib\TestModel;

class ExpressionInjectorTest extends TestCase
{
public function testRewriteConditionReplacesExpressionColumnByItsExpression()
{
$cond = new Equal('duration', 'FOOO');
$cond->metaData()->set('columnName', 'duration');
$this->assertSame('duration', $cond->getColumn());
$this->assertSame('FOOO', $cond->getValue());

$this->behavior()->rewriteCondition($cond);

$this->assertSame('FOOO', $cond->getValue());
$this->assertSame(TestModel::EXPRESSION, $cond->getColumn());
}

protected function behavior(): ExpressionInjector
{
return (new ExpressionInjector('duration'))
->setQuery(
(new Query())
->setDb(new Connection(['db' => 'mysql']))
->setModel(new TestModel())
);
}
}
92 changes: 92 additions & 0 deletions test/php/library/X509/Model/Behavior/IpTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

/* Icinga Web 2 X.509 Module | (c) 2023 Icinga GmbH | GPLv2 */

namespace Tests\Icinga\Modules\X509\Model\Behavior;

use Icinga\Module\X509\Model\Behavior\Ip;
use ipl\Orm\Query;
use ipl\Sql\Connection;
use PHPUnit\Framework\TestCase;

class IpTest extends TestCase
{
protected const IPV4 = '10.211.55.32';

protected const IPV6 = '2a01:4a0:4:2102:8a9:5103:1cba:4915';

protected const IPV4_HEX = '0000000000000000000000000ad33720';

protected const IPV6_HEX = '2a0104a00004210208a951031cba4915';

protected const COLUMN = 'ip';

public function testFromDbReturnsNullWhenNullIsPassed()
{
$this->assertNull($this->behavior()->retrieveProperty(null, static::COLUMN));
$this->assertNull($this->behavior(true)->retrieveProperty(null, static::COLUMN));
}

public function testFromDBTransformsBinaryIpToHumanReadable()
{
$this->assertSame(
static::IPV4,
$this->behavior()->retrieveProperty(hex2bin(static::IPV4_HEX), static::COLUMN)
);
$this->assertSame(
static::IPV6,
$this->behavior()->retrieveProperty(hex2bin(static::IPV6_HEX), static::COLUMN)
);

$this->assertSame(
static::IPV4,
$this->behavior(true)->retrieveProperty(hex2bin(static::IPV4_HEX), static::COLUMN)
);
$this->assertSame(
static::IPV6,
$this->behavior(true)->retrieveProperty(hex2bin(static::IPV6_HEX), static::COLUMN)
);
}

public function testToDbReturnsInvalidValueAsIs()
{
$this->assertNull($this->behavior()->persistProperty(null, static::COLUMN));
$this->assertSame('*', $this->behavior()->persistProperty('*', static::COLUMN));

$this->assertNull($this->behavior(true)->persistProperty(null, static::COLUMN));
$this->assertSame('*', $this->behavior(true)->persistProperty('*', static::COLUMN));

$ipv4Bin = hex2bin(static::IPV4_HEX);
$ipv6Bin = hex2bin(static::IPV6_HEX);

$this->assertSame($ipv4Bin, $this->behavior()->persistProperty($ipv4Bin, static::COLUMN));
$this->assertSame($ipv6Bin, $this->behavior()->persistProperty($ipv6Bin, static::COLUMN));

$this->assertSame($ipv4Bin, $this->behavior(true)->persistProperty($ipv4Bin, static::COLUMN));
$this->assertSame($ipv6Bin, $this->behavior(true)->persistProperty($ipv6Bin, static::COLUMN));
}

public function testToDbTransformsIpToBinaryCorrectly()
{
$this->assertSame(hex2bin(static::IPV4_HEX), $this->behavior()->persistProperty(static::IPV4, static::COLUMN));
$this->assertSame(hex2bin(static::IPV6_HEX), $this->behavior()->persistProperty(static::IPV6, static::COLUMN));

$this->assertSame(
sprintf('\\x%s', static::IPV4_HEX),
$this->behavior(true)->persistProperty(static::IPV4, static::COLUMN)
);
$this->assertSame(
sprintf('\\x%s', static::IPV6_HEX),
$this->behavior(true)->persistProperty(static::IPV6, static::COLUMN)
);
}

protected function behavior(bool $postgres = false): Ip
{
return (new Ip(['ip']))
->setQuery(
(new Query())
->setDb(new Connection(['db' => $postgres ? 'pgsql' : 'mysql']))
);
}
}

0 comments on commit 88d1d69

Please sign in to comment.