ENRE_WEB/gestor/reglas_test.go
SITO 7d5dbeec60 Cuenta de externas, arreglos de seguridad, títulos arriba y despliegue
- Rol «externas» para la asamblea de externas: pide sin cupo, siempre con el
  colectivo de fuera y su contacto, y sus solicitudes salen en naranja hasta
  que la asamblea de la Enre las confirma.
- /pedir/ explica en una línea que los colectivos externos piden fecha en la
  asamblea de externas, los lunes de 19:00 a 20:00.
- Seguridad: argon2 limitado a dos cálculos a la vez y el intento se cuenta
  antes de calcular (60 accesos simultáneos llevaban el proceso a 3,8 GB);
  bloqueo por cuenta a 20 fallos para que no se pueda dejar fuera a la
  asamblea; avisos por sesión en vez de por URL; sig sin «..»; eventos de
  31 días como mucho; parámetros de argon2 acotados.
- Títulos pegados arriba en todas las páginas; la franja de la enredadera
  recupera ese alto para seguir llenando la pantalla.
- despliegue/: instalar.sh, cuenta.sh, servicio de systemd con el proceso
  encerrado, fragmento de nginx que además deja de servir .git y las notas
  internas, y configuración de ejemplo. Ninguna contraseña en el repositorio.
2026-09-23 12:15:33 +02:00

276 lines
9.3 KiB
Go

package main
import (
"strings"
"testing"
)
const hoy = Dia("2026-09-22") // martes
func solicitud(usuario string, desde, hasta Dia) Solicitud {
return Solicitud{
Solicitante: usuario,
Rol: RolInterno,
Titulo: "Concierto de prueba",
Desde: desde,
Hasta: hasta,
Hora: "20:00",
}
}
func evento(id, usuario string, desde, hasta Dia, estado Estado) Evento {
return Evento{
ID: id,
Titulo: "Evento " + id,
Solicitante: usuario,
Desde: desde,
Hasta: hasta,
Estado: estado,
Creado: hoy.MustTime(),
}
}
func TestVentanaTresMeses(t *testing.T) {
rg := ReglasPorDefecto()
// 2026-10-02 es viernes, dentro de los tres meses.
if err := rg.Validar(solicitud("hacklab", "2026-10-02", "2026-10-02"), nil, hoy); err != nil {
t.Fatalf("una fecha dentro de la ventana deberia valer: %v", err)
}
// 2027-01-01 es viernes y cae fuera: hoy + 3 meses es 2026-12-22.
err := rg.Validar(solicitud("hacklab", "2027-01-01", "2027-01-01"), nil, hoy)
if err == nil || !strings.Contains(err.Error(), "3 meses") {
t.Fatalf("una fecha a mas de 3 meses tiene que fallar por la ventana, dio: %v", err)
}
}
func TestAntelacionMinima(t *testing.T) {
rg := ReglasPorDefecto()
// 2026-09-25 es el viernes de esta semana: a 3 dias, caducaria al instante.
err := rg.Validar(solicitud("hacklab", "2026-09-25", "2026-09-25"), nil, hoy)
if err == nil || !strings.Contains(err.Error(), "antelación") {
t.Fatalf("pedir con menos de 7 dias tiene que fallar, dio: %v", err)
}
}
func TestCupoTresDiasEnLaVentana(t *testing.T) {
rg := ReglasPorDefecto()
// Tres dias ya cogidos por el mismo colectivo: uno confirmado, dos solicitados.
eventos := []Evento{
evento("a", "hacklab", "2026-10-02", "2026-10-02", Confirmado),
evento("b", "hacklab", "2026-10-10", "2026-10-11", Solicitado),
}
err := rg.Validar(solicitud("hacklab", "2026-10-16", "2026-10-16"), eventos, hoy)
if err == nil || !strings.Contains(err.Error(), "cupo") {
t.Fatalf("el cuarto dia tiene que fallar por cupo, dio: %v", err)
}
// El cupo es por colectivo: otro colectivo si puede coger ese dia.
if err := rg.Validar(solicitud("feminismos", "2026-10-16", "2026-10-16"), eventos, hoy); err != nil {
t.Fatalf("otro colectivo no deberia arrastrar el cupo del primero: %v", err)
}
// Los dias rechazados o caducados no cuentan.
eventos[1].Estado = Caducado
if err := rg.Validar(solicitud("hacklab", "2026-10-16", "2026-10-17"), eventos, hoy); err != nil {
t.Fatalf("un evento caducado no deberia gastar cupo: %v", err)
}
}
func TestCupoNoCuentaFechasPasadas(t *testing.T) {
rg := ReglasPorDefecto()
viejos := []Evento{evento("v", "hacklab", "2026-08-07", "2026-08-09", Confirmado)}
if err := rg.Validar(solicitud("hacklab", "2026-10-02", "2026-10-04"), viejos, hoy); err != nil {
t.Fatalf("lo que ya paso no gasta cupo: %v", err)
}
}
func TestSinSolapes(t *testing.T) {
rg := ReglasPorDefecto()
eventos := []Evento{evento("a", "hacklab", "2026-10-03", "2026-10-03", Solicitado)}
err := rg.Validar(solicitud("feminismos", "2026-10-02", "2026-10-04"), eventos, hoy)
if err == nil || !strings.Contains(err.Error(), "ya está cogido") {
t.Fatalf("un dia solicitado por otro tiene que bloquear, dio: %v", err)
}
// Al caducar se libera la fecha.
eventos[0].Estado = Caducado
if err := rg.Validar(solicitud("feminismos", "2026-10-02", "2026-10-04"), eventos, hoy); err != nil {
t.Fatalf("una fecha caducada tiene que quedar libre: %v", err)
}
}
func TestSoloFindesSalvoLaEnre(t *testing.T) {
rg := ReglasPorDefecto()
// 2026-10-06 es martes.
err := rg.Validar(solicitud("hacklab", "2026-10-06", "2026-10-06"), nil, hoy)
if err == nil || !strings.Contains(err.Error(), "no es día reservable") {
t.Fatalf("un martes no es reservable para un colectivo, dio: %v", err)
}
s := solicitud("enre", "2026-10-06", "2026-10-06")
s.Rol = RolEnre
if err := rg.Validar(s, nil, hoy); err != nil {
t.Fatalf("la enre si puede poner cualquier dia: %v", err)
}
}
func TestLaEnreNoTieneCupoNiVentana(t *testing.T) {
rg := ReglasPorDefecto()
eventos := []Evento{
evento("a", "enre", "2026-10-02", "2026-10-04", Confirmado),
evento("b", "enre", "2026-10-09", "2026-10-11", Confirmado),
}
s := solicitud("enre", "2027-06-04", "2027-06-06")
s.Rol = RolEnre
if err := rg.Validar(s, eventos, hoy); err != nil {
t.Fatalf("la enre no deberia topar con cupo ni ventana: %v", err)
}
}
func TestAmadrinadoPideContacto(t *testing.T) {
rg := ReglasPorDefecto()
s := solicitud("hacklab", "2026-10-02", "2026-10-02")
s.Amadrinado = "Colectivo de fuera"
err := rg.Validar(s, nil, hoy)
if err == nil || !strings.Contains(err.Error(), "contacto") {
t.Fatalf("amadrinar sin contacto tiene que fallar, dio: %v", err)
}
s.Contacto = "fuera@riseup.net"
if err := rg.Validar(s, nil, hoy); err != nil {
t.Fatalf("con contacto deberia valer: %v", err)
}
}
func TestCaducidad(t *testing.T) {
rg := ReglasPorDefecto()
ahora := hoy.MustTime()
cerca := evento("a", "hacklab", "2026-09-27", "2026-09-27", Solicitado)
if m := rg.Caducidad(cerca, ahora); m == "" || !strings.Contains(m, "menos de 7") {
t.Fatalf("a 5 dias sin confirmar tiene que caducar, dio %q", m)
}
lejos := evento("b", "hacklab", "2026-11-06", "2026-11-06", Solicitado)
if m := rg.Caducidad(lejos, ahora); m != "" {
t.Fatalf("una solicitud reciente y lejana no caduca, dio %q", m)
}
vieja := lejos
vieja.Creado = ahora.AddDate(0, 0, -31)
if m := rg.Caducidad(vieja, ahora); m == "" || !strings.Contains(m, "esperando") {
t.Fatalf("31 dias esperando tiene que caducar, dio %q", m)
}
confirmada := cerca
confirmada.Estado = Confirmado
if m := rg.Caducidad(confirmada, ahora); m != "" {
t.Fatalf("un evento confirmado no caduca nunca, dio %q", m)
}
}
func TestTurnoDeFinde(t *testing.T) {
rg := ReglasPorDefecto() // ancla 2026-09-25, turno ruido
casos := []struct {
dia Dia
quer Turno
}{
{"2026-09-25", Ruido}, // viernes ancla
{"2026-09-26", Ruido}, // sabado del mismo finde
{"2026-09-27", Ruido}, // domingo del mismo finde
{"2026-10-02", Tranqui}, // finde siguiente
{"2026-10-09", Ruido},
{"2026-10-16", Tranqui},
{"2026-09-18", Tranqui}, // hacia atras tambien alterna
}
for _, c := range casos {
if got := rg.TurnoDe(c.dia, nil); got != c.quer {
t.Errorf("%s: turno %q, esperaba %q", c.dia, got, c.quer)
}
}
// Un dia de entre semana no tiene turno.
if got := rg.TurnoDe("2026-10-06", nil); got != "" {
t.Errorf("un martes no tiene turno de finde, dio %q", got)
}
// La excepcion escrita a mano manda sobre la alternancia.
exc := map[Dia]Turno{"2026-10-02": Ruido}
if got := rg.TurnoDe("2026-10-03", exc); got != Ruido {
t.Errorf("la excepcion del viernes tiene que valer para todo el finde, dio %q", got)
}
}
func TestRangoYDiaISO(t *testing.T) {
dias := Rango("2026-10-02", "2026-10-04")
if len(dias) != 3 || dias[0] != "2026-10-02" || dias[2] != "2026-10-04" {
t.Fatalf("rango mal calculado: %v", dias)
}
if Rango("2026-10-04", "2026-10-02") != nil {
t.Fatal("un rango invertido tiene que dar nada")
}
if got := Dia("2026-10-02").DiaISO(); got != 5 {
t.Fatalf("2026-10-02 es viernes, iso 5, dio %d", got)
}
if got := ViernesDe("2026-10-04"); got != "2026-10-02" {
t.Fatalf("el viernes del domingo 4 es el 2, dio %q", got)
}
}
func TestVentanaDevuelveTresMeses(t *testing.T) {
rg := ReglasPorDefecto()
primero, ultimo := rg.Ventana(hoy)
if primero != "2026-09-29" {
t.Errorf("primera fecha pedible %q, esperaba 2026-09-29", primero)
}
if ultimo != "2026-12-22" {
t.Errorf("ultima fecha pedible %q, esperaba 2026-12-22", ultimo)
}
}
func TestModificarNoChocaConsigoMismo(t *testing.T) {
rg := ReglasPorDefecto()
eventos := []Evento{
evento("a", "hacklab", "2026-10-02", "2026-10-03", Confirmado),
evento("b", "vivienda", "2026-10-09", "2026-10-09", Solicitado),
}
// La asamblea mueve la hora del evento «a» sin cambiarle los días.
s := solicitud("hacklab", "2026-10-02", "2026-10-03")
s.Rol, s.Excluir = RolEnre, "a"
if err := rg.Validar(s, eventos, hoy); err != nil {
t.Fatalf("modificar un evento en sus propios días deberia valer: %v", err)
}
// Pero no puede llevarlo encima del evento «b».
s.Desde, s.Hasta = "2026-10-09", "2026-10-09"
if err := rg.Validar(s, eventos, hoy); err == nil || !strings.Contains(err.Error(), "cogido") {
t.Fatalf("mover «a» encima de «b» deberia fallar por solape, dio %v", err)
}
}
func TestExternasSinCupoPeroConColectivo(t *testing.T) {
rg := ReglasPorDefecto()
eventos := []Evento{
evento("a", "externas", "2026-10-02", "2026-10-04", Solicitado),
evento("b", "externas", "2026-10-09", "2026-10-11", Solicitado),
}
s := solicitud("externas", "2026-10-16", "2026-10-16")
s.Rol = RolExternas
if err := rg.Validar(s, eventos, hoy); err == nil || !strings.Contains(err.Error(), "colectivo de fuera") {
t.Fatalf("sin decir de qué colectivo es deberia fallar, dio %v", err)
}
// Con seis días ya apuntados, un séptimo vale: externas no tiene cupo.
s.Amadrinado, s.Contacto = "Colectivo Sin Techo", "sintecho@example.org"
if err := rg.Validar(s, eventos, hoy); err != nil {
t.Fatalf("externas no deberia tener cupo: %v", err)
}
// Pero sigue sin poder pedir entre semana.
s.Desde, s.Hasta = "2026-10-14", "2026-10-14"
if err := rg.Validar(s, eventos, hoy); err == nil {
t.Fatal("externas no deberia poder pedir un miércoles")
}
}