['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']], ]; } }