完善文档与前端迁移,补充开源协议

This commit is contained in:
2026-04-17 19:48:13 +08:00
parent 466fa50aa8
commit 31916e68a6
94 changed files with 7019 additions and 480 deletions

225
scripts/smoke_e2e.ps1 Normal file
View File

@@ -0,0 +1,225 @@
param(
[string]$FrontendBase = "http://127.0.0.1:3000",
[string]$AdminUsername = "admin",
[string]$AdminPassword = "AdminTest2026!",
[string]$ProviderBaseUrl = "https://api.openai.com/v1",
[string]$ProviderApiKey = "sk-your-openai-api-key",
[string]$ProviderModel = "gpt-5.4",
[string]$SamplePath = "E:\QQuiz\test_data\sample_questions.txt"
)
$ErrorActionPreference = "Stop"
Add-Type -AssemblyName System.Net.Http
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
Invoke-WebRequest -UseBasicParsing `
-Uri "$FrontendBase/api/auth/login" `
-Method POST `
-WebSession $session `
-ContentType "application/json" `
-Body (@{
username = $AdminUsername
password = $AdminPassword
} | ConvertTo-Json) | Out-Null
Invoke-WebRequest -UseBasicParsing `
-Uri "$FrontendBase/api/proxy/admin/config" `
-Method PUT `
-WebSession $session `
-ContentType "application/json" `
-Body (@{
ai_provider = "openai"
openai_base_url = $ProviderBaseUrl
openai_api_key = $ProviderApiKey
openai_model = $ProviderModel
} | ConvertTo-Json) | Out-Null
$testUsername = "e2e_user"
$testPassword = "E2ETest2026!"
$resetPassword = "E2EPassword2026!"
try {
Invoke-WebRequest -UseBasicParsing `
-Uri "$FrontendBase/api/proxy/admin/users" `
-Method POST `
-WebSession $session `
-ContentType "application/json" `
-Body (@{
username = $testUsername
password = $testPassword
is_admin = $false
} | ConvertTo-Json) | Out-Null
} catch {
if (-not $_.Exception.Response -or $_.Exception.Response.StatusCode.value__ -ne 400) {
throw
}
}
$usersPayload = (
Invoke-WebRequest -UseBasicParsing `
-Uri "$FrontendBase/api/proxy/admin/users?skip=0&limit=100" `
-WebSession $session
).Content | ConvertFrom-Json
$testUser = $usersPayload.users | Where-Object { $_.username -eq $testUsername } | Select-Object -First 1
if (-not $testUser) {
throw "Failed to find $testUsername."
}
Invoke-WebRequest -UseBasicParsing `
-Uri "$FrontendBase/api/proxy/admin/users/$($testUser.id)" `
-Method PUT `
-WebSession $session `
-ContentType "application/json" `
-Body (@{
username = $testUsername
is_admin = $false
} | ConvertTo-Json) | Out-Null
Invoke-WebRequest -UseBasicParsing `
-Uri "$FrontendBase/api/proxy/admin/users/$($testUser.id)/reset-password" `
-Method POST `
-WebSession $session `
-ContentType "application/json" `
-Body (@{
new_password = $resetPassword
} | ConvertTo-Json) | Out-Null
$client = [System.Net.Http.HttpClient]::new()
$tokenCookie = $session.Cookies.GetCookies($FrontendBase) | Where-Object { $_.Name -eq "access_token" } | Select-Object -First 1
if (-not $tokenCookie) {
throw "Login cookie not found."
}
$client.DefaultRequestHeaders.Authorization = [System.Net.Http.Headers.AuthenticationHeaderValue]::new("Bearer", $tokenCookie.Value)
$apiHeaders = @{
Authorization = "Bearer $($tokenCookie.Value)"
}
$multipart = [System.Net.Http.MultipartFormDataContent]::new()
$multipart.Add([System.Net.Http.StringContent]::new("E2E Full Flow Exam"), "title")
$multipart.Add([System.Net.Http.StringContent]::new("false"), "is_random")
$bytes = [System.IO.File]::ReadAllBytes($SamplePath)
$fileContent = [System.Net.Http.ByteArrayContent]::new($bytes)
$fileContent.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse("text/plain")
$multipart.Add($fileContent, "file", [System.IO.Path]::GetFileName($SamplePath))
$createResponse = $client.PostAsync("http://127.0.0.1:8000/api/exams/create", $multipart).Result
$createBody = $createResponse.Content.ReadAsStringAsync().Result
if ($createResponse.StatusCode.value__ -ne 201) {
throw "Exam create failed: $createBody"
}
$createPayload = $createBody | ConvertFrom-Json
$examId = $createPayload.exam_id
$deadline = (Get-Date).AddMinutes(4)
$exam = $null
while ((Get-Date) -lt $deadline) {
$exam = (
Invoke-WebRequest -UseBasicParsing `
-Uri "http://127.0.0.1:8000/api/exams/$examId" `
-Headers $apiHeaders
).Content | ConvertFrom-Json
if ($exam.status -eq "ready" -or $exam.status -eq "failed") {
break
}
Start-Sleep -Seconds 5
}
if (-not $exam) {
throw "Exam polling returned no data."
}
if ($exam.status -ne "ready") {
throw "Exam parsing failed or timed out. Final status: $($exam.status)"
}
$questionsPayload = (
Invoke-WebRequest -UseBasicParsing `
-Uri "http://127.0.0.1:8000/api/questions/?exam_id=$examId&skip=0&limit=10" `
-Headers $apiHeaders
).Content | ConvertFrom-Json
if ($questionsPayload.total -lt 1) {
throw "Question list returned no questions."
}
$currentQuestion = (
Invoke-WebRequest -UseBasicParsing `
-Uri "http://127.0.0.1:8000/api/questions/exam/$examId/current" `
-Headers $apiHeaders
).Content | ConvertFrom-Json
$checkPayload = (
Invoke-WebRequest -UseBasicParsing `
-Uri "http://127.0.0.1:8000/api/questions/check" `
-Method POST `
-Headers $apiHeaders `
-ContentType "application/json" `
-Body (@{
question_id = $currentQuestion.id
user_answer = "Z"
} | ConvertTo-Json)
).Content | ConvertFrom-Json
if ($checkPayload.correct -eq $true) {
throw "Expected the forced wrong answer to be incorrect."
}
$mistakesPayload = (
Invoke-WebRequest -UseBasicParsing `
-Uri "http://127.0.0.1:8000/api/mistakes/?skip=0&limit=50" `
-Headers $apiHeaders
).Content | ConvertFrom-Json
if ($mistakesPayload.total -lt 1) {
throw "Mistake list did not record the wrong answer."
}
Invoke-WebRequest -UseBasicParsing `
-Uri "http://127.0.0.1:8000/api/exams/$examId/progress" `
-Method PUT `
-Headers $apiHeaders `
-ContentType "application/json" `
-Body '{"current_index":1}' | Out-Null
$summaryPayload = (
Invoke-WebRequest -UseBasicParsing `
-Uri "http://127.0.0.1:8000/api/exams/summary" `
-Headers $apiHeaders
).Content | ConvertFrom-Json
if ($summaryPayload.total_exams -lt 1) {
throw "Exam summary endpoint returned invalid totals."
}
$testSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession
Invoke-WebRequest -UseBasicParsing `
-Uri "$FrontendBase/api/auth/login" `
-Method POST `
-WebSession $testSession `
-ContentType "application/json" `
-Body (@{
username = $testUsername
password = $resetPassword
} | ConvertTo-Json) | Out-Null
$me = (
Invoke-WebRequest -UseBasicParsing `
-Uri "$FrontendBase/api/auth/me" `
-WebSession $testSession
).Content | ConvertFrom-Json
[pscustomobject]@{
exam_id = $examId
exam_status = $exam.status
total_questions = $exam.total_questions
users_total = $usersPayload.total
mistakes_total = $mistakesPayload.total
summary_total_exams = $summaryPayload.total_exams
test_user = $me.username
test_user_is_admin = $me.is_admin
} | ConvertTo-Json -Depth 4