ActiveFixture for elastic search tries to communicate with MySQL DB

Hey,

I like to set up an unit test in yii2 to test an model based on elasticsearch extension.
To avoid accesses to the Elasticsearch index I want to use \yii\elasticsearch\ActiveFixture

So I defined an fixture like that:

namespace app\tests\fixtures;
class UserFixture extends \yii\elasticsearch\ActiveFixture
{
    public $modelClass = 'app\models\User';
    
    protected function getData()
    {
        return [
            'data1' => [
                "name" => "Ben",
                "foo" => "xcv"
            ]
        ];
    }
}

My test, using this fixture, is this:

namespace tests\unit\models;

use app\models\User;
use app\tests\fixtures\UserFixture;

class UserTest extends \Codeception\Test\Unit
{
    
    use \Codeception\Specify;

    protected $tester;
    
    protected function _before()
    {
    }

    protected function _after()
    {
    }

    public function _fixtures()
    {
        return [
            'profiles' => [
                'class' => UserFixture::className(),
                'db' => 'elasticsearch',
                'index' => 'users'
            ]
        ];
    }

    function testIndexName()
    {
        $this->assertEquals('users', User::index());
    }
}

The test fails with the following error:

 Destroying application
  Starting application
  [ConnectionWatcher] watching new connections
  [Fixtures] Loading fixtures
  [ConnectionWatcher] watching new connections
  [yii\db\Connection::open] 'Opening DB connection: mysql:host=localhost;dbname=yii2basic_test'
E UserTest: Index name 
  Destroying application
  [ConnectionWatcher] no longer watching new connections
  [ConnectionWatcher] closing all (0) connections
  Suite done, restoring $_SERVER to original
---------------------------------------------------------------------------------------------

Time: 367 ms, Memory: 6.00 MB

There was 1 error:

---------
1) UserTest: Index name
 Test  tests/unit/models/UserTest.php:testIndexName
                                                                       
  [yii\db\Exception] SQLSTATE[HY000] [2002] No such file or directory  
                                                                       
/app/vendor/yiisoft/yii2/db/Connection.php:642
/app/vendor/yiisoft/yii2/db/Connection.php:710
/app/vendor/yiisoft/yii2/db/Connection.php:631
/app/vendor/yiisoft/yii2/db/Connection.php:1030
/app/vendor/yiisoft/yii2/db/Connection.php:1017
/app/vendor/yiisoft/yii2/db/mysql/QueryBuilder.php:406
/app/vendor/yiisoft/yii2/db/mysql/QueryBuilder.php:430
/app/vendor/yiisoft/yii2/db/mysql/QueryBuilder.php:59
/app/vendor/yiisoft/yii2/base/BaseObject.php:109
/app/vendor/yiisoft/yii2/db/QueryBuilder.php:116
/app/vendor/yiisoft/yii2/db/mysql/Schema.php:217
/app/vendor/yiisoft/yii2/db/Schema.php:249
/app/vendor/yiisoft/yii2/db/Connection.php:864
/app/vendor/yiisoft/yii2/db/Command.php:983
/app/vendor/yiisoft/yii2/test/InitDbFixture.php:99
/app/vendor/yiisoft/yii2/test/InitDbFixture.php:78
/app/vendor/yiisoft/yii2/test/FixtureTrait.php:117
/app/vendor/codeception/module-yii2/src/Codeception/Module/Yii2.php:475
/app/vendor/codeception/module-yii2/src/Codeception/Module/Yii2.php:344
/app/vendor/codeception/module-yii2/src/Codeception/Module/Yii2.php:324
/app/vendor/codeception/codeception/src/Codeception/Subscriber/Module.php:56
/app/vendor/symfony/event-dispatcher/EventDispatcher.php:230
/app/vendor/symfony/event-dispatcher/EventDispatcher.php:59
/app/vendor/codeception/phpunit-wrapper/src/DispatcherWrapper.php:22
/app/vendor/codeception/phpunit-wrapper/src/Listener.php:134
/app/vendor/codeception/phpunit-wrapper/src/Listener.php:103
/app/vendor/phpunit/phpunit/src/Framework/TestResult.php:423
/app/vendor/phpunit/phpunit/src/Framework/TestResult.php:640
/app/vendor/phpunit/phpunit/src/Framework/TestCase.php:819
/app/vendor/phpunit/phpunit/src/Framework/TestSuite.php:627
/app/vendor/codeception/phpunit-wrapper/src/Runner.php:117
/app/vendor/codeception/codeception/src/Codeception/SuiteManager.php:161
/app/vendor/codeception/codeception/src/Codeception/Codecept.php:208
/app/vendor/codeception/codeception/src/Codeception/Codecept.php:162
/app/vendor/codeception/codeception/src/Codeception/Command/Run.php:401
/app/vendor/symfony/console/Command/Command.php:256
/app/vendor/symfony/console/Application.php:971
/app/vendor/symfony/console/Application.php:290
/app/vendor/symfony/console/Application.php:166
/app/vendor/codeception/codeception/src/Codeception/Application.php:117
/app/vendor/codeception/codeception/app.php:46
/app/vendor/codeception/codeception/app.php:47
/app/vendor/codeception/codeception/codecept:7

My test-config:

 'components' => [
        'db' => $db,
[...]
        'elasticsearch' => [
            'class' => 'yii\elasticsearch\Connection',
            'nodes' => [
                ['http_address' => 'es01:9200'],
            ],
            'dslVersion' => 7, // default is 5
        ],

The test works fine, if I remove the _fixtures method. It looks like, the test tries to talk with an SQL DB. But the whole application does only use elasticsearch.

Is there any configuration missing?

//Edit:
I found out that fixtures for elasticsearch also need a SQL database.
The documentation is unfortunately not very clear here: in the documentation for fixtures it is described that a fixture creates a table in the DB with fixed values.
Below that it says that fixtures for elasticsearch are handled in a separate class. For me it was not expected that this would require a separate SQL DB, since the use of a document structure in elasticsearch would also be conceivable.

Anyway: I have now configured a SQLite DB.
However, the test fails with the error:
[Error] Wrong parameters for yii\base\Exception([string $message [, long $code [, Throwable $previous = NULL]]) .

The individual steps of the test went through well:

  Destroying application
  Starting application
  [ConnectionWatcher] watching new connections
  [Fixtures] Loading fixtures
  [ConnectionWatcher] watching new connections
  [yii\db\Connection::open] 'Opening DB connection: sqlite:/tmp/test.sq'
  [ConnectionWatcher] Connection opened!
  [ConnectionWatcher] Connection opened!
E UserTest: Index name 
  Destroying application
  [ConnectionWatcher] no longer watching new connections
  [ConnectionWatcher] closing all (1) connections
  Suite done, restoring $_SERVER to original

To answer my own question (partitial), if someone runs into the same problem:

1.) The Message
[Error] Wrong parameters for yii\base\Exception([string $message [, long $code [, Throwable $previous = NULL]])
seams to be based on a bug in /app/vendor/yiisoft/yii2-elasticsearch/ActiveFixture.php, where load() - method tries to rise an error. Without this error-information it’s hard to debug this problem.

2.) After making a workaround for 1.), I saw the real error produced by my code in my question above. This was an elasticsearch-message:
TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block];"},"status":429
But that’s not very meaningful. The main reason for this message is, that I used the same index in test and application. After changing the index-name from users to users_test, this problem was solved:

    public function _fixtures()
    {
        return [
            'profiles' => [
                'class' => UserFixture::className(),
                'db' => 'elasticsearch',
                'index' => 'users_test'
            ]
        ];
    }

3.) There is unfortunately a lack of documentation about /yii2-elasticsearch/ActiveFixture. This can lead to assumptions that are wrong. So it seams, there is no sql DB needed for the test. But if you use /yii2-elasticsearch/ActiveFixture out of the box, it generates an SQL Error [yii\db\Exception] SQLSTATE[HY000] [2002]. This is confusing.
But it works, if you define the elasticsearch connection array from the test-config. On the other hand, you need to define an dedicated indexname, like user_test for your test (see 2.). But this index name is not injected into the test. SO the test himself still tries to access the index name from the application, which is user not the index where the fixture resists (user_test). The indexname is loaded from Model::index(), like User::index(), which can not be mocked, because it’s an static function. :frowning:

The unresolved question, therefore, is: how can I focus the unit test to the index, where the fixture-data exits?