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

Fixed before and after class methods also called from primary process when test class or method is run in separated process. #6041

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

akotulu
Copy link

@akotulu akotulu commented Nov 19, 2024

Our project uses heavily define constants in multiple sub modules and integration tests are ran inside separated test class process using RunClassInSeparateProcess attribute. Every TestCase sets its own defines (constants) in setUpBeforeClass, but PHPUnit calls the function on every registered TestCase from primary process thus failing to initialize sub module resources after first call, and primary test process receives an exception (e.g. invalid path).

// Define application path
define('APPLICATION_PATH', realpath(PROJECT_APPLICATION_PATH . '/module/xxx'));
// Define assets' path
define('ASSETS_DIR', realpath(__DIR__ . '/../assets'));
// Define server name
define('SERVER_NAME', 'xxx.abc.ee');
// Boot
include __DIR__ . '/../../../boot.php';

Before and after class methods must not be called at all from primary process if the tests are ran inside separated process (sandbox).

Also there is a issue with the src/Framework/TestRunner/templates/class.tpl. Idk if the parameter RunClassInSeparateProcess isn't properly implemented, but the template is for sure invalid when set and setUpBeforeClass is called for every test defined in TestCase.

… when test class or method is run in separated process.
@sebastianbergmann sebastianbergmann added type/bug Something is broken feature/test-runner CLI test runner feature/process-isolation Issues related to running tests in separate PHP processes labels Nov 19, 2024
@sebastianbergmann
Copy link
Owner

Also there is a issue with the src/Framework/TestRunner/templates/class.tpl. Idk if the parameter RunClassInSeparateProcess isn't properly implemented, but the template is for sure invalid when set and setUpBeforeClass is called for every test defined in TestCase.

That would be #5230.

@sebastianbergmann
Copy link
Owner

Please target the 10.5 branch as this is the oldest branch that still receives bug fixes. And please add at least one test case that fails without the proposed changes but passes with them. Thank you!

@akotulu
Copy link
Author

akotulu commented Nov 19, 2024

I've added a test and fixed after class being called twice. How do I target this branch? Checked out only master.

Copy link

codecov bot commented Nov 19, 2024

Codecov Report

Attention: Patch coverage is 86.17021% with 13 lines in your changes missing coverage. Please review.

Project coverage is 94.69%. Comparing base (0fde984) to head (2fdaf3d).
Report is 45 commits behind head on main.

Files with missing lines Patch % Lines
src/Framework/TestSuite.php 87.50% 10 Missing ⚠️
...Framework/TestRunner/SeparateProcessTestRunner.php 78.57% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##               main    #6041   +/-   ##
=========================================
  Coverage     94.69%   94.69%           
- Complexity     6456     6463    +7     
=========================================
  Files           697      697           
  Lines         20307    20311    +4     
=========================================
+ Hits          19229    19234    +5     
+ Misses         1078     1077    -1     

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


//#[RunTestsInSeparateProcesses]
#[RunClassInSeparateProcess]
final class BeforeAndAfterClassMethodCallCountTest extends TestCase
Copy link
Contributor

Choose a reason for hiding this comment

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

Simillar test would be good for a class with some tests run in a separate process and some not.

Copy link
Author

@akotulu akotulu Nov 19, 2024

Choose a reason for hiding this comment

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

These tests will fail cause before and after method will be called multiple times when TestSuite is executed in another process. Purpose of this fix was to prevent main process executing before and after class methods when attribute is set. I don't have atm time to fix the issue with process isolation executing these functions multiple times, it requires a bit of redesign.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, I mean to have simillar test for all usecases - for RunClassInSeparateProcess attribute when all tests are run in a separate process and also when tests within a class are run in a separate process only partly.

@akotulu
Copy link
Author

akotulu commented Nov 20, 2024

I've fixed all the issues with separated process handling. Re-implemented separated process class template and added extra tests to validate all the before and after class methods are properly called.

New class template is missing these setters. I don't know if they are needed. Please comment

$test->setData('{dataName}', unserialize('{data}'));
$test->setDependencyInput(unserialize('{dependencyInput}'));

@@ -69,52 +72,67 @@ function __phpunit_run_isolated_test()

ErrorHandler::instance()->useDeprecationTriggers($deprecationTriggers);

$test = new {className}('{name}');
ini_set('xdebug.scream', '0');
Copy link
Contributor

Choose a reason for hiding this comment

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

is this line fixing a separate problem and should be separated from this PR?

Copy link
Author

@akotulu akotulu Nov 20, 2024

Choose a reason for hiding this comment

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

Well problem began with PHPUnit calling before and after class methods from primary process when run in separated process. After fixing the issue I stumbled on another one where those methods are called for every test while RunClassInSeparateProcess is defined. So yes, this PR contains fixes to before and after class methods being falsely called while using RunTestsInSeparateProcesses, RunClassInSeparateProcess and RunInSeparateProcess attribute.

Both of those templates (class.tpl, method.tpl) where diff identical and class template was invalid for those cases and causing undesired behavior.

Copy link
Contributor

Choose a reason for hiding this comment

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

To be more clear: my question was about this specific xdebug line.

Was this moved from elsewhere or is this a line we need for the after/before methods?

Copy link
Author

Choose a reason for hiding this comment

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

This line was in the source before my redesign. Copied common functionality from previous version.

$test->setData('{dataName}', unserialize('{data}'));
$test->setDependencyInput(unserialize('{dependencyInput}'));

These lines I don't known what they do. Are they for proxing primary process global state?
Our project now runs all the tests properly without any issues. We have suites without and with separated process. Also mixed tests.

Copy link
Owner

@sebastianbergmann sebastianbergmann Nov 21, 2024

Choose a reason for hiding this comment

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

$test->setData('{dataName}', unserialize('{data}'));
$test->setDependencyInput(unserialize('{dependencyInput}'));

These lines I don't known what they do.

They pass data from data providers and depended-upon tests to the test.

@sebastianbergmann
Copy link
Owner

Please fix the coding guidelines violations.

@akotulu
Copy link
Author

akotulu commented Nov 21, 2024

Weird behavior when project is pulled on Windows. php-cs-fixer tool reports all the project files having all kinds of issues. Had to pull the project inside wsl. CS issues have been fixed.

@sebastianbergmann
Copy link
Owner

This pull request has grown quite a bit since it was first proposed, making it hard to review. For instance, the change from an array to an object structure seems to be unrelated to problems that you want to address. And "problems" is a problem: this pull request addressed multiple problems. It would be easier to review smaller, more focused pull requests.

@akotulu
Copy link
Author

akotulu commented Nov 23, 2024

Well this pull request can't be split cause changes are related to each other. Running tests in a separated process would have returned an array containing arrays with tests information. To distinguish it from method template returning test data in an array, I changed returning array to object in both templates. Tests in separated process return array containing objects and method returns object.

@sebastianbergmann
Copy link
Owner

Please have a look at the failing tests.

@akotulu
Copy link
Author

akotulu commented Nov 25, 2024

Added a check for skipped and incomplete tests. This 'improvement' is kinda as is and can't be done the right way at the moment. TestBuilder is loading all the tests to the TestSuite in all cases from primary process. Loading tests step should come after analyzing the test file for attributes so TestRunner can be executed for a specific test file in either same or separated process and these checks with the boolean values can be removed. This would simplify a lot of unnecessary code. Also TestStatus class is kinda of overhead, you can't check for same class instance without using string ::class or static variable.

@sebastianbergmann
Copy link
Owner

Thank you for looking into the tests. However, I am unable to review this pull request which seems to get bigger and bigger.

@akotulu
Copy link
Author

akotulu commented Nov 25, 2024

Bigger? 5 files have changed + tests.
Changes:

  1. Rewrote class.tpl template to support running whole test file in separated process;
  2. Changed method.tpl returned array to object;
  3. Changed src/Framework/TestRunner/SeparateProcessTestRunner.php function processChildResult to support reading an array of results;
  4. In TestSuite added two booleans, changed invokeMethodsAfterLastTest and invokeMethodsAfterLastTest to public (moved private mothods to bottom);
  5. Fixed your tests/end-to-end/regression/5884/tests/FooTest.php not unlinking temp files when test fails by moving assert to end of test;
  6. Added new test directory called sandbox with 3 new tests;

If this is counted a big change then I don't know what is a small change. This change cannot be made smaller cause class.tpl wasn't actually implemented. Someone copied it from method.tpl and counted it as a day.

}

Facade::instance()->forward($childResult['events']);
PassedTests::instance()->import($childResult['passedTests']);
foreach ($childResult as $result) {
Copy link
Contributor

@staabm staabm Nov 29, 2024

Choose a reason for hiding this comment

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

Could this array to object transformation be extracted into a separate refactoring PR, without the actual bugfix?

I try to find ideas on how we can make this PR smaller and manageable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature/process-isolation Issues related to running tests in separate PHP processes feature/test-runner CLI test runner type/bug Something is broken
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants