Authelia 集成测试套件(Integration Suites)完全指南:从环境搭建到并发运行与自定义套件开发
【免费下载链接】autheliaThe Single Sign-On Multi-Factor portal for web apps. OpenID Certified™ and Post-Quantum Cryptography Ready.项目地址: https://gitcode.com/GitHub_Trending/au/authelia
Authelia 是单点登录生态中的一个组件,其功能必须与 NGINX、Redis、MariaDB、Traefik、HAProxy 等外部组件协同才能被完整验证。为此,Authelia 提出了Suite(套件)概念:一种为 Authelia 及其配套组件准备的虚拟化测试环境。本文以 integration-suites.md 为核心,结合 internal/suites 与 cmd/authelia-scripts 的源码实现,完整讲解如何启动、访问、调试、并发运行套件,以及如何从零创建一个新套件。
重要前提:本文所有操作均假设你已经完成了 环境准备(Prerequisites),并已通过 bootstrap.sh 引导进入Authelia 开发上下文(Development Context)。
什么是 Integration Suite
Authelia 是一个与许多外部系统交互的组件,因此其功能测试并不像单机程序那样简单。Suite 正是为了解决这一问题而生的抽象:它是一个由 Docker Compose 编排的虚拟环境 + 一组针对该环境的测试。
一个 Suite 可以拉起 NGINX、Redis、MariaDB、LDAP、Traefik、HAProxy、Kubernetes 等组件,让 Authelia 在其中真实运行并被测试。这套抽象同时服务于两个场景:
- 开发期手动测试:为开发者准备一套完整的、可交互的本地环境;
- 集成测试:高效地编写并运行自动化集成测试(基于 Selenium/chromedriver 驱动真实浏览器)。
从源码结构看,套件的核心实现位于 internal/suites 目录:suite_<name>.go定义环境生命周期,suite_<name>_test.go定义测试用例,同名目录存放资源文件(详见后文"创建新套件"一节)。
启动一个 Suite
启动名为Standalone的套件只需一条命令:
authelia-scripts suites setup Standalone该命令会执行套件的setup 阶段,即通过docker compose部署整套环境。对应实现位于 cmd/authelia-scripts/cmd/suites.go 的cmdSuitesSetupRun:它会先检查当前是否有其他套件正在运行(通过工作树根目录下的.suite文件记录),若存在且与目标套件不一致则直接拒绝启动,随后调用setupSuite执行部署。
以 Standalone 套件为例,其 setup 定义在 internal/suites/suite_standalone.go:
dockerEnvironment := NewDockerEnvironment([]string{ "internal/suites/compose.yml", "internal/suites/Standalone/compose.yml", "internal/suites/example/compose/authelia/compose.backend.{}.yml", "internal/suites/example/compose/authelia/compose.frontend.{}.yml", "internal/suites/example/compose/nginx/backend/compose.yml", "internal/suites/example/compose/nginx/portal/compose.yml", "internal/suites/example/compose/smtp/compose.yml", }) setup := func(suitePath string) (err error) { if err = dockerEnvironment.Up(); err != nil { return err } if err = waitUntilAutheliaIsReady(dockerEnvironment, standaloneSuiteName); err != nil { return err } return updateDevEnvFileForDomain(BaseDomain, dockerEnvironment) }可以看到,一个套件可以叠加多个 compose 文件:基础网络、套件专属资源、后端(注意{}占位符在 CI 环境下会被替换为dist,见 internal/suites/docker.go)、前端、反向代理(NGINX portal)以及 SMTP 邮件服务。部署完成后还会等待 Authelia 后端就绪,再按BaseDomain更新开发环境文件。
启动完成后,所有容器会持续运行,方便你进行手动探索或接着运行测试。
访问套件环境
开发套件采用标准化布局,让交互变得非常一致。
IP 地址
- Backend(Authelia 后端):
192.168.240.50 - Frontend(前端 Web 服务器):
192.168.240.100
其中 backend 是运行在 Docker 容器中的 Authelia 二进制,frontend 则是托管所有应用 Web 前端的 Web 服务器(含 NGINX、Traefik 等代理)。
这两处地址是本地开发的默认值。任何与其他套件共享同一个 Docker daemon 的运行(即所有 CI agent,以及开发机上第一个之外的工作树)都会设置SUITE_SLOT,从而获得独立的 compose project 与独立子网,此时本文所有地址的前三个八位段都会随之改变。详见下文 并发运行 与 环境变量 两节。
站点与应用
所有站点都托管在地址${SUITE_SUBNET}.100:8080上,本地开发即为192.168.240.100:8080。以下清单并非穷举且可能随时间变化;完整的 host 条目配置请看 internal/suites/hosts.go,其中HostEntries函数集中定义了所有套件域名到套件网络地址的映射。某个套件具体拉起哪些应用,可查看该套件suite_<name>.go文件中的dockerEnvironment变量。
- Authelia 门户:
https://login.example.com:8080 - Mailpit(邮件测试):
https://mail.example.com:8080 - OpenID Connect 1.0 测试应用:
https://oidc.example.com:8080https://oidc-public.example.com:8080
- Duo:
https://duo.example.com:8080 - Kubernetes Dashboard:
https://kubernetes.example.com:8080 - Traefik Dashboard:
https://traefik.example.com:8080 - HAProxy:
https://haproxy.example.com:8080 - 简单测试应用:
https://public.example.com:8080https://singlefactor.example.com:8080https://secure.example.com:8080https://admin.example.com:8080https://deny.example.com:8080
注意:这些站点均使用
https且带自签名证书,浏览器首次访问需要手动信任证书。
除了上述常见站点,hosts.go 还定义了网络 ACL 测试用的proxy-client1/2/3.example.com(192.168.240.201~203)、Redis 主从节点redis-node-0/1/2.example.com(.110~112)、Redis Sentinelredis-sentinel-0/1/2.example.com(.120~122)以及 PAM 套件的ssh.example.com(.130)。多 Cookie 域套件还会动态生成example2.com、example3.com下的全部子域条目(见hostEntriesCookieDomains)。
环境变量一览
当多个套件共享同一个 Docker daemon 时会并发运行多份副本,以下环境变量用于隔离它们。每个变量都是可选的,未设置时回退到单次本地运行的默认值。
| 变量 | 默认值 | 用途 |
|---|---|---|
SUITE_SLOT | 未设置 | 该 agent 或工作树拥有的槽位号。设置后,bootstrap.sh 会据此推导出COMPOSE_PROJECT_NAME、SUITE_SUBNET、LDAP_ADMIN_PORT、ENVOY_ADMIN_PORT,在 CI 之外还会推导SUITE_TMP与SUITE_TMP_PATH。带槽位的 shell 不再改动/etc/hosts。 |
SUITE_SLOT_AUTO | 未设置 | 设为false可阻止bootstrap.sh为本工作树自动分配槽位。CI 中无效果,因为 CI 的槽位由 agent 提供。 |
COMPOSE_PROJECT_NAME | authelia | Compose 项目名。同时用于限定 Traefik 的 Docker provider 只发现属于本项目自己的容器(见 internal/suites/docker.go 与autheliaNetworkName)。 |
SUITE_SUBNET | 192.168.240 | 套件网络的前三个八位段。SuiteAddress(octet)用它与末位段拼出完整地址(见 internal/suites/docker.go)。 |
SUITE_TMP | /tmp | 绑定挂载进套件容器的主机目录,容器内恒以/tmp看到它。每个 agent 或工作树应有自己的目录,因为任务结束时该目录顶层除 agent 自身工作文件外的所有内容都会被清除。 |
SUITE_TMP_PATH | /tmp | 测试进程自身读写同一份内容的路径。CI 中保持/tmp(SUITE_TMP被绑定到 agent 内的/tmp);本地则设为SUITE_TMP(测试进程跑在宿主机上)。对应实现见 internal/suites/docker.go 的SuiteTmpPath。 |
SUITE_IMAGE | authelia:dist | 后端容器运行的镜像。 |
AGENT_CONTAINER | 未设置 | 运行测试的容器名。设置后,该容器会在 setup 时被连接到套件网络、teardown 时断开(对应connectAgentNetwork/disconnectAgentNetwork,见 internal/suites/docker.go),从而让 Chrome 能访问到门户。 |
并发运行多套件
一台机器上可以同时运行多个套件,每个 git 工作树(working tree)各占一个。在工作树中执行:
source bootstrap.sh即可为该工作树分配一个槽位,并由此推导出所有可能冲突的资源:
[BOOTSTRAP] Using suite slot 2 for /home/user/authelia-feature槽位按工作树记忆:之后每次source都得到同一个槽位;当工作树被删除时,槽位自动释放。查看或管理分配情况:
authelia-scripts suites slot --list authelia-scripts suites slot --release从源码看,槽位分配由 cmd/authelia-scripts/cmd/slot.go 实现:allocateSlot总是给工作树分配当前最小的未用编号,--list输出形如2 "/home/user/authelia-feature"的登记表,--release则从登记中移除当前工作树。登记表存放在工作树之外的$XDG_STATE_HOME/authelia/suite-slots(未设置时回退到~/.local/state/authelia/suite-slots),并通过文件锁(flock)保证并发分配安全——两个同时source的 shell 绝不会拿到同一个槽位;读取登记表时会自动丢弃已不存在工作树的条目,从而实现"删除工作树即释放槽位"。
有了槽位号之后,bootstrap.sh 推导出的关键派生值如下:
export COMPOSE_PROJECT_NAME="authelia-${SUITE_SLOT}" export SUITE_SUBNET="10.240.${SUITE_SLOT}" export LDAP_ADMIN_PORT="$((9090 + SUITE_SLOT))" export ENVOY_ADMIN_PORT="$((9901 + SUITE_SLOT))"即槽位为 2 时,子网变为10.240.2.0/24。注意:带槽位的 shell 刻意不去碰/etc/hosts。原因是该文件是机器级的,而其背后的地址只属于某一个网络,只能由一个工作树独占。测试本身并不依赖它:Chrome 通过--host-resolver-rules解析套件域名,Go 客户端在拨号(dial)时解析域名,两者使用同一张来自 internal/suites/hosts.go 的映射表(HostResolverRules与ResolveAddr/DialContext)。这样/etc/hosts仍指向默认的192.168.240.0/24网络,未分槽位的工作树可以继续用上文列出的地址在浏览器中访问,而带槽位的套件并行运行不受影响。如果你想在浏览器里访问带槽位的套件,直接使用其地址即可,例如https://10.240.2.100:8080。
并发运行时还有两点共享资源值得注意:
- pnpm store(
~/.local/share/pnpm/store)与Go 模块/构建缓存(${GOPATH})会被绑定挂载进每个套件的开发容器。它们并发使用是安全的,但会存在竞争。 - 开发模式下,每个套件在后端、前端、代理容器上大约占用6 个 CPU 核心与 6 GB 内存,外加测试用的一个 Chrome 进程。请据此规划并发套件数量。
远程调试
所有套件的 Authelia 都以 delve 调试器运行,支持远程调试。调试器监听地址为${SUITE_SUBNET}.50:2345,未分槽位的工作树即192.168.240.50:2345。
连接示例:
dlv connect 192.168.240.50:2345连接成功后即可像本地调试一样设置断点、查看变量、单步执行 Authelia 后端代码。若套件带槽位运行,把地址替换为对应子网的.50地址即可(例如10.240.2.50:2345)。
运行套件测试
测试基于chromedriver + Selenium驱动真实 Chrome 浏览器完成,因此默认会弹出一个 Chrome 窗口。
对已运行套件执行测试
如果套件已在运行,直接执行:
authelia-scripts suites test命令会检测.suite文件中记录的当前运行套件,并只运行与之匹配的测试(见 cmd/authelia-scripts/cmd/suites.go)。其底层通过go test -count=1 -v -json ./internal/suites -run '^(Test<SuiteName>Suite)$'执行对应测试函数,测试超时取套件注册的TestTimeout。
无头模式运行
为避免弹出的 Chrome 干扰其他工作,可用无头模式:
authelia-scripts suites test --headless该模式通过设置HEADLESS=y环境变量实现(见 cmd/authelia-scripts/cmd/suites.go)。此外测试命令还支持--failfast(首个失败即停止)与--test '<pattern>'(只运行匹配的单个测试)。
对未运行套件执行测试
如果套件尚未启动,也可以一步到位直接运行指定套件的测试,例如HighAvailability:
authelia-scripts suites test HighAvailability该命令会先自动完成该套件的 setup,再运行测试,最后执行 teardown(withEnv=true路径)。若想一次运行多个套件,可用逗号分隔名称(如suites test Standalone,TwoFactor);不带任何参数时则会按顺序运行所有套件,例如 CI 中的全量集成测试。
测试结束后,每个套件的结果会以-json格式写入独立的结果文件(命名格式见testResultsFileFmt),失败时还会调用套件注册的OnError回调(如 Standalone 套件的displayAutheliaLogs)输出后端与前端日志帮助定位问题。
创建新套件
创建一个新套件非常简单。以Standalone套件为例,它由三部分组成:
internal/suites/suite_standalone.go— 定义套件的setup 与 teardown 阶段(通常使用 docker compose 拉起整套环境),同时定义各阶段超时时间。Standalone 套件的完整注册如下:
GlobalRegistry.Register(standaloneSuiteName, Suite{ SetUp: setup, SetUpTimeout: 5 * time.Minute, OnError: displayAutheliaLogs, OnSetupTimeout: displayAutheliaLogs, TearDown: teardown, TestTimeout: 5 * time.Minute, TearDownTimeout: 2 * time.Minute, Description: `This suite is used to test Authelia in a standalone configuration with in-memory sessions and a local sqlite db stored on disk`, })注意它的
init()函数还会在SuiteTmpPath("authelia/StandaloneSuite")下预写 jwt/session 密钥文件,teardown 时删除临时 sqlite 数据库——这体现了SUITE_TMP/SUITE_TMP_PATH在测试过程中的实际用途。internal/suites/suite_standalone_test.go— 定义针对该套件的测试集合(以
TestStandaloneSuite为前缀的 Go 测试函数)。internal/suites/Standalone目录 — 存放套件所需的资源文件(compose 覆盖文件、证书、配置等),通常会挂载进容器。
套件的复杂度可以远超 Standalone:例如Kubernetes 套件(internal/suites/suite_kubernetes.go)会搭建一整套完整的 Kubernetes 生态,作为复杂套件的参考范例。
新建套件时遵循同样的三步即可:编写suite_<name>.go注册环境生命周期、编写suite_<name>_test.go编写测试、创建同名资源目录;随后套件会自动出现在authelia-scripts suites list中,并可通过suites setup <name>与suites test <name>驱动。仓库中已内置 20 余个现成套件(internal/suites 下的suite_*.go),覆盖 LDAP、MySQL/MariaDB/Postgres、OIDC、Traefik/Envoy/HAProxy/Caddy、PAM、多 Cookie 域、网络 ACL、双因素等场景,可直接作为编写新套件的模板。
小结
Integration Suite 是 Authelia 开发与测试体系的基石:authelia-scripts suites setup|test|teardown|slot命令族负责环境生命周期与测试执行,SUITE_SLOT机制让同一台机器上的多个工作树互不干扰地并发运行,/etc/hosts之外的双重域名解析(Chrome 的--host-resolver-rules与 Go 的DialContext)保证了隔离网络的正确访问,而"三件套"(环境定义 + 测试 + 资源目录)的约定让新增套件的成本降到最低。无论是为修复某个 bug 搭建手动验证环境,还是在 CI 中跑全量集成测试,理解本文的机制都能让你事半功倍。
【免费下载链接】autheliaThe Single Sign-On Multi-Factor portal for web apps. OpenID Certified™ and Post-Quantum Cryptography Ready.项目地址: https://gitcode.com/GitHub_Trending/au/authelia
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考