Skip to content

Commit

Permalink
fix: Web Tests Errors Detection (#2666)
Browse files Browse the repository at this point in the history
* fix: Web Tests Errors Detection

* fix: Laravel ReflectionException (see notes)

Happens when the .env file is missing

* fix: Don't override env if set

* fix: Undefined function `wp_get_active_and_valid_themes`

* fix: Check `.env` file existence before bootstrap

* Remove log import

* fix: Check name, error, resource, and service names

* fix: Replace `home/circleci/app` by `/home/circleci/app`

* fix: Remove non-existing error checks

* feat: Allow SpanAssertion::NOT_TESTED errors

* fix: Symfony error tests

* fix: OTel Interoperability Service Propagation

* tests: Update ES tests
  • Loading branch information
PROFeNoM committed May 27, 2024
1 parent 47fd05a commit a40f7af
Show file tree
Hide file tree
Showing 45 changed files with 5,206 additions and 1,283 deletions.
10 changes: 7 additions & 3 deletions src/DDTrace/Integrations/Laravel/LaravelIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function (SpanData $span, $args, $response) use ($integration) {
'bootstrapWith',
function ($app) use ($integration) {
$integration->serviceName = ddtrace_config_app_name();
if (empty($integration->serviceName)) {
if (empty($integration->serviceName) && file_exists($app->environmentPath() . '/' . $app->environmentFile())) {
$app->make('Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables')->bootstrap($app);
$configPath = realpath($app->configPath());
if (file_exists($configPath . '/app.php')) {
Expand Down Expand Up @@ -468,8 +468,12 @@ public function getServiceName()
return $this->serviceName;
}
$this->serviceName = \ddtrace_config_app_name();
if (empty($this->serviceName) && is_callable('config')) {
$this->serviceName = config('app.name');
try {
if (empty($this->serviceName) && is_callable('config')) {
$this->serviceName = config('app.name');
}
} catch (\Throwable $e) {
return 'laravel';
}
return $this->serviceName ?: 'laravel';
}
Expand Down
46 changes: 28 additions & 18 deletions src/DDTrace/Integrations/WordPress/WordPressIntegrationLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -235,25 +235,35 @@ function (HookData $hook) use ($integration) {


hook_function('wp_templating_constants', null, function () use ($integration) {
foreach (wp_get_active_and_valid_themes() as $theme) {
if (file_exists($theme . '/functions.php')) {
install_hook(
$theme . '/functions.php',
function (HookData $hook) use ($integration, $theme) {
$span = $hook->span();
$themeName = explode('/', $theme);
$themeName = ucfirst(end($themeName));
WordPressIntegrationLoader::setCommonTags(
$integration,
$span,
'load_theme',
"$themeName (theme)"
);
$span->meta['wordpress.theme'] = $themeName;
global $wp_theme_directories;
if (empty($wp_theme_directories)) {
return;
}
$wp_theme_directories = (array) $wp_theme_directories;
foreach ($wp_theme_directories as $themeRoot) {
$dirs = scandir($themeRoot);
foreach ($dirs as $dir) {
if ($dir === '.' || $dir === '..' || $dir == 'index.php') {
continue;
}
if (file_exists($themeRoot . '/' . $dir . '/functions.php')) {
install_hook(
$themeRoot . '/' . $dir . '/functions.php',
function (HookData $hook) use ($integration, $themeRoot, $dir) {
$span = $hook->span();
$themeName = ucfirst($dir);
WordPressIntegrationLoader::setCommonTags(
$integration,
$span,
'load_theme',
"$themeName (theme)"
);
$span->meta['wordpress.theme'] = $themeName;

remove_hook($hook->id);
}
);
remove_hook($hook->id);
}
);
}
}
}
});
Expand Down
2 changes: 2 additions & 0 deletions src/DDTrace/OpenTelemetry/Span.php
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ private static function _setAttribute(SpanData $span, string $key, $value): void
|| \is_int($value)
|| (\is_array($value) && \count($value) > 0 && \is_numeric($value[0]))) { // Note: Assumes attribute with primitive, homogeneous array values
$span->metrics[$key] = $value;
} elseif ($key === 'service.name') {
$span->service = $value;
} else {
$span->meta[$key] = $value;
}
Expand Down
26 changes: 21 additions & 5 deletions tests/Common/SpanAssertion.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ final class SpanAssertion

/**
* @param string $name
* @param bool $error
* @param bool|string $error
* @param bool $onlyCheckExistance
*/
private function __construct($name, $error, $onlyCheckExistance)
Expand All @@ -47,12 +47,28 @@ private function __construct($name, $error, $onlyCheckExistance)
/**
* @param string $name
* @param null|string $resource
* @param bool $error
* @param bool|string $error
* @param null|string $service
* @return SpanAssertion
*/
public static function exists($name, $resource = null, $error = false, $service = null)
{
public static function exists(
$name,
$resource = SpanAssertion::NOT_TESTED,
$error = SpanAssertion::NOT_TESTED,
$service = SpanAssertion::NOT_TESTED
){
if ($error === null) {
$error = false;
}

if ($resource === null) {
$resource = SpanAssertion::NOT_TESTED;
}

if ($error === null) { // false is a valid value, we don't convert it
$error = SpanAssertion::NOT_TESTED;
}

return SpanAssertion::forOperation($name, $error, true)
->resource($resource)
->service($service);
Expand Down Expand Up @@ -90,7 +106,7 @@ public static function build(

/**
* @param string $name
* @param bool $error
* @param bool|string $error
* @param bool $onlyCheckExistence
* @return SpanAssertion
*/
Expand Down
64 changes: 36 additions & 28 deletions tests/Common/SpanChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ private function assertNode(

private function findOne(array $graph, SpanAssertion $expectedNodeRoot, $parentName, $parenResource)
{
if ($expectedNodeRoot->getResource()) {
$expectedNodeRootResource = $expectedNodeRoot->getResource();
if ($expectedNodeRootResource && $expectedNodeRootResource !== SpanAssertion::NOT_TESTED) {
// If the resource is specified, then we use it
$found = array_values(array_filter($graph, function (array $node) use ($expectedNodeRoot) {
return empty($node['__visited'])
Expand Down Expand Up @@ -264,14 +265,14 @@ private function exactWildcardsMatches($expected, $actual)
$normalizedExpected = $expected;
$normalizedActual = $actual;

if (substr($normalizedExpected, -1) === '*') {
if (substr($normalizedExpected ?? '', -1) === '*') {
// Ends with *
$length = strlen($normalizedExpected) - 1;
$normalizedExpected = substr($normalizedExpected, 0, $length);
$normalizedActual = substr($normalizedActual, 0, $length);
}

if (substr($normalizedExpected, 0, 1) === '*') {
if (substr($normalizedExpected ?? '', 0, 1) === '*') {
// Starts with *
$length = strlen($normalizedExpected) - 1;
$normalizedExpected = substr($normalizedExpected, -$length);
Expand Down Expand Up @@ -418,20 +419,43 @@ public function assertSpan($span, SpanAssertion $exp)
TestCase::assertGreaterThan(0, $span['duration']);
}

if ($exp->isOnlyCheckExistence()) {
return;
}

TestCase::assertSame(
$exp->getOperationName(),
isset($span['name']) ? $span['name'] : '',
$namePrefix . "Wrong value for 'operation name': " . print_r($span, true)
);
TestCase::assertSame(
$exp->hasError(),
isset($span['error']) && 1 === $span['error'],
$namePrefix . "Wrong value for 'error': " . print_r($span, true)
);
if ($exp->hasError() !== SpanAssertion::NOT_TESTED) {
TestCase::assertSame(
$exp->hasError(),
isset($span['error']) && 1 === $span['error'],
$namePrefix . "Wrong value for 'error': " . print_r($span, true)
);
}
if ($exp->getService() !== SpanAssertion::NOT_TESTED) {
TestCase::assertSame(
$exp->getService(),
isset($span['service']) ? $span['service'] : '',
$namePrefix . "Wrong value for 'service' " . print_r($span, true)
);
}
if ($exp->getResource() !== SpanAssertion::NOT_TESTED) {
$expectedResource = $exp->getResource();
$actualResource = isset($span['resource']) ? $span['resource'] : '';
TestCase::assertTrue(
$this->exactWildcardsMatches($expectedResource, $actualResource),
$namePrefix . "Wrong value for 'resource'. Exp: '$expectedResource' - Act: '$actualResource' "
. print_r($span, true)
);
}

foreach ($exp->getExistingTagNames(true) as $key) {
TestCase::assertArrayHasKey($key, $spanMeta);
}

if ($exp->isOnlyCheckExistence()) {
return;
}

if ($exp->getExactTags() !== SpanAssertion::NOT_TESTED) {
$filtered = [];
foreach ($spanMeta as $key => $value) {
Expand Down Expand Up @@ -522,29 +546,13 @@ function ($key) use ($pattern) {
$namePrefix . "Wrong value for 'metrics' " . print_r($span, true)
);
}
if ($exp->getService() != SpanAssertion::NOT_TESTED) {
TestCase::assertSame(
$exp->getService(),
isset($span['service']) ? $span['service'] : '',
$namePrefix . "Wrong value for 'service' " . print_r($span, true)
);
}
if ($exp->getType() != SpanAssertion::NOT_TESTED) {
TestCase::assertSame(
$exp->getType(),
isset($span['type']) ? $span['type'] : '',
$namePrefix . "Wrong value for 'type' " . print_r($span, true)
);
}
if ($exp->getResource() != SpanAssertion::NOT_TESTED) {
$expectedResource = $exp->getResource();
$actualResource = isset($span['resource']) ? $span['resource'] : '';
TestCase::assertTrue(
$this->exactWildcardsMatches($expectedResource, $actualResource),
$namePrefix . "Wrong value for 'resource'. Exp: '$expectedResource' - Act: '$actualResource' "
. print_r($span, true)
);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,8 @@ public function testScroll()
],
]);
$traces = $this->isolateTracer(function () use ($client, $docs) {
$root = \DDTrace\start_trace_span();
$root->name = "root";
// Now we loop until the scroll "cursors" are exhausted
$scroll_id = $docs['_scroll_id'];
while (\true) {
Expand All @@ -412,31 +414,40 @@ public function testScroll()
break;
}
}
\DDTrace\close_span();
});

$this->assertSpans($traces, [
SpanAssertion::exists('Elasticsearch.Serializers.SmartSerializer.deserialize'),
SpanAssertion::exists('Elasticsearch.Endpoint.performRequest'),
SpanAssertion::build(
'Elasticsearch.Client.scroll',
'elasticsearch',
'elasticsearch',
'scroll'
)->withExactTags([
Tag::SPAN_KIND => 'client',
Tag::COMPONENT => 'elasticsearch'
]),
SpanAssertion::exists('Elasticsearch.Serializers.SmartSerializer.deserialize'),
SpanAssertion::exists('Elasticsearch.Endpoint.performRequest'),
SpanAssertion::build(
'Elasticsearch.Client.scroll',
'elasticsearch',
'elasticsearch',
'scroll'
)->withExactTags([
Tag::SPAN_KIND => 'client',
Tag::COMPONENT => 'elasticsearch'
]),
$this->assertFlameGraph($traces, [
SpanAssertion::exists('root')->withChildren([
SpanAssertion::build(
'Elasticsearch.Client.scroll',
'elasticsearch',
'elasticsearch',
'scroll'
)->withExactTags([
Tag::SPAN_KIND => 'client',
Tag::COMPONENT => 'elasticsearch',
'_dd.base_service' => 'phpunit',
])->withChildren([
SpanAssertion::exists('Elasticsearch.Endpoint.performRequest')->withChildren([
SpanAssertion::exists('Elasticsearch.Serializers.SmartSerializer.deserialize'),
]),
]),
SpanAssertion::build(
'Elasticsearch.Client.scroll',
'elasticsearch',
'elasticsearch',
'scroll'
)->withExactTags([
Tag::SPAN_KIND => 'client',
Tag::COMPONENT => 'elasticsearch',
'_dd.base_service' => 'phpunit',
])->withChildren([
SpanAssertion::exists('Elasticsearch.Endpoint.performRequest')->withChildren([
SpanAssertion::exists('Elasticsearch.Serializers.SmartSerializer.deserialize'),
]),
]),
])
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,8 @@ public function testScroll()
],
]);
$traces = $this->isolateTracer(function () use ($client, $docs) {
$root = \DDTrace\start_trace_span();
$root->name = "root";
// Now we loop until the scroll "cursors" are exhausted
$scroll_id = $docs['_scroll_id'];
while (\true) {
Expand All @@ -388,34 +390,44 @@ public function testScroll()
break;
}
}
\DDTrace\close_span();
});

$this->assertSpans($traces, [
SpanAssertion::exists('Elastic.Transport.Serializer.JsonSerializer.unserialize', 'Elastic.Transport.Serializer.JsonSerializer.unserialize'),
SpanAssertion::exists('Psr\Http\Client\ClientInterface.sendRequest', 'sendRequest'),
SpanAssertion::exists('Elasticsearch.Endpoint.performRequest'),
SpanAssertion::build(
'Elasticsearch.Client.scroll',
'elasticsearch',
'elasticsearch',
'scroll'
)->withExactTags([
Tag::SPAN_KIND => 'client',
Tag::COMPONENT => 'elasticsearch'
]),
SpanAssertion::exists('Elastic.Transport.Serializer.JsonSerializer.unserialize', 'Elastic.Transport.Serializer.JsonSerializer.unserialize'),
SpanAssertion::exists('Psr\Http\Client\ClientInterface.sendRequest', 'sendRequest'),
SpanAssertion::exists('Elasticsearch.Endpoint.performRequest'),
SpanAssertion::build(
'Elasticsearch.Client.scroll',
'elasticsearch',
'elasticsearch',
'scroll'
)->withExactTags([
Tag::SPAN_KIND => 'client',
Tag::COMPONENT => 'elasticsearch'
]),
SpanAssertion::exists('Elastic.Transport.Serializer.JsonSerializer.unserialize', 'Elastic.Transport.Serializer.JsonSerializer.unserialize'),

$this->assertFlameGraph($traces, [
SpanAssertion::exists('root')->withChildren([
SpanAssertion::exists('Elastic.Transport.Serializer.JsonSerializer.unserialize', 'Elastic.Transport.Serializer.JsonSerializer.unserialize'),
SpanAssertion::exists('Elastic.Transport.Serializer.JsonSerializer.unserialize', 'Elastic.Transport.Serializer.JsonSerializer.unserialize'),
SpanAssertion::exists('Elastic.Transport.Serializer.JsonSerializer.unserialize', 'Elastic.Transport.Serializer.JsonSerializer.unserialize'),
SpanAssertion::build(
'Elasticsearch.Client.scroll',
'elasticsearch',
'elasticsearch',
'scroll'
)->withExactTags([
Tag::SPAN_KIND => 'client',
Tag::COMPONENT => 'elasticsearch',
'_dd.base_service' => 'phpunit',
])->withChildren([
SpanAssertion::exists('Elasticsearch.Endpoint.performRequest')->withChildren([
SpanAssertion::exists('Psr\Http\Client\ClientInterface.sendRequest', 'sendRequest'),
]),
]),
SpanAssertion::build(
'Elasticsearch.Client.scroll',
'elasticsearch',
'elasticsearch',
'scroll'
)->withExactTags([
Tag::SPAN_KIND => 'client',
Tag::COMPONENT => 'elasticsearch',
'_dd.base_service' => 'phpunit',
])->withChildren([
SpanAssertion::exists('Elasticsearch.Endpoint.performRequest')->withChildren([
SpanAssertion::exists('Psr\Http\Client\ClientInterface.sendRequest', 'sendRequest'),
]),
])
])
]);
}

Expand Down
Loading

0 comments on commit a40f7af

Please sign in to comment.