在 LinkedIn,我们经常开发需要与第三方网站交互的 Web 应用程序。我们还采用自动化测试来确保软件在发布到生产环境之前的质量。然而,测试的可靠性决定了它的有效性。
考虑到这一点,对于测试来说,具有外部依赖性(例如依赖于第三方网站)可能会带来很大的问题。这些外部站点可能会在没有通知的情况下更改、遭受停机,或者暂时无法访问,因为互联网并非 100% 可靠。
如果我们的某个测试依赖于与第三方网站通信,那么任何故障的原因都很难确定。故障可能是由于 LinkedIn 的内部更改、第三方网站维护人员进行的外部更改或网络基础设施问题造成的。您可以想象,与第三方网站交互可能会失败的原因有很多,因此您可能会想,我将如何处理这个问题?
好消息是,有很多互联网模拟工具可以提供帮助。其中一种工具是 Betamax。它的工作原理是拦截 Web 应用程序发起的 HTTP 连接,然后在稍后重放它们。对于测试,Betamax 可用于替换通过 HTTP 进行的任何交互,并使用先前记录的响应,这些响应可以非常可靠地提供服务。
最初,我们选择在 LinkedIn 的自动化测试中使用 Betamax。它工作得很好,但我们遇到了一些问题
- 出于安全原因,我们的测试环境没有互联网访问权限;但是,与大多数代理一样,Betamax 需要互联网连接才能正常运行。
- 我们有很多用例需要使用身份验证协议,例如 OAuth 和 OpenId。其中一些协议需要通过 HTTP 进行复杂的交互。为了模拟它们,我们需要一个复杂的模型来捕获和重放请求。
为了应对这些挑战,我们决定在 Betamax 建立的思想基础上构建我们自己的互联网模拟工具,名为 Flashback。我们也很自豪地宣布 Flashback 现在是开源的。
什么是 Flashback?
Flashback 旨在模拟 HTTP 和 HTTPS 资源,例如 Web 服务和 REST API,用于测试目的。它记录 HTTP/HTTPS 请求并回放先前记录的 HTTP 事务(我们称之为“场景”),以便完成测试无需外部互联网连接。
Flashback 还可以基于请求的部分匹配来重放场景。它使用“匹配规则”来实现这一点。匹配规则将传入的请求与先前记录的请求关联起来,然后用于生成响应。例如,以下代码片段实现了一个基本的匹配规则,其中测试方法通过 此 URL “匹配”传入的请求。
HTTP 请求通常包含 URL、方法、标头和正文。Flashback 允许为这些组件的任何组合定义匹配规则。Flashback 还允许用户向 URL 查询参数、标头和正文添加白名单或黑名单标签。
例如,在 OAuth 授权流程中,请求查询参数可能如下所示
oauth_consumer_key="jskdjfljsdklfjlsjdfs",
oauth_nonce="ajskldfjalksjdflkajsdlfjasldfja;lsdkj",
oauth_signature="asdfjaklsdjflasjdflkajsdklf",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1318622958",
oauth_token="asdjfkasjdlfajsdklfjalsdjfalksdjflajsdlfa",
oauth_version="1.0"
这些值中的许多值将在每次请求时更改,因为 OAuth 要求客户端每次都为 oauth_nonce 生成新值。在我们的测试中,我们需要验证 oauth_consumer_key、oauth_signature_method 和 oauth_version 的值,同时还要确保请求中存在 oauth_nonce、oauth_signature、oauth_timestamp 和 oauth_token。Flashback 使我们能够创建自己的匹配规则来实现此目标。此功能使我们能够测试具有随时间变化的数据、签名、令牌等的请求,而无需在客户端进行任何更改。
这种灵活的匹配以及无需连接到互联网即可运行的能力是将 Flashback 与其他模拟解决方案区分开来的属性。其他一些值得注意的功能包括
- Flashback 是一个跨平台和跨语言的解决方案,能够测试 JVM(Java 虚拟机)和非 JVM(C++、Python 等)应用程序。
- Flashback 可以动态生成 SSL/TLS 证书,以模拟 HTTPS 请求的安全通道。
如何记录 HTTP 事务
使用 Flashback 记录 HTTP 事务以供以后回放是一个相对简单的过程。在我们深入了解该过程之前,让我们首先介绍一些术语
- 场景 存储先前记录的 HTTP 事务(以 JSON 格式),这些事务可以在以后重放。例如,这是一个示例 Flashback 场景。
- 根路径 是包含 Flashback 场景数据的目录的文件路径。
- 场景名称 是给定场景的名称。
- 场景模式 是场景正在使用的模式——“记录”或“回放”。
- 匹配规则 是确定传入的客户端请求是否与给定场景的内容匹配的规则。
- Flashback 代理 是一个 HTTP 代理,具有两种操作模式:记录和回放。
- 主机 和 端口 是代理主机和端口。
为了记录场景,您必须向目标发出真实的外部请求,然后 HTTPS 请求和响应将与您指定的匹配规则一起存储在场景中。记录时,Flashback 的行为与典型的 MITM(中间人)代理完全一样——只有在回放模式下,连接流和数据流才仅限于客户端和代理之间。
为了查看 Flashback 的实际效果,让我们创建一个场景,通过执行以下操作来捕获与 example.org 的交互
1. 检出 Flashback 源代码
git clone https://github.com/linkedin/flashback.git
2. 启动 Flashback 管理服务器
./startAdminServer.sh -port 1234
3. 启动 Flashback 代理。请注意,上面的 Flashback 将在 localhost 的 5555 端口以记录模式启动。匹配规则需要精确匹配(匹配 HTTP 正文、标头和 URL)。场景将存储在 /tmp/test1 下。
4. Flashback 现在已准备好记录,因此使用它来代理对 example.org 的请求
curl http://www.example.org -x localhost:5555 -X GET
5. Flashback 可以(可选)在单个场景中记录多个请求。要完成记录,请 关闭 Flashback。
6. 为了验证已记录的内容,我们可以查看输出目录 (/tmp/test1) 中场景的内容。它应该 包含以下内容。
在您的 Java 代码中 使用 Flashback 也很容易。
如何重放 HTTP 事务
要重放先前存储的场景,请使用与记录时相同的基本设置;唯一的区别是您在上面的步骤 3 中 将“场景模式”设置为“回放”。
验证响应是否来自场景而不是外部源的一种方法是在执行步骤 1 到 6 时暂时禁用您的互联网连接。另一种方法是修改您的场景文件,看看响应是否与您文件中的内容相同。
这是一个 Java 示例。
如何记录和重放 HTTPS 事务
使用 Flashback 记录和重放 HTTPS 事务的过程与用于 HTTP 事务的过程非常相似。但是,需要特别注意用于 HTTPS 的 SSL 组件的安全证书。为了使 Flashback 充当 MITM 代理,创建证书颁发机构 (CA) 证书是必要的。此证书将用于在客户端和 Flashback 之间创建安全通道期间,并将允许 Flashback 检查其代理的 HTTPS 请求中的数据。然后应将此证书存储为受信任的来源,以便客户端在调用 Flashback 时能够对其进行身份验证。有关如何创建证书的说明,有很多资源(例如 这个)可能会很有帮助。大多数公司都有自己的内部策略来管理和保护证书——请务必遵守您的策略。
这里值得注意的是,Flashback 仅用于测试目的。您可以随时将 Flashback 与您的服务集成,但请注意,Flashback 的记录功能需要存储来自网络的所有内容,然后在重放模式期间使用它。我们建议您格外注意确保不会意外记录或存储任何敏感成员数据。任何可能违反您公司的数据保护或隐私政策的内容均由您负责。
一旦考虑了安全证书,HTTP 和 HTTPS 在记录设置方面的唯一区别是添加了一些额外的参数。
- RootCertificateInputStream:这可以是指示 CA 证书文件名的流或文件路径。
- RootCertificatePassphrase:这是为 CA 证书创建的密码。
- CertificateAuthority:这些是 CA 证书的属性。
查看用于记录 HTTPS 事务的代码,包括上述术语。
使用 Flashback 重放 HTTPS 事务的过程与记录相同。唯一的区别是将场景模式设置为“回放”。这在 此代码 中进行了演示。
支持动态更改
为了在测试中允许灵活性,Flashback 允许您动态更改场景和匹配规则。动态更改场景允许使用不同的响应测试相同的请求,例如成功、time_out、rate_limit 等。场景更改 仅适用于我们已 POST 数据以更新外部资源的情况。请参见下图作为示例。
能够动态地 更改匹配规则 使我们能够测试复杂的场景。例如,我们有一个用例,需要我们测试对 Twitter 的公共和私有资源的 HTTP 调用。对于公共资源,HTTP 请求是恒定的,因此我们可以使用“MatchAll”规则。但是,对于私有资源,我们需要使用 OAuth 消费者密钥和 OAuth 访问令牌对请求进行签名。这些请求包含许多具有不可预测值的参数,因此静态的 MatchAll 规则将不起作用。
用例
在 LinkedIn,Flashback 主要用于在集成测试中模拟不同的互联网提供商,如下面的图表所示。第一个图表显示了 LinkedIn 生产数据中心内的内部服务通过代理层与互联网提供商(例如 Google)进行交互。我们想在测试环境中测试此内部服务。
第二个和第三个图表显示了我们如何在不同的环境中记录和回放场景。记录发生在我们的开发环境中,用户在与代理启动的端口相同的端口上启动 Flashback。从内部服务到提供商的所有外部请求都将通过 Flashback 而不是我们的代理层。在记录必要的场景后,我们可以将它们部署到我们的测试环境。
在测试环境(隔离且没有互联网访问权限)中,Flashback 在与开发环境相同的端口上启动。所有 HTTP 请求仍然来自内部服务,但响应将来自 Flashback 而不是互联网提供商。
未来方向
我们希望看看将来是否可以支持非 HTTP 协议,例如 FTP 或 JDBC,甚至允许用户使用 MITM 代理框架注入他们自己的自定义协议。我们将继续改进 Flashback 设置 API,以使支持非 Java 语言变得更容易。
现在作为开源项目提供
我们很幸运能够在 GTAC 2015 上展示 Flashback。在展会上,一些听众询问我们是否会将 Flashback 作为开源项目发布,以便他们可以将它用于他们自己的测试工作。
Google TechTalks: GATC 2015—模拟互联网
我们很高兴地宣布 Flashback 现在是开源的,并根据 BSD(伯克利软件发行版)双条款许可证提供。要开始使用,请访问 Flashback GitHub 仓库。
最初发布在 LinkedIn 工程博客 上。经许可转载。
致谢
Flashback 由 Shangshang Feng、Yabin Kang 和 Dan Vinegrad 创建,并受到 Betamax 的启发。特别感谢 Hwansoo Lee、Eran Leshem、Kunal Kandekar、Keith Dsouza 和 Kang Wang 在代码审查方面的帮助。我们还要感谢我们的管理层——Byron Ma、Yaz Shimizu、Yuliya Averbukh、Christopher Hazlett 和 Brandon Duncan——感谢他们在 Flashback 的开发和开源方面的支持。
评论已关闭。