Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(agent): Drupal hook attribute instrumentation #1030

Open
wants to merge 16 commits into
base: dev
Choose a base branch
from

Conversation

bduranleau-nr
Copy link
Contributor

Adds support for Drupal Attribute Hooks added in Drupal 11.1.

@newrelic-php-agent-bot
Copy link

newrelic-php-agent-bot commented Feb 25, 2025

Test Suite Status Result
Multiverse 8/8 passing
SOAK 76/79 passing

@codecov-commenter
Copy link

codecov-commenter commented Feb 25, 2025

Codecov Report

Attention: Patch coverage is 90.90909% with 4 lines in your changes missing coverage. Please review.

Project coverage is 77.95%. Comparing base (8ddc8af) to head (2481b5b).
Report is 1 commits behind head on dev.

Files with missing lines Patch % Lines
agent/fw_drupal8.c 90.90% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #1030      +/-   ##
==========================================
+ Coverage   77.58%   77.95%   +0.37%     
==========================================
  Files         198      198              
  Lines       27715    27757      +42     
==========================================
+ Hits        21503    21639     +136     
+ Misses       6212     6118      -94     
Flag Coverage Δ
agent-for-php-7.2 77.97% <0.00%> (+0.24%) ⬆️
agent-for-php-7.3 77.98% <0.00%> (+0.24%) ⬆️
agent-for-php-7.4 77.85% <97.56%> (+0.39%) ⬆️
agent-for-php-8.0 77.24% <97.56%> (+0.39%) ⬆️
agent-for-php-8.1 77.74% <97.56%> (+0.39%) ⬆️
agent-for-php-8.2 77.35% <97.56%> (+0.39%) ⬆️
agent-for-php-8.3 77.35% <97.56%> (?)
agent-for-php-8.4 77.36% <97.56%> (+0.39%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

hook_attribute_instrumentation
= nr_drupal_hook_attribute_instrument(*retval_ptr);

if (!hook_attribute_instrumentation) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nr_drupal_hook_attribute_instrument will only return true if it's able to walk the entire hookImplementationsMap. What will happen if it fails mid way? Which hook instrumentation will be used? Does nr_drupal_hook_attribute_instrument cleanup its partial work if it fails to walk the entire hookImplementationsMap? Could you add a test for this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If walking the map fails halfway through, we exit the function and return false. The wraprecs that are already created remain, and we revert back to the old method of wrapping hooks.

Which hook instrumentation will be used?

The answer would be "both". The attribute based instrumentation would persist for anything it managed to wrap, and the other methods act as a fallback to hopefully plug the gaps. I don't see anticipate any negative side-effects from this, do you?

Could you add a test for this case?

This would be difficult and doesn't fit neatly into our established test paradigms, The dependency here is a lot of Drupal code, from Drupal::moduleHandler to the hookImplementationsMap. Is there a specific concern you have with this failing partway though walking the map?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given #1030 (comment), I would feel more comfortable having a test with mocked implementation of Drupal\Core\Extension\ModuleHandlerInterface that has corrupted hookImplementationsMap property in every possible way - invalid type of the property (not an array), first level has invalid key and value, second level has invalid key and value, third level has invalid key and value.

Copy link
Member

@lavarou lavarou Feb 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look here and here for inspiration how to mock implementation of Drupal\Core\Extension\ModuleHandlerInterface and use it in integration test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each example of a "bad" hookImplementationsMap would require it's own unique instance and definition of the ModuleHandler interface class, and all we'd really be testing is that the agent doesn't blow up. There isn't a return value we'd be able to check. I don't think it's appropriate to test this here- that's what our SOAK + valgrind and Multiverse tests are for.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each example of a "bad" hookImplementationsMap would require it's own unique instance and definition of the ModuleHandler interface class, and all we'd really be testing is that the agent doesn't blow up.

That is exactly right - these are corner cases that need to be covered by the tests! None of the tests you mention cover any of these corner case scenarios.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree that those tests are necessary. Every value here is checked before it's used. If the hook_implementation_map isn't an array, the function will return false. If the hook_key is NULL or the hook_val is not a valid array, the function will return false. If class_key is NULL or class_val is not a valid array, the function will return false. If method_key is NULL or module_val is not a valid string, the function will return false. Every nr_php_string_hash_key_t variable is guaranteed by ZEND_HASH_FOREACH_STR_KEY_VAL to be a zend_string. We've checked every single value we intend to use at every step in the process before we attempt to use it.

Mocking Drupal tests gives us a false view of the state of agent support. We already know that our mocked Drupal tests for page_cache are objectively wrong, but it doesn't trigger any errors. Even if done correctly, we open ourselves up to bitrot and the risks of using stale mocked framework code to verify our instrumentation.

If you would really like these tests incorporated, I'll add them. I'm just not seeing the value at this moment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests: 5a90282

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good. Could you add one positive test case to show what the agent expects hookImplementationsMap to look like? It will be easier to look at this mocked example than try to reconstruct it based on the C code or digging through Drupal's codebase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants