Problem/Motivation

When developing Kernel test, it was found that after applying the patch, that the time to run Kernel test was reduced by between 25% and 33%. Before applying the patch, the code created a file database called ':memory:' in the application root directory and to remove it and not use the SQLite in memory database functionality.

Here is example XML element in phpunit.xml for file based SQLite database in the /tmp directory called test.sqlite.
<env name="SIMPLETEST_DB" value="sqlite://localhost//tmp/test.sqlite"/>

Here is example XML element in phpunit.xml for file based SQLite database in the application root directory called test.sqlite.
<env name="SIMPLETEST_DB" value="sqlite://localhost/test.sqlite"/>

Here is example XML element in phpunit.xml for in memory SQLite database
<env name="SIMPLETEST_DB" value="sqlite://localhost/:memory:"/>;

See http://php.net/manual/en/ref.pdo-sqlite.connection.php for more information about using a in memory database.

Please note

  • In memory database is not shared between the client and server programs when running Functional or Functional-JavaScript unit tests and hence failures.
  • A database is not needed for Unit tests.

Proposed resolution

Support sqlite database connections being set up via a db url.

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

N/a

CommentFileSizeAuthor
#59 sqlite-support-in-memory-database-2983452-59-8.9.x.patch3.85 KBcburschka
#51 interdiff-48-51.txt458 bytesjungle
#51 2983452-51.patch3.35 KBjungle
#48 interdiff-43-48.txt1.33 KBjungle
#48 2983452-48.patch3.8 KBjungle
#43 interdiff_40-43.txt2.09 KBridhimaabrol24
#43 2983452-43.patch3.42 KBridhimaabrol24
#40 interdiff_37-40.txt2.01 KBridhimaabrol24
#40 2983452-40.patch3.63 KBridhimaabrol24
#37 interdiff_35-37.txt1.83 KBKwadz
#37 drupal-sqlite-support-in-memory-databases-2983452-37-9.1.x.patch3.54 KBKwadz
#35 interdiff_29-35.txt2.07 KBridhimaabrol24
#35 2983452-35.patch3.55 KBridhimaabrol24
#33 interdiff_27-33.txt4.45 KBKwadz
#33 drupal-sqlite-support-in-memory-databases-2983452-33-9.1.x.patch3.23 KBKwadz
#31 drupal-sqlite-support-in-memory-databases-2983452-31-9.1.x.patch2.83 KBKwadz
#29 interdiff_27-29.txt1.04 KBridhimaabrol24
#29 2983452-29.patch3.48 KBridhimaabrol24
#27 interdiff_25-27.txt3.05 KBridhimaabrol24
#27 2983452-27.patch3.49 KBridhimaabrol24
#25 interdiff-22-25.txt624 bytescburschka
#25 sqlite-support-in-memory-database-2983452-25-9.1.x.patch4.15 KBcburschka
#23 interdiff-21-22.txt513 bytescburschka
#22 sqlite-support-in-memory-database-2983452-22-8.9.x.patch4.01 KBcburschka
#22 sqlite-support-in-memory-database-2983452-22-9.1.x.patch4.15 KBcburschka
#21 drupal-sqlite-support-in-memory-databases-2983452-21-8.8.x.patch3.39 KBKwadz
#14 interdiff_4-14.txt652 bytesjulienjoye
#14 sqlite-support-in-memory-database-2983452-14-8.6.x.patch1.32 KBjulienjoye
#9 sqlite-support-in-memory-database-2983452-9.patch3.48 KBdhirendra.mishra
#4 sqlite-support-in-memory-database-2983452-4-8.6.x.patch1.33 KBberam
sqlite-support-in-memory-database-8.5.x.patch1.44 KBsomersoft
sqlite-support-in-memory-database-8.6.x.patch1.44 KBsomersoft
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

somersoft created an issue. See original summary.

somersoft’s picture

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

beram’s picture

Hi,

After updating Drupal Core from 8.5.6 to 8.6.1 the initial patch does not apply.

I rerolled it.

Since there is a lot of changes in the Core between initial patch and this one I did not add an interdiff. I could try if someone prefer to.

This is not perfect. I think it misses some comments to explain why this is needed.
I did not do it because IMHO the original code is not clear enough and I think it needs to be refactored.
I'll like to have opinion of someone else on this.

julienjoye’s picture

Patch #4 seems to be OK. Applied on 8.6.2
Possibly we can check if $url_components['path'] === ':memory:' instead of just trying the first char at line 450, since this value is checked at line 81.

daffie’s picture

Status: Active » Needs work

Putting the status of this issue to needs work, because of the feedback/review of @julienjoye.

daffie’s picture

Issue tags: +Needs manual testing

@julienjoye can you confirm that you have manual tested this patch and it does what is suppost to do?

dhirendra.mishra’s picture

Assigned: Unassigned » dhirendra.mishra

working on it.

dhirendra.mishra’s picture

Assigned: dhirendra.mishra » Unassigned
Status: Needs work » Needs review
FileSize
3.48 KB

Corrected from comment #7. Kindly review this patch.

beram’s picture

@dhirendra.mishra Could you add the interdiff please? :)

I don't understand why you change migrate_drupal. Could you explain please?

dhirendra.mishra’s picture

i have added below line according to comment 5.
before : if ($url_components['path'][0] === '/' || $url_components['path'][0] === ':') {
After : if ($url_components['path'][0] === '/' || $url_components['path'][0] === ':memory:') {

dhirendra.mishra’s picture

needs review on this.

beram’s picture

Status: Needs review » Needs work

Hi dhirendra.mishra,

As noticed with the comment https://www.drupal.org/project/drupal/issues/2983452#comment-12828451,
your patch from https://www.drupal.org/project/drupal/issues/2983452#comment-12827945 contains modifications of the migrate_drupal module. Could you explain why?

I think this needs a proper test to avoid regression in the future and I still think as stated in https://www.drupal.org/project/drupal/issues/2983452#comment-12815429 that:

This is not perfect. I think it misses some comments to explain why this is needed.
I did not do it because IMHO the original code is not clear enough and I think it needs to be refactored.
I'll like to have opinion of someone else on this.

PS: When I asked for an interdiff I meant https://www.drupal.org/documentation/git/interdiff ;)

julienjoye’s picture

Hi dhirendra.mishra,

As I wrote on my comment, the full string variable $url_components['path'] should be evaluated to match with ':memory:' instead of just checking the first letter (as you do with [0]).

I fixed this with my patch. I provide an interdiff between mine and Beram's (#4), too.

However, this warns us about the fact that the currently set tests are missing something. Your patch still lets a :memory: file after tests run.
Then, maybe we can add a test that checks if we are in sqlite in :memory: mode during our Kernel tests, and checks that the ':memory:' file is not created at the drupal root.

What do you think?

beram’s picture

Hi @julienjoye,

Thanks for the patch and the interdiff. I'll test it.

However, this warns us about the fact that the currently set tests are missing something. Your patch still lets a :memory: file after tests run.
Then, maybe we can add a test that checks if we are in sqlite in :memory: mode during our Kernel tests, and checks that the ':memory:' file is not created at the drupal root

That's because there is no test to cover the :memory: feature added by the patch ;)
The test you described cover the case described in this issue i.e. using SQLite in memory database when running the tests.
The patch allows to run a site with SQLite in memory database and not only when running tests.
We need to unit test those methods IMHO.

@julienjoye What do you think about the following statement?

This is not perfect. I think it misses some comments to explain why this is needed.
I did not do it because IMHO the original code is not clear enough and I think it needs to be refactored.
I'll like to have opinion of someone else on this.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

andypost’s picture

Additionally to memstorage there's no way to point full path to database
for example sqlite:///mnt/tmp.sqlite

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Kwadz’s picture

To summarise, we should be able to use:

- relative paths: sqlite://localhost/tmp/db.sqlite
- absolute paths: sqlite://localhost//tmp/db.sqlite
- in memory: sqlite://localhost/:memory:

I'm writing a unit test to cover this.

One question though, why did we add the following condition?

&& $this->connectionOptions['database'][0] != ':'

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Kwadz’s picture

cburschka’s picture

Adding the missing namespace declaration to ConnectionTest.

The patch does not apply to 9.0.x/9.1.x because the "database name does not start with colon" condition collided with an upstream change that adds a "database file exists" condition.

I've merged and added both conditions - in theory, the file_exists condition should be false for the in-memory database anyway, but why not be safe.

Patching against 9.1.x and 8.9.x.

cburschka’s picture

FileSize
513 bytes

interdiff from 21->22 on 8.9.x

(no interdiff on reroll for 9.1.x)

cburschka’s picture

Looks like 9.1.x wants return type hints on ::setUp().

daffie’s picture

Status: Needs review » Needs work

@cburschka: Thank you for working on this. Patch looks good! Some minor points to resolve:

  1. +++ b/core/tests/Drupal/Tests/Core/Database/Driver/sqlite/ConnectionTest.php
    @@ -0,0 +1,63 @@
    +  const WEB_ROOT = '/var/www/html/web';
    

    Can we change this to: protected $root; and then in the setup() do: $this->root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2);. In that way it works in all test environments.

  2. +++ b/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
    @@ -185,7 +185,7 @@ public function __destruct() {
    +          if ($count == 0 && $this->connectionOptions['database'][0] != ':' && file_exists($this->connectionOptions['database'] . '-' . $prefix)) {
    

    Can we change: $this->connectionOptions['database'][0] != ':' to: $this->connectionOptions['database'] != ':memory:'. It improves the readability of the code.

  3. +++ b/core/tests/Drupal/Tests/Core/Database/Driver/sqlite/ConnectionTest.php
    @@ -0,0 +1,63 @@
    +    $this->mockPdo = $this->createMock('Drupal\Tests\Core\Database\Stub\StubPDO');
    

    This can be moved to the test method. In this way we do not need the class variable. It is only used in one method. Also could you do the following change: createMock(StubPDO::class). It the new way of doing it on Drupal core and I think it helps generating an overview of which code is tested and which is not.

  4. +++ b/core/tests/Drupal/Tests/Core/Database/Driver/sqlite/ConnectionTest.php
    @@ -0,0 +1,63 @@
    +  public function getDatabaseUrls(): array {
    

    Could you change the name of the provider method to: "providerCreateConnectionOptionsFromUrl". For better readability.

ridhimaabrol24’s picture

Implemented the changes suggested in #26.

ridhimaabrol24’s picture

Status: Needs work » Needs review
ridhimaabrol24’s picture

Corrected the failed testcase from #27.

Status: Needs review » Needs work

The last submitted patch, 29: 2983452-29.patch, failed testing. View results

Kwadz’s picture

Thanks @ridhimaabrol24!

I fixed the @dataProvider phpDoc comment that didn't match anymore with the new name of the provider method. About that, the new name of the provider method is not more readable IMO and we even loose the info about what it's doing. We should start method with a verb, like Symfony and us usually do for this (the PHPUnit doc is not a good example). So I renamed it to provideDatabaseUrls.

I added missing use statement for StubPDO.

In the meantime we find a working way I reverted dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2) to the constant since it didn't provide the web root but the Drupal root.

daffie’s picture

@ridhimaabrol24: Debugging test is a lot easier when you run the PHPUnit test locally. See: https://www.drupal.org/docs/8/testing/phpunit-in-drupal-8/running-phpuni...

@Kwadz: Could you add an interdiff.txt. It makes reviewing your patch a lot easier. Also the constant WEB_ROOT needs to go. The test needs to work on different environments. The number 2 needs to change to get the right directory, but for the rest it is the right way to do it (dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2)).

Kwadz’s picture

@daffie, all right, I switched to the var that uses dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2)), and added the interdiff.txt.

Kwadz’s picture

Oops, it seems I made a mistake with my patch command. Sorry guys. Going to fix it.

ridhimaabrol24’s picture

I have made the changes and tested on local. Although I am still facing an error with 'sqlite relative path' but I am updating the patch with interdiff provided from #29.

daffie’s picture

@ridhimaabrol24: I could very well be that the provider method does not get the right value and that $this->root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2); also needs to happen in the provider method.

Kwadz’s picture

Cleaned forgotten comment and renamed $root to $drupal_root.

The test runs OK on my local install which doesn't use a web/ directory.

Kwadz’s picture

Status: Needs work » Needs review
daffie’s picture

Status: Needs review » Needs work

Patch still needs some more improvement. Thank you all for working on this!

  1. +++ b/core/tests/Drupal/Tests/Core/Database/Driver/sqlite/ConnectionTest.php
    @@ -0,0 +1,62 @@
    +    $this->root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2);
    ...
    +    $database = $sqlite_connection->createConnectionOptionsFromUrl($url, $this->drupal_root);
    ...
    +      'sqlite relative path' => ['sqlite://localhost/tmp/test', $this->drupal_root . '/tmp/test'],
    

    You are mixing 2 different variables: $this->root and $this->drupal_root. Please make them the same. See my comments #32 and #36 for more info.

  2. +++ b/core/tests/Drupal/Tests/Core/Database/Driver/sqlite/ConnectionTest.php
    @@ -0,0 +1,62 @@
    +   * @dataProvider provideDatabaseUrls
    ...
    +  public function provideDatabaseUrls(): array {
    

    Can we change the name of the provider method to: "providorCreateConnectionOptionsFromUrl".

ridhimaabrol24’s picture

Uploading the patch after implementing changes from #39. I have used the same variable $root at all places. Tested on local and it works fine.

jungle’s picture

Status: Needs work » Needs review

I think would be great to test against SQLite stack(s) as we are working on an issue SQLite related. Queued testing against PHP 7.4 & SQLite 3.27

New patch uploaded, so setting back to Needs review. Thanks, @ridhimaabrol24!

daffie’s picture

Status: Needs review » Needs work

@jungle: This patch only contains Unit tests. They are without a database connection and therefor only need to be tested against a single database (any will do).

@ridhimaabrol24: Thank you for working on the patch. I looks great, only we can make it a little better. This is because we needed to add the line: $this->root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2); to the provider method. We can now add the same line to the method "testCreateConnectionOptionsFromUrl()". When we do that the class variable $root and the setup() method can then be removed. After that the patch will be RTBC for me.

ridhimaabrol24’s picture

@daffie changes done! Please review.

pavnish’s picture

Status: Needs work » Needs review
Kwadz’s picture

@daffie, could you explain why in this case we shouldn't factorise dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2) (DRY principle) like we do elsewhere, for example in core/tests/Drupal/Tests/Core/Database/DatabaseTest?

About that, I don't understand why we don't use UnitTestCase::$root in that case.

daffie’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Kernel Base Tests, -Needs manual testing

@Kwadz: You are right that we should not repeat dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2). The problem is that when you set the value of $this->root in the method setUp(), for the provider method the value of $this->root does not get set by the method setUp() (it is still NULL). That makes the test of course fail. Therefor we need to set it twice. I took me the first time also by surprise. One of the strange things of PHPUnit testing. When this explanation is not enough, then please say so.

All the code changes look good to me.
The patch has been manual tested.
All my points have been addressed.
A CR has been created.
For me it is RTBC.

Great work everybody!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Yep the provider is run before setUp. It makes sense when you think about it.

+++ b/core/tests/Drupal/Tests/Core/Database/Driver/sqlite/ConnectionTest.php
@@ -0,0 +1,49 @@
+    $root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2);
...
+    $root = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__)), 2);

Can this be dirname(__DIR__, 8)? I think it is 8 but that needs local testing... less to think about. And less methods involved and this is becoming more common in other tests.

jungle’s picture

Status: Needs work » Needs review
FileSize
3.8 KB
1.33 KB

Re #47, tested on my local, it's 8. Thanks @alexpott!

daffie’s picture

Status: Needs review » Reviewed & tested by the community

Point of @alexpott is addressed.
Back to RTBC.

alexpott’s picture

Title: Support for SQLite in memory database » Improve support for SQLite in memory database
Issue summary: View changes
Status: Reviewed & tested by the community » Needs work

So we already use in memory sqlite databases for testing :) We use them in migrate kernel tests. What we don't support is creating connections to them using our db url format which this patch adds so I'm re-titling.

I'm not a huge fan of the db url format because database connections cannot fully be represented as URLs or treated as such. sqlite: is not a valid URL scheme, for example. But that's out-of-scope here.

Also I'm not that convinced of the utility of using sqlite memory tests to speed up kernel testing but that is also not a reason to not fix this bug.

Unfortunately there's an unexpected change in the most recent patch.

+++ b/core/phpcs.xml.dist
@@ -149,6 +149,7 @@
+  <rule ref="DrupalPractice.InfoFiles.NamespacedDependency"/>

This change should not be here.

jungle’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
3.35 KB
458 bytes

Sorry, my bad!

Removed the change of <rule ref="DrupalPractice.InfoFiles.NamespacedDependency"/>

daffie’s picture

My bad too. I only looked at the interdiff.txt file.
+1 for RTBC.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 51: 2983452-51.patch, failed testing. View results

jungle’s picture

Looks like a random failure. Requeued. I will cycle back later, and set it back to RTBC if testing passes.

daffie’s picture

Status: Needs work » Reviewed & tested by the community

Back to RTBC.

alexpott’s picture

Version: 9.1.x-dev » 9.0.x-dev
Status: Reviewed & tested by the community » Fixed

Committed and pushed ce8dfe3d27 to 9.1.x and d19389aeb1 to 9.0.x. Thanks!

The patch didn't apply to 8.9.x. We can backport if someone wants to.

  • alexpott committed ce8dfe3 on 9.1.x
    Issue #2983452 by ridhimaabrol24, Kwadz, cburschka, jungle, somersoft,...

  • alexpott committed d19389a on 9.0.x
    Issue #2983452 by ridhimaabrol24, Kwadz, cburschka, jungle, somersoft,...
cburschka’s picture

Version: 9.0.x-dev » 8.9.x-dev
Status: Fixed » Needs review
FileSize
3.85 KB

Backport to 8.9.x (just needed to undo the forward port from #22).

daffie’s picture

Status: Needs review » Patch (to be ported)
jungle’s picture

Status: Patch (to be ported) » Reviewed & tested by the community

The patch has been successfully committed to a branch of the project, and still needs to be committed to another, but the current patch doesn't apply to the target branch and needs to be modified in order to do so.

See https://www.drupal.org/issue-queue/status#patch-to-be-ported

Patch (to be ported) means NW. From my understanding, the proper status should be RTBC if the rerolled/backported patch passed your review. And I guess @daffie intended to RTBC, but misunderstand the Patch (to be ported) status. So setting to RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 7a75718 and pushed to 8.9.x. Thanks!

  • alexpott committed 7a75718 on 8.9.x
    Issue #2983452 by ridhimaabrol24, Kwadz, cburschka, jungle, somersoft,...

Status: Fixed » Closed (fixed)

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

quietone’s picture

Publish the CR