大家好!我很高兴地宣布项目已经完全实施,并进入了审查和测试阶段。在以下段落中,我将介绍系统的各个部分,并在最后描述如何使用它。
项目介绍
项目的一般目的是为每个新提交的 Joomla 扩展代码获取早期反馈。通过创建一个可以运行 Joomla 测试的完全工作环境,以便它们可以在一个并行(基于容器的)环境中运行,从而提高 PHP 和 Joomla 版本的速度和覆盖率。这里的关键要求是速度,对新 PR 获取早期反馈至关重要。为了达到这个目标,将同时在不同容器上运行不相互依赖的测试。
项目的范围是将 Joomla! 链接扩展现有的测试集成到新的测试环境中。因此,需要使用预安装的 Joomla 容器,以便能够快速运行测试。
预期结果是自动化测试环境,从其创建(通过运行带有 Joomla/PHP 组合的容器和测试 selenium 容器),到并行测试执行(通过协调并行测试运行并考虑它们的依赖关系)以及报告(为每个失败的测试存储日志和截图)。
虚拟化
虚拟化仓库已经更新,现在支持 Memcached 容器。虚拟化的工作方式是使用 4 个默认的 xml 配置文件
- database.xml
- default.xml
- selenium.xml
- network.xml
每一个都定义了数据库、Joomla 服务器、memcached、selenium 容器和最后但同样重要的是,它们所工作的网络的配置。
为了便于在其他项目中使用(如本项目),为虚拟化项目定义了一个 API。API 期望一个环境配置,该配置用于扩展和覆盖上述定义的 xml 中的配置。
这将是一个典型的环境配置
$env = array( 'php' => ['5.4', '5.5', '5.6', '7.0', '7.1'], 'joomla' => ['3.6'], 'selenium.no' => 3, 'extension.path' => $tmpDir . '/extension', 'host.dockyard' => '.tmp/dockyard', );
这样,就创建了所有并行测试所需的容器。
选择列表
选择列表的主要目的是加载并维护扩展测试的运行顺序。它确保仅服务于准备运行的测试,保证它们的依赖已经成功,否则将任务标记为失败。
为了维护测试的状态,使用了三个(四个)标志
final class Flag { const NO_FLAG = 0; const ASSIGNED = 1; const EXECUTED = 2; const FAILED = 3; }
现在,在选择列表能够加载测试之前,扩展应该定义了一个tests.yml文件用于验收测试。该文件应包含所有需要运行的测试,缩进表示测试之间的依赖关系。如果一个测试有两个分离的依赖,那么它需要相应地缩进两次,按照所需的依赖关系。对于Weblinks来说,没有这种情况,但解决方案仍然呈现。以下是一个简化的weblinks的tests.yml文件示例
install/InstallWeblinksCest.php:installWeblinks: administrator/AdminCategoriesCest.php:adminCreateCategoryWithoutTitleFails: administrator/AdminCategoriesCest.php:adminCreateCategory: administrator/AdminCategoriesCest.php:adminPublishCategory: administrator/AdminCategoriesCest.php:adminUnpublishCategory: administrator/AdminCategoriesCest.php:adminVerifyAvailableTabs: administrator/AdminWeblinksCest.php:adminCreateWeblink: administrator/AdminWeblinksCest.php:adminTrashWeblink:
已经定义了一个递归读取函数来读取yml文件并将测试数据存储在内存中。数据未规范化,以便于未来的操作,任务同时存储在一个简单列表中(以便于检查它们的依赖)和一个以它们的标志为键的映射中(以便于管理选择过程)。仅通过内存的线性增加(*2),就实现了复杂度的指数级改进。
读取完成后,选择列表的下一个重要职责是“pop()”准备执行的测试。如果有任务没有标志并且所有依赖都已执行,则返回该任务,否则返回“false”。
因为这个项目(测试运行)的所有行为都是异步的,所以定义了一个isFinished方法。这让我们知道何时将每个选择列表的测试总体结果写入日志,这最终代表了一个服务器。
主协调器
主协调器类被命名为MCS,是MainCoordinatorStatic的缩写。这是因为它的所有方法都是静态的。测试需要异步运行,因此,为了保持执行所需的信息,如选择列表,使用缓存(Memcached)作为持久存储。因此,MCS每次需要在对选择列表执行操作时查询缓存,并在操作后将信息写回。为了避免并发问题,实现了一个简单的锁定系统。
MCS的首要任务是准备测试执行所需的数据。首先,它加载选择列表,然后创建runQueue和manageQueue。如最初提议中讨论的,runQueue存储准备执行的任务,但同时也受到客户端数量的限制。manageQueue用于在服务器之间保持测试覆盖率的平衡,从而确保最大效率。此外,为每个服务器创建codeception配置文件,以重用相同的weblinks克隆,并分别存储失败的屏幕截图和日志。
使用虚拟化API创建和启动测试环境。在运行测试之前,MCS等待数据库初始化完成。
最后,MCS负责填充执行队列并运行可用的任务。执行队列的填充进行到达到最大容量,最后一次执行测试的服务器中的测试具有优先权。任务的运行将继续,直到有可用的客户端(selenium容器)和执行队列中的任务。
Robo运行测试任务
为了使测试异步执行,需要创建一个robo任务。任务的执行基本上是一个“docker exec”命令,在客户端容器内运行codeception测试。然后验证结果,如果成功,测试会被标记为“已执行”,并且整个填充和运行流程会重新加载,所有这些都是异步的,不会知道其他客户端或测试的状态。如果失败,则会存储一个包含所有codeception输出的附加日志。
Robo运行协调任务
项目的设计意味着它将由Travis或其他CI工具运行。因此,robo任务最适合这个工作。它期望作为参数的仓库所有者、名称和分支,并应按如下方式使用
vendor/bin/robo run:coordinator isacandrei weblinks container-test
在这个版本中,环境配置需要在robo任务的实现中定义,但稍后它将被定义为外部,以允许测试的不同需求。
总体图表
个人经验
对我来说,这个项目是一个挑战,这也是我选择它的原因。最吸引我注意的是Docker。我是一个容器化的粉丝,我认为这是自动化系统部署的最佳方式之一。我喜欢这个项目的另一个原因是它需要构思一个并行运行任务的算法。
所以,在陷入一个难题后,我开始工作,第一个月很难,但在理解了项目概念背后的深层知识后,设计和编写实际代码变得容易多了。
我相信这个项目帮助我成为一个更好的软件工程师,并让我对开源世界有了更深入的了解。