377 lines
13 KiB
PHP
377 lines
13 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace OpenTelemetry\Tests\Unit\API\Trace\Propagation;
|
|
|
|
use OpenTelemetry\API\Common\Log\LoggerHolder;
|
|
use OpenTelemetry\API\Trace\Propagation\TraceContextPropagator;
|
|
use OpenTelemetry\API\Trace\SpanContext;
|
|
use OpenTelemetry\API\Trace\SpanContextInterface;
|
|
use OpenTelemetry\API\Trace\SpanContextValidator;
|
|
use OpenTelemetry\API\Trace\TraceState;
|
|
use OpenTelemetry\API\Trace\TraceStateInterface;
|
|
use OpenTelemetry\Context\Context;
|
|
use OpenTelemetry\Context\ContextInterface;
|
|
use OpenTelemetry\SDK\Trace\Span;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\NullLogger;
|
|
|
|
/**
|
|
* @covers \OpenTelemetry\API\Trace\Propagation\TraceContextPropagator
|
|
*/
|
|
class TraceContextPropagatorTest extends TestCase
|
|
{
|
|
private const TRACE_ID_BASE16 = 'ff000000000000000000000000000041';
|
|
private const SPAN_ID_BASE16 = 'ff00000000000041';
|
|
private const TRACEPARENT_HEADER_SAMPLED = '00-' . self::TRACE_ID_BASE16 . '-' . self::SPAN_ID_BASE16 . '-01';
|
|
private const TRACEPARENT_HEADER_NOT_SAMPLED = '00-' . self::TRACE_ID_BASE16 . '-' . self::SPAN_ID_BASE16 . '-00';
|
|
private const TRACESTATE_NOT_DEFAULT_ENCODING = 'bar=baz,foo=bar';
|
|
private const TRACESTATE_NOT_DEFAULT_ENCODING_WITH_SPACES = 'bar=baz , foo=bar';
|
|
|
|
private TraceContextPropagator $traceContextPropagator;
|
|
private TraceStateInterface $traceState;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
LoggerHolder::set(new NullLogger());
|
|
$this->traceContextPropagator = TraceContextPropagator::getInstance();
|
|
$this->traceState = (new TraceState())->with('bar', 'baz')->with('foo', 'bar');
|
|
}
|
|
|
|
public function test_fields(): void
|
|
{
|
|
$this->assertSame(
|
|
['traceparent', 'tracestate'],
|
|
$this->traceContextPropagator->fields()
|
|
);
|
|
}
|
|
|
|
public function test_inject_empty(): void
|
|
{
|
|
$carrier = [];
|
|
$this->traceContextPropagator->inject($carrier);
|
|
$this->assertEmpty($carrier);
|
|
}
|
|
|
|
public function test_inject_invalid_context(): void
|
|
{
|
|
$carrier = [];
|
|
$this
|
|
->traceContextPropagator
|
|
->inject(
|
|
$carrier,
|
|
null,
|
|
$this->withSpanContext(
|
|
SpanContext::create(
|
|
SpanContextValidator::INVALID_TRACE,
|
|
SpanContextValidator::INVALID_SPAN,
|
|
SpanContextInterface::TRACE_FLAG_SAMPLED
|
|
),
|
|
Context::getCurrent()
|
|
)
|
|
);
|
|
$this->assertEmpty($carrier);
|
|
}
|
|
|
|
public function test_inject_sampled_context(): void
|
|
{
|
|
$carrier = [];
|
|
$this
|
|
->traceContextPropagator
|
|
->inject(
|
|
$carrier,
|
|
null,
|
|
$this->withSpanContext(
|
|
SpanContext::create(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16, SpanContextInterface::TRACE_FLAG_SAMPLED),
|
|
Context::getCurrent()
|
|
)
|
|
);
|
|
|
|
$this->assertSame(
|
|
[TraceContextPropagator::TRACEPARENT => self::TRACEPARENT_HEADER_SAMPLED],
|
|
$carrier
|
|
);
|
|
}
|
|
|
|
public function test_inject_sampled_context_with_trace_state(): void
|
|
{
|
|
$carrier = [];
|
|
$this
|
|
->traceContextPropagator
|
|
->inject(
|
|
$carrier,
|
|
null,
|
|
$this->withSpanContext(
|
|
SpanContext::create(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16, SpanContextInterface::TRACE_FLAG_SAMPLED, $this->traceState),
|
|
Context::getCurrent()
|
|
)
|
|
);
|
|
|
|
$this->assertSame(
|
|
[
|
|
TraceContextPropagator::TRACEPARENT => self::TRACEPARENT_HEADER_SAMPLED,
|
|
TraceContextPropagator::TRACESTATE => 'foo=bar,bar=baz',
|
|
],
|
|
$carrier
|
|
);
|
|
}
|
|
|
|
public function test_inject_non_sampled_context(): void
|
|
{
|
|
$carrier = [];
|
|
$this
|
|
->traceContextPropagator
|
|
->inject(
|
|
$carrier,
|
|
null,
|
|
$this->withSpanContext(
|
|
SpanContext::create(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16),
|
|
Context::getCurrent()
|
|
)
|
|
);
|
|
|
|
$this->assertSame(
|
|
[TraceContextPropagator::TRACEPARENT => self::TRACEPARENT_HEADER_NOT_SAMPLED],
|
|
$carrier
|
|
);
|
|
}
|
|
|
|
public function test_inject_non_sampled_context_with_trace_state(): void
|
|
{
|
|
$carrier = [];
|
|
$this
|
|
->traceContextPropagator
|
|
->inject(
|
|
$carrier,
|
|
null,
|
|
$this->withSpanContext(
|
|
SpanContext::create(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16, SpanContextInterface::TRACE_FLAG_DEFAULT, $this->traceState),
|
|
Context::getCurrent()
|
|
)
|
|
);
|
|
|
|
$this->assertSame(
|
|
[
|
|
TraceContextPropagator::TRACEPARENT => self::TRACEPARENT_HEADER_NOT_SAMPLED,
|
|
TraceContextPropagator::TRACESTATE => 'foo=bar,bar=baz',
|
|
],
|
|
$carrier
|
|
);
|
|
}
|
|
|
|
public function test_extract_nothing(): void
|
|
{
|
|
$this->assertSame(
|
|
Context::getCurrent(),
|
|
$this->traceContextPropagator->extract([])
|
|
);
|
|
}
|
|
|
|
public function test_extract_sampled_context(): void
|
|
{
|
|
$carrier = [
|
|
TraceContextPropagator::TRACEPARENT => self::TRACEPARENT_HEADER_SAMPLED,
|
|
];
|
|
|
|
$this->assertEquals(
|
|
SpanContext::createFromRemoteParent(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16, SpanContextInterface::TRACE_FLAG_SAMPLED),
|
|
$this->getSpanContext($this->traceContextPropagator->extract($carrier))
|
|
);
|
|
}
|
|
|
|
public function test_extract_sampled_context_with_trace_state(): void
|
|
{
|
|
$carrier = [
|
|
TraceContextPropagator::TRACEPARENT => self::TRACEPARENT_HEADER_SAMPLED,
|
|
TraceContextPropagator::TRACESTATE => self::TRACESTATE_NOT_DEFAULT_ENCODING,
|
|
];
|
|
|
|
$this->assertEquals(
|
|
SpanContext::createFromRemoteParent(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16, SpanContextInterface::TRACE_FLAG_SAMPLED, $this->traceState),
|
|
$this->getSpanContext($this->traceContextPropagator->extract($carrier))
|
|
);
|
|
}
|
|
|
|
public function test_extract_non_sampled_context(): void
|
|
{
|
|
$carrier = [
|
|
TraceContextPropagator::TRACEPARENT => self::TRACEPARENT_HEADER_NOT_SAMPLED,
|
|
];
|
|
|
|
$this->assertEquals(
|
|
SpanContext::createFromRemoteParent(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16),
|
|
$this->getSpanContext($this->traceContextPropagator->extract($carrier))
|
|
);
|
|
}
|
|
|
|
public function test_extract_non_sampled_context_with_trace_state(): void
|
|
{
|
|
$carrier = [
|
|
TraceContextPropagator::TRACEPARENT => self::TRACEPARENT_HEADER_NOT_SAMPLED,
|
|
TraceContextPropagator::TRACESTATE => self::TRACESTATE_NOT_DEFAULT_ENCODING,
|
|
];
|
|
|
|
$this->assertEquals(
|
|
SpanContext::createFromRemoteParent(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16, SpanContextInterface::TRACE_FLAG_DEFAULT, $this->traceState),
|
|
$this->getSpanContext($this->traceContextPropagator->extract($carrier))
|
|
);
|
|
}
|
|
|
|
public function test_extract_and_inject(): void
|
|
{
|
|
$traceParent = '00-' . self::TRACE_ID_BASE16 . '-' . self::SPAN_ID_BASE16 . '-01';
|
|
$extractCarrier = [
|
|
TraceContextPropagator::TRACEPARENT => $traceParent,
|
|
];
|
|
$context = $this->traceContextPropagator->extract($extractCarrier);
|
|
$injectCarrier = [];
|
|
$this->traceContextPropagator->inject($injectCarrier, null, $context);
|
|
$this->assertSame($injectCarrier, $extractCarrier);
|
|
}
|
|
|
|
public function test_extract_trace_state_with_spaces(): void
|
|
{
|
|
$carrier = [
|
|
TraceContextPropagator::TRACEPARENT => self::TRACEPARENT_HEADER_NOT_SAMPLED,
|
|
TraceContextPropagator::TRACESTATE => self::TRACESTATE_NOT_DEFAULT_ENCODING_WITH_SPACES,
|
|
];
|
|
|
|
$this->assertEquals(
|
|
SpanContext::createFromRemoteParent(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16, SpanContextInterface::TRACE_FLAG_DEFAULT, $this->traceState),
|
|
$this->getSpanContext($this->traceContextPropagator->extract($carrier))
|
|
);
|
|
}
|
|
|
|
public function test_extract_empty_trace_state(): void
|
|
{
|
|
$carrier = [
|
|
TraceContextPropagator::TRACEPARENT => self::TRACEPARENT_HEADER_NOT_SAMPLED,
|
|
TraceContextPropagator::TRACESTATE => '',
|
|
];
|
|
|
|
$this->assertEquals(
|
|
SpanContext::createFromRemoteParent(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16, SpanContextInterface::TRACE_FLAG_DEFAULT, new TraceState()),
|
|
$this->getSpanContext($this->traceContextPropagator->extract($carrier))
|
|
);
|
|
}
|
|
|
|
public function test_extract_empty_header(): void
|
|
{
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => '',
|
|
]);
|
|
}
|
|
|
|
public function test_extract_future_version(): void
|
|
{
|
|
$carrierFuture = [
|
|
TraceContextPropagator::TRACEPARENT => 'aa-' . self::TRACE_ID_BASE16 . '-' . self::SPAN_ID_BASE16 . '-' . '00',
|
|
TraceContextPropagator::TRACESTATE => self::TRACESTATE_NOT_DEFAULT_ENCODING,
|
|
];
|
|
|
|
// Tolerant of future versions with same parts.
|
|
$this->assertEquals(
|
|
SpanContext::createFromRemoteParent(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16, SpanContextInterface::TRACE_FLAG_DEFAULT, $this->traceState),
|
|
$this->getSpanContext($this->traceContextPropagator->extract($carrierFuture)),
|
|
);
|
|
|
|
$carrierFutureMoreParts = [
|
|
TraceContextPropagator::TRACEPARENT => 'af-' . self::TRACE_ID_BASE16 . '-' . self::SPAN_ID_BASE16 . '-' . '00' . '-000-this-is-the-future',
|
|
TraceContextPropagator::TRACESTATE => self::TRACESTATE_NOT_DEFAULT_ENCODING,
|
|
];
|
|
|
|
// Tolerant of future versions with more parts.
|
|
$this->assertEquals(
|
|
SpanContext::createFromRemoteParent(self::TRACE_ID_BASE16, self::SPAN_ID_BASE16, SpanContextInterface::TRACE_FLAG_DEFAULT, $this->traceState),
|
|
$this->getSpanContext($this->traceContextPropagator->extract($carrierFutureMoreParts)),
|
|
);
|
|
}
|
|
|
|
public function test_invalid_traceparent_version_0xff(): void
|
|
{
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => 'ff-' . self::TRACE_ID_BASE16 . '-' . self::SPAN_ID_BASE16 . '-' . '00',
|
|
]);
|
|
}
|
|
|
|
public function test_invalid_traceparent_version(): void
|
|
{
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => 'aaa-' . self::TRACE_ID_BASE16 . '-' . self::SPAN_ID_BASE16 . '-' . '00',
|
|
]);
|
|
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => 'gx-' . self::TRACE_ID_BASE16 . '-' . self::SPAN_ID_BASE16 . '-' . '00',
|
|
]);
|
|
}
|
|
|
|
public function test_invalid_trace_format(): void
|
|
{
|
|
// More than 4 parts to the trace but not a future version.
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => '00-' . self::TRACE_ID_BASE16 . '-' . self::SPAN_ID_BASE16 . '-' . '00' . '-000-this-is-not-the-future',
|
|
]);
|
|
}
|
|
|
|
public function test_empty_trace_id(): void
|
|
{
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => '00--' . self::SPAN_ID_BASE16 . '-01',
|
|
]);
|
|
}
|
|
|
|
public function test_invalid_trace_id(): void
|
|
{
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => '00-abcdefghijklmnopabcdefghijklmnop-' . self::SPAN_ID_BASE16 . '-01',
|
|
]);
|
|
}
|
|
|
|
public function test_invalid_trace_id_size(): void
|
|
{
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => '00-' . self::TRACE_ID_BASE16 . '00-' . self::SPAN_ID_BASE16 . '-01',
|
|
]);
|
|
}
|
|
|
|
public function test_empty_span_id(): void
|
|
{
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => '00-' . self::TRACE_ID_BASE16 . '--01',
|
|
]);
|
|
}
|
|
|
|
public function test_invalid_span_id(): void
|
|
{
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => '00-' . self::TRACE_ID_BASE16 . '-abcdefghijklmnop-01',
|
|
]);
|
|
}
|
|
|
|
public function test_invalid_span_id_size(): void
|
|
{
|
|
$this->assertInvalid([
|
|
TraceContextPropagator::TRACEPARENT => '00-' . self::TRACE_ID_BASE16 . '-' . self::SPAN_ID_BASE16 . '00-01',
|
|
]);
|
|
}
|
|
|
|
private function assertInvalid(array $carrier): void
|
|
{
|
|
$this->assertSame(
|
|
Context::getCurrent(),
|
|
$this->traceContextPropagator->extract($carrier),
|
|
);
|
|
}
|
|
|
|
private function getSpanContext(ContextInterface $context): SpanContextInterface
|
|
{
|
|
return Span::fromContext($context)->getContext();
|
|
}
|
|
|
|
private function withSpanContext(SpanContextInterface $spanContext, ContextInterface $context): ContextInterface
|
|
{
|
|
return $context->withContextValue(Span::wrap($spanContext));
|
|
}
|
|
}
|