479 lines
15 KiB
PHP
479 lines
15 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace OpenTelemetry\Tests\Unit\SDK\Common\Configuration;
|
|
|
|
use AssertWell\PHPUnitGlobalState\EnvironmentVariables;
|
|
use Exception;
|
|
use Generator;
|
|
use OpenTelemetry\SDK\Common\Configuration\Configuration;
|
|
use OpenTelemetry\SDK\Common\Configuration\Defaults;
|
|
use OpenTelemetry\SDK\Common\Configuration\KnownValues;
|
|
use OpenTelemetry\SDK\Common\Configuration\Variables;
|
|
use OpenTelemetry\SDK\Common\Configuration\VariableTypes;
|
|
use PHPUnit\Framework\TestCase;
|
|
use UnexpectedValueException;
|
|
|
|
/**
|
|
* @covers \OpenTelemetry\SDK\Common\Configuration\Configuration
|
|
*/
|
|
class ConfigurationTest extends TestCase
|
|
{
|
|
use EnvironmentVariables;
|
|
|
|
private const ALLOW_EMPTY = [
|
|
VariableTypes::LIST,
|
|
VariableTypes::MAP,
|
|
VariableTypes::MIXED,
|
|
];
|
|
|
|
private const METHOD_NAMES = [
|
|
VariableTypes::STRING => ['getString'],
|
|
VariableTypes::BOOL => ['getBoolean'],
|
|
VariableTypes::INTEGER => ['getInt'],
|
|
VariableTypes::FLOAT => ['getFloat'],
|
|
VariableTypes::RATIO => ['getRatio'],
|
|
VariableTypes::ENUM => ['getEnum'],
|
|
VariableTypes::LIST => ['getList'],
|
|
VariableTypes::MAP => ['getMap'],
|
|
VariableTypes::MIXED => ['getMixed'],
|
|
];
|
|
|
|
private const TYPES = [
|
|
VariableTypes::STRING => [Variables::OTEL_SERVICE_NAME],
|
|
VariableTypes::BOOL => [Variables::OTEL_EXPORTER_OTLP_INSECURE],
|
|
VariableTypes::INTEGER => [Variables::OTEL_BSP_MAX_QUEUE_SIZE],
|
|
VariableTypes::ENUM => [Variables::OTEL_LOG_LEVEL],
|
|
VariableTypes::LIST => [Variables::OTEL_PROPAGATORS],
|
|
VariableTypes::MAP => [Variables::OTEL_RESOURCE_ATTRIBUTES],
|
|
VariableTypes::MIXED => [Variables::OTEL_TRACES_SAMPLER_ARG],
|
|
];
|
|
|
|
private const USER_VALUES = [
|
|
VariableTypes::STRING => ['foo', 'foo'],
|
|
VariableTypes::BOOL => ['true', true],
|
|
VariableTypes::INTEGER => ['42', 42],
|
|
VariableTypes::ENUM => ['val1', 'val1'],
|
|
VariableTypes::LIST => [['val1', 'val2'], ['val1','val2']],
|
|
VariableTypes::MAP => [['var1' => 'val1', 'var2' => 'val2'], ['var1'=>'val1','var2'=>'val2']],
|
|
VariableTypes::MIXED => ['foo', 'foo'],
|
|
];
|
|
|
|
private const USER_ENV_VALUES = [
|
|
VariableTypes::STRING => ['foo', 'foo'],
|
|
VariableTypes::BOOL => ['true', true],
|
|
VariableTypes::INTEGER => ['42', 42],
|
|
VariableTypes::ENUM => ['val1', 'val1'],
|
|
VariableTypes::LIST => ['val1,val2', ['val1','val2']],
|
|
VariableTypes::MAP => ['var1=val1,var2=val2', ['var1'=>'val1','var2'=>'val2']],
|
|
VariableTypes::MIXED => ['foo', 'foo'],
|
|
];
|
|
|
|
private const LIBRARY_DEFAULTS = [
|
|
VariableTypes::STRING => [Variables::OTEL_EXPORTER_OTLP_ENDPOINT, 'http://localhost:4318'],
|
|
VariableTypes::BOOL => [Variables::OTEL_EXPORTER_OTLP_INSECURE, false],
|
|
VariableTypes::INTEGER => [Variables::OTEL_BSP_MAX_QUEUE_SIZE, 2048],
|
|
VariableTypes::ENUM => [Variables::OTEL_LOG_LEVEL, 'info'],
|
|
VariableTypes::LIST => [Variables::OTEL_PROPAGATORS, ['tracecontext', 'baggage']],
|
|
];
|
|
|
|
private const DEFAULT_VALUES = [
|
|
'log level' => [Variables::OTEL_LOG_LEVEL, Defaults::OTEL_LOG_LEVEL],
|
|
'attribute count limit' => [Variables::OTEL_ATTRIBUTE_COUNT_LIMIT, Defaults::OTEL_ATTRIBUTE_COUNT_LIMIT],
|
|
'trace exporter' => [Variables::OTEL_PHP_TRACES_PROCESSOR, Defaults::OTEL_PHP_TRACES_PROCESSOR],
|
|
];
|
|
|
|
private const NO_DEFAULTS = [
|
|
VariableTypes::STRING => [Variables::OTEL_SERVICE_NAME],
|
|
VariableTypes::ENUM => [Variables::OTEL_EXPORTER_OTLP_COMPRESSION],
|
|
VariableTypes::MAP => [Variables::OTEL_EXPORTER_OTLP_HEADERS],
|
|
VariableTypes::MIXED => [Variables::OTEL_TRACES_SAMPLER_ARG],
|
|
];
|
|
|
|
private const KNOWN_VALUES = [
|
|
'log level' => [Variables::OTEL_LOG_LEVEL, KnownValues::OTEL_LOG_LEVEL],
|
|
'trace sampler' => [Variables::OTEL_TRACES_SAMPLER, KnownValues::OTEL_TRACES_SAMPLER],
|
|
'trace processor' => [Variables::OTEL_PHP_TRACES_PROCESSOR, KnownValues::OTEL_PHP_TRACES_PROCESSOR],
|
|
];
|
|
|
|
public function tearDown(): void
|
|
{
|
|
$this->restoreEnvironmentVariables();
|
|
}
|
|
|
|
public function test_has_variable_from_environment(): void
|
|
{
|
|
$this->assertFalse(Configuration::has('FOO_VAR'));
|
|
$this->setEnvironmentVariable('FOO_VAR', 'FOO');
|
|
$this->assertTrue(Configuration::has('FOO_VAR'));
|
|
}
|
|
|
|
public function test_integer_get(): void
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_FOO', '100');
|
|
$value = Configuration::getInt('OTEL_FOO', 999);
|
|
$this->assertSame(100, $value);
|
|
}
|
|
|
|
public function test_integer_failure(): void
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_FOO', 'foo');
|
|
$this->expectException(Exception::class);
|
|
Configuration::getInt('OTEL_FOO', 99);
|
|
}
|
|
|
|
public function environment_variables_integer_uses_default_if_env_var_not_defined()
|
|
{
|
|
$this->assertSame(20, Configuration::getInt('OTEL_FOO', 20));
|
|
}
|
|
|
|
public function test_string_get(): void
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_FOO', 'foo');
|
|
$value = Configuration::getString('OTEL_FOO', 'bar');
|
|
$this->assertSame('foo', $value);
|
|
}
|
|
|
|
/**
|
|
* The SDK MUST interpret an empty value of an environment variable the same way as when the variable is unset
|
|
* @dataProvider emptyProvider
|
|
*/
|
|
public function test_string_uses_default_when_empty_value(?string $input): void
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_FOO', $input);
|
|
$value = Configuration::getString('OTEL_FOO', 'bar');
|
|
$this->assertSame('bar', $value);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider emptyProvider
|
|
*/
|
|
public function test_int_uses_default_when_empty_value(?string $input): void
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_FOO', $input);
|
|
$value = Configuration::getInt('OTEL_FOO', 99);
|
|
$this->assertSame(99, $value);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider emptyProvider
|
|
*/
|
|
public function test_bool_uses_default_when_empty_value(?string $input): void
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_FOO', $input);
|
|
$value = Configuration::getBoolean('OTEL_FOO', true);
|
|
$this->assertTrue($value);
|
|
}
|
|
|
|
public function emptyProvider()
|
|
{
|
|
return [
|
|
'no value' => [null],
|
|
'empty string' => [''],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider booleanProvider
|
|
*/
|
|
public function test_bool_get(string $input, bool $default, bool $expected)
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_BOOL', $input);
|
|
$this->assertSame($expected, Configuration::getBoolean('OTEL_BOOL', $default));
|
|
}
|
|
|
|
public function booleanProvider()
|
|
{
|
|
return [
|
|
'false' => ['false', true, false],
|
|
'true' => ['true', false, true],
|
|
'TRUE' => ['TRUE', false, true],
|
|
'FALSE' => ['FALSE', true, false],
|
|
];
|
|
}
|
|
|
|
public function test_list_get()
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_LIST', 'a,b,c');
|
|
$this->assertSame(['a', 'b', 'c'], Configuration::getList('OTEL_LIST'));
|
|
}
|
|
|
|
public function test_map_get()
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_MAP', 'a=b,c=d');
|
|
$this->assertSame(['a'=>'b', 'c'=>'d'], Configuration::getMap('OTEL_MAP'));
|
|
}
|
|
|
|
public function test_enum_get()
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_ENUM', 'foo');
|
|
$this->assertSame('foo', Configuration::getEnum('OTEL_ENUM'));
|
|
}
|
|
|
|
public function test_ratio_get()
|
|
{
|
|
$this->setEnvironmentVariable('OTEL_RATIO', '0.5');
|
|
$this->assertSame(0.5, Configuration::getRatio('OTEL_RATIO'));
|
|
}
|
|
|
|
/**
|
|
* @dataProvider userEnvValueProvider
|
|
*/
|
|
public function test_return_user_env_vars(string $methodName, string $variable, string $value, $result)
|
|
{
|
|
$this->setEnvironmentVariable($variable, $value);
|
|
|
|
$this->assertSame(
|
|
$result,
|
|
call_user_func([Configuration::class, $methodName], $variable)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider userValueProvider
|
|
*/
|
|
public function test_return_user_default_value(string $methodName, string $variable, $defaultValue, $result)
|
|
{
|
|
$this->assertSame(
|
|
$result,
|
|
call_user_func([Configuration::class, $methodName], $variable, $defaultValue)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider libraryDefaultValueProvider
|
|
*/
|
|
public function test_return_library_default_value(string $methodName, string $variable, $result)
|
|
{
|
|
$this->assertSame(
|
|
$result,
|
|
call_user_func([Configuration::class, $methodName], $variable)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider nonEmptyMethodNameProvider
|
|
*/
|
|
public function test_no_value_throws_exception(string $methodName)
|
|
{
|
|
$this->expectException(UnexpectedValueException::class);
|
|
|
|
call_user_func([Configuration::class, $methodName], 'FOO_BAR_' . $methodName);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider invalidTypeProvider
|
|
*/
|
|
public function test_invalid_type_throws_exception(string $methodName, string $variable)
|
|
{
|
|
$this->expectException(UnexpectedValueException::class);
|
|
|
|
call_user_func([Configuration::class, $methodName], $variable);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider noDefaultProvider
|
|
*/
|
|
public function test_null_result_throws_exception(string $methodName, string $variable)
|
|
{
|
|
$this->expectException(UnexpectedValueException::class);
|
|
|
|
call_user_func([Configuration::class, $methodName], $variable);
|
|
}
|
|
|
|
public function userValueProvider(): Generator
|
|
{
|
|
foreach (self::USER_VALUES as $varType => $values) {
|
|
[$default, $result] = $values;
|
|
|
|
yield $varType => [
|
|
self::METHOD_NAMES[$varType][0],
|
|
self::TYPES[$varType][0],
|
|
$default,
|
|
$result,
|
|
];
|
|
}
|
|
}
|
|
|
|
public function userEnvValueProvider(): Generator
|
|
{
|
|
foreach (self::USER_ENV_VALUES as $varType => $values) {
|
|
[$default, $result] = $values;
|
|
|
|
yield $varType => [
|
|
self::METHOD_NAMES[$varType][0],
|
|
self::TYPES[$varType][0],
|
|
$default,
|
|
$result,
|
|
];
|
|
}
|
|
}
|
|
|
|
public function libraryDefaultValueProvider(): Generator
|
|
{
|
|
foreach (self::LIBRARY_DEFAULTS as $varType => $values) {
|
|
[$variable, $result] = $values;
|
|
|
|
yield $varType => [
|
|
self::METHOD_NAMES[$varType][0],
|
|
$variable,
|
|
$result,
|
|
];
|
|
}
|
|
}
|
|
|
|
public function nonEmptyMethodNameProvider(): Generator
|
|
{
|
|
foreach (self::METHOD_NAMES as $varType => $names) {
|
|
if (in_array($varType, self::ALLOW_EMPTY)) {
|
|
continue;
|
|
}
|
|
|
|
yield $varType => $names;
|
|
}
|
|
}
|
|
|
|
public function invalidTypeProvider(): Generator
|
|
{
|
|
foreach (self::METHOD_NAMES as $varType => $names) {
|
|
if ($varType === VariableTypes::MIXED) {
|
|
continue;
|
|
}
|
|
$methodName = $names[0];
|
|
foreach (self::TYPES as $methodType => $types) {
|
|
if ($varType === $methodType || $methodType === VariableTypes::MIXED) {
|
|
continue;
|
|
}
|
|
$variableName = $types[0];
|
|
|
|
yield sprintf('%s - %s', $varType, $methodType) => [$methodName, $variableName];
|
|
}
|
|
}
|
|
}
|
|
|
|
public function noDefaultProvider(): Generator
|
|
{
|
|
foreach (self::NO_DEFAULTS as $varType => $values) {
|
|
if (in_array($varType, self::ALLOW_EMPTY)) {
|
|
continue;
|
|
}
|
|
|
|
yield $varType => [self::METHOD_NAMES[$varType][0], $values[0]];
|
|
}
|
|
}
|
|
|
|
public function test_default_ratio_for_non_existent_variable(): void
|
|
{
|
|
$value = Configuration::getRatio('not-set', 0);
|
|
$this->assertSame(0.0, $value);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider knownValuesProvider
|
|
*/
|
|
public function test_get_known_values(string $varName, array $varValue): void
|
|
{
|
|
$this->assertSame(
|
|
$varValue,
|
|
Configuration::getKnownValues($varName)
|
|
);
|
|
}
|
|
|
|
public function knownValuesProvider(): array
|
|
{
|
|
return self::KNOWN_VALUES;
|
|
}
|
|
|
|
public function test_retrieve_value_library_default(): void
|
|
{
|
|
$value = 'simple';
|
|
$variable = Variables::OTEL_PHP_TRACES_PROCESSOR;
|
|
|
|
$this->assertFalse(
|
|
Configuration::has($variable)
|
|
);
|
|
|
|
$this->assertSame(
|
|
$value,
|
|
Configuration::getEnum($variable, $value)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider typeProvider
|
|
*/
|
|
public function test_get_type(string $varName, string $type): void
|
|
{
|
|
$this->assertSame(
|
|
$type,
|
|
Configuration::getType($varName)
|
|
);
|
|
}
|
|
|
|
public function typeProvider(): array
|
|
{
|
|
return [
|
|
'bool' => ['OTEL_EXPORTER_OTLP_INSECURE', VariableTypes::BOOL],
|
|
'string' => ['OTEL_SERVICE_NAME', VariableTypes::STRING],
|
|
'integer' => ['OTEL_BSP_MAX_QUEUE_SIZE', VariableTypes::INTEGER],
|
|
'enum' => ['OTEL_LOG_LEVEL', VariableTypes::ENUM],
|
|
'list' => ['OTEL_PROPAGATORS', VariableTypes::LIST],
|
|
'map' => ['OTEL_RESOURCE_ATTRIBUTES', VariableTypes::MAP],
|
|
'mixed' => ['OTEL_TRACES_SAMPLER_ARG', VariableTypes::MIXED],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider defaultValueProvider
|
|
*/
|
|
public function test_get_default_value_with_empty_var(string $varName, $varValue): void
|
|
{
|
|
$this->setEnvironmentVariable($varName, '');
|
|
|
|
$this->assertSame(
|
|
$varValue,
|
|
Configuration::getDefault($varName)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider defaultValueProvider
|
|
*/
|
|
public function test_get_default_value(string $varName, $varValue): void
|
|
{
|
|
$this->assertSame(
|
|
$varValue,
|
|
Configuration::getDefault($varName)
|
|
);
|
|
}
|
|
|
|
public function defaultValueProvider(): array
|
|
{
|
|
return self::DEFAULT_VALUES;
|
|
}
|
|
|
|
/**
|
|
* @dataProvider nonStringProvider
|
|
*/
|
|
public function test_get_non_string_value(string $method, $value): void
|
|
{
|
|
$_SERVER['OTEL_FOO'] = $value;
|
|
$this->assertTrue(Configuration::has('OTEL_FOO'));
|
|
$this->assertSame($value, call_user_func([Configuration::class, $method], 'OTEL_FOO'));
|
|
}
|
|
|
|
public function nonStringProvider(): array
|
|
{
|
|
return [
|
|
['getFloat', 3.14159],
|
|
['getInt', 22],
|
|
['getBoolean', true],
|
|
['getRatio', 0.44],
|
|
['getMixed', [25, 'green']],
|
|
['getList', ['foo', 'bar']],
|
|
['getMap', ['key1' => 'val1', 'key2' => 'val2']],
|
|
];
|
|
}
|
|
}
|