Pruebas¶
Los tipos de pruebas¶
flowchart LR
unit[Pruebas unitarias<br/>funciones puras, imitaciones] --> golden[Archivos de referencia<br/>salida de la generación]
golden --> envtest[envtest<br/>servidor de la API + etcd reales]
envtest --> store[Pruebas del almacén<br/>Postgres real]
store --> itest[Integración<br/>construcciones reales en el clúster]
itest --> live[Comprobaciones en vivo<br/>vigilancia durante las migraciones]
| Tipo | Dónde | Necesita | Qué demuestra |
|---|---|---|---|
| Unitarias | cada paquete | nada | el análisis, la validación, la planeación, la detección, las huellas, la lectura de registros… |
| De referencia | internal/render (testdata/*.golden.yaml) |
nada | los objetos de Kubernetes exactos en que se convierte una especificación |
| envtest | internal/controller, internal/platform |
un servidor de la API y un etcd de prueba (los descarga setup-envtest) |
los controladores contra una API de Kubernetes real: aplicar, adoptar, podar, ganchos, necesidades, finalizadores |
| Del almacén | internal/store, internal/api, internal/platform |
Postgres (TEST_DATABASE_URL) |
el SQL, las migraciones, la cola de ejecuciones, las sesiones |
| De integración | internal/pipeline (etiqueta de construcción integration) |
el grupo de BuildKit del clúster | una construcción real con Dockerfile y una real con Railpack, enviadas con huella |
| De la interfaz | web |
Node | que el TypeScript compila (npm run typecheck) |
Ejecutarlas¶
make test-remote # todo, en un nodo trabajador (use esta)
go test ./internal/spec ./internal/render # paquetes ligeros, bien en cualquier lado
go test ./internal/render -run Golden -update # reescribe los archivos de referencia tras un cambio intencional
make itest # construcciones reales en el grupo de BuildKit (minutos)
Pruebas remotas¶
make test-remote (hack/test-remote.sh) corre los pasos de make test en un pod en un nodo trabajador, porque compilar y correr envtest en main (el plano de control) hace lento a todo el clúster:
echo "test-remote: starting $POD…"
kubectl wait -n "$NS" --for=condition=Ready "pod/$POD" --timeout=10m >/dev/null
echo "test-remote: on $(kubectl get pod -n "$NS" "$POD" -o jsonpath='{.spec.nodeName}'); shipping the working tree"
git ls-files -co --exclude-standard -z | tar --null -T - -czf - | kubectl exec -i -n "$NS" "$POD" -c go -- tar xzf - -C /src
go_status=0
kubectl exec -n "$NS" "$POD" -c go -- env CONTROLLER_GEN="$CONTROLLER_GEN" SETUP_ENVTEST="$SETUP_ENVTEST" ENVTEST_K8S="$ENVTEST_K8S" bash -euo pipefail -c "
until (echo > /dev/tcp/127.0.0.1/5432) 2>/dev/null; do sleep 1; done
hack/ci-test.sh
" || go_status=$?
# Bring back what generate produced, so the repo matches what was tested.
kubectl exec -n "$NS" "$POD" -c go -- tar czf - api/v1alpha1/zz_generated.deepcopy.go internal/spec/zz_generated.deepcopy.go deploy/crds | tar xzf - -C .
ui_status=0
kubectl exec -n "$NS" "$POD" -c node -- bash -euo pipefail -c "
cd /src/web
echo '== ui typecheck'
npm ci --prefer-offline --no-audit --no-fund --loglevel=error
npm run typecheck
" || ui_status=$?
- Se crea un pod con tres contenedores en
rendimiento-builds, lejos del plano de control y de cualquier nodo enTEST_EXCLUDE_NODES: go (las herramientas), node (la revisión de tipos) y postgres (un acompañante que las pruebas del almacén usan enlocalhost). - Un volumen de caché local del nodo (
rendimiento-test-cache, local-path) guarda entre ejecuciones los módulos de Go, la caché de construcción, los programas de envtest y la caché de npm; la primera ejecución lo llena (unos 20 minutos), las siguientes lo reutilizan. - El árbol de trabajo, incluidos los cambios sin confirmar, se manda como un archivo tar.
-
hack/ci-test.shcorrecontroller-gen,go vetygo test -p 1 ./...; luego correnpm run typecheck, y su salida llega aquí en vivo:echo '== generate' controller-gen object paths=./api/... paths=./internal/spec/... controller-gen crd paths=./api/... output:crd:dir=deploy/crds if [ -n "${CHECK_GENERATED:-}" ] && ! git diff --quiet -- api internal/spec deploy/crds; then git diff --stat -- api internal/spec deploy/crds echo "generated files are out of date: run make generate (or make test-remote) and commit them" exit 1 fi echo '== vet' go vet ./... echo '== test' # -p 1: store, platform and api tests share one test database. KUBEBUILDER_ASSETS=$(setup-envtest use "$ENVTEST_K8S" -p path --bin-dir "$(dirname "$TOOLS")/envtest") go test -p 1 ./... -
Los archivos regenerados se copian de vuelta, así el repositorio coincide con lo que se probó.
- Se borra el pod.
-p 1 corre los paquetes uno tras otro: las pruebas del almacén, de la plataforma y de la API comparten una base de datos.
En cada envío¶
El repositorio de rendimiento es una aplicación más de rendimiento: su rendimiento.yaml incluye el libro (un servicio) y la imagen de la plataforma (builds: platform). Así, cada envío y cada solicitud de incorporación también corre el mismo hack/ci-test.sh, como el paso platform:test, con un Postgres desechable (postgres: true) y una caché que se conserva (cache: true); después platform:build construye la imagen, cuyo Dockerfile corre npm run typecheck. El resultado es la comprobación de la confirmación en GitHub. En la integración continua, el script también falla si no se confirmaron los archivos generados (deepcopy, CRD) (CHECK_GENERATED=1). Para probar cambios sin confirmar, se sigue usando make test-remote. Vea Cómo se construye rendimiento a sí mismo.
Escribir pruebas¶
Pruebas unitarias: con tablas¶
for _, tc := range []struct{ yaml, want string }{
{"services: [{name: a, lan: {ip: 8.8.8.8}}]", "private IPv4"},
} { … }
Diga en el mensaje de fallo qué se está comprobando, e incluya el valor obtenido y el esperado.
Imitaciones en lugar de simulacros¶
El código depende de interfaces pequeñas, así que las pruebas le pasan imitaciones sencillas: un fakeExec que anota el orden de ejecución, un fakeDNS que guarda los registros en un mapa, un fakeGit que sirve un fstest.MapFS, un resolvedor fakeSRV, un httptest.Server que hace de repositorio de Helm. No hace falta ningún marco de simulacros.
envtest¶
setup(t) / setupAddons(t) arrancan un servidor de la API y un etcd reales, instalan los CRD de deploy/crds, arrancan el administrador con el controlador que se prueba y devuelven un cliente. Las pruebas crean objetos y usan eventually(t, what, cond) para esperar (hasta 20 segundos) a que el controlador actúe.
envtest no tiene kubelet ni más controladores que los suyos: los pods nunca corren, los Deployments nunca quedan listos, la recolección de basura nunca ocurre. Las pruebas hacen esos papeles cuando hace falta: TestAddonHooks marca los pods de los ganchos como Succeeded o Failed actualizando su estado.
Archivos de referencia¶
render_test.go genera una especificación y compara el YAML con testdata/*.golden.yaml. Ante un cambio intencional: corra con -update y luego lea las diferencias antes de confirmar; es la revisión más clara posible de cómo se verán las cargas de trabajo de los usuarios.
Lo que todavía no está cubierto¶
- el comportamiento de la interfaz (no hay pruebas en navegador);
- pruebas de punta a punta de toda la plataforma en un clúster desechable (incorporar, enviar, publicar, revertir);
- pruebas de carga de la cola de ejecuciones y de muchas construcciones simultáneas.
Están en la hoja de ruta.