diff --git a/services/build.gradle.kts b/services/build.gradle.kts index 601ddf52a5e..b5805b4aa64 100644 --- a/services/build.gradle.kts +++ b/services/build.gradle.kts @@ -102,6 +102,12 @@ subprojects { } } + if (project.name == "route53") { + dependencies { + implementation(libraries.smithy.kotlin.http.test) // needed for URI E2E tests + } + } + // Run the tests with the classpath containing the compile dependencies (including 'main'), // runtime dependencies, and the outputs of this compilation: classpath = compileDependencyFiles + runtimeDependencyFiles + output.allOutputs diff --git a/services/route53/e2eTest/src/Route53UriTest.kt b/services/route53/e2eTest/src/Route53UriTest.kt new file mode 100644 index 00000000000..6ec9e6ac25d --- /dev/null +++ b/services/route53/e2eTest/src/Route53UriTest.kt @@ -0,0 +1,168 @@ +package aws.sdk.kotlin.services.route53 + +import aws.sdk.kotlin.runtime.auth.credentials.StaticCredentialsProvider +import aws.smithy.kotlin.runtime.auth.awscredentials.Credentials +import aws.smithy.kotlin.runtime.client.ProtocolRequestInterceptorContext +import aws.smithy.kotlin.runtime.http.interceptors.HttpInterceptor +import aws.smithy.kotlin.runtime.http.request.HttpRequest +import aws.smithy.kotlin.runtime.httptest.TestEngine +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.fail + +class Route53UriTest { + /** + * Validates that HostedZoneId isn't trimmed when not prefixed + */ + @Test + fun listResourceRecordSetsNoTrim() = runTest { + Route53Client { + region = "us-east-1" + httpClient = TestEngine() + interceptors = mutableListOf( + AssertUrlInterceptor( + expectedUrl = "/0000-00-00/hostedzone/IDOFMYHOSTEDZONE/rrset", + ), + ) + credentialsProvider = StaticCredentialsProvider(Credentials("AKID", "SECRETAK")) + }.use { client -> + client.listResourceRecordSets { + hostedZoneId = "IDOFMYHOSTEDZONE" + } + } + } + + /** + * Validates that HostedZoneId is trimmed + */ + @Test + fun listResourceRecordSetsTrim() = runTest { + Route53Client { + region = "us-east-1" + httpClient = TestEngine() + interceptors = mutableListOf( + AssertUrlInterceptor( + expectedUrl = "/0000-00-00/hostedzone/IDOFMYHOSTEDZONE/rrset", + ), + ) + credentialsProvider = StaticCredentialsProvider(Credentials("AKID", "SECRETAK")) + }.use { client -> + client.listResourceRecordSets { + hostedZoneId = "hostedzone/IDOFMYHOSTEDZONE" + } + } + } + + /** + * Validates that HostedZoneId is trimmed even with a leading slash + */ + @Test + fun listResourceRecordSetsTrimLeadingSlash() = runTest { + Route53Client { + region = "us-east-1" + httpClient = TestEngine() + interceptors = mutableListOf( + AssertUrlInterceptor( + expectedUrl = "/0000-00-00/hostedzone/IDOFMYHOSTEDZONE/rrset", + ), + ) + credentialsProvider = StaticCredentialsProvider(Credentials("AKID", "SECRETAK")) + }.use { client -> + client.listResourceRecordSets { + hostedZoneId = "/hostedzone/IDOFMYHOSTEDZONE" + } + } + } + + /** + * Validates that HostedZoneId isn't over-trimmed + */ + @Test + fun listResourceRecordSetsTrimMultiSlash() = runTest { + Route53Client { + region = "us-east-1" + httpClient = TestEngine() + interceptors = mutableListOf( + AssertUrlInterceptor( + expectedUrl = "/0000-00-00/hostedzone/IDOFMY%2FHOSTEDZONE/rrset", + ), + ) + credentialsProvider = StaticCredentialsProvider(Credentials("AKID", "SECRETAK")) + }.use { client -> + client.listResourceRecordSets { + hostedZoneId = "/hostedzone/IDOFMY/HOSTEDZONE" + } + } + } + + /** + * This test validates that change id is correctly trimmed + */ + @Test + fun getChangeTrimChangeId() = runTest { + Route53Client { + region = "us-east-1" + httpClient = TestEngine() + interceptors = mutableListOf( + AssertUrlInterceptor( + expectedUrl = "/0000-00-00/change/SOMECHANGEID", + ), + ) + credentialsProvider = StaticCredentialsProvider(Credentials("AKID", "SECRETAK")) + }.use { client -> + client.getChange { + id = "/change/SOMECHANGEID" + } + } + } + + /** + * This test validates that delegation set id is correctly trimmed + */ + @Test + fun getReusableDelegationSetTrimDelegationSetId() = runTest { + Route53Client { + region = "us-east-1" + httpClient = TestEngine() + interceptors = mutableListOf( + AssertUrlInterceptor( + expectedUrl = "/0000-00-00/delegationset/DELEGATIONSETID", + ), + ) + credentialsProvider = StaticCredentialsProvider(Credentials("AKID", "SECRETAK")) + }.use { client -> + client.getReusableDelegationSet { + id = "/delegationset/DELEGATIONSETID" + } + } + } + + /** + * Model version can change the URL used as it's included in the URL. + * This interceptor removes the model version from the expected and actual URLs. + * Then performs an equality assertion between the two. + * + * https://github.com/awslabs/aws-sdk-kotlin/issues/1370 + */ + private class AssertUrlInterceptor(private val expectedUrl: String) : HttpInterceptor { + override fun readBeforeTransmit(context: ProtocolRequestInterceptorContext) { + val actualUrl = context.protocolRequest.url.path.toString() + + val parsedActualUrl = removeModelVersion(actualUrl) + val parsedExpectedUrl = removeModelVersion(expectedUrl) + + assertEquals(parsedExpectedUrl, parsedActualUrl) + } + + private fun removeModelVersion(url: String) = + try { + url.replaceFirst( + Regex("^/\\d{4}-\\d{2}-\\d{2}/"), + "//", + ) + } catch (e: Exception) { + fail("The URL '$url' is not in the expected format", e) + } + } +} diff --git a/services/route53/model/route53-tests.smithy b/services/route53/model/route53-tests.smithy deleted file mode 100644 index f30e73777c3..00000000000 --- a/services/route53/model/route53-tests.smithy +++ /dev/null @@ -1,81 +0,0 @@ -$version: "1.0" - -namespace com.amazonaws.route53 - -use smithy.test#httpRequestTests - - -apply ListResourceRecordSets @httpRequestTests([ - { - id: "ListResourceRecordSetsNoTrim", - documentation: "Validates that HostedZoneId isn't trimmed when not prefixed.", - method: "GET", - protocol: "aws.protocols#restXml", - uri: "/2013-04-01/hostedzone/IDOFMYHOSTEDZONE/rrset", - bodyMediaType: "application/xml", - params: { - "HostedZoneId": "IDOFMYHOSTEDZONE" - } - }, - { - id: "ListResourceRecordSetsTrim", - documentation: "Validates that HostedZoneId is trimmed.", - method: "GET", - protocol: "aws.protocols#restXml", - uri: "/2013-04-01/hostedzone/IDOFMYHOSTEDZONE/rrset", - bodyMediaType: "application/xml", - params: { - "HostedZoneId": "hostedzone/IDOFMYHOSTEDZONE" - } - }, - { - id: "ListResourceRecordSetsTrimLeadingSlash", - documentation: "Validates that HostedZoneId is trimmed even with a leading slash.", - method: "GET", - protocol: "aws.protocols#restXml", - uri: "/2013-04-01/hostedzone/IDOFMYHOSTEDZONE/rrset", - bodyMediaType: "application/xml", - params: { - "HostedZoneId": "/hostedzone/IDOFMYHOSTEDZONE" - } - }, - { - id: "ListResourceRecordSetsTrimMultislash", - documentation: "Validates that HostedZoneId isn't over-trimmed.", - method: "GET", - protocol: "aws.protocols#restXml", - uri: "/2013-04-01/hostedzone/IDOFMY%2FHOSTEDZONE/rrset", - bodyMediaType: "application/xml", - params: { - "HostedZoneId": "/hostedzone/IDOFMY/HOSTEDZONE" - } - }, -]) - -apply GetChange @httpRequestTests([ - { - id: "GetChangeTrimChangeId", - documentation: "This test validates that change id is correctly trimmed", - method: "GET", - protocol: "aws.protocols#restXml", - uri: "/2013-04-01/change/SOMECHANGEID", - bodyMediaType: "application/xml", - params: { - "Id": "/change/SOMECHANGEID" - } - }, -]) - -apply GetReusableDelegationSet @httpRequestTests([ - { - id: "GetReusableDelegationSetTrimDelegationSetId", - documentation: "This test validates that delegation set id is correctly trimmed", - method: "GET", - protocol: "aws.protocols#restXml", - uri: "/2013-04-01/delegationset/DELEGATIONSETID", - bodyMediaType: "application/xml", - params: { - "Id": "/delegationset/DELEGATIONSETID" - } - }, -]) \ No newline at end of file