Токен-аутентификация Sanctum (login/logout по устройствам), эндпоинты /api/v1 для зон/устройств/правил автоматизации с тем же RBAC (owner/viewer), что и в веб-версии — контроллеры переиспользуют существующие Policy и FormRequest. Устройства отдают живой статус из Device Shadow (Redis) и историю телеметрии из ClickHouse, плюс управление (turn-on/turn-off/set-level) через device-control-service.
83 lines
2.4 KiB
PHP
83 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Api\V1;
|
|
|
|
use App\Enums\UserRole;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class AuthTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_login_issues_a_token(): void
|
|
{
|
|
$user = User::factory()->create([
|
|
'role' => UserRole::Owner,
|
|
'password' => bcrypt('secret1234'),
|
|
]);
|
|
|
|
$response = $this->postJson('/api/v1/login', [
|
|
'email' => $user->email,
|
|
'password' => 'secret1234',
|
|
'device_name' => 'iphone-15',
|
|
]);
|
|
|
|
$response->assertOk();
|
|
$response->assertJsonStructure(['token', 'user' => ['id', 'name', 'email', 'role']]);
|
|
$this->assertDatabaseHas('personal_access_tokens', [
|
|
'tokenable_id' => $user->id,
|
|
'name' => 'iphone-15',
|
|
]);
|
|
}
|
|
|
|
public function test_login_rejects_wrong_password(): void
|
|
{
|
|
$user = User::factory()->create(['password' => bcrypt('secret1234')]);
|
|
|
|
$response = $this->postJson('/api/v1/login', [
|
|
'email' => $user->email,
|
|
'password' => 'wrong-password',
|
|
'device_name' => 'iphone-15',
|
|
]);
|
|
|
|
$response->assertStatus(422);
|
|
$response->assertJsonValidationErrors('email');
|
|
}
|
|
|
|
public function test_authenticated_token_can_reach_protected_route(): void
|
|
{
|
|
$user = User::factory()->create(['password' => bcrypt('secret1234')]);
|
|
|
|
$token = $this->postJson('/api/v1/login', [
|
|
'email' => $user->email,
|
|
'password' => 'secret1234',
|
|
'device_name' => 'iphone-15',
|
|
])->json('token');
|
|
|
|
$this->withHeader('Authorization', "Bearer {$token}")
|
|
->getJson('/api/v1/me')
|
|
->assertOk()
|
|
->assertJsonPath('data.email', $user->email);
|
|
}
|
|
|
|
public function test_logout_revokes_the_current_token(): void
|
|
{
|
|
$user = User::factory()->create(['password' => bcrypt('secret1234')]);
|
|
|
|
$tokenModel = $user->createToken('iphone-15');
|
|
|
|
$this->withHeader('Authorization', "Bearer {$tokenModel->plainTextToken}")
|
|
->postJson('/api/v1/logout')
|
|
->assertNoContent();
|
|
|
|
$this->assertDatabaseMissing('personal_access_tokens', ['id' => $tokenModel->accessToken->id]);
|
|
}
|
|
|
|
public function test_guest_cannot_reach_protected_route(): void
|
|
{
|
|
$this->getJson('/api/v1/me')->assertUnauthorized();
|
|
}
|
|
}
|