Playrix CI / CD:我们如何构建和测试游戏

团队应该专注于创造精美且成功的游戏,因为CI以外的所有其他功能。

我们在哪里应用CI? 我们使用什么方法和概念? 为什么要构建和测试构建? 有关CI及其在Playrix中的组织方式的详细故事将吸引一系列课程。 在切开处-短暂挤压,并带有一些口音。


你好

首先,要进行一些热身:什么是持续集成? 如果团队使用存储库并收集夜间构建-该CI是否已经存在? 连续部署和交付之间有什么区别? 这几乎不重要。 详细信息-适用于狭窄的专家圈。 如果您想让整个公司参与某个过程,请给它起一个简单而好听的名字。 在Playrix中,我们将所有这些方法称为CI。 这是一个这样的本地品牌和一个很酷的徽标:

主意


CI不是目标,而是工具。 使用持续集成必须要实现一个目标,这是一个需要解决的问题。 碰巧的是,团队中的开发和发布过程是建立在“祈祷并投入生产”的原则之上的。 有时它是有道理的,但很少。

我们制定了以下目标:最小化集成问题的可能性,最小化纠正发现的错误所需的资源,减少项目开发团队支持和支持CI流程的时间。
CI是构建过程的自动化,代码的测试及其在各种环境中的交付,例行开发过程的自动化,我们都使用的服务的相互集成。

这个想法是在一个系统中,该系统可以自动收集所有内容,经常执行,测试并交付构建,并在出现问题时逐点针对方便的报告。

我们在哪里应用CI?


  • 引擎和实用程序,
  • 我们在所有平台上的游戏,
  • 服务器代码
  • 分析,营销服务,各种自动化,CI服务,
  • 基础设施。

那无处不在或几乎无处不在。

组装和测试容器,在Test,Staging和Prod,Rolling和Canary更新中自动部署-所有这些我们都拥有,并且更适用于服务和Web应用程序。 今天,我们将专注于游戏的CI:构建,测试并交付它们。

范式


为了实现上述目标,您需要解决几个问题。 以下是在开发过程中自动化某些流程时要遵循的计划,例如,组装手机游戏客户端。 列出问题列表非常方便,可以回答这些问题,您可以解决CI团队遇到的任何问题。

  • 文献资料


组装说明是文档,是对我们自动化过程的描述。 这样的文档通常在程序员的脑海中。 如果团队在构建过程中拥有超级专家,而没有团队,那么任何人都无法构建快速且无错误的构建-现在该进行更改了,就不会提交了。

好吧,如果这样的文档以脚本的形式进行了框架:我在具有准备好的环境的机器上输入了命令行和一组参数-我得到了一个构建。

最好的过程文档是cat代码。 即使出于某种原因需要手动重复该操作,也可以始终通过查看来进行操作。
  • 记录中


构建日志使您始终可以肯定地说:谁,何时,从哪个提交以及收集了该构建或该构建的结果。 昨天构建即将完成,但今天不是。 我们在日志中查找,找到了第一个软盘构建,我们看到了到达那里的提交列表-利润。

例如,在涉及服务器代码时,该杂志更加有用。 如果没有有关谁更新了产品以及何时更新的信息,那么通常情况下,不知道哪个代码在那儿工作。 有时这非常重要,非常重要。

您可以在分类帐中保留这种日记,最好在表格或Wiki中。 CI系统中的构建清单是无价的。


  • 安全性


当涉及到构建构建并将其部署到某种环境中时,总是会出现一个问题:在哪里存储登录/访问密码? 他们通常需要很多东西:到存储库下载源数据,到文件存储以填充游戏资源,到HockeyApp发送角色,到服务器更新代码,等等。

碰巧所有必要的访问都存储在存储库中。 有一个假设,这不是很好。 通常,您会在Jenkins中看到“输入密码”字段,例如,构建的作者在其中输入隐藏的字符。

牢记所有密码是一项很好的技能。 我们的CI服务器本身会根据程序集接收必要的访问权限。 通常,这些是短暂的令牌,这些令牌是在构建开始时生成的,并且在我们部署内容或从中读取内容的位置提供最小的权限。

组装和部署的集中管理使您能够解决区分基础结构访问权限的问题。 如果您只能授予对在此服务器上进行必要操作的相应版本的程序集的访问权限,为什么要授予某人对该服务器的访问权限? 而且,由于有构建,所以我们有了文档和日记,您明白了。

  • 可追溯性


在构建期间通常会留下很多痕迹。 不,不是那样的:在构建过程中,有必要留下尽可能多的痕迹。 在存储库中,在任务跟踪器中,在构建分发系统中。 无论您在哪里遇到建筑物,无论走到哪里,都应该有痕迹引导您完成有关建筑物的信息。

这些痕迹不需要清除掉,相反,必须将其小心翼翼并妥善保存。 进一步,我将告诉您更多有关此的内容,但是首先我们需要收集我们的构建。 走吧

预提交挂钩


同样,这个想法是一个收集,测试和报告一切的系统。 但是,如果无法构建,为什么还要构建?

我们游戏的所有开发人员均已安装了预先提交的挂钩。 尝试提交某些内容时执行的一组检查。 检查仅针对修改后的文件运行,但是我们实现了一个非常狡猾的跨依赖搜索系统,也可以检查所有相关内容。 即 如果艺术家添加了纹理,则挂钩将检查它们是否忘记在需要的地方注册它,并且从未密封过。

事实证明,钩子捕获了大量的小错误。 他们节省了构建系统的资源,并帮助开发人员快速解决问题:他看到一条消息,详细说明出了什么问题。 而且他不需要在任务之间进行切换:他实际上只是在进行更改,并且处于上下文中。 纠错时间最短。

我们非常喜欢它,甚至我们制作了一个系统来检查是否对进入存储库的提交进行了钩子。 如果不是,则此类提交的作者将自动收到任务,要求他们对其进行配置,以及有关如何执行此操作的详细说明。

挂钩对所有项目都是标准化的。 自定义测试的数量很少。 方便的自定义,包括根据运行的用户而定:这对于测试测试非常方便。

建立


要尽早发现构建中的问题,您需要尽可能频繁地收集和测试这些构建。 我们游戏的客户聚集在所有平台,每次提交,所有项目上。 可能有一些例外,但不是很多。

通常,客户端(尤其是移动客户端)具有几种不同的版本:带有或不带有作弊功能,签名不同等。 对于每次提交,我们都会收集“常规”构建,开发人员和测试人员会不断使用它们。

有些版本很少使用,例如store ios版本-在提交中仅一次,即 大约每月一次。 但是,我们认为应定期收集所有构建。 如果这种类型的组装出现问题,则在开发或基础架构方面,项目团队将不会在构建交付之日就知道该问题,而是要早得多,并且能够提前做出响应并解决问题。

因此,我们有一个简单的规则:任何构建每天至少启动一次。 在问题出现在存储库中的第二天早晨,最坏的情况下,项目开发团队会发现任何平台上是否存在任何问题。

如此频繁的组装和测试需要一种特殊的方法来优化其执行时间。

  • 所有常规客户构建都是增量的。
  • 打包地图集和准备资源也是递增的。
  • 程序集非常详细:某些步骤位于单独的构建配置中-这使您可以并行执行它们,并重用中间结果。

这是WildScapes构建和测试链的几乎完整的屏幕截图。 无法完成:大约是原来的两倍。


静态测试


组装后,将执行静态测试:我们将文件夹与构建一起进行,并对其中的所有内容执行一组检查。 代码也是内容,因此它的静态分析(cppcheck + PVS-Studio)也在此处。

我非常推荐关于哈伯的静态材料的详细资料 。 我仅强调,构建后和预提交挂钩中的静态测试由同一代码执行。 这大大简化了系统支持。

运行时测试


如果静态测试构建成功,则可以继续尝试运行组装的构建。 我们正在除UWP以外的所有平台上测试构建,即 Windows,MacO,iOS,Android。 UWP-也将会,但是稍后。

如果似乎仅在开发中需要桌面构建,为什么还要对其进行测试? 问题的答案是:如果美术师或关卡设计师的构建因某些可笑的原因而在启动时崩溃,那是很糟糕的。 因此,对所有平台都执行Smoke-Test,这是对可运行性和基本游戏玩法的最少检查。

以上关于构建的所有内容也适用于在设备上进行测试-至少每天一次。 除少数例外:测试时间很长,一天没有时间完成。

每次提交都会执行冒烟测试。 成功完成基本检查是构建进入分发系统的先决条件。 通常,让某人访问显然不起作用的版本是没有意义的。 在这里,您可以提出异议并提出例外。 项目提供了一种变通方法来提供对无法正常运行的内部版本的访问,但是他们几乎不使用它。

还有哪些其他测试:

  • 基准测试:我们会检查各种情况下以及所有设备上FPS和内存的性能。
  • 第3场单元测试:每个元素和每个力学都经过单独测试以及以交互的所有组合进行测试。
  • 整个游戏从开始到结束的整个过程。
  • 各种回归测试,例如本地化测试,或者所有UI窗口都正确打开,或者Fishdom中的fishdom场景播放没有错误。
  • 都一样,但是使用AddressSanitizer
  • 游戏版本的兼容性测试:从以前的版本中获取用户保存的文件,在新版本中打开它,并确保一切正常。
  • 与特定项目的机制相关的各种自定义测试。

要运行测试,我们使用自己的ios和android设备测试台。 这使我们能够灵活地在设备上启动所需的构建,并通过代码与设备进行交互。 我们拥有完全的控制权,可理解的可靠性水平,我们知道我们可能会遇到什么问题以及解决这些问题将花费多长时间。 提供测试设备的云服务都无法提供这种舒适感。


上面列出的测试是在项目代码中实现的。 从理论上讲,这允许进行任何复杂性的测试,但是需要项目开发中的工作和资源来实施和支持这些测试。 这些资源通常不可用,并且手动测试多重回归很困难,没有必要。 我真的希望测试人员自己进行测试自动化。 我们为他们提出了一个框架-持续自动化测试系统或CATS。

这是什么主意:使测试脚本作者能够与游戏应用程序进行交互,而完全不必关心其所有工作原理。 我们用原始python编写脚本,我们通过一组抽象来访问应用程序。 例如:“家庭景观,请向我打开购物窗口并购买此类产品。” 检查结果,宾果游戏。

脚本命令的整个实现都隐藏在一组抽象后面。 实现与应用程序交互的API允许您以几种方式执行任何操作:

  • 使用某种命令将http请求发送到游戏引擎内置的服务器。 该命令由游戏代码处理。 通常这是某种作弊,它可以任意简单或复杂。 例如,“给我具有指定标识符的按钮中心的坐标”。 或“将我的游戏从此处传递到具有指定编号的关卡”。
  • 我们可以通过作弊打开一个窗口,或找出打开该窗口的按钮的坐标,我们可以模拟单击该按钮,也可以对其进行虚拟单击。
  • 最后,我们可以在指定的坐标上执行“真实”单击,就像用手指在屏幕上完成一样。

后一种方法为经常想测试没有作弊的“战斗”构架的测试人员提供了想象的空间。 维护这样的场景更加困难,但是“战斗构建”就是“战斗”构建。


事实证明,使用按钮中心的坐标非常方便:坐标有时会更改,但是按钮标识符很少见。 这导致了系统的另一个重要特性:为所有平台和所有屏幕分辨率编写一个测试脚本的能力。

交付,报告和跟踪


交付后,一切都变得非常简单:我们使用单个共享存储来构建构件并存储在分发系统中。 构建的“加载”归结为向构建分发服务的api调用一对请求,实质上是注册。 这样,我们节省了一些时间来抽出构建物并节省了存储成本。

记住,您曾讨论过要最小化修复构建中发现的错误所需的资源吗? 报告和跟踪-仅此而已:

  • 报告发现的问题是Asana的一项任务。 如果基础架构出现问题,可以轻松控制,将其分配给合适的开发人员,再将其转移给CI团队。
  • 我们为每次提交收集构建。 我们知道此提交的作者,因此只有他会看到此任务。 因此,我们为其他开发人员节省了时间:他们不必因与他们无关的问题而分心,并帮助解决他们最有可能无法解决的问题。
  • 如果您从下一次提交构建一个版本,那么很可能仍然被破坏。 任务中将有一条注释:“构建仍被破坏”,新提交的作者将看不到该任务,也不会在其他人的问题上浪费时间。
  • 我们将报告发送给Slack。 有必要-亲自给“打破”构建的人,以及项目需要的人-到特殊渠道或任何Playrix员工。 一切都尽可能灵活。

需要跟踪,以便到处都有关于构建及其从中收集更改的完整信息。 为了不寻找任何东西,以便一切都在手边,并且无需花费时间搜索在研究问题时通常必需的细节。

  • 该报告包含指向构建,构建日志,发现的编译错误的文本以及翻转的测试的名称的链接。 通常,程序员在收到报告任务后可以立即纠正错误:文件名,行和错误文本在报告中。
  • Slack中的消息包含所有相同的内容以及指向Asana中任务的链接。
  • 在Teamcity中,是指向任务的链接。 构建工程师可以立即执行任务,只需单击一下,您无需寻找任何东西。
  • 在github中-带有构建链接的状态,在提交的注释中-指向进行此构建的任务的链接。 在任务中-带有提交链接的注释。
  • 在构建分发服务中:链接到构建,链接到提交。

没有什么可记住的,但是您了解了这个主意:链接到所有地方的所有内容。 这极大地加快了对任何无法理解的情况的研究。

农场


我们收集并测试所有平台的构建。 为此,我们需要许多不同的代理。 手动跟踪和维护它们很长且很困难。 所有座席都是自动准备的。 我们使用Packer和Ansible。

我们保存了所有座席的所有日志,Teamcity,周围的所有服务(在本例中为ELK)。 处理构建的所有服务都会将此构建的编号添加到每行日志中。 我们可以在单个请求中看到构建的整个生命周期,即从队列中的外观到发送所有报告的结束。

我们已经实现了自己的队列优化机制。 在我们的数字上,Teamcity中的一个不能很好地工作。 谈到数字:

  • 我们每天收集约5,000个建筑物。 这大约需要500个工作小时。
  • 第三个百万建造是一个月前。
  • 我们在10个不同的位置拥有50多个构建服务器。
  • 在测试台上使用40多种移动设备。
  • 恰好1个Teamcity服务器。


CI即服务


Playrix CI是一项服务。 有很多项目,也有很多想法。

我们优化了从将构建放入队列到执行结束之间的时间,因为这正是服务的用户(开发人员)所考虑的“构建时间”。 这使我们可以搜索并找到构建时间和它在队列中花费的时间之间的平衡。 随着公司的发展和项目数量的增加,合乎逻辑的是,收集这些项目的构建场也将增长。 但是,由于进行了优化,该农场的增长率远远低于公司的增长率。

任何优化都要从监视开始,并有条不紊地收集统计信息。 我们收集了大量的统计信息,并且我们完全了解我们的构建的所有内容。 但是,除了构建服务器场的数量之外,还有一个团队支持CI系统并使之变得无人问津。

这个团队的流程优化也是一个有趣而有趣的过程。例如,我们编写用于设置构建配置的测试,因为其中有许多配置,没有类似的测试,就很难找到所有需要编辑的位置。对于几乎所有更改,我们首先编写一个测试,然后进行更改,即实际上我们拥有TDD。有许多与职责,事件管理,计划传入任务流程相关的过程。

开发人员应专注于创建出色且成功的游戏,而不必担心构建的来源。为此,Playrix具有CI。使用持续集成必须要实现一个目标,这是一个需要解决的问题。重要的是不要提出问题,即找到问题。当您找到她时,请记住我们的经验并做得更好。切记:

CI永不睡觉,
再见!

Source: https://habr.com/ru/post/zh-CN479966/


All Articles