Integration/setup testing of migrations cause trouble


I am just trying to write some integration tests to tackle a certain issue on an app. In fact, one of the migrations caused trouble as some assumptions on the table content were wrong.

Here come some general information, the main questions are at the ending.

In order to test this properly, the idea was to use integration/installation tests based on PHPUnit. (This is, in general, a good idea as I think to test as much as possible.) What is existing/working:

  • A fixture is generated that allows to reset the complete database and files to a vanilla state (NC installed with app enabled).
  • A PHPUnit\Framework\TestCase is created to run the tests with various cases
    • The setUp() function first drops the app’s tables (using OC\SchemaWrapper) and resets the oc_migrations table to reflect that
    • The OC\SchemaWrapper::performDropTableCalls() is needed to carry out the drops itself.
    • Then an appropriate occ migrations:migrate command is issued to migrate to the previous version (just before the critical migration)
    • The main test just uses occ again to perform the single migration and check some constraints.

The problem here is that the NC core somehow seems to cache the dropped tables: In the first test case, everything works as expected. The removal of the table is carried out and the test is run.
For any further test case, however, the NC core (aka OC\SchemaWrapper) has the cached information that the relevant table was dropped and refuses to drop it again. As the recreation was done outside using occ, the SchemaWrapper is not aware of the outdated cache.

The alternative to reloading the cache was to use a completely new instance of OC\SchemaWrapper. The setUp() does something like

$app = new App('cookbook');
$this->container = $app->getContainer();

The container is used to query for the SchemaWrapper. So, it seems that the created object is saved in the container and will be reused in the next invocations. Therefore I tried to use the process separation of PHPUnit. Unfortunately, I am running into issues related with serializing of Closure objects in the internals of PHPUnit. I just asked on stack overflow but I am not sure about the output given my recent experience there.

So the main questions become:

  • Has anyone realized an integration testing approach with setup of the fixtures?
  • Can I somehow reset the container of an app in order to start fresh?
  • Can I force the schema to be reread from the DB?

I while ago I wrote GitHub - ChristophWurst/nextcloud_testing: Simple and fast unit and integration testing framework for Nextcloud, based on PHPUnit and it’s still used in some apps. It gives you some isolation and resetting but it doesn’t go as far as resetting the whole instance and db schema.

The problem with that solution is that it uses rolled back transactions to smehow undo the changes in the DB. Unfortunately, at least MySQL is not capable to undo table modifications (DDL). So, to test a migration, this will not help much.

Currently I have the (technical) problem that PHPUnit is refusing my tests. What would help is to clean out the caches in the NC core (and symfony). So, I need to close all database connection and drop all other caches. I tried to unset(\OC::$server). Are there other variables that I can reset in order to restart the core?

Thank you anyways for the hint. I will take into account for further work.

I finished this issue by using process isolation (@runInSeparateProcess). I had to unset all obtained objects from the containers in the tearDown but it seems to work for now.

1 Like