Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration Testing (SQLite Mock) #15

Merged
merged 7 commits into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Test

on: [push]
env:
APP_KEY: ${{ secrets.TESTING_KEY }}

jobs:
feature-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install dependencies
uses: php-actions/composer@v6
- name: phpunit
uses: php-actions/phpunit@v3
with:
php_version: 7.3
2 changes: 1 addition & 1 deletion app/Http/Controllers/UploadController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function upload(Request $request)

$uploadName = $request->name;
$description = $request->description;
$filename = date('Ymd_His') . '-mismatch-upload.' . $request->user()->mw_userid . '.csv';
$filename = now()->format('Ymd_His') . '-mismatch-upload.' . $request->user()->mw_userid . '.csv';
$request->file('mismatchFile')->storeAs('mismatch-files', $filename);

return response([
Expand Down
2 changes: 1 addition & 1 deletion app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ class User extends Authenticatable
public function canUpload() : bool
{
//TODO replace this with proper allow list
return mt_rand(0, 1);
return 1;
}
}
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ services:
- sail
depends_on:
- mariadb

mariadb:
image: 'mariadb:10'
ports:
Expand All @@ -37,6 +38,7 @@ services:
test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
retries: 3
timeout: 5s

networks:
sail:
driver: bridge
Expand Down
29 changes: 29 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- [Destroy all the things](#destroy-all-the-things)
- [Working with OAuth](#oauth)
- [PHP Linting](#phpcs)
- [Testing](#testing)
- [Troubleshooting](#troubleshooting)
- [Address already in use](#address-already-in-use)
- [OAuth Error retrieving temporary credentials](#oauth-error-retrieving-temporary-credentials)
Expand Down Expand Up @@ -140,6 +141,34 @@ To fix style errors automatically run: `sail composer run fix`

Note: Laravel uses the [PSR2](https://www.php-fig.org/psr/psr-2/) Standard which expects camel caps method names. So you might get the error: `Method name my_method() is not in camel caps` if you scaffold your application. The recommendation there is to change the method names to camel case.

## Testing <a id="testing"></a>

The Laravel framework supports two types of testing: unit and feature tests. In contrast to unit tests, feature tests will boot your Laravel application and therefore are able to access your application's database and other framework services. Mismatch finder uses an in-memory SQLite database for testing, so that the feature tests will leave your mariadb instance untouched. You can find the config settings for sqlite in `phpunit.xml`:
```
<php>
[...]
<server name="DB_CONNECTION" value="sqlite"/>
<server name="DB_DATABASE" value=":memory:"/>
[...]
</php>
```

Simply run `# sail artisan test` to start both unit and integration tests:

```
$ sail artisan test

PASS Tests\Unit\ExampleTest
✓ example

PASS Tests\Feature\ExampleTest
✓ example

Tests: 2 passed
Time: 0.16s
```


## Troubleshooting <a id="troubleshooting"></a>

### Address already in use
Expand Down
4 changes: 2 additions & 2 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<!-- <server name="DB_CONNECTION" value="sqlite"/> -->
<!-- <server name="DB_DATABASE" value=":memory:"/> -->
<server name="DB_CONNECTION" value="sqlite"/>
<server name="DB_DATABASE" value=":memory:"/>
<server name="MAIL_MAILER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
Expand Down
115 changes: 115 additions & 0 deletions tests/Feature/ApiRouteTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
use Laravel\Sanctum\Sanctum;

class ApiRouteTest extends TestCase
{
// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps

use RefreshDatabase;

/**
* Test non authenticated api/user route
*
* @return void
*/
public function test_nonAuthenticated_api_user_willRedirect()
{
$response = $this->get('/api/user');
$response->assertStatus(302);
}

/**
* Test the /api/upload route's get method
*
* @return void
*/
public function test_get_upload_wrongMethod()
{
$response = $this->get('/api/upload');
$response->assertStatus(405);
}

/**
* Test the /api/user route
*
* @return void
*/
// phpcs:ignore
public function test_user_returns_user_data()
{
$user = User::factory()->create();

Sanctum::actingAs($user);
$response = $this->get('/api/user');

$response->assertStatus(200)
->assertJsonStructure([
'username',
'mw_userid',
'updated_at',
'created_at',
'id'
]);
}

// TODO: re-work after merging of
// https://github.com/wmde/wikidata-mismatch-finder/pull/12

/**
* Test the /api/upload route
*
* @return void
*/
// phpcs:ignore
public function test_upload_file()
{
$this->travelTo(now()); // freezes time to ensure correct filenames

$user = User::factory()->create();

Storage::fake('local');
$file = UploadedFile::fake()->create('mismatchFile.csv');

Sanctum::actingAs($user);

$response = $this->post('/api/upload', ['mismatchFile' => $file]);

guergana marked this conversation as resolved.
Show resolved Hide resolved
$response->assertStatus(201);

$filename = now()->format('Ymd_His') . '-mismatch-upload.' . $user->getAttribute('mw_userid') . '.csv';

Storage::disk('local')->assertExists('mismatch-files/' . $filename);

$this->travelBack(); // resumes the clock
}

/**
* Test the /api/upload route
*
* @return void
*/
// phpcs:ignore
public function test_upload_file_not_bigger_10Mb()
{
$user = User::factory()->create();

Storage::fake('mismatchFiles');
$sizeInKilobytes = 12000; //maximum file size is 10000

$file = UploadedFile::fake()->create('mismatchFile.csv', $sizeInKilobytes);

Sanctum::actingAs($user);

$response = $this->post('/api/upload', ['mismatchFile' => $file]);

$response->assertStatus(302);
}
}
107 changes: 107 additions & 0 deletions tests/Feature/AuthTokenTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AuthTokenTest extends TestCase
{
// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps

use RefreshDatabase;

public function authRoutesProvider()
{
return [
['/auth/token'],
['/auth/createToken'],
['/auth/revokeToken']
];
}

/**
* Test non authenticated auth routes
*
* @return void
* @dataProvider authRoutesProvider
*/
public function test_nonAuthenticated_willRedirect($authRoute)
{
$response = $this->get($authRoute);
$response->assertStatus(302);
}

/**
* Test the /auth/token route
*
* @return void
*/
// phpcs:ignore
public function test_token_returnsShowToken()
{
$user = User::factory()->create();
$response = $this->actingAs($user)
->get('/auth/token');

$response->assertStatus(200);
$response->assertViewIs('showToken');
}

/**
* Test the /auth/token route when no token exists
*
* @return void
*/
public function test_createTokenWhenNoneExists_returnsNewToken()
{
$user = User::factory()->create();
$response = $this->actingAs($user)
->get('/auth/createToken');

$response->assertStatus(200);
$response->assertViewIs('newToken');
$response->assertViewHas('newToken');

// check token by loading the User from db
$this->assertCount(1, User::find($user->id)->tokens);
}

/**
* Test the /auth/createToken route when a token exists already
*
* @return void
*/
public function test_createTokenWhenOneExists_returnsRedirect()
{
$user = User::factory()->create();
$user->createToken('testToken');

$response = $this->actingAs($user)
->get('/auth/createToken');

$response->assertStatus(302);

// check token by loading the User from db
$this->assertCount(1, User::find($user->id)->tokens);
}

/**
* Test the /auth/revokeToken route
*
* @return void
*/
public function test_revokeToken_returnsRedirect()
{
$user = User::factory()->create();
$user->createToken('testToken');
$response = $this->actingAs($user)
->get('/auth/revokeToken?id=' . $user->tokens->first()->id);

$response->assertStatus(302);

// check tokens by loading the User from db
$this->assertEmpty(User::find($user->id)->tokens);
}
}
24 changes: 24 additions & 0 deletions tests/Feature/WebRouteTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Tests\Feature;

use Tests\TestCase;

class WebRouteTest extends TestCase
{
// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps

/**
* Test the /auth/token route
*
* @return void
*/
// phpcs:ignore
public function test_welcome_route()
{
$response = $this->get('/');

$response->assertStatus(200);
$response->assertViewIs('welcome');
guergana marked this conversation as resolved.
Show resolved Hide resolved
}
}