Skip to content

Commit

Permalink
Switch tests to SQLite to remove the need for MySQL server (#2616)
Browse files Browse the repository at this point in the history
  • Loading branch information
GromNaN committed Sep 13, 2023
1 parent 9956dc5 commit c112ef7
Show file tree
Hide file tree
Showing 16 changed files with 103 additions and 171 deletions.
11 changes: 0 additions & 11 deletions .github/workflows/build-ci.yml
Expand Up @@ -22,15 +22,6 @@ jobs:
php:
- '8.1'
- '8.2'
services:
mysql:
image: mysql:8.0
ports:
- 3307:3306
env:
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
MYSQL_DATABASE: 'unittest'
MYSQL_ROOT_PASSWORD:

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -77,8 +68,6 @@ jobs:
./vendor/bin/phpunit --coverage-clover coverage.xml
env:
MONGODB_URI: 'mongodb://127.0.0.1/?replicaSet=rs'
MYSQL_HOST: 0.0.0.0
MYSQL_PORT: 3307
- uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
3 changes: 1 addition & 2 deletions CONTRIBUTING.md
Expand Up @@ -39,11 +39,10 @@ Before submitting a pull request:
## Run Tests

The full test suite requires PHP cli with mongodb extension, a running MongoDB server and a running MySQL server.
Tests requiring MySQL will be skipped if it is not running.
Duplicate the `phpunit.xml.dist` file to `phpunit.xml` and edit the environment variables to match your setup.

```bash
$ docker-compose up -d mongodb mysql
$ docker-compose up -d mongodb
$ docker-compose run tests
```

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Expand Up @@ -6,7 +6,7 @@ RUN apt-get update && \
apt-get install -y autoconf pkg-config libssl-dev git unzip libzip-dev zlib1g-dev && \
pecl install mongodb && docker-php-ext-enable mongodb && \
pecl install xdebug && docker-php-ext-enable xdebug && \
docker-php-ext-install -j$(nproc) pdo_mysql zip
docker-php-ext-install -j$(nproc) zip

COPY --from=composer:2.6.2 /usr/bin/composer /usr/local/bin/composer

Expand Down
13 changes: 0 additions & 13 deletions docker-compose.yml
Expand Up @@ -12,22 +12,9 @@ services:
working_dir: /code
environment:
MONGODB_URI: 'mongodb://mongodb/'
MYSQL_HOST: 'mysql'
depends_on:
mongodb:
condition: service_healthy
mysql:
condition: service_started

mysql:
container_name: mysql
image: mysql:8.0
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD:
MYSQL_DATABASE: unittest
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'

mongodb:
container_name: mongodb
Expand Down
2 changes: 1 addition & 1 deletion docs/eloquent-models.md
Expand Up @@ -427,7 +427,7 @@ If you want this functionality to work both ways, your SQL-models will need to u

**This functionality only works for `hasOne`, `hasMany` and `belongsTo`.**

The MySQL model should use the `HybridRelations` trait:
The SQL model should use the `HybridRelations` trait:

```php
use MongoDB\Laravel\Eloquent\HybridRelations;
Expand Down
34 changes: 2 additions & 32 deletions phpunit.xml.dist
Expand Up @@ -11,44 +11,14 @@
>
<coverage/>
<testsuites>
<testsuite name="all">
<testsuite name="Test Suite">
<directory>tests/</directory>
</testsuite>
<testsuite name="schema">
<file>tests/SchemaTest.php</file>
</testsuite>
<testsuite name="seeder">
<file>tests/SeederTest.php</file>
</testsuite>
<testsuite name="builder">
<file>tests/QueryBuilderTest.php</file>
<file>tests/QueryTest.php</file>
</testsuite>
<testsuite name="transaction">
<file>tests/TransactionTest.php</file>
</testsuite>
<testsuite name="model">
<file>tests/ModelTest.php</file>
<file>tests/RelationsTest.php</file>
</testsuite>
<testsuite name="relations">
<file>tests/RelationsTest.php</file>
<file>tests/EmbeddedRelationsTest.php</file>
</testsuite>
<testsuite name="mysqlrelations">
<file>tests/RelationsTest.php</file>
</testsuite>
<testsuite name="validation">
<file>tests/ValidationTest.php</file>
</testsuite>
</testsuites>
<php>
<env name="MONGODB_URI" value="mongodb://mongodb/"/>
<env name="MONGODB_DATABASE" value="unittest"/>
<env name="MYSQL_HOST" value="mysql"/>
<env name="MYSQL_PORT" value="3306"/>
<env name="MYSQL_DATABASE" value="unittest"/>
<env name="MYSQL_USERNAME" value="root"/>
<env name="SQLITE_DATABASE" value=":memory:"/>
<env name="QUEUE_CONNECTION" value="database"/>
</php>
<source>
Expand Down
2 changes: 1 addition & 1 deletion src/Query/Builder.php
Expand Up @@ -276,7 +276,7 @@ public function toMql(): array
$group['_id'][$column] = '$' . $column;

// When grouping, also add the $last operator to each grouped field,
// this mimics MySQL's behaviour a bit.
// this mimics SQL's behaviour a bit.
$group[$column] = ['$last' => '$' . $column];
}

Expand Down
118 changes: 59 additions & 59 deletions tests/HybridRelationsTest.php
Expand Up @@ -4,13 +4,13 @@

namespace MongoDB\Laravel\Tests;

use Illuminate\Database\MySqlConnection;
use Illuminate\Database\SQLiteConnection;
use Illuminate\Support\Facades\DB;
use MongoDB\Laravel\Tests\Models\Book;
use MongoDB\Laravel\Tests\Models\MysqlBook;
use MongoDB\Laravel\Tests\Models\MysqlRole;
use MongoDB\Laravel\Tests\Models\MysqlUser;
use MongoDB\Laravel\Tests\Models\Role;
use MongoDB\Laravel\Tests\Models\SqlBook;
use MongoDB\Laravel\Tests\Models\SqlRole;
use MongoDB\Laravel\Tests\Models\SqlUser;
use MongoDB\Laravel\Tests\Models\User;
use PDOException;

Expand All @@ -21,90 +21,90 @@ public function setUp(): void
parent::setUp();

try {
DB::connection('mysql')->select('SELECT 1');
DB::connection('sqlite')->select('SELECT 1');
} catch (PDOException) {
$this->markTestSkipped('MySQL connection is not available.');
$this->markTestSkipped('SQLite connection is not available.');
}

MysqlUser::executeSchema();
MysqlBook::executeSchema();
MysqlRole::executeSchema();
SqlUser::executeSchema();
SqlBook::executeSchema();
SqlRole::executeSchema();
}

public function tearDown(): void
{
MysqlUser::truncate();
MysqlBook::truncate();
MysqlRole::truncate();
SqlUser::truncate();
SqlBook::truncate();
SqlRole::truncate();
}

public function testMysqlRelations()
public function testSqlRelations()
{
$user = new MysqlUser();
$this->assertInstanceOf(MysqlUser::class, $user);
$this->assertInstanceOf(MySqlConnection::class, $user->getConnection());
$user = new SqlUser();
$this->assertInstanceOf(SqlUser::class, $user);
$this->assertInstanceOf(SQLiteConnection::class, $user->getConnection());

// Mysql User
// SQL User
$user->name = 'John Doe';
$user->save();
$this->assertIsInt($user->id);

// SQL has many
$book = new Book(['title' => 'Game of Thrones']);
$user->books()->save($book);
$user = MysqlUser::find($user->id); // refetch
$user = SqlUser::find($user->id); // refetch
$this->assertCount(1, $user->books);

// MongoDB belongs to
$book = $user->books()->first(); // refetch
$this->assertEquals('John Doe', $book->mysqlAuthor->name);
$this->assertEquals('John Doe', $book->sqlAuthor->name);

// SQL has one
$role = new Role(['type' => 'admin']);
$user->role()->save($role);
$user = MysqlUser::find($user->id); // refetch
$user = SqlUser::find($user->id); // refetch
$this->assertEquals('admin', $user->role->type);

// MongoDB belongs to
$role = $user->role()->first(); // refetch
$this->assertEquals('John Doe', $role->mysqlUser->name);
$this->assertEquals('John Doe', $role->sqlUser->name);

// MongoDB User
$user = new User();
$user->name = 'John Doe';
$user->save();

// MongoDB has many
$book = new MysqlBook(['title' => 'Game of Thrones']);
$user->mysqlBooks()->save($book);
$book = new SqlBook(['title' => 'Game of Thrones']);
$user->sqlBooks()->save($book);
$user = User::find($user->_id); // refetch
$this->assertCount(1, $user->mysqlBooks);
$this->assertCount(1, $user->sqlBooks);

// SQL belongs to
$book = $user->mysqlBooks()->first(); // refetch
$book = $user->sqlBooks()->first(); // refetch
$this->assertEquals('John Doe', $book->author->name);

// MongoDB has one
$role = new MysqlRole(['type' => 'admin']);
$user->mysqlRole()->save($role);
$role = new SqlRole(['type' => 'admin']);
$user->sqlRole()->save($role);
$user = User::find($user->_id); // refetch
$this->assertEquals('admin', $user->mysqlRole->type);
$this->assertEquals('admin', $user->sqlRole->type);

// SQL belongs to
$role = $user->mysqlRole()->first(); // refetch
$role = $user->sqlRole()->first(); // refetch
$this->assertEquals('John Doe', $role->user->name);
}

public function testHybridWhereHas()
{
$user = new MysqlUser();
$otherUser = new MysqlUser();
$this->assertInstanceOf(MysqlUser::class, $user);
$this->assertInstanceOf(MySqlConnection::class, $user->getConnection());
$this->assertInstanceOf(MysqlUser::class, $otherUser);
$this->assertInstanceOf(MySqlConnection::class, $otherUser->getConnection());

//MySql User
$user = new SqlUser();
$otherUser = new SqlUser();
$this->assertInstanceOf(SqlUser::class, $user);
$this->assertInstanceOf(SQLiteConnection::class, $user->getConnection());
$this->assertInstanceOf(SqlUser::class, $otherUser);
$this->assertInstanceOf(SQLiteConnection::class, $otherUser->getConnection());

// SQL User
$user->name = 'John Doe';
$user->id = 2;
$user->save();
Expand All @@ -130,19 +130,19 @@ public function testHybridWhereHas()
new Book(['title' => 'Harry Planter']),
]);

$users = MysqlUser::whereHas('books', function ($query) {
$users = SqlUser::whereHas('books', function ($query) {
return $query->where('title', 'LIKE', 'Har%');
})->get();

$this->assertEquals(2, $users->count());

$users = MysqlUser::whereHas('books', function ($query) {
$users = SqlUser::whereHas('books', function ($query) {
return $query->where('title', 'LIKE', 'Harry%');
}, '>=', 2)->get();

$this->assertEquals(1, $users->count());

$books = Book::whereHas('mysqlAuthor', function ($query) {
$books = Book::whereHas('sqlAuthor', function ($query) {
return $query->where('name', 'LIKE', 'Other%');
})->get();

Expand All @@ -151,14 +151,14 @@ public function testHybridWhereHas()

public function testHybridWith()
{
$user = new MysqlUser();
$otherUser = new MysqlUser();
$this->assertInstanceOf(MysqlUser::class, $user);
$this->assertInstanceOf(MySqlConnection::class, $user->getConnection());
$this->assertInstanceOf(MysqlUser::class, $otherUser);
$this->assertInstanceOf(MySqlConnection::class, $otherUser->getConnection());

//MySql User
$user = new SqlUser();
$otherUser = new SqlUser();
$this->assertInstanceOf(SqlUser::class, $user);
$this->assertInstanceOf(SQLiteConnection::class, $user->getConnection());
$this->assertInstanceOf(SqlUser::class, $otherUser);
$this->assertInstanceOf(SQLiteConnection::class, $otherUser->getConnection());

// SQL User
$user->name = 'John Doe';
$user->id = 2;
$user->save();
Expand All @@ -171,18 +171,18 @@ public function testHybridWith()
$this->assertIsInt($otherUser->id);
// Clear to start
Book::truncate();
MysqlBook::truncate();
SqlBook::truncate();
// Create books
// Mysql relation
$user->mysqlBooks()->saveMany([
new MysqlBook(['title' => 'Game of Thrones']),
new MysqlBook(['title' => 'Harry Potter']),
// SQL relation
$user->sqlBooks()->saveMany([
new SqlBook(['title' => 'Game of Thrones']),
new SqlBook(['title' => 'Harry Potter']),
]);

$otherUser->mysqlBooks()->saveMany([
new MysqlBook(['title' => 'Harry Plants']),
new MysqlBook(['title' => 'Harveys']),
new MysqlBook(['title' => 'Harry Planter']),
$otherUser->sqlBooks()->saveMany([
new SqlBook(['title' => 'Harry Plants']),
new SqlBook(['title' => 'Harveys']),
new SqlBook(['title' => 'Harry Planter']),
]);
// SQL has many Hybrid
$user->books()->saveMany([
Expand All @@ -196,12 +196,12 @@ public function testHybridWith()
new Book(['title' => 'Harry Planter']),
]);

MysqlUser::with('books')->get()
SqlUser::with('books')->get()
->each(function ($user) {
$this->assertEquals($user->id, $user->books->count());
});

MysqlUser::whereHas('mysqlBooks', function ($query) {
SqlUser::whereHas('sqlBooks', function ($query) {
return $query->where('title', 'LIKE', 'Harry%');
})
->with('books')
Expand Down
4 changes: 2 additions & 2 deletions tests/Models/Book.php
Expand Up @@ -24,8 +24,8 @@ public function author(): BelongsTo
return $this->belongsTo(User::class, 'author_id');
}

public function mysqlAuthor(): BelongsTo
public function sqlAuthor(): BelongsTo
{
return $this->belongsTo(MysqlUser::class, 'author_id');
return $this->belongsTo(SqlUser::class, 'author_id');
}
}
4 changes: 2 additions & 2 deletions tests/Models/Role.php
Expand Up @@ -18,8 +18,8 @@ public function user(): BelongsTo
return $this->belongsTo(User::class);
}

public function mysqlUser(): BelongsTo
public function sqlUser(): BelongsTo
{
return $this->belongsTo(MysqlUser::class);
return $this->belongsTo(SqlUser::class);
}
}

0 comments on commit c112ef7

Please sign in to comment.