Unverified Commit 61b7a774 authored by ysaito1001's avatar ysaito1001 Committed by GitHub
Browse files

Allow integration tests to run in both runtime modes (#2709)



## Description
This will allow integration tests under `aws/sdk/integration-tests` to
run in both smithy runtime modes. Prior to the PR, the integration tests
use `map_operation` to customize operations, which is not supported in
the orchestrator, preventing us from running them in the orchestrator
mode. Fortunately, all the usages of `map_operation` in the integration
tests involve setting a test request time and a test user agent in a
property bag.

This PR stops using `map_operation` in those tests and instead
introduces separate test helper methods in both runtime modes: one for
setting a test request and the other for setting a test user agent. They
allow the integration tests to compile and run in both modes.

Note that the integration tests in the orchestrator do not necessarily
pass at this time. We'll address the failures subsequently.

## Testing
Confirmed integration tests continue passing with the changes when run
in the middleware . Confirmed those complied (but not necessarily
passed) in the orchestrator.

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._

---------

Co-authored-by: default avatarYuki Saito <awsaito@amazon.com>
parent 3a9e64e5
Loading
Loading
Loading
Loading
+103 −0
Original line number Diff line number Diff line
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

package software.amazon.smithy.rustsdk

import software.amazon.smithy.rust.codegen.client.smithy.generators.client.CustomizableOperationCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.client.CustomizableOperationSection
import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
import software.amazon.smithy.rust.codegen.core.rustlang.writable
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType

class CustomizableOperationTestHelpers(runtimeConfig: RuntimeConfig) :
    CustomizableOperationCustomization() {
    private val codegenScope = arrayOf(
        *RuntimeType.preludeScope,
        "AwsUserAgent" to AwsRuntimeType.awsHttp(runtimeConfig)
            .resolve("user_agent::AwsUserAgent"),
        "BeforeTransmitInterceptorContextMut" to RuntimeType.smithyRuntimeApi(runtimeConfig)
            .resolve("client::interceptors::BeforeTransmitInterceptorContextMut"),
        "ConfigBag" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("config_bag::ConfigBag"),
        "ConfigBagAccessors" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::orchestrator::ConfigBagAccessors"),
        "http" to CargoDependency.Http.toType(),
        "InterceptorContext" to RuntimeType.smithyRuntimeApi(runtimeConfig)
            .resolve("client::interceptors::InterceptorContext"),
        "RequestTime" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::orchestrator::RequestTime"),
        "SharedInterceptor" to RuntimeType.smithyRuntimeApi(runtimeConfig)
            .resolve("client::interceptors::SharedInterceptor"),
        "TestParamsSetterInterceptor" to CargoDependency.smithyRuntime(runtimeConfig).withFeature("test-util")
            .toType().resolve("client::test_util::interceptor::TestParamsSetterInterceptor"),
    )

    override fun section(section: CustomizableOperationSection): Writable =
        writable {
            if (section is CustomizableOperationSection.CustomizableOperationImpl) {
                if (section.operationShape == null) {
                    // TODO(enableNewSmithyRuntime): Delete this branch when middleware is no longer used
                    // This branch customizes CustomizableOperation in the middleware. section.operationShape being
                    // null means that this customization is rendered in a place where we don't need to figure out
                    // the module for an operation (which is the case for CustomizableOperation in the middleware
                    // that is rendered in the customize module).
                    rustTemplate(
                        """
                        ##[doc(hidden)]
                        // This is a temporary method for testing. NEVER use it in production
                        pub fn request_time_for_tests(mut self, request_time: ::std::time::SystemTime) -> Self {
                            self.operation.properties_mut().insert(request_time);
                            self
                        }

                        ##[doc(hidden)]
                        // This is a temporary method for testing. NEVER use it in production
                        pub fn user_agent_for_tests(mut self) -> Self {
                            self.operation.properties_mut().insert(#{AwsUserAgent}::for_tests());
                            self
                        }
                        """,
                        *codegenScope,
                    )
                } else {
                    // The else branch is for rendering customization for the orchestrator.
                    rustTemplate(
                        """
                        ##[doc(hidden)]
                        // This is a temporary method for testing. NEVER use it in production
                        pub fn request_time_for_tests(mut self, request_time: ::std::time::SystemTime) -> Self {
                            use #{ConfigBagAccessors};
                            let interceptor = #{TestParamsSetterInterceptor}::new(move |_: &mut #{BeforeTransmitInterceptorContextMut}<'_>, cfg: &mut #{ConfigBag}| {
                                cfg.set_request_time(#{RequestTime}::new(request_time));
                            });
                            self.interceptors.push(#{SharedInterceptor}::new(interceptor));
                            self
                        }

                        ##[doc(hidden)]
                        // This is a temporary method for testing. NEVER use it in production
                        pub fn user_agent_for_tests(mut self) -> Self {
                            let interceptor = #{TestParamsSetterInterceptor}::new(|context: &mut #{BeforeTransmitInterceptorContextMut}<'_>, _: &mut #{ConfigBag}| {
                                let headers = context.request_mut().headers_mut();
                                let user_agent = #{AwsUserAgent}::for_tests();
                                headers.insert(
                                    #{http}::header::USER_AGENT,
                                    #{http}::HeaderValue::try_from(user_agent.ua_header()).unwrap(),
                                );
                                headers.insert(
                                    #{http}::HeaderName::from_static("x-amz-user-agent"),
                                    #{http}::HeaderValue::try_from(user_agent.aws_ua_header()).unwrap(),
                                );
                            });
                            self.interceptors.push(#{SharedInterceptor}::new(interceptor));
                            self
                        }
                        """,
                        *codegenScope,
                    )
                }
            }
        }
}
+1 −1
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ class AwsFluentClientDecorator : ClientCodegenDecorator {
                AwsFluentClientDocs(codegenContext),
            ),
            retryClassifier = AwsRuntimeType.awsHttp(runtimeConfig).resolve("retry::AwsResponseRetryClassifier"),
        ).render(rustCrate)
        ).render(rustCrate, listOf(CustomizableOperationTestHelpers(runtimeConfig)))
        rustCrate.withModule(ClientRustModule.Client.customize) {
            renderCustomizableOperationSendMethod(runtimeConfig, generics, this)
        }
+5 −21
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@

use aws_config::SdkConfig;
use aws_credential_types::provider::SharedCredentialsProvider;
use aws_http::user_agent::AwsUserAgent;
use aws_sdk_s3::config::{Credentials, Region};
use aws_sdk_s3::types::ChecksumMode;
use aws_sdk_s3::Client;
@@ -14,10 +13,7 @@ use aws_smithy_client::test_connection::{capture_request, TestConnection};
use aws_smithy_http::body::SdkBody;
use http::header::AUTHORIZATION;
use http::{HeaderValue, Uri};
use std::{
    convert::Infallible,
    time::{Duration, UNIX_EPOCH},
};
use std::time::{Duration, UNIX_EPOCH};
use tracing_test::traced_test;

/// Test connection for the movies IT
@@ -77,14 +73,8 @@ async fn test_checksum_on_streaming_response(
        .customize()
        .await
        .unwrap()
        .map_operation(|mut op| {
            op.properties_mut()
                .insert(UNIX_EPOCH + Duration::from_secs(1624036048));
            op.properties_mut().insert(AwsUserAgent::for_tests());

            Result::Ok::<_, Infallible>(op)
        })
        .unwrap()
        .request_time_for_tests(UNIX_EPOCH + Duration::from_secs(1624036048))
        .user_agent_for_tests()
        .send()
        .await
        .unwrap();
@@ -191,14 +181,8 @@ async fn test_checksum_on_streaming_request<'a>(
        .customize()
        .await
        .unwrap()
        .map_operation(|mut op| {
            op.properties_mut()
                .insert(UNIX_EPOCH + Duration::from_secs(1624036048));
            op.properties_mut().insert(AwsUserAgent::for_tests());

            Result::Ok::<_, Infallible>(op)
        })
        .unwrap()
        .request_time_for_tests(UNIX_EPOCH + Duration::from_secs(1624036048))
        .user_agent_for_tests()
        .send()
        .await
        .unwrap();
+2 −10
Original line number Diff line number Diff line
@@ -5,12 +5,10 @@

use aws_config::SdkConfig;
use aws_credential_types::provider::SharedCredentialsProvider;
use aws_http::user_agent::AwsUserAgent;
use aws_sdk_s3::config::{Credentials, Region};
use aws_sdk_s3::Client;
use aws_smithy_client::test_connection::capture_request;

use std::convert::Infallible;
use std::time::{Duration, UNIX_EPOCH};

#[tokio::test]
@@ -29,14 +27,8 @@ async fn test_s3_ops_are_customizable() {
        .customize()
        .await
        .expect("list_buckets is customizable")
        .map_operation(|mut op| {
            op.properties_mut()
                .insert(UNIX_EPOCH + Duration::from_secs(1624036048));
            op.properties_mut().insert(AwsUserAgent::for_tests());

            Result::<_, Infallible>::Ok(op)
        })
        .expect("inserting into the property bag is infallible");
        .request_time_for_tests(UNIX_EPOCH + Duration::from_secs(1624036048))
        .user_agent_for_tests();

    // The response from the fake connection won't return the expected XML but we don't care about
    // that error in this test
+1 −7
Original line number Diff line number Diff line
@@ -9,7 +9,6 @@ use aws_sdk_s3::config::Builder;
use aws_sdk_s3::config::{Credentials, Region};
use aws_sdk_s3::Client;
use aws_smithy_client::test_connection::{capture_request, CaptureRequestReceiver};
use std::convert::Infallible;
use std::time::{Duration, UNIX_EPOCH};

fn test_client(update_builder: fn(Builder) -> Builder) -> (CaptureRequestReceiver, Client) {
@@ -90,12 +89,7 @@ async fn s3_object_lambda() {
        .customize()
        .await
        .unwrap()
        .map_operation(|mut op| {
            op.properties_mut()
                .insert(UNIX_EPOCH + Duration::from_secs(1234567890));
            Result::<_, Infallible>::Ok(op)
        })
        .unwrap()
        .request_time_for_tests(UNIX_EPOCH + Duration::from_secs(1234567890))
        .send()
        .await
        .unwrap();
Loading