Spaces:
Sleeping
Sleeping
| use Illuminate\Http\Client\Request as HttpRequest; | |
| use Illuminate\Support\Facades\Http; | |
| use Inertia\Testing\AssertableInertia as Assert; | |
| function adminAuthUserCookie(): string | |
| { | |
| return json_encode([ | |
| 'email' => 'admin@example.com', | |
| 'id' => 99, | |
| 'identity_number' => 'ADM001', | |
| 'name' => 'Admin', | |
| 'role' => 'admin', | |
| 'status' => 'active', | |
| ], JSON_THROW_ON_ERROR); | |
| } | |
| test('admin dashboard fetches rag config and users from backend', function () { | |
| config(['services.rag.base_url' => 'https://rag.test/api/v1']); | |
| Http::fake([ | |
| 'https://rag.test/api/v1/admin/rag/config' => Http::response([ | |
| 'llm' => [], | |
| 'path' => 'config/rag.yaml', | |
| 'retrieval' => [], | |
| 'vector_db' => [], | |
| ]), | |
| 'https://rag.test/api/v1/admin/rag/config/llm' => Http::response([ | |
| 'max_tokens' => 2048, | |
| 'model' => 'gpt-test', | |
| 'request_timeout' => 30, | |
| 'temperature' => 0.2, | |
| ]), | |
| 'https://rag.test/api/v1/admin/rag/config/retrieval' => Http::response([ | |
| 'bm25_weight' => 0.2, | |
| 'candidate_pool_size' => 20, | |
| 'dense_weight' => 0.6, | |
| 'enable_reranker' => true, | |
| 'history_turns' => 3, | |
| 'lexical_weight' => 0.2, | |
| 'max_context_chars' => 6000, | |
| 'neighbor_window' => 1, | |
| 'reranker_model' => 'rerank-test', | |
| 'similarity_threshold' => 0.1, | |
| 'top_k' => 4, | |
| ]), | |
| 'https://rag.test/api/v1/admin/rag/config/vector_db' => Http::response([ | |
| 'chunk_overlap' => 100, | |
| 'chunk_size' => 800, | |
| 'embedding_model' => 'embed-test', | |
| ]), | |
| 'https://rag.test/api/v1/user*' => Http::response([ | |
| 'founds' => [ | |
| [ | |
| 'created_at' => '2026-05-01T10:00:00Z', | |
| 'email' => 'admin@example.com', | |
| 'id' => 99, | |
| 'identity_number' => 'ADM001', | |
| 'is_active' => true, | |
| 'is_superuser' => true, | |
| 'name' => 'Admin', | |
| 'role' => 'admin', | |
| 'updated_at' => '2026-05-01T10:00:00Z', | |
| ], | |
| ], | |
| 'search_options' => [], | |
| ]), | |
| ]); | |
| $this->withCookie('sevima_raghub_auth_token', 'token') | |
| ->withCookie('sevima_raghub_auth_user', adminAuthUserCookie()) | |
| ->get(route('admin.dashboard', ['name' => 'Admin'])) | |
| ->assertOk() | |
| ->assertInertia(fn (Assert $page) => $page | |
| ->component('admin/dashboard') | |
| ->where('backendMessage', null) | |
| ->where('ragConfig.path', 'config/rag.yaml') | |
| ->where('ragConfig.llm.model', 'gpt-test') | |
| ->has('users', 1) | |
| ->where('users.0.email', 'admin@example.com') | |
| ->where('userFilters.name', 'Admin')); | |
| Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'GET' | |
| && $request->url() === 'https://rag.test/api/v1/admin/rag/config' | |
| && $request->hasHeader('Authorization', 'Bearer token')); | |
| Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'GET' | |
| && $request->url() === 'https://rag.test/api/v1/admin/rag/config/llm' | |
| && $request->hasHeader('Authorization', 'Bearer token')); | |
| Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'GET' | |
| && $request->url() === 'https://rag.test/api/v1/admin/rag/config/vector_db' | |
| && $request->hasHeader('Authorization', 'Bearer token')); | |
| Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'GET' | |
| && $request->url() === 'https://rag.test/api/v1/admin/rag/config/retrieval' | |
| && $request->hasHeader('Authorization', 'Bearer token')); | |
| Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'GET' | |
| && str_starts_with($request->url(), 'https://rag.test/api/v1/user?') | |
| && $request['name'] === 'Admin' | |
| && $request->hasHeader('Authorization', 'Bearer token')); | |
| }); | |
| test('admin config pages render separate inertia components', function (string $routeName, string $component) { | |
| config(['services.rag.base_url' => 'https://rag.test/api/v1']); | |
| Http::fake([ | |
| 'https://rag.test/api/v1/admin/rag/config' => Http::response([ | |
| 'llm' => [], | |
| 'path' => 'config/rag.yaml', | |
| 'retrieval' => [], | |
| 'vector_db' => [], | |
| ]), | |
| 'https://rag.test/api/v1/admin/rag/config/llm' => Http::response([ | |
| 'model' => 'gpt-test', | |
| ]), | |
| 'https://rag.test/api/v1/admin/rag/config/retrieval' => Http::response([ | |
| 'top_k' => 4, | |
| ]), | |
| 'https://rag.test/api/v1/admin/rag/config/vector_db' => Http::response([ | |
| 'chunk_size' => 800, | |
| ]), | |
| ]); | |
| $this->withCookie('sevima_raghub_auth_token', 'token') | |
| ->withCookie('sevima_raghub_auth_user', adminAuthUserCookie()) | |
| ->get(route($routeName)) | |
| ->assertOk() | |
| ->assertInertia(fn (Assert $page) => $page | |
| ->component($component) | |
| ->where('backendMessage', null) | |
| ->where('ragConfig.path', 'config/rag.yaml')); | |
| })->with([ | |
| 'rag config' => ['admin.rag-config', 'admin/rag-config'], | |
| 'llm config' => ['admin.llm-config', 'admin/llm-config'], | |
| 'vector retrieval config' => ['admin.vector-retrieval-config', 'admin/vector-retrieval-config'], | |
| ]); | |
| test('admin config update endpoints are proxied to backend', function (string $routeName, string $redirectRouteName, string $url, array $payload, string $assertKey) { | |
| config(['services.rag.base_url' => 'https://rag.test/api/v1']); | |
| Http::fake([ | |
| $url => Http::response($payload), | |
| ]); | |
| $this->withCookie('sevima_raghub_auth_token', 'token') | |
| ->withCookie('sevima_raghub_auth_user', adminAuthUserCookie()) | |
| ->from(route('admin.dashboard')) | |
| ->patch(route($routeName), $payload) | |
| ->assertRedirect(route($redirectRouteName)) | |
| ->assertSessionHasNoErrors(); | |
| Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'PATCH' | |
| && $request->url() === $url | |
| && $request[$assertKey] === $payload[$assertKey] | |
| && $request->hasHeader('Authorization', 'Bearer token')); | |
| })->with([ | |
| 'llm' => [ | |
| 'admin.rag.llm.update', | |
| 'admin.llm-config', | |
| 'https://rag.test/api/v1/admin/rag/config/llm', | |
| ['model' => 'gpt-test', 'temperature' => 0.1], | |
| 'model', | |
| ], | |
| 'vector db' => [ | |
| 'admin.rag.vector-db.update', | |
| 'admin.vector-retrieval-config', | |
| 'https://rag.test/api/v1/admin/rag/config/vector_db', | |
| ['chunk_size' => 900, 'embedding_model' => 'embed-test'], | |
| 'chunk_size', | |
| ], | |
| 'retrieval' => [ | |
| 'admin.rag.retrieval.update', | |
| 'admin.vector-retrieval-config', | |
| 'https://rag.test/api/v1/admin/rag/config/retrieval', | |
| ['enable_reranker' => true, 'top_k' => 5], | |
| 'top_k', | |
| ], | |
| ]); | |
| test('admin api key generation is proxied and flashes generated key', function () { | |
| config(['services.rag.base_url' => 'https://rag.test/api/v1']); | |
| Http::fake([ | |
| 'https://rag.test/api/v1/auth/api-keys' => Http::response([ | |
| 'api_key' => 'rag_sk_test', | |
| 'expires_at' => null, | |
| ], 201), | |
| ]); | |
| $this->withCookie('sevima_raghub_auth_token', 'token') | |
| ->withCookie('sevima_raghub_auth_user', adminAuthUserCookie()) | |
| ->from(route('admin.dashboard')) | |
| ->post(route('admin.api-keys.store')) | |
| ->assertRedirect(route('admin.dashboard')) | |
| ->assertSessionHas('generatedApiKey.api_key', 'rag_sk_test') | |
| ->assertSessionHasNoErrors(); | |
| Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'POST' | |
| && $request->url() === 'https://rag.test/api/v1/auth/api-keys' | |
| && $request->hasHeader('Authorization', 'Bearer token')); | |
| }); | |
| test('admin user crud actions are proxied to backend', function () { | |
| config(['services.rag.base_url' => 'https://rag.test/api/v1']); | |
| Http::fake([ | |
| 'https://rag.test/api/v1/user' => Http::response([ | |
| 'email' => 'student@example.com', | |
| 'id' => 10, | |
| 'role' => 'student', | |
| ]), | |
| 'https://rag.test/api/v1/user/10' => Http::response([ | |
| 'email' => 'student@example.com', | |
| 'id' => 10, | |
| 'role' => 'student', | |
| ]), | |
| ]); | |
| $this->withCookie('sevima_raghub_auth_token', 'token') | |
| ->withCookie('sevima_raghub_auth_user', adminAuthUserCookie()) | |
| ->from(route('admin.dashboard')) | |
| ->post(route('admin.users.store'), [ | |
| 'email' => 'student@example.com', | |
| 'identity_number' => 'M001', | |
| 'is_active' => true, | |
| 'is_superuser' => false, | |
| 'name' => 'Student', | |
| 'role' => 'student', | |
| ]) | |
| ->assertRedirect(route('admin.dashboard')) | |
| ->assertSessionHasNoErrors(); | |
| $this->withCookie('sevima_raghub_auth_token', 'token') | |
| ->withCookie('sevima_raghub_auth_user', adminAuthUserCookie()) | |
| ->from(route('admin.dashboard')) | |
| ->patch(route('admin.users.update', ['userId' => 10]), [ | |
| 'email' => 'student@example.com', | |
| 'identity_number' => 'M001', | |
| 'is_active' => false, | |
| 'is_superuser' => false, | |
| 'name' => 'Student Updated', | |
| 'role' => 'student', | |
| ]) | |
| ->assertRedirect(route('admin.dashboard')) | |
| ->assertSessionHasNoErrors(); | |
| $this->withCookie('sevima_raghub_auth_token', 'token') | |
| ->withCookie('sevima_raghub_auth_user', adminAuthUserCookie()) | |
| ->from(route('admin.dashboard')) | |
| ->delete(route('admin.users.destroy', ['userId' => 10])) | |
| ->assertRedirect(route('admin.dashboard')) | |
| ->assertSessionHasNoErrors(); | |
| Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'POST' | |
| && $request->url() === 'https://rag.test/api/v1/user' | |
| && $request['email'] === 'student@example.com' | |
| && $request->hasHeader('Authorization', 'Bearer token')); | |
| Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'PATCH' | |
| && $request->url() === 'https://rag.test/api/v1/user/10' | |
| && $request['name'] === 'Student Updated' | |
| && $request->hasHeader('Authorization', 'Bearer token')); | |
| Http::assertSent(fn (HttpRequest $request): bool => $request->method() === 'DELETE' | |
| && $request->url() === 'https://rag.test/api/v1/user/10' | |
| && $request->hasHeader('Authorization', 'Bearer token')); | |
| }); | |
| test('admin actions use backend error messages', function () { | |
| config(['services.rag.base_url' => 'https://rag.test/api/v1']); | |
| Http::fake([ | |
| 'https://rag.test/api/v1/user' => Http::response([ | |
| 'detail' => [ | |
| ['msg' => 'Email already exists.'], | |
| ], | |
| ], 422), | |
| ]); | |
| $this->withCookie('sevima_raghub_auth_token', 'token') | |
| ->withCookie('sevima_raghub_auth_user', adminAuthUserCookie()) | |
| ->from(route('admin.dashboard')) | |
| ->post(route('admin.users.store'), [ | |
| 'email' => 'admin@example.com', | |
| 'role' => 'admin', | |
| ]) | |
| ->assertRedirect(route('admin.dashboard')) | |
| ->assertSessionHasErrors(['user' => 'Email already exists.']); | |
| }); | |