Skip to content

Commit

Permalink
feat: add check 'requireVarsMatchValues' - wip
Browse files Browse the repository at this point in the history
  • Loading branch information
eleftrik committed Jun 2, 2024
1 parent 250c603 commit 26536fb
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 9 deletions.
5 changes: 4 additions & 1 deletion resources/lang/en/translations.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

return [
'every_var_has_been_set' => 'Every required .env variable has been set',
'not_every_var_has_been_set' => 'Not every required .env variable has been set!',
'missing_vars_list' => 'Missing .env variables: :list',
'missing_vars_list_in_environment' => "Missing .env variables in ':environment' environment: :list",
'not_every_var_has_been_set' => 'Not every required .env variable has been set!',
'var_not_matching_value' => ":name is set to ':actual' instead of ':expected'",
'vars_not_matching_values' => 'Some variables does not match their expected value',
'vars_not_matching_values_list' => "Some variables does not match their expected value in ':environment' environment: :list",
];
5 changes: 4 additions & 1 deletion resources/lang/it/translations.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

return [
'every_var_has_been_set' => 'Tutte le variabili .env richieste sono state valorizzate',
'not_every_var_has_been_set' => 'Non tutte le variabili .env richieste sono state valorizzate!',
'missing_vars_list' => 'Variabili .env mancanti: :list',
'missing_vars_list_in_environment' => "Variabili .env mancanti nell'ambiente ':environment': :list",
'not_every_var_has_been_set' => 'Non tutte le variabili .env richieste sono state valorizzate!',
'var_not_matching_value' => ":name è valorizzata a ':actual' invece di ':expected'",
'vars_not_matching_values' => 'Alcune variabili non sono state valorizzate come previsto',
'vars_not_matching_values_list' => "Alcune variabili non sono state valorizzate come previsto nell'ambiente ':environment': :list",
];
46 changes: 46 additions & 0 deletions src/Health/Checks/CheckResultDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace Encodia\Health\Checks;

final class CheckResultDto
{
public function __construct(
public bool $ok,
/** @var array<string,mixed> */
public array $meta,
public string $summary,
public string $message
) {
//
}

public static function ok(): self
{
return new self(
ok: true,
meta: [],
summary: '',
message: ''
);
}

/**
* @param array<string,mixed> $meta
*/
public static function error(array $meta, string $summary, string $message): self
{
return new self(
ok: false,
meta: $meta,
summary: $summary,
message: $message
);
}

public function hasFailed(): bool
{
return ! $this->ok;
}
}
75 changes: 69 additions & 6 deletions src/Health/Checks/EnvVars.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,34 @@ class EnvVars extends Check
/** @var Collection<int,string> */
protected Collection $requiredVars;

/** @var Collection<int,string> */
/** @var Collection<string,mixed> */
protected Collection $requiredVarsWithValues;

/** @var Collection<string,string> */
protected Collection $environmentSpecificVars;

/** @var Collection<string,array<string,mixed>> */
protected Collection $environmentSpecificVarsWithValues;

/**
* Run the check and return the Result
*/
public function run(): Result
{
$this->requiredVars ??= Collection::empty();
$this->environmentSpecificVars ??= Collection::empty();
$this->requiredVars ??= collect();
$this->environmentSpecificVars ??= collect();
$this->requiredVarsWithValues ??= collect();

$result = Result::make();

// Check required vars with values
$check = $this->checkRequiredVarsWithValues($this->requiredVarsWithValues);
if ($check->hasFailed()) {
return $result->meta($check->meta)
->shortSummary($check->summary)
->failed($check->message);
}

// Check all provided variable names match .env variables with non-empty value
$missingVars = $this->missingVars($this->requiredVars);

Expand All @@ -43,9 +58,9 @@ public function run(): Result
/** @var string $currentEnvironment */
$currentEnvironment = App::environment();
// Same for environment specific vars (if any), returning different error messages
$missingVars = $this->missingVars(
$this->environmentSpecificVars->get($currentEnvironment, Collection::empty())
);
/** @var Collection<int,string> $environmentSpecificVars */
$environmentSpecificVars = $this->environmentSpecificVars->get($currentEnvironment, collect());
$missingVars = $this->missingVars($environmentSpecificVars);

if ($missingVars->count() > 0) {
return $result->meta($missingVars->toArray())
Expand Down Expand Up @@ -75,6 +90,20 @@ public function requireVars(array $names): self
return $this;
}

/**
* Require the given variable names to be set (no matter in which environment) to the
* values supplied.
*
* @param array<string,mixed> $values
* @return $this
*/
public function requireVarsMatchValues(array $values): self
{
$this->requiredVarsWithValues = collect($values);

return $this;
}

/**
* Require the given variable names to be set in the given environment
*
Expand Down Expand Up @@ -128,4 +157,38 @@ protected function missingVars(Collection $vars): Collection

return $missingVars;
}

/**
* @param Collection<string,mixed> $requiredVarsWithValues
*/
protected function checkRequiredVarsWithValues(Collection $requiredVarsWithValues): CheckResultDto
{
$failingVarNames = collect();
$failingVarMessages = collect();

$requiredVarsWithValues->each(function ($expectedValue, $name) use ($failingVarNames, $failingVarMessages) {
$actualValue = getenv($name);
if ($expectedValue != $actualValue) {
$failingVarNames->push($name);
$failingVarMessages->push(trans('health-env-vars::translations.var_not_matching_value', [
'name' => $name,
'expected' => $expectedValue,
'actual' => $actualValue,
]));
}
});

if ($failingVarNames->isEmpty()) {
return CheckResultDto::ok();
}

return CheckResultDto::error(
meta: $failingVarNames->toArray(),
summary: trans('health-env-vars::translations.vars_not_matching_values'),
message: trans('health-env-vars::translations.vars_not_matching_values_list', [
'environment' => App::environment(),
'list' => $failingVarMessages->implode('; '),
])
);
}
}
47 changes: 47 additions & 0 deletions tests/MultipleEnvironmentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,53 @@

const ENVIRONMENTS = ['staging', 'qa', 'production'];

afterEach(function () {
unsetEnvVars(['VAR1', 'VAR2', 'VAR3', 'VAR4']);
});

describe('when vars need to match values', function () {
it(
"returns an error if a var doesn't match the expected value in the current environment",
function (string $currentEnvironment) {
// ARRANGE

$environments = ENVIRONMENTS;
$variableName = 'VAR1';
$variableExpectedValue = 'expected value';
$variableActualValue = 'another value';
$missingList = "$variableName is set to '$variableActualValue' instead of '$variableExpectedValue'";

expect($currentEnvironment)->toBeIn($environments);
mockCurrentEnvironment($currentEnvironment);

// init variable with a value different from the expected one
initEnvVars([
$variableName => $variableActualValue,
]);
expect(env($variableName))->not->toEqual($variableExpectedValue);

// ACT & ASSERT
$result = EnvVars::new()
->requireVarsMatchValues([
$variableName => $variableExpectedValue,
])
->run();

expect($result)
->meta->toEqual([$variableName])
->status->toBe(Status::failed())
->shortSummary->toBe(trans('health-env-vars::translations.vars_not_matching_values'))
->notificationMessage->toBe(
trans('health-env-vars::translations.vars_not_matching_values_list', [
'environment' => currentEnvironment(),
'list' => $missingList,
])
);

}
)->with(ENVIRONMENTS);
});

it(
"returns an error if vars are required in multiple environments and at least one var hasn't been set in the ".
'current environment',
Expand Down
12 changes: 11 additions & 1 deletion tests/Pest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@
function initEnvVars(array $vars): void
{
foreach ($vars as $name => $value) {
putenv("{$name}={$value}");
putenv("$name=$value");
}
}

/**
* Unset the given .env variables.
*/
function unsetEnvVars(array $vars): void
{
foreach ($vars as $name) {
putenv($name);
}
}

Expand Down

0 comments on commit 26536fb

Please sign in to comment.