在适用于 Rust 的 AWS SDK 中使用静态重播模拟 HTTP 流量 - 适用于 Rust 的 AWS SDK

在适用于 Rust 的 AWS SDK 中使用静态重播模拟 HTTP 流量

适用于 Rust 的 AWS SDK 提供了多种方法来测试与 AWS 服务交互的代码。本主题介绍了如何使用 StaticReplayClient 创建虚假 HTTP 客户端,该客户端可以代替 AWS 服务通常使用的标准 HTTP 客户端。该客户端返回您指定的 HTTP 响应,而不是通过网络与服务通信,以便测试能够获得已知数据用于测试目的。

aws-smithy-http-client crate 包含一个名为 StaticReplayClient 的测试实用程序类。创建 AWS 服务 对象时,可以指定此 HTTP 客户端类而不是默认的 HTTP 客户端。

初始化 StaticReplayClient 时,您可以提供 HTTP 请求和响应对的列表作为 ReplayEvent 对象。在测试运行时,系统会记录每个 HTTP 请求,客户端将在事件列表中下一个 ReplayEvent 中找到的下一个 HTTP 响应作为 HTTP 客户端的响应返回。这样,测试就可以在没有网络连接的情况下使用已知数据运行。

使用静态重播

要使用静态重播,无需使用包装器。但是,您需要确定测试将使用的数据的实际网络流量应是什么样的,并将该流量数据提供给 StaticReplayClient,以便在每次 SDK 从 AWS 服务 客户端发出请求时使用。

注意

有多种方法可以收集预期的网络流量,包括 AWS CLI 和许多网络流量分析器及数据包嗅探器工具。

  • 创建 ReplayEvent 对象列表,指定预期的 HTTP 请求以及应针对这些请求返回的响应。

  • 使用上一步创建的 HTTP 事务列表创建 StaticReplayClient

  • 为 AWS 客户端创建配置对象,将 StaticReplayClient 指定为 Config 对象的 http_client

  • 使用上一步创建的配置创建 AWS 服务客户端对象。

  • 使用配置为使用 StaticReplayClient 的服务对象,执行您要测试的操作。每当 SDK 向 AWS 发送 API 请求时,系统都会使用列表中的下一个响应。

    注意

    即使发送的请求与 ReplayEvent 对象向量中的请求不匹配,系统也总是会返回列表中的下一个响应。

  • 发出所有所需请求后,调用 StaticReplayClient.assert_requests_match() 函数以验证 SDK 发送的请求是否与 ReplayEvent 对象列表中的请求相匹配。

示例

我们来看上一个示例中同一 determine_prefix_file_size() 函数的测试,但这次使用的是静态重播而不是模拟。

  1. 在项目目录的命令提示符中,将 aws-smithy-http-client crate 添加为依赖项:

    $ cargo add --dev aws-smithy-http-client --features test-util

    使用 --dev 选项可将 crate 添加到 Cargo.toml 文件的 [dev-dependencies] 部分。作为开发依赖项,它不会被编译并包含在用于生产代码的最终二进制文件中。

    此示例代码还使用 Amazon Simple Storage Service 作为示例 AWS 服务。

    $ cargo add aws-sdk-s3

    这会将 crate 添加到 Cargo.toml 文件的 [dependencies] 部分。

  2. 在测试代码模块中,包含您需要的两种类型。

    use aws_smithy_http_client::test_util::{ReplayEvent, StaticReplayClient}; use aws_sdk_s3::primitives::SdkBody;
  3. 测试首先创建表示测试期间应发生的每个 HTTP 事务的 ReplayEvent 结构。每个事件都包含一个 HTTP 请求对象和一个 HTTP 响应对象,表示 AWS 服务通常会回复的信息。这些事件会传递到对 StaticReplayClient::new() 的调用中:

    let page_1 = ReplayEvent::new( http::Request::builder() .method("GET") .uri("https://test-bucket.s3.us-east-1.amazonaws.com/?list-type=2&prefix=test-prefix") .body(SdkBody::empty()) .unwrap(), http::Response::builder() .status(200) .body(SdkBody::from(include_str!("./testing/response_multi_1.xml"))) .unwrap(), ); let page_2 = ReplayEvent::new( http::Request::builder() .method("GET") .uri("https://test-bucket.s3.us-east-1.amazonaws.com/?list-type=2&prefix=test-prefix&continuation-token=next") .body(SdkBody::empty()) .unwrap(), http::Response::builder() .status(200) .body(SdkBody::from(include_str!("./testing/response_multi_2.xml"))) .unwrap(), ); let replay_client = StaticReplayClient::new(vec![page_1, page_2]);

    结果存储在 replay_client 中。这表示一个 HTTP 客户端,适用于 Rust 的 SDK 可以通过在客户端配置中指定该客户端来使用它。

  4. 要创建 Amazon S3 客户端,请使用配置对象调用客户端类的 from_conf() 函数来创建客户端:

    let client: s3::Client = s3::Client::from_conf( s3::Config::builder() .behavior_version(BehaviorVersion::latest()) .credentials_provider(make_s3_test_credentials()) .region(s3::config::Region::new("us-east-1")) .http_client(replay_client.clone()) .build(), );

    使用生成器的 http_client() 方法指定配置对象,使用 credentials_provider() 方法指定凭证。凭证是使用名为 make_s3_test_credentials() 的函数创建的,该函数会返回一个虚假凭证结构:

    fn make_s3_test_credentials() -> s3::config::Credentials { s3::config::Credentials::new( "ATESTCLIENT", "astestsecretkey", Some("atestsessiontoken".to_string()), None, "", ) }

    这些凭证不一定是有效的,因为它们实际上不会被发送到 AWS。

  5. 通过调用需要测试的函数来运行测试。在此示例中,该函数名称为 determine_prefix_file_size()。它的第一个参数是用于其请求的 Amazon S3 客户端对象。因此,请指定使用 StaticReplayClient 创建的客户端,以便请求由该客户端处理,而不是通过网络传出:

    let size = determine_prefix_file_size(client, "test-bucket", "test-prefix") .await .unwrap(); assert_eq!(19, size); replay_client.assert_requests_match(&[]);

    determine_prefix_file_size() 的调用完成后,系统会使用断言来确认返回的值是否与预期值匹配。然后,调用 StaticReplayClient 方法 assert_requests_match() 函数。此函数扫描记录的 HTTP 请求,并确认它们是否与创建重播客户端时提供的 ReplayEvent 对象数组中指定的请求相匹配。

您可以在 GitHub 上查看完整的示例代码