Complete phpunit tests

This commit is contained in:
Bubka 2020-11-05 22:54:49 +01:00
parent 67fa859b2a
commit 785332f62c
6 changed files with 838 additions and 8 deletions

View File

@ -0,0 +1,24 @@
<?php
/* @var $group \Illuminate\Database\Eloquent\Factory */
use App\Group;
use Faker\Generator as Faker;
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| This directory should contain each of the model factory definitions for
| your application. Factories provide a convenient way to generate new
| model instances for testing / seeding your application's database.
|
*/
$factory->define(Group::class, function (Faker $faker) {
return [
'name' => $faker->word,
];
});

View File

@ -0,0 +1,294 @@
<?php
namespace Tests\Feature;
use App\User;
use App\Group;
use Tests\TestCase;
use App\TwoFAccount;
class AccountsGroupTest extends TestCase
{
/** @var \App\User, \App\TwoFAccount, \App\Group */
protected $user, $twofaccounts, $group;
/**
* @test
*/
public function setUp(): void
{
parent::setUp();
$this->user = factory(User::class)->create();
$this->twofaccounts = factory(Twofaccount::class, 3)->create();
$this->group = factory(Group::class)->create();
}
/**
* test 2FAccounts creation associated to a user group via API
*
* @test
*/
public function testCreateAccountWhenDefaultGroupIsASpecificOne()
{
// Set the default group to the existing one
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'defaultGroup' => $this->group->id,
])
->assertStatus(200);
// Create the account
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/twofaccounts', [
'service' => 'testCreation',
'account' => 'test@example.org',
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
'icon' => 'test.png',
])
->assertStatus(201)
->assertJsonFragment([
'group_id' => $this->group->id
]);
}
/**
* test 2FAccounts creation associated to a user group via API
*
* @test
*/
public function testCreateAccountWhenDefaultGroupIsSetToActiveOne()
{
// Set the default group as the active one
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'defaultGroup' => -1,
])
->assertStatus(200);
// Set the active group
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'activeGroup' => 1,
])
->assertStatus(200);
// Create the account
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/twofaccounts', [
'service' => 'testCreation',
'account' => 'test@example.org',
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
'icon' => 'test.png',
])
->assertStatus(201)
->assertJsonFragment([
'group_id' => 1
]);
}
/**
* test 2FAccounts creation associated to a user group via API
*
* @test
*/
public function testCreateAccountWhenDefaultIsNoGroup()
{
// Set the default group to No group
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'defaultGroup' => 0,
])
->assertStatus(200);
// Create the account
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/twofaccounts', [
'service' => 'testCreation',
'account' => 'test@example.org',
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
'icon' => 'test.png',
])
->assertStatus(201)
->assertJsonMissing([
'group_id' => null
]);
}
/**
* test 2FAccounts creation associated to a user group via API
*
* @test
*/
public function testCreateAccountWhenDefaultGroupDoNotExists()
{
// Set the default group to a non existing one
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'defaultGroup' => 1000,
])
->assertStatus(200);
// Create the account
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/twofaccounts', [
'service' => 'testCreation',
'account' => 'test@example.org',
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
'icon' => 'test.png',
])
->assertStatus(201)
->assertJsonMissing([
'group_id' => null
]);
}
/**
* test 2FAccounts association with a user group via API
*
* @test
*/
public function testMoveAccountsToGroup()
{
// We associate all 3 accounts to the user group
$response = $this->actingAs($this->user, 'api')
->json('PATCH', '/api/group/accounts/', [
'groupId' => $this->group->id,
'accountsIds' => [1,2,3]
])
->assertJsonFragment([
'id' => $this->group->id,
'name' => $this->group->name
])
->assertStatus(200);
// test if the accounts have the correct foreign key
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/1')
->assertJsonFragment([
'group_id' => (string) $this->group->id
]);
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/2')
->assertJsonFragment([
'group_id' => (string) $this->group->id
]);
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/3')
->assertJsonFragment([
'group_id' => (string) $this->group->id
]);
// test the accounts count of the user group
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/groups')
->assertJsonFragment([
'twofaccounts_count' => '3'
]
);
}
/**
* test 2FAccounts are scoped when an active group is set via API
*
* @test
*/
public function testScopedAccounts()
{
// Set the default group to the existing one
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'activeGroup' => $this->group->id,
])
->assertStatus(200);
// We associate 2 accounts to the group
$response = $this->actingAs($this->user, 'api')
->json('PATCH', '/api/group/accounts/', [
'groupId' => $this->group->id,
'accountsIds' => [1,2]
])
->assertStatus(200);
// Test accounts index is scoped with active group
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts')
->assertJsonCount(2)
->assertJsonFragment([
'id' => 1,
'id' => 2
]);
}
/**
* test 2FAccounts association with a missing group via API
*
* @test
*/
public function testMoveAccountsToMissingGroup()
{
$response = $this->actingAs($this->user, 'api')
->json('PATCH', '/api/group/accounts/', [
'groupId' => '1000',
'accountsIds' => $this->twofaccounts->keys()
])
->assertStatus(404);
}
/**
* test 2FAccounts association with the pseudo group via API
*
* @test
*/
public function testMoveAccountsToPseudoGroup()
{
$response = $this->actingAs($this->user, 'api')
->json('PATCH', '/api/group/accounts/', [
'groupId' => $this->group->id,
'accountsIds' => [1,2,3]
]);
// We associate the first account to the pseudo group
$response = $this->actingAs($this->user, 'api')
->json('PATCH', '/api/group/accounts/', [
'groupId' => 0,
'accountsIds' => [1]
])
->assertStatus(200);
// test if the forein keys are set to NULL
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/1')
->assertJsonFragment([
'group_id' => null
]);
// test the accounts count of the group
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/groups')
->assertJsonFragment([
'twofaccounts_count' => '3', // the 3 accounts for 'all'
'twofaccounts_count' => '2' // the 2 accounts that remain in the user group
]
);
}
}

View File

@ -0,0 +1,279 @@
<?php
namespace Tests\Feature;
use App\User;
use Tests\TestCase;
use App\TwoFAccount;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Crypt;
class ProtectDbTest extends TestCase
{
/** @var \App\User, \App\TwoFAccount */
protected $user, $twofaccounts;
/**
* @test
*/
public function setUp(): void
{
parent::setUp();
$this->user = factory(User::class)->create();
$this->twofaccount = factory(Twofaccount::class,)->create([
'service' => 'test',
'account' => 'test@test.com',
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test',
]);
$this->twofaccountAlt = factory(Twofaccount::class,)->create([
'service' => 'testAlt',
'account' => 'testAlt@test.com',
'uri' => 'otpauth://totp/testAlt@test.com?secret=A4GRFHVVRBGY7UIW&issuer=testAlt',
]);
}
/**
* test db encryption via API
*
* @test
*/
public function testDbEncryption()
{
// Encrypt db
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'useEncryption' => true,
])
->assertStatus(200);
// Get the raw encrypted records
$encrypted = DB::table('twofaccounts')->find($this->twofaccount->id);
$encryptedAlt = DB::table('twofaccounts')->find($this->twofaccountAlt->id);
// Get the accounts via API and check their consistency with raw data
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/' . $this->twofaccount->id)
->assertStatus(200)
->assertJsonFragment([
'service' => 'test',
'account' => Crypt::decryptString($encrypted->account),
'uri' => Crypt::decryptString($encrypted->uri),
]);
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/' . $this->twofaccountAlt->id)
->assertStatus(200)
->assertJsonFragment([
'service' => 'testAlt',
'account' => Crypt::decryptString($encryptedAlt->account),
'uri' => Crypt::decryptString($encryptedAlt->uri),
]);
}
/**
* test Account update on protected DB via API
*
* @test
*/
public function testTwoFAccountUpdateOnProtectedDB()
{
// Encrypt db
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'useEncryption' => true,
])
->assertStatus(200);
// Only the Account field is encrypted
$response = $this->actingAs($this->user, 'api')
->json('PUT', '/api/twofaccounts/' . $this->twofaccount->id, [
'service' => 'testUpdate',
'account' => 'testUpdate@test.com',
])
->assertStatus(200)
->assertJsonFragment([
'id' => 1,
'service' => 'testUpdate',
'account' => 'testUpdate@test.com',
]);
}
/**
* test db encryption via API
*
* @test
*/
public function testPreventDbEncryptionOnDbAlreadyEncrypted()
{
// Encrypt db
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'useEncryption' => true,
]);
// Set the option again to force another encryption pass
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'useEncryption' => true,
]);
// Get the account, it should be readable
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/' . $this->twofaccount->id)
->assertStatus(200)
->assertJsonFragment([
'service' => 'test',
'account' => 'test@test.com',
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test',
]);
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/' . $this->twofaccountAlt->id)
->assertStatus(200)
->assertJsonFragment([
'service' => 'testAlt',
'account' => 'testAlt@test.com',
'uri' => 'otpauth://totp/testAlt@test.com?secret=A4GRFHVVRBGY7UIW&issuer=testAlt',
]);
}
/**
* test db deciphering via API
*
* @test
*/
public function testDbDeciphering()
{
// Encrypt db
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'useEncryption' => true,
]);
// Decipher db
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'useEncryption' => false,
])
->assertStatus(200);
// Get the accounts, they should be readable
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/' . $this->twofaccount->id)
->assertStatus(200)
->assertJsonFragment([
'service' => 'test',
'account' => 'test@test.com',
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHVVRBGY7UIW&issuer=test',
]);
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/' . $this->twofaccountAlt->id)
->assertStatus(200)
->assertJsonFragment([
'service' => 'testAlt',
'account' => 'testAlt@test.com',
'uri' => 'otpauth://totp/testAlt@test.com?secret=A4GRFHVVRBGY7UIW&issuer=testAlt',
]);
}
/**
* test Protect DB option not being persisted if encryption fails via API
*
* @test
*/
public function testAbortEncryptionIfSomethingGoesWrong()
{
// Set no APP_KEY to break Laravel encryption capability
config(['app.key' => '']);
// Decipher db
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'useEncryption' => true,
])
->assertStatus(422);
// Check ProtectDB option is not active
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/settings/options')
->assertJsonFragment([
'useEncryption' => false
]);
}
/**
* test Protect DB option not being persisted if decyphering fails via API
*
* @test
*/
public function testAbortDecipheringIfSomethingGoesWrong()
{
// Encrypt db
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'useEncryption' => true,
])
->assertStatus(200);
// alter the ciphertext to make deciphering impossible
$affected = DB::table('twofaccounts')
->where('id', 1)
->update(['account' => 'xxxxxxxxx', 'uri' => 'yyyyyyyyy']);
// Decipher db
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'useEncryption' => false,
])
->assertStatus(422);
// Check ProtectDB option has been restored
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/settings/options')
->assertJsonFragment([
'useEncryption' => true
]);
}
/**
* test bad payload don't breaks anything via API
*
* @test
*/
public function testBadPayloadDontBreakEncryptedAccountFetching()
{
// Encrypt db
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/settings/options', [
'useEncryption' => true,
])
->assertStatus(200);
// break the payload
DB::table('twofaccounts')
->where('id', 1)
->update([
'account' => 'IAmYourFather',
'uri' => 'YouShallNotPass',
]);
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/1')
->assertStatus(200)
->assertJsonFragment([
'uri' => '*encrypted*',
'account' => '*encrypted*',
]);
}
}

175
tests/Unit/GroupTest.php Normal file
View File

@ -0,0 +1,175 @@
<?php
namespace Tests\Unit;
use App\User;
use App\Group;
use Tests\TestCase;
use App\TwoFAccount;
class GroupTest extends TestCase
{
/** @var \App\User */
protected $user;
/**
* @test
*/
public function setUp(): void
{
parent::setUp();
$this->user = factory(User::class)->create();
}
/**
* test Group display via API
*
* @test
*/
public function testGroupDisplay()
{
$group = factory(Group::class)->create([
'name' => 'My group',
]);
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/groups/' . $group->id)
->assertStatus(200)
->assertJsonFragment([
'name' => 'My group',
]);
}
/**
* test missing Group display via API
*
* @test
*/
public function testMissingGroupDisplay()
{
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/groups/1000')
->assertStatus(404);
}
/**
* test Group creation via API
*
* @test
*/
public function testGroupCreation()
{
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/groups', [
'name' => 'My second group',
])
->assertStatus(201)
->assertJsonFragment([
'name' => 'My second group',
]);
}
/**
* test Group creation when fields are empty via API
*
* @test
*/
public function testGroupCreationWithEmptyRequest()
{
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/groups', [
'name' => '',
])
->assertStatus(422);
}
/**
* test Group update via API
*
* @test
*/
public function testGroupUpdate()
{
$group = factory(Group::class)->create();
$response = $this->actingAs($this->user, 'api')
->json('PUT', '/api/groups/' . $group->id, [
'name' => 'name updated',
])
->assertStatus(200)
->assertJsonFragment([
'name' => 'name updated',
]);
}
/**
* test Group update via API
*
* @test
*/
public function testGroupUpdateOfMissingGroup()
{
$group = factory(Group::class)->create();
$id = $group->id;
$group->delete();
$response = $this->actingAs($this->user, 'api')
->json('PUT', '/api/groups/' . $id, [
'name' => 'testUpdate',
])
->assertStatus(404);
}
/**
* test Group index fetching via API
*
* @test
*/
public function testGroupIndexListing()
{
factory(Group::class, 3)->create();
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/groups')
->assertStatus(200)
->assertJsonCount(4, $key = null)
->assertJsonStructure([
'*' => [
'id',
'name',
'twofaccounts_count',
'isActive',
]
])
->assertJsonFragment([
'id' => 0,
'name' => 'All',
]);
}
/**
* test Group deletion via API
*
* @test
*/
public function testGroupDeletion()
{
$group = factory(Group::class)->create();
$response = $this->actingAs($this->user, 'api')
->json('DELETE', '/api/groups/' . $group->id)
->assertStatus(204);
}
}

View File

@ -2,13 +2,15 @@
namespace Tests\Unit;
use App\User;
use Zxing\QrReader;
use Tests\TestCase;
use App\TwoFAccount;
use App\Classes\Options;
use Tests\Classes\LocalFile;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
use Tests\Classes\LocalFile;
use App\Classes\Options;
class QrcodeTest extends TestCase
{
@ -32,7 +34,7 @@ public function testQrcodeDecodeWithMissingImage()
/**
* test delete an uploaded icon via API
* test decode an invalid QR code uplloaded via API
*
* @test
*/
@ -43,9 +45,10 @@ public function testDecodeInvalidQrcode()
$response = $this->withHeaders([
'Content-Type' => 'multipart/form-data',
])
->json('POST', '/api/qrcode/decode', [
'qrcode' => $file
]);
->json('POST', '/api/qrcode/decode', [
'qrcode' => $file,
'inputFormat' => 'fileUpload'
]);
$response->assertStatus(422);
}
@ -91,7 +94,8 @@ public function testDecodeValidQrcode()
$response = $this->withHeaders(['Content-Type' => 'multipart/form-data'])
->json('POST', '/api/qrcode/decode', [
'qrcode' => $file
'qrcode' => $file,
'inputFormat' => 'fileUpload'
]);
$response->assertStatus(200)

View File

@ -5,6 +5,7 @@
use App\User;
use Tests\TestCase;
use App\TwoFAccount;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
class TwoFAccountTest extends TestCase
@ -126,6 +127,37 @@ public function testTwoFAccountCreationWithInvalidTOTP()
}
/**
* test otpType is null in case of invalid uri via API
*
* @test
*/
public function testOtpTypeIsNullForAccountWithInvalidUri()
{
$response = $this->actingAs($this->user, 'api')
->json('POST', '/api/twofaccounts', [
'service' => 'testCreation',
'account' => 'test@example.org',
'uri' => 'otpauth://totp/test@test.com?secret=A4GRFHZVRBGY7UIW&issuer=test',
'icon' => 'test.png',
])
->assertStatus(201);
DB::table('twofaccounts')
->where('id', 1)
->update([
'uri' => 'iCanHasCheeseBurger',
]);
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/twofaccounts/1')
->assertStatus(200)
->assertJsonFragment([
'otpType' => null,
]);
}
/**
* test TOTP generation for a given existing account via API
*
@ -318,4 +350,26 @@ public function testTwoFAccountReorder()
'orderedIds' => [3,2,1]])
->assertStatus(200);
}
/**
* test show QR code via API
*
* @test
*/
public function testShowQRCode()
{
$twofaccount = factory(TwoFAccount::class)->create();
$response = $this->actingAs($this->user, 'api')
->json('GET', '/api/qrcode/' . $twofaccount->id)
->assertJsonStructure([
'qrcode',
])
->assertStatus(200);
$this->assertStringStartsWith('data:image/png;base64', $response->getData()->qrcode);
}
}