Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a diagnosis tool #60

Merged
merged 5 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Add Finder::diagnose()
  • Loading branch information
theofidry committed Dec 7, 2022
commit c09656360c277be78bf06382756d2a29660225d0
13 changes: 13 additions & 0 deletions src/Finder/CpuCoreFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@
interface CpuCoreFinder
{
/**
* Provides an explanation which may offer some insight as to what the finder
* will be able to find.
*
* This is practical to have an idea of what each finder will find an collect
* information for the unit tests, since integration tests are quite complicated
* as dependent on complex infrastructures.
*/
public function diagnose(): string;

/**
* Find the number of CPU cores. If it could not find it, returns null. The
* means used to find the cores are at the implementation discretion.
*
* @return positive-int|null
*/
public function find(): ?int;
Expand Down
28 changes: 28 additions & 0 deletions src/Finder/CpuInfoFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

use function file_get_contents;
use function is_file;
use function sprintf;
use function substr_count;
use const PHP_EOL;

/**
* Find the number of CPU cores looking up at the cpuinfo file which is available
Expand All @@ -28,6 +30,32 @@ final class CpuInfoFinder implements CpuCoreFinder
{
private const CPU_INFO_PATH = '/proc/cpuinfo';

public function diagnose(): string
{
if (!is_file(self::CPU_INFO_PATH)) {
return sprintf(
'The file "%s" could not be found.',
self::CPU_INFO_PATH
);
}

$cpuInfo = file_get_contents(self::CPU_INFO_PATH);

if (false === $cpuInfo) {
return sprintf(
'Could not get the content of the file "%s".',
self::CPU_INFO_PATH
);
}

return sprintf(
'Found the file "%s" with the content:%s%s',
self::CPU_INFO_PATH,
PHP_EOL,
$cpuInfo
);
}

/**
* @return positive-int|null
*/
Expand Down
10 changes: 10 additions & 0 deletions src/Finder/DummyCpuCoreFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace Fidry\CpuCoreCounter\Finder;

use function sprintf;

/**
* This finder returns whatever value you gave to it. This is useful for testing
* or as a fallback to avoid to catch the NumberOfCpuCoreNotFound exception.
Expand All @@ -24,6 +26,14 @@ final class DummyCpuCoreFinder implements CpuCoreFinder
*/
private $count;

public function diagnose(): string
{
return sprintf(
'Will return "%d".',
$this->count
);
}

/**
* @param positive-int $count
*/
Expand Down
52 changes: 50 additions & 2 deletions src/Finder/NProcFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
use function filter_var;
use function function_exists;
use function is_int;
use function sprintf;
use function trim;
use const FILTER_VALIDATE_INT;
use const PHP_EOL;

/**
* The number of (logical) cores.
Expand All @@ -29,6 +31,8 @@
*/
final class NProcFinder implements CpuCoreFinder
{
private const DETECT_NPROC_COMMAND = 'command -v nproc';

/**
* @var bool
*/
Expand All @@ -42,6 +46,50 @@ public function __construct(bool $all = true)
$this->all = $all;
}

public function diagnose(): string
{
if (!function_exists('shell_exec')) {
return 'The function "shell_exec" is not available.';
}

try {
$commandNproc = ShellExec::execute(self::DETECT_NPROC_COMMAND);
} catch (ExecException $nprocCommandNotFound) {
return sprintf(
'The command nproc was not detected. The command "%s" failed: %s',
self::DETECT_NPROC_COMMAND,
$nprocCommandNotFound->getMessage()
);
}

if ('' === trim($commandNproc)) {
return sprintf(
'The command nproc was not detected. The command "%s" gave an empty output.',
self::DETECT_NPROC_COMMAND
);
}

$nprocCommand = 'nproc'.($this->all ? ' --all' : '');

try {
// TODO: clarify what happens with the STDERR here
$nproc = ShellExec::execute($nprocCommand);
} catch (ExecException $nprocFailed) {
return sprintf(
'The command "%s" failed: %s',
$nprocCommand,
$nprocFailed->getMessage()
);
}

return sprintf(
'The command "%s" gave the following output:%s%s',
$nprocCommand,
PHP_EOL,
$nproc
);
}

/**
* @return positive-int|null
*/
Expand All @@ -67,8 +115,8 @@ private static function supportsNproc(): bool
}

try {
$commandNproc = ShellExec::execute('command -v nproc');
} catch (ExecException $noNprocCommand) {
$commandNproc = ShellExec::execute(self::DETECT_NPROC_COMMAND);
} catch (ExecException $nprocCommandNotFound) {
return false;
}

Expand Down
5 changes: 5 additions & 0 deletions src/Finder/NullCpuCoreFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
*/
final class NullCpuCoreFinder implements CpuCoreFinder
{
public function diagnose(): string
{
return 'Will return "null".';
}

public function find(): ?int
{
return null;
Expand Down
43 changes: 43 additions & 0 deletions src/Finder/PopenBasedFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,53 @@
use function is_resource;
use function pclose;
use function popen;
use function sprintf;
use const FILTER_VALIDATE_INT;
use const PHP_EOL;

abstract class PopenBasedFinder implements CpuCoreFinder
{
public function diagnose(): string
{
if (!function_exists('popen')) {
return 'The function "popen" is not available.';
}

// Redirect the STDERR to the STDOUT since popen cannot capture the
// STDERR.
// We could use proc_open but this would be a greater difference between
// the command we really execute when using the finder and what we will
// diagnose.
$command = $this->getCommand().' 2>&1';

$process = popen($command, 'rb');

if (!is_resource($process)) {
return sprintf(
'Could not execute the function "popen" with the command "%s".',
$command,
);
}

$processResult = fgets($process);
$exitCode = pclose($process);

return 0 === $exitCode
? sprintf(
'Executed the command "%s" and got the following output:%s%s',
$command,
PHP_EOL,
$processResult
)
: sprintf(
'Executed the command "%s" which exited with a non-success exit code (%d) with the following output:%s%s',
$command,
$exitCode,
PHP_EOL,
$processResult
);
}

/**
* @return positive-int|null
*/
Expand Down
5 changes: 5 additions & 0 deletions tests/Finder/LabeledFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public function getLabel(): string
return $this->label;
}

public function diagnose(): string
{
return $this->decoratedFinder->diagnose();
}

public function find(): ?int
{
return $this->decoratedFinder->find();
Expand Down
2 changes: 2 additions & 0 deletions tests/Finder/LabeledFinderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public function test_it_decorates_a_finder_with_its_class_short_name_as_a_label(

self::assertSame('DummyCpuCoreFinder', $finder->getLabel());
self::assertSame(7, $finder->find());
self::assertSame('Will return "7".', $finder->diagnose());
}

public function test_it_decorates_a_finder_with_the_given_label_when_specified(): void
Expand All @@ -42,5 +43,6 @@ public function test_it_decorates_a_finder_with_the_given_label_when_specified()

self::assertSame('Foo', $finder->getLabel());
self::assertSame(7, $finder->find());
self::assertSame('Will return "7".', $finder->diagnose());
}
}