diff --git a/lib/OperatingSystems/DefaultOs.php b/lib/OperatingSystems/DefaultOs.php index 981c2293..c81f4c3e 100644 --- a/lib/OperatingSystems/DefaultOs.php +++ b/lib/OperatingSystems/DefaultOs.php @@ -25,8 +25,13 @@ use OCA\ServerInfo\Resources\Disk; use OCA\ServerInfo\Resources\Memory; +use OCA\ServerInfo\Resources\NetInterface; +use RuntimeException; class DefaultOs implements IOperatingSystem { + private const AF_INET = 2; + private const AF_INET6 = 10; + public function supported(): bool { return true; } @@ -36,7 +41,7 @@ public function getMemory(): Memory { try { $meminfo = $this->readContent('/proc/meminfo'); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { return $data; } @@ -79,7 +84,7 @@ public function getCpuName(): string { try { $cpuinfo = $this->readContent('/proc/cpuinfo'); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { return $data; } @@ -100,7 +105,7 @@ public function getCpuName(): string { $pattern = '/processor\s+:\s(.+)/'; - $result = preg_match_all($pattern, $cpuinfo, $matches); + preg_match_all($pattern, $cpuinfo, $matches); $cores = count($matches[1]); if ($cores === 1) { @@ -121,7 +126,7 @@ public function getUptime(): int { try { $uptime = $this->readContent('/proc/uptime'); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { return $data; } @@ -141,42 +146,44 @@ public function getNetworkInfo(): array { } public function getNetworkInterfaces(): array { - $interfaces = glob('/sys/class/net/*') ?: []; - $result = []; + $data = []; - foreach ($interfaces as $interface) { - $iface = []; - $iface['interface'] = basename($interface); - $iface['mac'] = shell_exec('ip addr show dev ' . $iface['interface'] . ' | grep "link/ether " | cut -d \' \' -f 6 | cut -f 1 -d \'/\''); - $iface['ipv4'] = shell_exec('ip addr show dev ' . $iface['interface'] . ' | grep "inet " | cut -d \' \' -f 6 | cut -f 1 -d \'/\''); - $iface['ipv6'] = shell_exec('ip -o -6 addr show ' . $iface['interface'] . ' | sed -e \'s/^.*inet6 \([^ ]\+\).*/\1/\''); - if ($iface['interface'] !== 'lo') { - $iface['status'] = shell_exec('cat /sys/class/net/' . $iface['interface'] . '/operstate'); - $iface['speed'] = (int)shell_exec('cat /sys/class/net/' . $iface['interface'] . '/speed'); - if (isset($iface['speed']) && $iface['speed'] > 0) { - if ($iface['speed'] >= 1000) { - $iface['speed'] = $iface['speed'] / 1000 . ' Gbps'; - } else { - $iface['speed'] = $iface['speed'] . ' Mbps'; - } - } else { - $iface['speed'] = 'unknown'; + foreach ($this->getNetInterfaces() as $interfaceName => $interface) { + $netInterface = new NetInterface($interfaceName, $interface['up']); + $data[] = $netInterface; + + foreach ($interface['unicast'] as $unicast) { + if ($unicast['family'] === self::AF_INET) { + $netInterface->addIPv4($unicast['address']); } - $duplex = shell_exec('cat /sys/class/net/' . $iface['interface'] . '/duplex'); - if (isset($duplex) && $duplex !== '') { - $iface['duplex'] = 'Duplex: ' . $duplex; + if ($unicast['family'] === self::AF_INET6) { + $netInterface->addIPv6($unicast['address']); + } + } + + if ($netInterface->isLoopback()) { + continue; + } + + $interfacePath = '/sys/class/net/' . $interfaceName; + + try { + $netInterface->setMAC($this->readContent($interfacePath . '/address')); + + $speed = (int)$this->readContent($interfacePath . '/speed'); + if ($speed >= 1000) { + $netInterface->setSpeed($speed / 1000 . ' Gbps'); } else { - $iface['duplex'] = ''; + $netInterface->setSpeed($speed . ' Mbps'); } - } else { - $iface['status'] = 'up'; - $iface['speed'] = 'unknown'; - $iface['duplex'] = ''; + + $netInterface->setDuplex($this->readContent($interfacePath . '/duplex')); + } catch (RuntimeException $e) { + // unable to read interface data } - $result[] = $iface; } - return $result; + return $data; } public function getDiskInfo(): array { @@ -184,7 +191,7 @@ public function getDiskInfo(): array { try { $disks = $this->executeCommand('df -TPk'); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { return $data; } @@ -227,7 +234,7 @@ public function getThermalZones(): array { $tzone['hash'] = md5($thermalZone); $tzone['type'] = $this->readContent($thermalZone . '/type'); $tzone['temp'] = (float)((int)($this->readContent($thermalZone . '/temp')) / 1000); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { continue; } $result[] = $tzone; @@ -236,19 +243,35 @@ public function getThermalZones(): array { return $result; } + /** + * @throws RuntimeException + */ protected function readContent(string $filename): string { $data = @file_get_contents($filename); if ($data === false || $data === '') { - throw new \RuntimeException('Unable to read: "' . $filename . '"'); + throw new RuntimeException('Unable to read: "' . $filename . '"'); } - return $data; + return trim($data); } protected function executeCommand(string $command): string { $output = @shell_exec(escapeshellcmd($command)); if ($output === false || $output === null || $output === '') { - throw new \RuntimeException('No output for command: "' . $command . '"'); + throw new RuntimeException('No output for command: "' . $command . '"'); } return $output; } + + /** + * Wrapper for net_get_interfaces + * + * @throws RuntimeException + */ + protected function getNetInterfaces(): array { + $data = net_get_interfaces(); + if ($data === false) { + throw new RuntimeException('Unable to get network interfaces'); + } + return $data; + } } diff --git a/lib/OperatingSystems/FreeBSD.php b/lib/OperatingSystems/FreeBSD.php index e39d88b5..c3ffd29f 100644 --- a/lib/OperatingSystems/FreeBSD.php +++ b/lib/OperatingSystems/FreeBSD.php @@ -25,8 +25,13 @@ use OCA\ServerInfo\Resources\Disk; use OCA\ServerInfo\Resources\Memory; +use OCA\ServerInfo\Resources\NetInterface; +use RuntimeException; class FreeBSD implements IOperatingSystem { + private const AF_INET = 2; + private const AF_INET6 = 28; + public function supported(): bool { return false; } @@ -36,7 +41,7 @@ public function getMemory(): Memory { try { $swapinfo = $this->executeCommand('/usr/sbin/swapinfo -k'); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { $swapinfo = ''; } @@ -53,7 +58,7 @@ public function getMemory(): Memory { try { $meminfo = $this->executeCommand('/sbin/sysctl -n hw.realmem hw.pagesize vm.stats.vm.v_inactive_count vm.stats.vm.v_cache_count vm.stats.vm.v_free_count'); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { $meminfo = ''; } @@ -80,7 +85,7 @@ public function getCpuName(): string { } else { $data = $model . ' (' . $cores . ' cores)'; } - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { return $data; } return $data; @@ -89,7 +94,7 @@ public function getCpuName(): string { public function getTime(): string { try { return $this->executeCommand('date'); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { return ''; } } @@ -102,7 +107,7 @@ public function getUptime(): int { preg_match("/[\d]+/", $shell_boot, $boottime); $time = $this->executeCommand('date +%s'); $uptime = (int)$time - (int)$boottime[0]; - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { return $uptime; } return $uptime; @@ -122,83 +127,61 @@ public function getNetworkInfo(): array { if (count($gw[0]) > 0) { $result['gateway'] = implode(", ", array_map("trim", $gw[0])); } - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { return $result; } return $result; } public function getNetworkInterfaces(): array { - $result = []; + $data = []; - try { - $ifconfig = $this->executeCommand('/sbin/ifconfig -a'); - } catch (\RuntimeException $e) { - return $result; - } + foreach ($this->getNetInterfaces() as $interfaceName => $interface) { + $netInterface = new NetInterface($interfaceName, $interface['up']); + $data[] = $netInterface; - preg_match_all("/^(?<=(?!\t)).*(?=:)/m", $ifconfig, $interfaces); + foreach ($interface['unicast'] as $unicast) { + if ($unicast['family'] === self::AF_INET) { + $netInterface->addIPv4($unicast['address']); + } + if ($unicast['family'] === self::AF_INET6) { + $netInterface->addIPv6($unicast['address']); + } + } - foreach ($interfaces[0] as $interface) { - $iface = []; - $iface['interface'] = $interface; + if ($netInterface->isLoopback()) { + continue; + } try { - $intface = $this->executeCommand('/sbin/ifconfig ' . $iface['interface']); - } catch (\RuntimeException $e) { + $details = $this->executeCommand('/sbin/ifconfig ' . $interfaceName); + } catch (RuntimeException $e) { continue; } - preg_match_all("/(?<=inet ).\S*/m", $intface, $ipv4); - preg_match_all("/(?<=inet6 )((.*(?=%))|(.\S*))/m", $intface, $ipv6); - $iface['ipv4'] = implode(' ', $ipv4[0]); - $iface['ipv6'] = implode(' ', $ipv6[0]); - - if ($iface['interface'] !== 'lo0') { - preg_match_all("/(?<=ether ).*/m", $intface, $mac); - preg_match("/(?<=status: ).*/m", $intface, $status); - preg_match("/\b[0-9].*?(?=base)/m", $intface, $speed); - preg_match("/(?<=\<).*(?=-)/m", $intface, $duplex); - - if (isset($mac[0])) { - $iface['mac'] = implode(' ', $mac[0]); - } - - if (isset($speed[0])) { - $iface['speed'] = $speed[0]; - } - - if (isset($status[0])) { - $iface['status'] = $status[0]; - } else { - $iface['status'] = 'active'; - } + preg_match("/(?<=ether ).*/m", $details, $mac); + if (isset($mac[0])) { + $netInterface->setMAC($mac[0]); + } - if (isset($iface['speed'])) { - if (strpos($iface['speed'], 'G')) { - $iface['speed'] = rtrim($iface['speed'], 'G'); - $iface['speed'] = $iface['speed'] . ' Gbps'; - } else { - $iface['speed'] = $iface['speed'] . ' Mbps'; - } + preg_match("/\b[0-9].*?(?=base)/m", $details, $speed); + if (isset($speed[0])) { + if (substr($speed[0], -1) === 'G') { + $netInterface->setSpeed(rtrim($speed[0], 'G') . ' Gbps'); } else { - $iface['speed'] = 'unknown'; + $netInterface->setSpeed($speed[0] . ' Mbps'); } + } - if (isset($duplex[0])) { - $iface['duplex'] = 'Duplex: ' . $duplex[0]; - } else { - $iface['duplex'] = ''; - } - } else { - $iface['status'] = 'active'; - $iface['speed'] = 'unknown'; - $iface['duplex'] = ''; + preg_match("/(?<=\<).*(?=-)/m", $details, $duplex); + if (isset($duplex[0])) { + $netInterface->setDuplex($duplex[0]); } - $result[] = $iface; + + unset($mac, $speed, $duplex); } - return $result; + return $data; } public function getDiskInfo(): array { @@ -206,7 +189,7 @@ public function getDiskInfo(): array { try { $disks = $this->executeCommand('df -TPk'); - } catch (\RuntimeException $e) { + } catch (RuntimeException $e) { return $data; } @@ -245,8 +228,21 @@ public function getThermalZones(): array { protected function executeCommand(string $command): string { $output = @shell_exec(escapeshellcmd($command)); if ($output === null || $output === '' || $output === false) { - throw new \RuntimeException('No output for command: "' . $command . '"'); + throw new RuntimeException('No output for command: "' . $command . '"'); } return $output; } + + /** + * Wrapper for net_get_interfaces + * + * @throws RuntimeException + */ + protected function getNetInterfaces(): array { + $data = net_get_interfaces(); + if ($data === false) { + throw new RuntimeException('Unable to get network interfaces'); + } + return $data; + } } diff --git a/lib/OperatingSystems/IOperatingSystem.php b/lib/OperatingSystems/IOperatingSystem.php index 3c05faef..16e207e3 100644 --- a/lib/OperatingSystems/IOperatingSystem.php +++ b/lib/OperatingSystems/IOperatingSystem.php @@ -28,6 +28,7 @@ use OCA\ServerInfo\Resources\Disk; use OCA\ServerInfo\Resources\Memory; +use OCA\ServerInfo\Resources\NetInterface; interface IOperatingSystem { public function supported(): bool; @@ -67,17 +68,7 @@ public function getNetworkInfo(): array; /** * Get info about available network interfaces. * - * [ - * [ - * 'duplex' => string, - * 'interface' => string, - * 'ipv4' => string, - * 'ipv6' => string, - * 'mac' => string, - * 'speed' => string, - * 'status' => string, - * ], - * ] + * @return NetInterface[] */ public function getNetworkInterfaces(): array; diff --git a/lib/Os.php b/lib/Os.php index 8c906a16..b3448f77 100644 --- a/lib/Os.php +++ b/lib/Os.php @@ -106,8 +106,7 @@ public function getNetworkInfo(): array { } public function getNetworkInterfaces(): array { - $data = $this->backend->getNetworkInterfaces(); - return $data; + return $this->backend->getNetworkInterfaces(); } public function getThermalZones(): array { diff --git a/lib/Resources/NetInterface.php b/lib/Resources/NetInterface.php new file mode 100644 index 00000000..b8dbee44 --- /dev/null +++ b/lib/Resources/NetInterface.php @@ -0,0 +1,114 @@ + + * + * @author Daniel Kesselberg + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\ServerInfo\Resources; + +class NetInterface { + private string $name = ''; + private bool $up = false; + private array $ipv4 = []; + private array $ipv6 = []; + private string $mac = ''; + private string $speed = 'unknown'; + private string $duplex = 'unknown'; + private bool $loopback = false; + + public function __construct(string $name, bool $up) { + $this->name = $name; + $this->up = $up; + } + + public function getName(): string { + return $this->name; + } + + public function setName(string $name): void { + $this->name = $name; + } + + public function isUp(): bool { + return $this->up; + } + + public function setUp(bool $up): void { + $this->up = $up; + } + + /** + * @return string[] + */ + public function getIPv4(): array { + return $this->ipv4; + } + + public function addIPv4(string $ipv4): void { + $this->ipv4[] = $ipv4; + if ($ipv4 === '127.0.0.1') { + $this->loopback = true; + } + } + + /** + * @return string[] + */ + public function getIPv6(): array { + return $this->ipv6; + } + + public function addIPv6(string $ipv6): void { + $this->ipv6[] = $ipv6; + if ($ipv6 === '::1') { + $this->loopback = true; + } + } + + public function getMAC(): string { + return $this->mac; + } + + public function setMAC(string $mac): void { + $this->mac = $mac; + } + + public function getSpeed(): string { + return $this->speed; + } + + public function setSpeed(string $speed): void { + $this->speed = $speed; + } + + public function getDuplex(): string { + return $this->duplex; + } + + public function setDuplex(string $duplex): void { + $this->duplex = $duplex; + } + + public function isLoopback(): bool { + return $this->loopback; + } +} diff --git a/templates/settings-admin.php b/templates/settings-admin.php index 8127c11a..3e9d35de 100644 --- a/templates/settings-admin.php +++ b/templates/settings-admin.php @@ -22,6 +22,11 @@ * */ +use OCA\ServerInfo\Resources\Disk; +use OCA\ServerInfo\Resources\Memory; +use OCA\ServerInfo\Resources\NetInterface; +use OCP\Util; + script('serverinfo', 'script'); script('serverinfo', 'smoothie'); script('serverinfo', 'Chart.min'); @@ -38,10 +43,13 @@ function FormatMegabytes(int $byte): string { return number_format($byte, 2, '.', '.') . ' ' . $unim[$count]; } -/** @var \OCA\ServerInfo\Resources\Memory $memory */ +/** @var Memory $memory */ $memory = $_['memory']; -/** @var \OCA\ServerInfo\Resources\Disk[] $disks */ +/** @var Disk[] $disks */ $disks = $_['diskinfo']; +/** @var NetInterface[] $interfaces */ +$interfaces = $_['networkinterfaces']; + ?>
@@ -90,8 +98,8 @@ function FormatMegabytes(int $byte): string {
- -
+ +

@@ -192,25 +200,25 @@ function FormatMegabytes(int $byte): string {

- +
-

+

getName()) ?>

t('Status:')); ?> -
+ isUp() ? 'up' : 'down'; ?>
t('Speed:')); ?> -
- + getSpeed()) ?> (t('Duplex:') . ' ' . $interface->getDuplex()) ?>)
+ getMAC())): ?> t('MAC:')); ?> -
+ getMAC()) ?>
t('IPv4:')); ?> -
+ getIPv4())); ?> +
t('IPv6:')); ?> - + getIPv6())); ?>
diff --git a/tests/data/freebsd_interface_lo0 b/tests/data/freebsd_interface_lo0 deleted file mode 100644 index b377291f..00000000 --- a/tests/data/freebsd_interface_lo0 +++ /dev/null @@ -1,7 +0,0 @@ -lo0: flags=8049 metric 0 mtu 16384 - options=680003 - inet6 ::1 prefixlen 128 - inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 - inet 127.0.0.1 netmask 0xff000000 - groups: lo - nd6 options=21 diff --git a/tests/data/freebsd_interfaces b/tests/data/freebsd_interfaces deleted file mode 100644 index f42787b6..00000000 --- a/tests/data/freebsd_interfaces +++ /dev/null @@ -1,18 +0,0 @@ -lo0: flags=8049 metric 0 mtu 16384 - options=680003 - inet6 ::1 prefixlen 128 - inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 - inet 127.0.0.1 netmask 0xff000000 - groups: lo - nd6 options=21 -pflog0: flags=0<> metric 0 mtu 33160 - groups: pflog -epair0b: flags=8843 metric 0 mtu 1500 - options=8 - ether 1a:c0:4d:ba:b5:82 - hwaddr 02:60:e8:04:f6:0b - inet 192.168.178.150 netmask 0xffffff00 broadcast 192.168.178.255 - groups: epair - media: Ethernet 10Gbase-T (10Gbase-T ) - status: active - nd6 options=1 diff --git a/tests/data/freebsd_net_get_interfaces.json b/tests/data/freebsd_net_get_interfaces.json new file mode 100644 index 00000000..966ba1f0 --- /dev/null +++ b/tests/data/freebsd_net_get_interfaces.json @@ -0,0 +1,87 @@ +{ + "epair0b": { + "unicast": [ + { + "flags": 34915, + "family": 18 + }, + { + "flags": 34915, + "family": 28, + "address": "fe80::a00:27ff:fe91:f84b", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "flags": 34915, + "family": 2, + "address": "10.0.2.15", + "netmask": "255.255.255.0", + "broadcast": "10.0.2.255" + } + ], + "up": true + }, + "pflog0": { + "unicast": [ + { + "flags": 34915, + "family": 18 + }, + { + "flags": 34915, + "family": 2, + "address": "192.168.2.20", + "netmask": "255.255.255.0", + "broadcast": "192.168.2.255" + }, + { + "flags": 34915, + "family": 28, + "address": "fe80::a00:27ff:fe8b:d03d", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "flags": 34915, + "family": 2, + "address": "192.168.2.21", + "netmask": "255.255.255.0", + "broadcast": "192.168.2.255" + }, + { + "flags": 34915, + "family": 2, + "address": "192.168.2.22", + "netmask": "255.255.255.0", + "broadcast": "192.168.2.255" + } + ], + "up": true + }, + "lo0": { + "unicast": [ + { + "flags": 32841, + "family": 18 + }, + { + "flags": 32841, + "family": 28, + "address": "::1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + }, + { + "flags": 32841, + "family": 28, + "address": "fe80::1", + "netmask": "ffff:ffff:ffff:ffff::" + }, + { + "flags": 32841, + "family": 2, + "address": "127.0.0.1", + "netmask": "255.0.0.0" + } + ], + "up": true + } +} \ No newline at end of file diff --git a/tests/data/linux_net_get_interfaces.json b/tests/data/linux_net_get_interfaces.json new file mode 100644 index 00000000..87b8cd30 --- /dev/null +++ b/tests/data/linux_net_get_interfaces.json @@ -0,0 +1,45 @@ +{ + "lo": { + "unicast": [ + { + "flags": 65609, + "family": 17 + }, + { + "flags": 65609, + "family": 2, + "address": "127.0.0.1", + "netmask": "255.0.0.0" + }, + { + "flags": 65609, + "family": 10, + "address": "::1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + } + ], + "up": true + }, + "eth0": { + "unicast": [ + { + "flags": 69699, + "family": 17 + }, + { + "flags": 69699, + "family": 2, + "address": "10.0.2.15", + "netmask": "255.255.255.0", + "broadcast": "10.0.2.255" + }, + { + "flags": 69699, + "family": 10, + "address": "fe80::a00:27ff:fe91:f84b", + "netmask": "ffff:ffff:ffff:ffff::" + } + ], + "up": true + } +} \ No newline at end of file diff --git a/tests/lib/DefaultOsTest.php b/tests/lib/DefaultOsTest.php index 7c4bd523..4cabe690 100644 --- a/tests/lib/DefaultOsTest.php +++ b/tests/lib/DefaultOsTest.php @@ -29,7 +29,9 @@ use OCA\ServerInfo\OperatingSystems\DefaultOs; use OCA\ServerInfo\Resources\Disk; use OCA\ServerInfo\Resources\Memory; +use OCA\ServerInfo\Resources\NetInterface; use PHPUnit\Framework\MockObject\MockObject; +use RuntimeException; use Test\TestCase; /** @@ -38,7 +40,7 @@ * @package OCA\ServerInfo\Tests */ class DefaultOsTest extends TestCase { - /** @var DefaultOs|MockObject */ + /** @var DefaultOs&MockObject */ protected $os; protected function setUp(): void { @@ -49,7 +51,7 @@ protected function setUp(): void { ->disableOriginalClone() ->disableArgumentCloning() ->disallowMockingUnknownTypes() - ->setMethods(['readContent', 'executeCommand']) + ->setMethods(['readContent', 'executeCommand', 'getNetInterfaces']) ->getMock(); } @@ -70,7 +72,7 @@ public function testGetMemory(): void { public function testGetMemoryNoData(): void { $this->os->method('readContent') ->with('/proc/meminfo') - ->willThrowException(new \RuntimeException('Unable to read: "/proc/meminfo"')); + ->willThrowException(new RuntimeException('Unable to read: "/proc/meminfo"')); $this->assertEquals(new Memory(), $this->os->getMemory()); } @@ -102,7 +104,7 @@ public function testGetCPUNameOneCore(): void { public function testGetCPUNameNoData(): void { $this->os->method('readContent') ->with('/proc/cpuinfo') - ->willThrowException(new \RuntimeException('Unable to read: "/proc/cpuinfo"')); + ->willThrowException(new RuntimeException('Unable to read: "/proc/cpuinfo"')); $this->assertEquals('Unknown Processor', $this->os->getCpuName()); } @@ -126,7 +128,7 @@ public function testGetUptime(): void { public function testGetUptimeNoData(): void { $this->os->method('readContent') ->with('/proc/uptime') - ->willThrowException(new \RuntimeException('Unable to read: "/proc/uptime"')); + ->willThrowException(new RuntimeException('Unable to read: "/proc/uptime"')); $this->assertEquals(-1, $this->os->getUptime()); } @@ -190,7 +192,7 @@ public function testGetDiskInfo(): void { public function testGetDiskInfoNoCommandOutput(): void { $this->os->method('executeCommand') ->with('df -TP') - ->willThrowException(new \RuntimeException('No output for command "df -TP"')); + ->willThrowException(new RuntimeException('No output for command "df -TP"')); $this->assertEquals([], $this->os->getDiskInfo()); } @@ -206,4 +208,39 @@ public function testGetDiskInfoInvalidCommandOutput(): void { public function testSupported(): void { $this->assertTrue($this->os->supported()); } + + public function testGetNetworkInterfaces(): void { + $this->os->method('getNetInterfaces') + ->willReturn(json_decode(file_get_contents(__DIR__ . '/../data/linux_net_get_interfaces.json'), true, 512, JSON_THROW_ON_ERROR)); + $this->os->method('readContent') + ->willReturnCallback(static function ($filename) { + if ($filename === '/sys/class/net/eth0/address') { + return '02:42:ac:13:00:0a'; + } + if ($filename === '/sys/class/net/eth0/speed') { + return '10000'; + } + if ($filename === '/sys/class/net/eth0/duplex') { + return 'full'; + } + throw new RuntimeException(); + }); + + + $net1 = new NetInterface('lo', true); + $net1->addIPv4('127.0.0.1'); + $net1->addIPv6('::1'); + + $net2 = new NetInterface('eth0', true); + $net2->addIPv4('10.0.2.15'); + $net2->addIPv6('fe80::a00:27ff:fe91:f84b'); + $net2->setMAC('02:42:ac:13:00:0a'); + $net2->setSpeed('10 Gbps'); + $net2->setDuplex('full'); + + $expected = [$net1, $net2]; + $actual = $this->os->getNetworkInterfaces(); + + $this->assertEquals($expected, $actual); + } } diff --git a/tests/lib/FreeBSDTest.php b/tests/lib/FreeBSDTest.php index aaedc5e8..17412f2e 100644 --- a/tests/lib/FreeBSDTest.php +++ b/tests/lib/FreeBSDTest.php @@ -28,7 +28,9 @@ use OCA\ServerInfo\OperatingSystems\FreeBSD; use OCA\ServerInfo\Resources\Memory; +use OCA\ServerInfo\Resources\NetInterface; use PHPUnit\Framework\MockObject\MockObject; +use RuntimeException; use Test\TestCase; /** @@ -37,7 +39,7 @@ * @package OCA\ServerInfo\Tests */ class FreeBSDTest extends TestCase { - /** @var FreeBSD|MockObject */ + /** @var FreeBSD&MockObject */ protected $os; protected function setUp(): void { @@ -48,7 +50,7 @@ protected function setUp(): void { ->disableOriginalClone() ->disableArgumentCloning() ->disallowMockingUnknownTypes() - ->setMethods(['executeCommand']) + ->setMethods(['executeCommand', 'getNetInterfaces']) ->getMock(); } @@ -96,54 +98,41 @@ public function testGetMemoryNoData(): void { } public function testGetNetworkInterfaces(): void { + $this->os->method('getNetInterfaces') + ->willReturn(json_decode(file_get_contents(__DIR__ . '/../data/freebsd_net_get_interfaces.json'), true, 512, JSON_THROW_ON_ERROR)); $this->os->method('executeCommand') ->willReturnCallback(static function ($command) { - if ($command === '/sbin/ifconfig -a') { - return file_get_contents(__DIR__ . '/../data/freebsd_interfaces'); - } - if ($command === '/sbin/ifconfig lo0') { - return file_get_contents(__DIR__ . '/../data/freebsd_interface_lo0'); - } if ($command === '/sbin/ifconfig pflog0') { return file_get_contents(__DIR__ . '/../data/freebsd_interface_pflog0'); } if ($command === '/sbin/ifconfig epair0b') { return file_get_contents(__DIR__ . '/../data/freebsd_interface_epair0b'); } - - // Regex matches way more than the interface names, so if it doesn't match any of the defined ones, throw. - throw new \RuntimeException(); + throw new RuntimeException(); }); - $interfaces = $this->os->getNetworkInterfaces(); - $this->assertEquals([ - [ - "interface" => "lo0", - "ipv4" => "127.0.0.1", - "ipv6" => "::1 fe80::1", - "status" => "active", - "speed" => "unknown", - "duplex" => "", - ], - [ - "interface" => "pflog0", - "ipv4" => "", - "ipv6" => "", - "mac" => "", - "status" => "active", - "speed" => "unknown", - "duplex" => "", - ], - [ - "interface" => "epair0b", - "ipv4" => "192.168.178.150", - "ipv6" => "", - "mac" => "1a:c0:4d:ba:b5:82", - "speed" => "10 Gbps", - "status" => "active", - "duplex" => "Duplex: full", - ] - ], $interfaces); + $net1 = new NetInterface('epair0b', true); + $net1->addIPv4('10.0.2.15'); + $net1->addIPv6('fe80::a00:27ff:fe91:f84b'); + $net1->setMAC('1a:c0:4d:ba:b5:82'); + $net1->setSpeed('10 Gbps'); + $net1->setDuplex('full'); + + $net2 = new NetInterface('pflog0', true); + $net2->addIPv4('192.168.2.20'); + $net2->addIPv6('fe80::a00:27ff:fe8b:d03d'); + $net2->addIPv4('192.168.2.21'); + $net2->addIPv4('192.168.2.22'); + + $net3 = new NetInterface('lo0', true); + $net3->addIPv4('127.0.0.1'); + $net3->addIPv6('::1'); + $net3->addIPv6('fe80::1'); + + $expected = [$net1, $net2, $net3]; + $actual = $this->os->getNetworkInterfaces(); + + $this->assertEquals($expected, $actual); } public function testSupported(): void { diff --git a/tests/lib/NetInterfaceTest.php b/tests/lib/NetInterfaceTest.php new file mode 100644 index 00000000..60819817 --- /dev/null +++ b/tests/lib/NetInterfaceTest.php @@ -0,0 +1,44 @@ + + * + * @author Daniel Kesselberg + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\ServerInfo\Tests; + +use OCA\ServerInfo\Resources\NetInterface; +use Test\TestCase; + +class NetInterfaceTest extends TestCase { + public function testIsLoopback4(): void { + $net = new NetInterface('eth0', true); + $net->addIPv4('127.0.0.1'); + $this->assertTrue($net->isLoopback()); + } + + public function testIsLoopback6(): void { + $net = new NetInterface('eth0', true); + $net->addIPv6('::1'); + $this->assertTrue($net->isLoopback()); + } +}