Problem/Motivation

Follow up to #3129043: Move core database drivers to modules of their own and to #3230714-11: ConnectionUnitTest should be skipped for any database not psql or mysql:

Once #3129043: Move core database drivers to modules of their own is complete, it would be good to split the Database tests in 'core' ones and 'driver specific' ones, with the 'driver specifc' ones running dependent on the db driver in use by the SUT.

Proposed resolution

At the moment we have 4 possible solutions:

1: From the MR. Split Database tests in 'core' ones and 'driver specific' ones for the kerneltests in Drupal\KernelTests\Core\Database only. For most contrib database drivers this is enough, only for the one for MongoDB this is not the case.

2: No patch/MR. Move the core/phpunit.xml.dist file to the root of the database driver module and let every module with a database driver have its own phpunit.xml.dist. Use that file for the testbot and in that file the tests that must be skipped for the module can be added to the file. The Drupal testbot must be changed for this to work. The advantage is that all tests can be overridden.

3: From the patch (comment #18): Change the class Drupal\Core\Test\TestDiscovery, so that the method
getTestClasses() only returns the tests that need to be run. It skips the tests from the modules with a database driver that is not fromthe active database connection. The script run-tests.sh will need to be changed a bit and the option "--list" will need the "--dburl" to have it return the correct list of test classes.

4: From the patch (coomment #19): The method Drupal\KernelTests\KernelTestBase::setUp() now has code that skips tests that are from module with a database driver that is not from the active database connection and it skips tests that have been overridden by the module with the databse driver that is used in the active database connection. It only works for kerneltests, but the same solution can also be used for browsertests.

This issue implements option #1.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Issue fork drupal-3231950

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

mondrake created an issue. See original summary.

mondrake’s picture

Version: 10.0.x-dev » 9.3.x-dev
StatusFileSize
new16.36 KB

This can be started also in 9.3 already, provided that #3129043: Move core database drivers to modules of their own happens. See a PoC here, built on top of #3129043: Move core database drivers to modules of their own. This would split ConnectionUnitTest kernel test in 3 tests classes, one with a method relevant for core, then one for MySql and one for PostgreSql.

daffie’s picture

+++ b/core/modules/pgsql/tests/src/Kernel/pgsql/ConnectionUnitTest.php
@@ -0,0 +1,25 @@
+use Drupal\Tests\mysql\Kernel\mysql\ConnectionUnitTest as MySqlConnectionUnitTest;

I do not think that extending a test from another database driver is going to work, because when we are running the testbot for PostgreSQL the mysql module will NOT be enabled.

I like the idea of making the base test class abstract and letting each driver override that abstract class in a way that is best for the driver. Or not override at all when they do not want to use the test. Good idea!

mondrake’s picture

#3 I think it works - at least my tests seem to: https://github.com/mondrake/d8-unit/actions/runs/1217939693

In kernel tests as long as the class is autoloadable, it does not matter the module to be installed.

mondrake’s picture

Title: Split Database tests in 'core' ones and 'driver specific' ones » [pp-1] Split Database tests in 'core' ones and 'driver specific' ones
Status: Active » Postponed

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mondrake’s picture

Title: [pp-1] Split Database tests in 'core' ones and 'driver specific' ones » Split Database tests in 'core' ones and 'driver specific' ones
Assigned: Unassigned » mondrake
Status: Postponed » Active

I am working on this.

mondrake’s picture

Status: Active » Needs review

Ready for review - this only moves tests for the @group Database - other may be moved but I'd leave that for other issues after this one has been done.

DrupalCI does not report currently skipped tests (see #2905007: Allow run-tests.sh to report skipped/incomplete PHPUnit tests), you can see locally the new DriverSpecificDatabaseTestBase class in action with

vendor/bin/phpunit -v -c core --color=always --group=Database

In a test run with an Sqlite based SUT, the MySql tests will skip with

11) Drupal\Tests\mysql\Kernel\mysql\NextIdTest::testDbNextIdClosedConnection
This test only runs for the database driver 'mysql' provided by the 'mysql' module. Connected database driver is 'sqlite' provided by 'sqlite'.
mondrake’s picture

Assigned: mondrake » Unassigned
mondrake’s picture

daffie’s picture

@mondrake: Thank you for working on this.

To me this a good solution for the by core supported database drivers.

I am not sure how it is for contrib database drivers. If I have some core test that will not pass for my contrib database driver and that test is not extending DriverSpecificDatabaseTestBase, then I will have a problem. I will need to create a patch that will change the test to one that is extending DriverSpecificDatabaseTestBase and add for each by core supported database driver a new test (with a comment that it is needed for a contrib database driver). It works, only the idea that I will need to get a patch to land in core, just so that I can override a core test is to me a bit hmmm. It is not how overriding core should be.

My preference would be to place a phpunit.xml.dist file in every database drivers module and let the testbot use that instead of the one in the core directory. Each phpunit.xml.dist file can then add element to skip the tests in the other 2 by core supported database driver modules and also skip any other test it need to and replace it by its own version.
Contrib database drivers can place phpunit.xml.dist in their module. They will need to exclude the 3 by core supported database driver modules and add any other core test they want to override. No need to patch core.
We can write a test that will keep the different versions of the phpunit.xml.dist files in sync (with the exception of the element). Just as the as the core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldTest.php does for the files core/assets/scaffold/files/default.settings.php and sites/default/default.settings.php.
To me, this is more the way the PHP community would expect it to be fixed. Feel free to disagree.

mondrake’s picture

Yes, I disagree. To me, the 'core' tests should ideally be driver-abstract, and test the Database API regardless of what is the real DBMS under the hood. If contrib cannot match an API behaviour, then either a) the API is not abstract enough, and therefore core should change or b) contrib should try to adjust to support. Or, c) core should not make an API of it and demote to driver-specific. There's no easy way, I know, but for me it's stellar to adhere to the concept of abstract API.

Swapping the phpunit configuration file to manage different backends seems to me awkward, and would require DrupalCI infra changes. doctrine/dbal does have separate phpunit.xml per backend, but that's to provide test credentials for the DBMS spinned up, and actually ALL the tests are run on every workflow run, then tests are skipped if not relevant for the SUT's DBMS. Here we are doing the same.

daffie’s picture

I took some time to think about your solution in this issue. The problem is that for my MongoDB database driver it is just not enough. Let me give some examples:

  1. Each entity is stored in a single document, not as multiple row in different tables. Testing the table 'node_field_data' does not work
  2. MongoDB does not do SQL and Views uses almost only SQL and is based on the SQL table structure, not MongoDB's document storage.
  3. For MongoDB is an integer with the value 4 not the same as the string with the value '4'. I am not sure if we can update core test with (int) to make the test also pass for MongoDB?

For MongoDB is just allowing the test in Drupal\KernelTests\Core\Database just not enough. Maybe splitting the tests in 'core' tests and 'driver specific' ones works when it is part of a larger solution. Sorry.

mondrake’s picture

Looks like your problem in #14 is to run Database API tests on a non-SQL backend... which is not the scope of this issue (and, yes, I'm pretty certain they do not and most likely will never work - can your MongoDB database driver be installed as a inplace replacement of a core db driver?).

This issue's scope is just moving some of the Database API tests (i.e. those marked @group Database) around. If a test can only pass on a specific driver, what's the reason to keep it in the core namespaces?

daffie’s picture

I am afraid that when we do this your way (@mondrake), then it will work for all contrib databse driver with the exception of the one for MongoDB. And for MongoDB will it never be solved.

daffie’s picture

This patch has a different approach for overriding tests by the module that is proving the current database driver. The Drupal testbot uses the script core/scripts/run-tests.sh. That script uses the class core/lib/Drupal/Core/Test/TestDiscovery.php to create the list of tests that need to be run. I have made some modifications to that class to exclude the test from the database modules that not providing the current database driver. Also only the module that is providing the current database driver can override tests with the annotation "overrideTastClass".

The problem with the current patch is that the testbot is failing with;

--- Commands Executed ---
sudo -u www-data php /var/www/html/core/scripts/run-tests.sh --list > /var/lib/drupalci/workdir/run_tests.phpunit/testgroups.txt
Return Code: 2
--- Output ---

--- Errors ---
daffie’s picture

Should fix it for the testbot.

daffie’s picture

The method Drupal\KernelTests\KernelTestBase::setUp() now has code that skips tests that are from module with a database driver that is not from the active database connection and it skips tests that have been overridden by the module with the databse driver that is used in the active database connection. This solution is is a mix between the solution #1 and #3.

mondrake’s picture

Status: Needs review » Needs work

I'm still not very convinced @daffie, this still seems some sort of magic where if you place a class with a specific name in a module, then you disable running another test class somewhere else.

Can I suggest we split off moving the unit tests to a separate issue? I think that's not controversial and would make reviewing the patch here simpler.

  1. +++ b/core/tests/Drupal/KernelTests/KernelTestBase.php
    @@ -250,6 +250,37 @@ protected function setUp(): void {
    +      $tail = substr(get_class($this), 19);
    ...
    +      $tail = substr(get_class($this), 21 + strlen($module));
    

    Wouldn't it be better to implode the relevant remaining parts rather than hardcoding the offset?

  2. +++ b/core/tests/Drupal/KernelTests/KernelTestBase.php
    @@ -250,6 +250,37 @@ protected function setUp(): void {
    +      // Tests that overridden by the module that is providing the current
    +      // database driver should also be skipped.
    
    +++ b/core/tests/Drupal/KernelTests/KernelTestBase.php
    @@ -250,6 +250,37 @@ protected function setUp(): void {
    +    // Tests from modules that have database drivers should be skipped unless
    +    // they are from the module that is providing the current database driver.
    

    The comments on what's happening are not very clear.

  3. +++ b/core/tests/Drupal/KernelTests/KernelTestBase.php
    @@ -250,6 +250,37 @@ protected function setUp(): void {
    +      if (in_array($module, ['mysql', 'pgsql', 'sqlite'], TRUE) && $provider !== $module) {
    

    if we have a contrib database driver module in the codebase and run all the tests, then other db drivers (include core) will run the tests of the contrib driver, no? And we don't want that.

mondrake’s picture

daffie’s picture

Status: Needs work » Needs review
StatusFileSize
new12.96 KB

@mondrake: Thank you for reviewing my patch. Hopefully the new patch makes it more clear how it works.

I have removed the UnitTests and moved the code in KernelTestBase::setUp() to its own method.

For #20.1: Fixed.

For #20.2: I did my best to improve them.

For #20.3: Yes, this is something we need to support, only we need #3256642: Introduce database driver extensions and autoload database drivers' dependencies for that. My suggestion is to that in a followup.

daffie’s picture

StatusFileSize
new3.87 KB

The missing interdiff file.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mondrake’s picture

Rebased the MR onto 9.5.x

mondrake’s picture

As discussed in slack, let's focus this issue on splitting core tests in a way that those that are specific to only a subset of the database drivers supported by core, can be moved to the appropriate module namespaces.

And have a separate issue to discuss how to enable custom/contrib db drivers to run core tests when needed.

daffie’s picture

Status: Needs review » Needs work

@mondrake: Let go for your solution.

mondrake’s picture

Status: Needs work » Postponed

Thanks @daffie. Let's wait for #3260007: Decouple Connection from the wrapped PDO connection to allow alternative clients to get in, too, so we can also move testPrepareStatementFailOnExecution() to the pgsql and mysql modules only.

daffie’s picture

mondrake’s picture

Assigned: Unassigned » mondrake

On this.

mondrake’s picture

Assigned: mondrake » Unassigned
Status: Needs work » Needs review

Thanks @daffie for the inline comments in the MR.

Before moving further, a conceptual thing I think we need to discuss - IMHO we should do this only for kernel tests, and only for tests of the @group Database.

If a non-db test (kernel or functional) needs to skip or switch depending on the db driver, that would smell like our DB API need to be fixed not being 'abstract' enough. In other words, if the test does that, probably it's the runtime code that behaves differently on the driver under the hood, and that means that core would potentially not be compatible with non-core drivers. In that case, I think we should strive to fix the API rather than giving the testing framework ways to workaround. Yes, it's for SQL db-drivers only, but I think that support for non-SQL drivers is a totally different story.

daffie’s picture

Before moving further, a conceptual thing I think we need to discuss - IMHO we should do this only for kernel tests, and only for tests of the @group Database.

As far as this issue is concerned, yes lets do that.

Some of the tests in that category are extending DataBaseTestBase and some are extending KernelTestBase. Can we make the base DriverSpecificKernelTestBase extend KernelTestBase and have DriverSpecificDatabaseTestBase extend DriverSpecificKernelTestBase. To do that we can/need to move the DatabaseTestBase table creations and the sample data to a trait. We can than removed the new class variable $installSchemaAndData.

If a non-db test (kernel or functional) needs to skip or switch depending on the db driver, that would smell like our DB API need to be fixed not being 'abstract' enough. In other words, if the test does that, probably it's the runtime code that behaves differently on the driver under the hood, and that means that core would potentially not be compatible with non-core drivers. In that case, I think we should strive to fix the API rather than giving the testing framework ways to workaround.

+1 for this solution. Not sure if this solution will work for every SQL-database driver. I also think that some of the Database API testing is done in tests that are outside of the directory core/tests/Drupal/KernelTests/Core/Database and/or @group Database, but that is another problem.

mondrake’s picture

Assigned: Unassigned » mondrake
Status: Needs review » Needs work

Let's do then. On it. Thanks @daffie.

mondrake’s picture

Assigned: mondrake » Unassigned
Status: Needs work » Needs review

Moved the reusable code to a trait as suggested by @daffie.

daffie’s picture

StatusFileSize
new60.94 KB
new9.54 KB

I have refactored the MR a bit to get rid of the variable $installSchemaAndData.

For the rest does it look great.

mondrake’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

I was not very convinced on the need of a DriverSpecificKernelTestBase, but this makes sense.

I'm RTBCing since I cannot see who else would.

This issue is doing what it says in the title, using option 1 from the list of options in the IS.

mondrake’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs reroll
joegraduate’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new59.27 KB

Re-rolled patch from #36 against current 9.5.x branch.

daffie’s picture

Status: Needs review » Needs work

The reroll in comment #40 looks good to me.
Now we need a version for D10.0 and D10.1.
Back to needs work.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new57.2 KB

A D10 patch

mondrake’s picture

Version: 9.5.x-dev » 10.1.x-dev
Assigned: Unassigned » mondrake
Status: Needs review » Needs work
mondrake’s picture

StatusFileSize
new58.18 KB

PHPStan found quite some stuff in the 9.5 patch. So I am retargeting 10.1 first, and we'll backport in case.

mondrake’s picture

StatusFileSize
new58.17 KB

Fix

mondrake’s picture

Assigned: mondrake » Unassigned
Status: Needs work » Needs review
daffie’s picture

Status: Needs review » Reviewed & tested by the community

The version for D10.0 and D10.1 looks good to me.
Back to RTBC.

daffie’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/tests/Drupal/KernelTests/Core/Database/DatabaseTestSchemaDataTrait.php
@@ -0,0 +1,121 @@
+trait DatabaseTestSchemaDataTrait {

+++ b/core/tests/Drupal/KernelTests/Core/Database/DatabaseTestSchemaInstallTrait.php
@@ -0,0 +1,32 @@
+trait DatabaseTestSchemaInstallTrait {

@mondrake: In your D10.0 patch you have created 2 traits called DatabaseTestSchemaDataTrait and DatabaseTestSchemaInstallTrait. The 9.5 version only has the trait InstallDatabaseTestSchemaAndDataTrait. Could you update either one, so that they both do the same thing. Or explain why you made them different.

mondrake’s picture

Status: Needs work » Needs review

See the test failure in #42.

 ------ ----------------------------------------------------------------------- 
  Line   core/tests/Drupal/KernelTests/Core/Database/InstallDatabaseTestSchema  
         AndDataTrait.php (in context of class                                  
         Drupal\Tests\system\Functional\Database\DatabaseTestBase)              
 ------ ----------------------------------------------------------------------- 
  16     Call to an undefined method                                            
         Drupal\Tests\system\Functional\Database\DatabaseTestBase::installSche  
         ma().                      

PHPStan is quite right here, installSchema() is not defined for functional tests. So, we need the sample data adding in both kernel and functional tests (one trait), and the schema install in two kernel base tests (the other trait).

Let's backport to 9.5 only once we have cleared out the D10.0 and D10.1 are ok, if you don't mind. Too much effort to try and keep many versions in sync.

daffie’s picture

Status: Needs review » Reviewed & tested by the community

@mondrake: Thank you for the explanation.

Back to RTBC.

For the comitter: The patch for D9.5 has the trait InstallDatabaseTestSchemaAndDataTrait and the patch for D10.X has the traits DatabaseTestSchemaDataTrait and DatabaseTestSchemaInstallTrait. I leave it up to you to determine if the difference is acceptable or that it must be the same for both patches.

alexpott’s picture

Version: 10.1.x-dev » 9.5.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Committed and pushed d755c76eb1 to 10.1.x and 8d8b24055f to 10.0.x. Thanks!

So we need to backport the changes talked about in #48/#49 to the 9.5.x version (might even got for 9.4.x given this is all test related).

Please make sure the patch passes on PHP 7.3 as I see some things in the 10.x patch that require a higher PHP version.

  • alexpott committed d755c76 on 10.1.x
    Issue #3231950 by mondrake, daffie, joegraduate: Split Database tests in...

  • alexpott committed 8d8b240 on 10.0.x
    Issue #3231950 by mondrake, daffie, joegraduate: Split Database tests in...
mondrake’s picture

Status: Patch (to be ported) » Needs review
StatusFileSize
new58.29 KB

Here's a new 9.5 patch

mondrake’s picture

StatusFileSize
new58.21 KB
daffie’s picture

Status: Needs review » Needs work

Testbot is not happy

anchal_gupta’s picture

StatusFileSize
new58.17 KB
new549 bytes

fix cs error. Please review it

alexpott’s picture

Status: Needs work » Needs review
daffie’s picture

Status: Needs review » Reviewed & tested by the community

The patch for D9.5 looks good to me.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Needs to pass on PHP7.3

pradhumanjain2311’s picture

Status: Needs work » Needs review
StatusFileSize
new48.94 KB
new572 bytes

Fix
PHP Parse error: syntax error, unexpected 'Connection' (T_STRING), expecting function (T_FUNCTION) or const (T_CONST) in /var/www/html/core/modules/system/tests/src/Functional/Database/DatabaseTestBase.php on line 20. Needs Review

pradhumanjain2311’s picture

StatusFileSize
new48.9 KB
new595 bytes

Checking core/modules/system/tests/src/Functional/Database/DatabaseTestBase.php

FILE: ...odules/system/tests/src/Functional/Database/DatabaseTestBase.php
----------------------------------------------------------------------
FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE
----------------------------------------------------------------------
5 | WARNING | [x] Unused use statement
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY.

Fix unused use statement.

Status: Needs review » Needs work

The last submitted patch, 62: 3231950-62.patch, failed testing. View results

daffie’s picture

Testbot is failing.

pradhumanjain2311’s picture

Hi @daffie @alexpott
i m new to contribution would you please guide how to solve this error
ERROR: PHP Fatal error: Trait "Drupal\KernelTests\Core\Database\DatabaseTestSchemaDataTrait" not found in /var/www/html/core/tests/Drupal/KernelTests/Core/Database/DatabaseTestBase.php on line 14

daffie’s picture

Version: 9.5.x-dev » 10.1.x-dev

@pradhumanjainOSL: The patch for D10.0 is adding 2 traits and they are not in your patch for D9.5 (DatabaseTestSchemaDataTrait and DatabaseTestSchemaInstallTrait). Please look carefully how it is done in the patch for D10.0.

pradhumanjain2311’s picture

Status: Needs work » Needs review
StatusFileSize
new58.12 KB
new820 bytes

@daffie Thanks for your guidance.
But i fix the patch now please review and apologies.

Status: Needs review » Needs work

The last submitted patch, 67: 3231950-67.patch, failed testing. View results

daffie’s picture

Status: Needs work » Reviewed & tested by the community

The D9.5 looks good to me.
It passes the testbot for all by 3 by core supported databases.
It passes the testbot for PHP7.3 and PHP8.0.
For me it is RTBC.

alexpott’s picture

Version: 10.1.x-dev » 9.5.x-dev
Status: Reviewed & tested by the community » Fixed

Committed b855673 and pushed to 9.5.x. Thanks!

  • alexpott committed b855673 on 9.5.x
    Issue #3231950 by mondrake, daffie, pradhumanjainOSL, Anchal_gupta,...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.