Add tests for the Authentication log feature

This commit is contained in:
Bubka 2024-04-16 20:38:05 +02:00
parent ec396b00e8
commit 5a74a37348
2 changed files with 436 additions and 0 deletions

View File

@ -10,6 +10,7 @@
use Illuminate\Auth\Notifications\ResetPassword;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Notification;
@ -19,6 +20,8 @@
use Laravel\Passport\TokenRepository;
use Mockery\MockInterface;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\Data\AuthenticationLogData;
use Tests\FeatureTestCase;
#[CoversClass(UserManagerController::class)]
@ -518,4 +521,278 @@ public function test_demote_the_only_admin_returns_forbidden() : void
])
->assertForbidden();
}
protected function feedAuthenticationLog() : int
{
// Do not change creation order
$this->user->authentications()->create(AuthenticationLogData::beforeLastYear());
$this->user->authentications()->create(AuthenticationLogData::duringLastYear());
$this->user->authentications()->create(AuthenticationLogData::duringLastSixMonth());
$this->user->authentications()->create(AuthenticationLogData::duringLastThreeMonth());
$this->user->authentications()->create(AuthenticationLogData::duringLastMonth());
$this->user->authentications()->create(AuthenticationLogData::noLogin());
$this->user->authentications()->create(AuthenticationLogData::noLogout());
return 7;
}
/**
* @test
*/
public function test_authentications_returns_all_entries() : void
{
$created = $this->feedAuthenticationLog();
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications')
->assertOk()
->assertJsonCount($created);
}
/**
* @test
*/
public function test_authentications_returns_expected_resource() : void
{
$this->user->authentications()->create(AuthenticationLogData::duringLastMonth());
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications')
->assertJsonStructure([
'*' => [
'id',
'ip_address',
'user_agent',
'browser',
'platform',
'device',
'login_at',
'logout_at',
'login_successful',
'duration',
]
]);
}
/**
* @test
*/
public function test_authentications_returns_no_login_entry() : void
{
$this->user->authentications()->create(AuthenticationLogData::noLogin());
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?period=1')
->assertJsonCount(1)
->assertJsonFragment([
'login_at' => null
]);
}
/**
* @test
*/
public function test_authentications_returns_no_logout_entry() : void
{
$this->user->authentications()->create(AuthenticationLogData::noLogout());
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?period=1')
->assertJsonCount(1)
->assertJsonFragment([
'logout_at' => null
]);
}
/**
* @test
*/
public function test_authentications_returns_failed_entry() : void
{
$this->user->authentications()->create(AuthenticationLogData::failedLogin());
$expected = Carbon::parse(AuthenticationLogData::failedLogin()['login_at'])->toDayDateTimeString();
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?period=1')
->assertJsonCount(1)
->assertJsonFragment([
'login_at' => $expected,
'login_successful' => false,
]);
}
/**
* @test
*/
public function test_authentications_returns_last_month_entries() : void
{
$this->feedAuthenticationLog();
$expected = Carbon::parse(AuthenticationLogData::duringLastMonth()['login_at'])->toDayDateTimeString();
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?period=1')
->assertJsonCount(3)
->assertJsonFragment([
'login_at' => $expected
]);
}
/**
* @test
*/
public function test_authentications_returns_last_three_months_entries() : void
{
$this->feedAuthenticationLog();
$expectedOneMonth = Carbon::parse(AuthenticationLogData::duringLastMonth()['login_at'])->toDayDateTimeString();
$expectedThreeMonth = Carbon::parse(AuthenticationLogData::duringLastThreeMonth()['login_at'])->toDayDateTimeString();
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?period=3')
->assertJsonCount(4)
->assertJsonFragment([
'login_at' => $expectedOneMonth
])
->assertJsonFragment([
'login_at' => $expectedThreeMonth
]);
}
/**
* @test
*/
public function test_authentications_returns_last_six_months_entries() : void
{
$this->feedAuthenticationLog();
$expectedOneMonth = Carbon::parse(AuthenticationLogData::duringLastMonth()['login_at'])->toDayDateTimeString();
$expectedThreeMonth = Carbon::parse(AuthenticationLogData::duringLastThreeMonth()['login_at'])->toDayDateTimeString();
$expectedSixMonth = Carbon::parse(AuthenticationLogData::duringLastSixMonth()['login_at'])->toDayDateTimeString();
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?period=6')
->assertJsonCount(5)
->assertJsonFragment([
'login_at' => $expectedOneMonth
])
->assertJsonFragment([
'login_at' => $expectedThreeMonth
])
->assertJsonFragment([
'login_at' => $expectedSixMonth
]);
}
/**
* @test
*/
public function test_authentications_returns_last_year_entries() : void
{
$this->feedAuthenticationLog();
$expectedOneMonth = Carbon::parse(AuthenticationLogData::duringLastMonth()['login_at'])->toDayDateTimeString();
$expectedThreeMonth = Carbon::parse(AuthenticationLogData::duringLastThreeMonth()['login_at'])->toDayDateTimeString();
$expectedSixMonth = Carbon::parse(AuthenticationLogData::duringLastSixMonth()['login_at'])->toDayDateTimeString();
$expectedYear = Carbon::parse(AuthenticationLogData::duringLastYear()['login_at'])->toDayDateTimeString();
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?period=12')
->assertJsonCount(6)
->assertJsonFragment([
'login_at' => $expectedOneMonth
])
->assertJsonFragment([
'login_at' => $expectedThreeMonth
])
->assertJsonFragment([
'login_at' => $expectedSixMonth
])
->assertJsonFragment([
'login_at' => $expectedYear
]);
}
/**
* @test
*/
#[DataProvider('LimitProvider')]
public function test_authentications_returns_limited_entries($limit) : void
{
$this->feedAuthenticationLog();
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?limit=' . $limit)
->assertOk()
->assertJsonCount($limit);
}
/**
* Provide various limit
*/
public static function LimitProvider()
{
return [
'limited to 1' => [1],
'limited to 2' => [2],
'limited to 3' => [3],
];
}
/**
* @test
*/
public function test_authentications_returns_expected_ip_and_useragent_chunks() : void
{
$this->user->authentications()->create([
'ip_address' => '127.0.0.1',
'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
'login_at' => now(),
'login_successful' => true,
'logout_at' => null,
'location' => null,
]);
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?period=1')
->assertJsonFragment([
'ip_address' => '127.0.0.1',
'browser' => 'Firefox',
'platform' => 'Windows',
'device' => 'desktop',
]);
}
/**
* @test
*/
#[DataProvider('invalidQueryParameterProvider')]
public function test_authentications_with_invalid_limit_returns_validation_error($limit) : void
{
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?limit=' . $limit)
->assertStatus(422);
}
/**
* @test
*/
#[DataProvider('invalidQueryParameterProvider')]
public function test_authentications_with_invalid_period_returns_validation_error($period) : void
{
$this->actingAs($this->admin, 'api-guard')
->json('GET', '/api/v1/users/' . $this->user->id . '/authentications?period=' . $period)
->assertStatus(422);
}
/**
* Provide various invalid value to test query parameter
*/
public static function invalidQueryParameterProvider()
{
return [
'empty' => [''],
'null' => ['null'],
'boolean' => ['true'],
'string' => ['string'],
'array' => ['[]'],
];
}
}

View File

@ -0,0 +1,159 @@
<?php
namespace Tests\Data;
class AuthenticationLogData
{
/**
* Indicate that the model should have login date.
*
* @return array
*/
public static function failedLogin()
{
$loginDate = now()->subDays(15);
return [
'ip_address' => fake()->ipv4(),
'user_agent' => fake()->userAgent(),
'login_at' => $loginDate,
'login_successful' => false,
'logout_at' => null,
'location' => null,
];
}
/**
* Indicate that the model should have no login date
*
* @return array
*/
public static function noLogin()
{
return [
'ip_address' => fake()->ipv4(),
'user_agent' => fake()->userAgent(),
'login_at' => null,
'login_successful' => false,
'logout_at' => now(),
'location' => null,
];
}
/**
* Indicate that the model should have no logout date
*
* @return array
*/
public static function noLogout()
{
return [
'ip_address' => fake()->ipv4(),
'user_agent' => fake()->userAgent(),
'login_at' => now(),
'login_successful' => true,
'logout_at' => null,
'location' => null,
];
}
/**
* Indicate that the model should have login during last month
*
* @return array
*/
public static function duringLastMonth()
{
$loginDate = now()->subDays(15);
$logoutDate = $loginDate->addHours(1);
return [
'ip_address' => '127.0.0.1',
'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0',
'login_at' => $loginDate,
'login_successful' => true,
'logout_at' => $logoutDate,
'location' => null,
];
}
/**
* Indicate that the model should have login during last 3 month
*
* @return array
*/
public static function duringLastThreeMonth()
{
$loginDate = now()->subMonths(2);
$logoutDate = $loginDate->addHours(1);
return [
'ip_address' => fake()->ipv4(),
'user_agent' => fake()->userAgent(),
'login_at' => $loginDate,
'login_successful' => true,
'logout_at' => $logoutDate,
'location' => null,
];
}
/**
* Indicate that the model should have login during last 6 month
*
* @return array
*/
public static function duringLastSixMonth()
{
$loginDate = now()->subMonths(4);
$logoutDate = $loginDate->addHours(1);
return [
'ip_address' => fake()->ipv4(),
'user_agent' => fake()->userAgent(),
'login_at' => $loginDate,
'login_successful' => true,
'logout_at' => $logoutDate,
'location' => null,
];
}
/**
* Indicate that the model should have login during last month
*
* @return array
*/
public static function duringLastYear()
{
$loginDate = now()->subMonths(10);
$logoutDate = $loginDate->addHours(1);
return [
'ip_address' => fake()->ipv4(),
'user_agent' => fake()->userAgent(),
'login_at' => $loginDate,
'login_successful' => true,
'logout_at' => $logoutDate,
'location' => null,
];
}
/**
* Indicate that the model should have login during last month
*
* @return array
*/
public static function beforeLastYear()
{
$loginDate = now()->subYears(2);
$logoutDate = $loginDate->addHours(1);
return [
'ip_address' => fake()->ipv4(),
'user_agent' => fake()->userAgent(),
'login_at' => $loginDate,
'login_successful' => true,
'logout_at' => $logoutDate,
'location' => null,
];
}
}