Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/awslabs/aws-sdk-kotlin into…
Browse files Browse the repository at this point in the history
… jmespath-flatten
  • Loading branch information
0marperez committed Dec 13, 2024
2 parents 1a2d989 + eb24838 commit 7d8d115
Show file tree
Hide file tree
Showing 159 changed files with 179,717 additions and 21,486 deletions.
465 changes: 417 additions & 48 deletions CHANGELOG.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ AWS service clients are generated from [Smithy](https://awslabs.github.io/smithy
As such the code in `aws-sdk-kotlin` is a layer on top of generic Smithy based code generation tooling.


2. Smithy Kotlin Codegen repo ([awslabs/smithy-kotlin](https://github.com/awslabs/smithy-kotlin))
2. Smithy Kotlin Codegen repo ([smithy-lang/smithy-kotlin](https://github.com/smithy-lang/smithy-kotlin))

The `smithy-kotlin` repository contains the generic Smithy code generation tools for Kotlin.

If you want to contribute by diving into the codegen machinery and helping develop the SDK please refer to the [contributing guide](https://github.com/awslabs/smithy-kotlin/blob/main/CONTRIBUTING.md) in that repo.
If you want to contribute by diving into the codegen machinery and helping develop the SDK please refer to the [contributing guide](https://github.com/smithy-lang/smithy-kotlin/blob/main/CONTRIBUTING.md) in that repo.


## Reporting Bugs/Feature Requests
Expand Down Expand Up @@ -78,7 +78,7 @@ following fields:
| `id` | `string` | yes | | A unique identifier for this entry. We recommend you generate a UUID for this field. |
| `type` | `string` | yes | `bugfix`, `feature`, `documentation`, `misc` | The type of change being made. |
| `description` | `string` | yes | | A description of the change being made.<ul><li>Prefix with `**Breaking**:` if the change is breaking</li><li>Use the imperative present tense (e.g., "change" not "changed" nor "changes")</li><li>Capitalize first letter</li><li>No dot (.) at the end unless there are multiple sentences</li></ul> |
| `issues` | `string[]` | no | | A list of references to any related issues in the relevant repositories. A reference can be specified in several ways:<ul><li>The issue number, if local to this repository (eg. `#12345`)</li><li>A fully-qualified issue ID (eg.`awslabs/smithy-kotlin#12345`)</li><li>A fully-qualified URL (eg. `https://issuetracker.com/12345`)</li></ul> |
| `issues` | `string[]` | no | | A list of references to any related issues in the relevant repositories. A reference can be specified in several ways:<ul><li>The issue number, if local to this repository (eg. `#12345`)</li><li>A fully-qualified issue ID (eg.`smithy-lang/smithy-kotlin#12345`)</li><li>A fully-qualified URL (eg. `https://issuetracker.com/12345`)</li></ul> |
| `module` | `string` | no | | The area of the code affected by your changes. If unsure, leave this value unset. |
| `requiresMinorVersionBump` | `boolean` | no | | Indicates the change will require a new minor version. This is usually the case after a breaking change. Defaults to false if flag is not included. |

Expand Down
1 change: 1 addition & 0 deletions aws-runtime/aws-http/api/aws-http.api
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ public final class aws/sdk/kotlin/runtime/http/interceptors/AwsBusinessMetric :
public static final field S3_EXPRESS_BUCKET Laws/sdk/kotlin/runtime/http/interceptors/AwsBusinessMetric;
public static fun getEntries ()Lkotlin/enums/EnumEntries;
public fun getIdentifier ()Ljava/lang/String;
public fun toString ()Ljava/lang/String;
public static fun valueOf (Ljava/lang/String;)Laws/sdk/kotlin/runtime/http/interceptors/AwsBusinessMetric;
public static fun values ()[Laws/sdk/kotlin/runtime/http/interceptors/AwsBusinessMetric;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,19 @@ 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.http.request.toBuilder
import aws.smithy.kotlin.runtime.telemetry.logging.Logger
import aws.smithy.kotlin.runtime.telemetry.logging.logger
import kotlin.coroutines.coroutineContext

/**
* Appends business metrics to the `User-Agent` header.
*/
public class BusinessMetricsInterceptor : HttpInterceptor {
override suspend fun modifyBeforeTransmit(context: ProtocolRequestInterceptorContext<Any, HttpRequest>): HttpRequest {
val logger = coroutineContext.logger<BusinessMetricsInterceptor>()

context.executionContext.getOrNull(BusinessMetrics)?.let { metrics ->
val metricsString = formatMetrics(metrics)
val metricsString = formatMetrics(metrics, logger)
val currentUserAgentHeader = context.protocolRequest.headers[USER_AGENT]
val modifiedRequest = context.protocolRequest.toBuilder()

Expand All @@ -34,10 +39,22 @@ public class BusinessMetricsInterceptor : HttpInterceptor {

/**
* Makes sure the metrics do not exceed the maximum size and truncates them if so.
* Makes sure that metric identifiers are not > 2 chars in length. Skips them if so.
*/
private fun formatMetrics(metrics: MutableSet<BusinessMetric>): String {
if (metrics.isEmpty()) return ""
val metricsString = metrics.joinToString(",", "m/") { it.identifier }
private fun formatMetrics(metrics: MutableSet<BusinessMetric>, logger: Logger): String {
val allowedMetrics = metrics.filter {
if (it.identifier.length > 2) {
logger.warn {
"Business metric '${it.identifier}' will be skipped due to length being > 2. " +
"This is likely a bug. Please raise an issue at https://github.com/awslabs/aws-sdk-kotlin/issues/new/choose"
}
false
} else {
true
}
}
if (allowedMetrics.isEmpty()) return ""
val metricsString = allowedMetrics.joinToString(",", "m/") { it.identifier }
val metricsByteArray = metricsString.encodeToByteArray()

if (metricsByteArray.size <= BUSINESS_METRICS_MAX_LENGTH) return metricsString
Expand Down Expand Up @@ -65,4 +82,7 @@ private fun formatMetrics(metrics: MutableSet<BusinessMetric>): String {
public enum class AwsBusinessMetric(public override val identifier: String) : BusinessMetric {
S3_EXPRESS_BUCKET("J"),
DDB_MAPPER("d"),
;

override fun toString(): String = identifier
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class UserAgent(

// NOTE: Due to legacy issues with processing the user agent, the original content for
// x-amz-user-agent and User-Agent is swapped here. See top note in the
// sdk-user-agent-header SEP and https://github.com/awslabs/smithy-kotlin/issues/373
// sdk-user-agent-header SEP and https://github.com/smithy-lang/smithy-kotlin/issues/373
// for further details.
req.subject.headers[USER_AGENT] = requestMetadata.xAmzUserAgent
req.subject.headers[X_AMZ_USER_AGENT] = requestMetadata.userAgent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ import aws.smithy.kotlin.runtime.businessmetrics.BusinessMetric
import aws.smithy.kotlin.runtime.businessmetrics.SmithyBusinessMetric
import aws.smithy.kotlin.runtime.businessmetrics.emitBusinessMetric
import aws.smithy.kotlin.runtime.client.ProtocolRequestInterceptorContext
import aws.smithy.kotlin.runtime.collections.get
import aws.smithy.kotlin.runtime.http.*
import aws.smithy.kotlin.runtime.http.request.HttpRequest
import aws.smithy.kotlin.runtime.net.url.Url
import aws.smithy.kotlin.runtime.operation.ExecutionContext
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlin.test.*

class BusinessMetricsInterceptorTest {
@Test
Expand All @@ -32,6 +28,23 @@ class BusinessMetricsInterceptorTest {
assertFalse(userAgentHeader.endsWith("m/"))
}

@Test
fun noValidBusinessMetrics() = runTest {
val executionContext = ExecutionContext()

val invalidBusinessMetric = object : BusinessMetric {
override val identifier: String = "All work and no play makes Jack a dull boy".repeat(1000)
}

executionContext.emitBusinessMetric(invalidBusinessMetric)

val interceptor = BusinessMetricsInterceptor()
val request = interceptor.modifyBeforeTransmit(interceptorContext(executionContext))
val userAgentHeader = request.headers[USER_AGENT]!!

assertFalse(userAgentHeader.endsWith("m/"))
}

@Test
fun businessMetrics() = runTest {
val executionContext = ExecutionContext()
Expand Down Expand Up @@ -66,49 +79,57 @@ class BusinessMetricsInterceptorTest {
}

@Test
fun truncateBusinessMetrics() = runTest {
fun businessMetricsMaxLength() = runTest {
val executionContext = ExecutionContext()
executionContext.attributes[aws.smithy.kotlin.runtime.businessmetrics.BusinessMetrics] = mutableSetOf()

for (i in 0..1024) {
for (i in 0..BUSINESS_METRICS_MAX_LENGTH) {
executionContext.emitBusinessMetric(
object : BusinessMetric {
override val identifier: String = i.toString()
},
)
}

val rawMetrics = executionContext[aws.smithy.kotlin.runtime.businessmetrics.BusinessMetrics]
val rawMetricsString = rawMetrics.joinToString(",", "m/")
val rawMetricsByteArray = rawMetricsString.encodeToByteArray()

assertTrue(rawMetricsByteArray.size >= BUSINESS_METRICS_MAX_LENGTH)

val interceptor = BusinessMetricsInterceptor()
val request = interceptor.modifyBeforeTransmit(interceptorContext(executionContext))
val userAgentHeader = request.headers[USER_AGENT]!!
val truncatedMetrics = "m/" + userAgentHeader.substringAfter("m/")
val metrics = "m/" + userAgentHeader.substringAfter("m/")

assertTrue(truncatedMetrics.encodeToByteArray().size <= BUSINESS_METRICS_MAX_LENGTH)
assertFalse(truncatedMetrics.endsWith(","))
assertTrue(metrics.encodeToByteArray().size <= BUSINESS_METRICS_MAX_LENGTH)
assertFalse(metrics.endsWith(","))
}

@Test
fun malformedBusinessMetrics() = runTest {
fun invalidBusinessMetric() = runTest {
val executionContext = ExecutionContext()
val reallyLongMetric = "All work and no play makes Jack a dull boy".repeat(1000)

executionContext.attributes.emitBusinessMetric(
object : BusinessMetric {
override val identifier: String = reallyLongMetric
},
)
val validMetric = AwsBusinessMetric.S3_EXPRESS_BUCKET
val invalidMetric = object : BusinessMetric {
override val identifier: String = "All work and no play makes Jack a dull boy".repeat(1000)
}

executionContext.attributes.emitBusinessMetric(validMetric)
executionContext.attributes.emitBusinessMetric(invalidMetric)

val interceptor = BusinessMetricsInterceptor()
val request = interceptor.modifyBeforeTransmit(interceptorContext(executionContext))
val userAgentHeader = request.headers[USER_AGENT]!!

assertFailsWith<IllegalStateException>("Business metrics are incorrectly formatted:") {
interceptor.modifyBeforeTransmit(interceptorContext(executionContext))
}
assertTrue(
userAgentHeader.contains(validMetric.identifier),
)
assertFalse(
userAgentHeader.contains(invalidMetric.identifier),
)
}

@Test
fun businessMetricToString() {
val businessMetricToString = AwsBusinessMetric.S3_EXPRESS_BUCKET.toString()
val businessMetricIdentifier = AwsBusinessMetric.S3_EXPRESS_BUCKET.identifier

assertEquals(businessMetricIdentifier, businessMetricToString)
}
}

Expand Down
5 changes: 5 additions & 0 deletions bom/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ fun createBomConstraintsAndVersionCatalog() {
}
}

// Add the BOM itself to the version catalog
catalogExt.versionCatalog {
library("bom", "aws.sdk.kotlin:bom:$version")
}

val ignoredSmithyKotlin = setOf(
"smithy.kotlin.codegen",
"smithy.kotlin.http.test",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package aws.sdk.kotlin.codegen.smoketests

import software.amazon.smithy.kotlin.codegen.KotlinSettings
import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration
import software.amazon.smithy.kotlin.codegen.integration.SectionWriterBinding
import software.amazon.smithy.kotlin.codegen.rendering.smoketests.SmokeTestSectionIds.SmokeTestsFile
import software.amazon.smithy.model.Model

/**
* SDK ID's of services that are deny listed from smoke test code generation.
*/
val smokeTestDenyList = setOf(
"S3Tables",
)

/**
* Will wipe the smoke test runner file for services that are deny listed.
* Some services model smoke tests incorrectly and the code generated file will not compile.
*/
class SmokeTestsDenyListIntegration : KotlinIntegration {
override fun enabledForService(model: Model, settings: KotlinSettings): Boolean =
settings.sdkId in smokeTestDenyList

override val sectionWriters: List<SectionWriterBinding>
get() = listOf(
SectionWriterBinding(
SmokeTestsFile,
) { writer, _ ->
writer.write("// Smoke tests for service are deny listed")
},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ aws.sdk.kotlin.codegen.customization.s3.express.S3ExpressIntegration
aws.sdk.kotlin.codegen.customization.s3.S3ExpiresIntegration
aws.sdk.kotlin.codegen.BusinessMetricsIntegration
aws.sdk.kotlin.codegen.smoketests.AwsSmokeTestsRunnerGeneratorIntegration
aws.sdk.kotlin.codegen.smoketests.SmokeTestsDenyListIntegration
aws.sdk.kotlin.codegen.smoketests.testing.SmokeTestSuccessHttpEngineIntegration
aws.sdk.kotlin.codegen.smoketests.testing.SmokeTestFailHttpEngineIntegration
aws.sdk.kotlin.codegen.customization.AwsQueryModeCustomization
Loading

0 comments on commit 7d8d115

Please sign in to comment.