feat(ops): генератор нагрузки и подготовка аккаунтов для теста
- cmd/loadgen: держит заданное число WS-клиентов Gateway, шлёт сообщения с нужной частотой, измеряет задержку доставки (p50/p95/p99/max), ответы API, разрывы соединений и пишет отчёт в JSON; - glchat create-user (CLI + обёртка): создаёт аккаунты в обход выключенной регистрации, пакетно (--count/--prefix), при --sessions сразу выдаёт сессии и складывает учётные данные в файл 600 — иначе сотня клиентов не сможет войти из-за лимита попыток по IP; - auth: CreateUserByOperator и IssueSessionForOperator с тестом; - web/e2e/voice-ten.spec.ts: десять участников в одной голосовой комнате, проверка плиток, входящего аудио и слоя 1080p60 у клиента; сессии берутся из файла (без формы входа); - .gitignore: каталоги вывода Playwright test-results*.
This commit is contained in:
@@ -459,3 +459,48 @@ func totpCode(t *testing.T, secret string) string {
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
// TestCreateUserByOperator проверяет команду обслуживания: аккаунт создаётся
|
||||
// даже при выключенной регистрации, дубликаты и слабые пароли отклоняются
|
||||
// (AGENT.md 10.7, 11.4 — подготовка нагрузки).
|
||||
func TestCreateUserByOperator(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
service, st := newService(t)
|
||||
|
||||
if err := st.SetInstanceSetting(ctx, "registration_enabled", "false"); err != nil {
|
||||
t.Fatalf("SetInstanceSetting: %v", err)
|
||||
}
|
||||
// Публичная регистрация закрыта.
|
||||
if _, _, _, err := service.Register(ctx, auth.RegisterInput{
|
||||
Username: "operator_blocked", Email: "blocked@example.com", Password: "correct-horse-battery",
|
||||
}); !errors.Is(err, auth.ErrRegistrationOff) {
|
||||
t.Fatalf("Register with registration off = %v, want ErrRegistrationOff", err)
|
||||
}
|
||||
|
||||
user, err := service.CreateUserByOperator(ctx, auth.RegisterInput{
|
||||
Username: "loadtest1", Email: "loadtest1@loadtest.local", Password: "correct-horse-battery",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateUserByOperator: %v", err)
|
||||
}
|
||||
if user.Username != "loadtest1" || user.IsInstanceAdmin {
|
||||
t.Fatalf("created user = %+v", user)
|
||||
}
|
||||
// Вход новым аккаунтом работает без выдачи сессии создателю.
|
||||
if _, _, _, err := service.Login(ctx, auth.LoginInput{
|
||||
Email: "loadtest1@loadtest.local", Password: "correct-horse-battery",
|
||||
}); err != nil {
|
||||
t.Fatalf("Login as created user: %v", err)
|
||||
}
|
||||
|
||||
if _, err := service.CreateUserByOperator(ctx, auth.RegisterInput{
|
||||
Username: "loadtest1", Email: "other@loadtest.local", Password: "correct-horse-battery",
|
||||
}); !errors.Is(err, auth.ErrUsernameTaken) {
|
||||
t.Fatalf("duplicate username = %v, want ErrUsernameTaken", err)
|
||||
}
|
||||
if _, err := service.CreateUserByOperator(ctx, auth.RegisterInput{
|
||||
Username: "loadtest2", Email: "loadtest2@loadtest.local", Password: "short",
|
||||
}); !errors.Is(err, auth.ErrWeakPassword) {
|
||||
t.Fatalf("weak password = %v, want ErrWeakPassword", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user