diff --git a/.github/actions/setup-build/action.yml b/.github/actions/setup-build/action.yml index 0a2b5cbb99..5e72c0c6d5 100644 --- a/.github/actions/setup-build/action.yml +++ b/.github/actions/setup-build/action.yml @@ -5,11 +5,20 @@ description: > runs: using: composite steps: - - name: Checkout tools + - name: Extract aws-kotlin-repo-tools version + working-directory: ./smithy-kotlin + shell: bash + run: | + export AWS_KOTLIN_REPO_TOOLS_VERSION=$(grep '^aws-kotlin-repo-tools-version' ./gradle/libs.versions.toml | sed -E 's/.*= "(.*)"/\1/') + echo "Using aws-kotlin-repo-tools version $AWS_KOTLIN_REPO_TOOLS_VERSION" + echo "aws_kotlin_repo_tools_version=$AWS_KOTLIN_REPO_TOOLS_VERSION" >> $GITHUB_ENV + + - name: Checkout aws-kotlin-repo-tools uses: actions/checkout@v4 with: path: 'aws-kotlin-repo-tools' repository: 'awslabs/aws-kotlin-repo-tools' + ref: ${{ env.aws_kotlin_repo_tools_version }} sparse-checkout: | .github @@ -19,6 +28,7 @@ runs: # checkout aws-crt-kotlin as a sibling which will automatically make it an included build path: 'aws-crt-kotlin' repository: 'awslabs/aws-crt-kotlin' + submodules: 'true' # Cache the Kotlin/Native toolchain based on the input Kotlin version from version catalog # see https://kotlinlang.org/docs/native-improving-compilation-time.html diff --git a/.github/scripts/run-container-test.py b/.github/scripts/run-container-test.py new file mode 100755 index 0000000000..56d9be34d3 --- /dev/null +++ b/.github/scripts/run-container-test.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +Run precompiled Kotlin/Native test binaries in a Docker container for a specific Linux distribution and architecture. + +This requires Docker multiarch support, see https://docs.docker.com/build/building/multi-platform/ and https://github.com/multiarch/qemu-user-static +In GitHub we use a provided action for this: https://github.com/docker/setup-qemu-action + +Locally you would need to run one of: + +`docker run --rm --privileged multiarch/qemu-user-static --reset -p yes --credential yes` + +OR + +`docker run --privileged --rm tonistiigi/binfmt --install all` +""" + +import argparse +import os +import subprocess +import shlex +import shutil + +VERBOSE = False + +DISTRO_TO_IMAGE_NAME = { + "ubuntu-22.04": "public.ecr.aws/lts/ubuntu:22.04_stable", + "al2023": "public.ecr.aws/amazonlinux/amazonlinux:2023", + "al2": "public.ecr.aws/amazonlinux/amazonlinux:2" +} + +DOCKER_PLATFORM_BY_ARCH = { + "x64": "linux/amd64", + "arm64": "linux/arm64" +} + + +def vprint(message): + global VERBOSE + if VERBOSE: + print(message) + + +def running_in_github_action(): + """ + Test if currently running in a GitHub action or running locally + :return: True if running in GH, False otherwise + """ + return "GITHUB_WORKFLOW" in os.environ + + +def shell(command, cwd=None, check=True, capture_output=False): + """ + Run a command + :param command: command to run + :param cwd: the current working directory to change to before executing the command + :param check: flag indicating if the status code should be checked. When true an exception will be + thrown if the command exits with a non-zero exit status. + :returns: the subprocess CompletedProcess output + """ + vprint(f"running `{command}`") + return subprocess.run(command, shell=True, check=check, cwd=cwd, capture_output=capture_output) + + +def oci_executable(): + """ + Attempt to find the OCI container executor used to build and run docker containers + """ + oci_exe = os.environ.get('OCI_EXE') + if oci_exe is not None: + return oci_exe + + executors = ['finch', 'podman', 'docker'] + + for exe in executors: + if shutil.which(exe) is not None: + return exe + + print("cannot find container executor") + exit(1) + + +def run_docker_test(opts): + """ + Run a docker test for a precompiled Kotlin/Native binary + + :param opts: the parsed command line options + """ + platform = DOCKER_PLATFORM_BY_ARCH[opts.arch] + oci_exe = oci_executable() + + test_bin_dir = os.path.abspath(opts.test_bin_dir) + image_name = DISTRO_TO_IMAGE_NAME[opts.distro] + path_to_exe = f'./linux{opts.arch.capitalize()}/debugTest/test.kexe' + + cmd = [ + oci_exe, + 'run', + '--rm', + f'-v{test_bin_dir}:/test', + ] + if not opts.no_system_certs: + cmd.append(f'-v/etc/ssl:/etc/ssl') + + cmd.extend( + [ + '-w/test', + '-e DEBIAN_FRONTEND=noninteractive', + '--platform', + platform, + image_name, + path_to_exe, + ] + ) + + cmd = shlex.join(cmd) + print(cmd) + shell(cmd) + + +def create_cli(): + parser = argparse.ArgumentParser( + prog="run-container-test", + description="Run cross platform test binaries in a container", + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + + parser.add_argument("-v", "--verbose", help="enable verbose output", action="store_true") + + parser.add_argument("--distro", required=True, choices=DISTRO_TO_IMAGE_NAME.keys(), help="the distribution name to run the task on") + parser.add_argument("--arch", required=True, choices=DOCKER_PLATFORM_BY_ARCH.keys(), help="the architecture to use") + parser.add_argument("--test-bin-dir", required=True, help="the path to the test binary directory root") + parser.add_argument("--no-system-certs", action='store_true', help="disable mounting system certificates into the container") + + return parser + + +def main(): + cli = create_cli() + opts = cli.parse_args() + if opts.verbose: + global VERBOSE + VERBOSE = True + + run_docker_test(opts) + + +if __name__ == '__main__': + main() diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45b7b9cacc..a3cdbee204 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,7 +67,7 @@ jobs: # FIXME K2. Re-enable warnings as errors after this warning is removed: https://youtrack.jetbrains.com/issue/KT-68532 # echo "kotlinWarningsAsErrors=true" >> $GITHUB_WORKSPACE/local.properties ./gradlew apiCheck - ./gradlew -Paws.sdk.kotlin.crt.disableCrossCompile=true build + ./gradlew -Paws.sdk.kotlin.crt.disableCrossCompile=true -Paws.kotlin.native.disableCrossCompile=true build - name: Save Test Reports if: failure() @@ -126,7 +126,7 @@ jobs: working-directory: ./smithy-kotlin run: | ./gradlew apiCheck - ./gradlew -P"aws.sdk.kotlin.crt.disableCrossCompile"=true build + ./gradlew -P"aws.kotlin.native=false" build - name: Save Test Reports if: failure() diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0c24fffbf..5d6bba774e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -223,3 +223,25 @@ If you discover a potential security issue in this project we ask that you notif See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. + +## Kotlin/Native +Support for Kotlin/Native is in active development. The following sections cover how to effectively test your work. + +### Linux/Unix + +#### Testing Different Linux Distros and Architectures + +1. Build the test executable(s) for the architecture(s) you want to test. + +```sh +# build specific arch +./gradlew linuxX64TestBinaries +``` + +2. Use the `run-container-test.py` helper script to execute tests locally. Change the directory as needed. + +```sh +OCI_EXE=docker python3 .github/scripts/run-container-test.py --distro al2 --arch x64 --test-bin-dir ./runtime/runtime-core/build/bin +``` + +See the usage/help for different distributions provided: `python3 .github/scripts/run-container.py -h` diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts index 51b05616c1..8af09dbf58 100644 --- a/bom/build.gradle.kts +++ b/bom/build.gradle.kts @@ -7,8 +7,6 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget -import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget -import java.util.* plugins { `maven-publish` @@ -52,7 +50,6 @@ fun createBomConstraintsAndVersionCatalog() { fun Project.artifactId(target: KotlinTarget): String = when (target) { is KotlinMetadataTarget -> name - is KotlinJsTarget -> "$name-js" else -> "$name-${target.targetName.lowercase()}" } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f52b1a56cb..31cf20db25 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ kotlin-version = "2.0.21" dokka-version = "1.9.10" -aws-kotlin-repo-tools-version = "0.4.15-kn" +aws-kotlin-repo-tools-version = "0.4.20-kn" # libs coroutines-version = "1.9.0" @@ -96,6 +96,7 @@ ktor-server-netty = { module = "io.ktor:ktor-server-netty", version.ref = "ktor- ktor-server-jetty-jakarta = { module = "io.ktor:ktor-server-jetty-jakarta", version.ref = "ktor-version" } ktor-server-cio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor-version" } ktor-network-tls-certificates = { module = "io.ktor:ktor-network-tls-certificates", version.ref = "ktor-version" } +ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor-version" } kaml = { module = "com.charleskorn.kaml:kaml", version.ref = "kaml-version" } jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup-version" } diff --git a/runtime/auth/aws-signing-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/auth/awssigning/crt/CrtSigningSuiteTest.kt b/runtime/auth/aws-signing-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/auth/awssigning/crt/CrtSigningSuiteTest.kt index 1b7ed92a07..f312bf09a0 100644 --- a/runtime/auth/aws-signing-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/auth/awssigning/crt/CrtSigningSuiteTest.kt +++ b/runtime/auth/aws-signing-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/auth/awssigning/crt/CrtSigningSuiteTest.kt @@ -9,10 +9,4 @@ import aws.smithy.kotlin.runtime.auth.awssigning.tests.SigningSuiteTestBase class CrtSigningSuiteTest : SigningSuiteTestBase() { override val signer: AwsSigner = CrtAwsSigner - - override val disabledTests = super.disabledTests + setOf( - // FIXME - Signature mismatch possibly related to https://github.com/awslabs/aws-crt-java/pull/419. Needs - // investigation. - "get-utf8", - ) } diff --git a/runtime/build.gradle.kts b/runtime/build.gradle.kts index 2c136ebdbf..393b614360 100644 --- a/runtime/build.gradle.kts +++ b/runtime/build.gradle.kts @@ -4,6 +4,7 @@ */ import aws.sdk.kotlin.gradle.dsl.configurePublishing import aws.sdk.kotlin.gradle.kmp.* +import aws.sdk.kotlin.gradle.util.typedProp import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { @@ -17,6 +18,15 @@ val sdkVersion: String by project // Apply KMP configuration from build plugin configureKmpTargets() +// Disable cross compilation if flag is set +val disableCrossCompile = typedProp("aws.kotlin.native.disableCrossCompile") == true +if (disableCrossCompile) { + logger.warn("aws.kotlin.native.disableCrossCompile=true: Cross compilation is disabled.") + allprojects { + disableCrossCompileTargets() + } +} + // capture locally - scope issue with custom KMP plugin val libraries = libs diff --git a/runtime/protocol/http-client-engines/http-client-engine-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/http/engine/crt/AsyncStressTest.kt b/runtime/protocol/http-client-engines/http-client-engine-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/http/engine/crt/AsyncStressTest.kt index 96efc44f7a..39f4170550 100644 --- a/runtime/protocol/http-client-engines/http-client-engine-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/http/engine/crt/AsyncStressTest.kt +++ b/runtime/protocol/http-client-engines/http-client-engine-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/http/engine/crt/AsyncStressTest.kt @@ -13,7 +13,6 @@ import aws.smithy.kotlin.runtime.http.request.url import aws.smithy.kotlin.runtime.httptest.TestWithLocalServer import aws.smithy.kotlin.runtime.net.Host import aws.smithy.kotlin.runtime.net.Scheme -import aws.smithy.kotlin.runtime.testing.IgnoreWindows import io.ktor.server.cio.* import io.ktor.server.engine.* import io.ktor.server.response.* @@ -25,9 +24,7 @@ import kotlinx.coroutines.yield import kotlin.test.Test import kotlin.time.Duration.Companion.seconds -// FIXME This test implements [TestWithLocalServer] which is JVM-only. class AsyncStressTest : TestWithLocalServer() { - override val server = embeddedServer(CIO, serverPort) { routing { get("/largeResponse") { @@ -37,9 +34,8 @@ class AsyncStressTest : TestWithLocalServer() { call.respondText(text.repeat(respSize / text.length)) } } - } + }.start() - @IgnoreWindows("FIXME - times out after upgrade to kotlinx.coroutines 1.6.0") @Test fun testStreamNotConsumed() = runBlocking { // test that filling the stream window and not consuming the body stream still cleans up resources diff --git a/runtime/protocol/http-client-engines/http-client-engine-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/http/engine/crt/SendChunkedBodyTest.kt b/runtime/protocol/http-client-engines/http-client-engine-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/http/engine/crt/SendChunkedBodyTest.kt index d0e2e2cf94..88366c41f0 100644 --- a/runtime/protocol/http-client-engines/http-client-engine-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/http/engine/crt/SendChunkedBodyTest.kt +++ b/runtime/protocol/http-client-engines/http-client-engine-crt/jvmAndNative/test/aws/smithy/kotlin/runtime/http/engine/crt/SendChunkedBodyTest.kt @@ -33,7 +33,7 @@ class SendChunkedBodyTest { val chunkedBytes = """ 100;chunk-signature=${"0".repeat(64)}\r\n${"0".repeat(256)}\r\n\r\n - """.trimIndent().toByteArray() + """.trimIndent().encodeToByteArray() val source = chunkedBytes.source() @@ -52,7 +52,7 @@ class SendChunkedBodyTest { val chunkedBytes = """ ${chunkSize.toString(16)};chunk-signature=${"0".repeat(64)}\r\n${"0".repeat(chunkSize)}\r\n\r\n - """.trimIndent().toByteArray() + """.trimIndent().encodeToByteArray() val source = chunkedBytes.source() @@ -71,7 +71,7 @@ class SendChunkedBodyTest { val chunkedBytes = """ 100;chunk-signature=${"0".repeat(64)}\r\n${"0".repeat(256)}\r\n\r\n - """.trimIndent().toByteArray() + """.trimIndent().encodeToByteArray() val channel = SdkByteReadChannel(chunkedBytes) @@ -91,7 +91,7 @@ class SendChunkedBodyTest { val chunkedBytes = """ ${chunkSize.toString(16)};chunk-signature=${"0".repeat(64)}\r\n${"0".repeat(chunkSize)}\r\n\r\n - """.trimIndent().toByteArray() + """.trimIndent().encodeToByteArray() val channel = SdkByteReadChannel(chunkedBytes) diff --git a/runtime/protocol/http-test/build.gradle.kts b/runtime/protocol/http-test/build.gradle.kts index a2077a979c..e966832924 100644 --- a/runtime/protocol/http-test/build.gradle.kts +++ b/runtime/protocol/http-test/build.gradle.kts @@ -28,6 +28,14 @@ kotlin { } } + jvmAndNativeMain { + dependencies { + api(libs.ktor.server.cio) + implementation(libs.ktor.client.core) + implementation(libs.ktor.server.core) + } + } + all { languageSettings.optIn("aws.smithy.kotlin.runtime.InternalApi") } diff --git a/runtime/protocol/http-test/jvm/src/aws/smithy/kotlin/runtime/httptest/TestWithLocalServer.kt b/runtime/protocol/http-test/jvmAndNative/src/aws/smithy/kotlin/runtime/httptest/TestWithLocalServer.kt similarity index 56% rename from runtime/protocol/http-test/jvm/src/aws/smithy/kotlin/runtime/httptest/TestWithLocalServer.kt rename to runtime/protocol/http-test/jvmAndNative/src/aws/smithy/kotlin/runtime/httptest/TestWithLocalServer.kt index 3ffc1a868c..370c8f9b7c 100644 --- a/runtime/protocol/http-test/jvm/src/aws/smithy/kotlin/runtime/httptest/TestWithLocalServer.kt +++ b/runtime/protocol/http-test/jvmAndNative/src/aws/smithy/kotlin/runtime/httptest/TestWithLocalServer.kt @@ -5,11 +5,17 @@ package aws.smithy.kotlin.runtime.httptest -import io.ktor.server.engine.* +import io.ktor.client.request.get +import io.ktor.network.selector.SelectorManager +import io.ktor.network.sockets.InetSocketAddress +import io.ktor.network.sockets.aSocket +import io.ktor.server.application.ApplicationStarted +import io.ktor.server.engine.EmbeddedServer +import io.ktor.utils.io.core.use +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout -import java.net.* -import java.util.concurrent.* import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.time.Duration.Companion.seconds @@ -19,13 +25,27 @@ import kotlin.time.Duration.Companion.seconds * mocking an HTTP client engine is difficult. */ public abstract class TestWithLocalServer { - protected val serverPort: Int = ServerSocket(0).use { it.localPort } + protected val serverPort: Int = runBlocking { + SelectorManager(this.coroutineContext).use { + aSocket(it) + .tcp() + .bind() + .use { (it.localAddress as InetSocketAddress).port } + } + } + protected val testHost: String = "localhost" public abstract val server: EmbeddedServer<*, *> @BeforeTest public fun startServer(): Unit = runBlocking { + val serverStarted = CompletableDeferred() + + server.monitor.subscribe(ApplicationStarted) { + serverStarted.complete(Unit) + } + withTimeout(5.seconds) { var attempt = 0 @@ -33,32 +53,20 @@ public abstract class TestWithLocalServer { attempt++ try { server.start() - println("test server listening on: $testHost:$serverPort") break } catch (cause: Throwable) { if (attempt >= 10) throw cause - Thread.sleep(250L * attempt) + delay(250L * attempt) } } while (true) - ensureServerRunning() + serverStarted.await() } } @AfterTest public fun stopServer() { - server.stop(0, 0, TimeUnit.SECONDS) + server.stop(0, 0) println("test server stopped") } - - private fun ensureServerRunning() { - do { - try { - Socket("localhost", serverPort).close() - break - } catch (_: Throwable) { - Thread.sleep(100) - } - } while (true) - } } diff --git a/runtime/runtime-core/build.gradle.kts b/runtime/runtime-core/build.gradle.kts index bbaa9d60ef..d902f42a7f 100644 --- a/runtime/runtime-core/build.gradle.kts +++ b/runtime/runtime-core/build.gradle.kts @@ -23,6 +23,12 @@ kotlin { } } + nativeMain { + dependencies { + api(libs.crt.kotlin) + } + } + commonTest { dependencies { // Coroutines' locking features are used in retry token bucket implementations diff --git a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/hashing/Crc32.kt b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/hashing/Crc32.kt index 84b76b89a0..454c4fc552 100644 --- a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/hashing/Crc32.kt +++ b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/hashing/Crc32.kt @@ -11,11 +11,13 @@ public abstract class Crc32Base : HashFunction { override val blockSizeBytes: Int = 4 override val digestSizeBytes: Int = 4 + /** + * Digest the current checksum, returning it as a [UInt] + */ public abstract fun digestValue(): UInt override fun digest(): ByteArray { val x = digestValue() - reset() return byteArrayOf( ((x shr 24) and 0xffu).toByte(), ((x shr 16) and 0xffu).toByte(), diff --git a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/hashing/Crc32c.kt b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/hashing/Crc32c.kt index da77560226..a6d9e10a61 100644 --- a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/hashing/Crc32c.kt +++ b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/hashing/Crc32c.kt @@ -21,7 +21,7 @@ public class Crc32c : Crc32Base() { override fun update(input: ByteArray, offset: Int, length: Int): Unit = md.update(input, offset, length) - override fun digestValue(): UInt = md.getValue().toUInt() + override fun digestValue(): UInt = md.getValue().toUInt().also { reset() } override fun reset(): Unit = md.reset() } diff --git a/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/hashing/Crc32Test.kt b/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/hashing/Crc32Test.kt index e3b489aba0..8f622fd513 100644 --- a/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/hashing/Crc32Test.kt +++ b/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/hashing/Crc32Test.kt @@ -20,7 +20,6 @@ class Crc32Test { val input = "foobar" crc.update(input.encodeToByteArray(), 0, input.length) - assertEquals(2666930069U, crc.digestValue()) // checksum of "foobar" assertEquals("nvYflQ==", crc.digest().encodeBase64String()) } @@ -39,9 +38,8 @@ class Crc32Test { val crc = Crc32() val input = "foobar" crc.update(input.encodeToByteArray(), 0, input.length / 2) - assertEquals(2356372769U, crc.digestValue()) // checksum of "foo" crc.update(input.encodeToByteArray(), (input.length - input.length / 2), input.length / 2) - assertEquals(2666930069U, crc.digestValue()) // checksum of "foobar" + assertEquals("nvYflQ==", crc.digest().encodeBase64String()) // checksum of "foobar" } @Test @@ -49,8 +47,7 @@ class Crc32Test { val crc = Crc32() val input = "foobar" crc.update(input.encodeToByteArray(), 0, input.length) - assertEquals(2666930069U, crc.digestValue()) // checksum of "foobar" - crc.digest() + assertEquals("nvYflQ==", crc.digest().encodeBase64String()) // checksum of "foobar" assertEquals(0U, crc.digestValue()) } } diff --git a/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/hashing/Crc32cTest.kt b/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/hashing/Crc32cTest.kt index 184f62cbd9..0123036e53 100644 --- a/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/hashing/Crc32cTest.kt +++ b/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/hashing/Crc32cTest.kt @@ -33,8 +33,6 @@ class Crc32cTest { val input = "foobar" crc.update(input.encodeToByteArray(), 0, input.length / 2) - assertEquals(3485773341U, crc.digestValue()) // checksum of "foo" - crc.update(input.encodeToByteArray(), (input.length - input.length / 2), input.length / 2) assertEquals(224353407U, crc.digestValue()) // checksum of "foobar" } @@ -45,8 +43,7 @@ class Crc32cTest { val input = "foobar" crc.update(input.encodeToByteArray(), 0, input.length) - assertEquals(224353407U, crc.digestValue()) // checksum of "foobar" - assertEquals("DV9cfw==", crc.digest().encodeBase64String()) + assertEquals("DV9cfw==", crc.digest().encodeBase64String()) // checksum of "foobar" } @Test diff --git a/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/hashing/Crc32JVM.kt b/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/hashing/Crc32JVM.kt index 0c42a47434..5afae09bad 100644 --- a/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/hashing/Crc32JVM.kt +++ b/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/hashing/Crc32JVM.kt @@ -13,7 +13,7 @@ public actual class Crc32 : Crc32Base() { actual override fun update(input: ByteArray, offset: Int, length: Int): Unit = md.update(input, offset, length) - actual override fun digestValue(): UInt = md.value.toUInt() + actual override fun digestValue(): UInt = md.value.toUInt().also { reset() } actual override fun reset(): Unit = md.reset() } diff --git a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Crc32Native.kt b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Crc32Native.kt index 2c40576e88..ef86e4e519 100644 --- a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Crc32Native.kt +++ b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Crc32Native.kt @@ -5,6 +5,7 @@ package aws.smithy.kotlin.runtime.hashing import aws.smithy.kotlin.runtime.InternalApi +import aws.sdk.kotlin.crt.util.hashing.Crc32 as CrtCrc32 /** * CRC-32 checksum. Note: [digest] will return the bytes (big endian) of the CRC32 integer value. Access [digestValue] @@ -12,15 +13,16 @@ import aws.smithy.kotlin.runtime.InternalApi */ @InternalApi public actual class Crc32 actual constructor() : Crc32Base() { - actual override fun digestValue(): UInt { - TODO("Not yet implemented") - } + private val delegate = CrtCrc32() - actual override fun update(input: ByteArray, offset: Int, length: Int) { - TODO("Not yet implemented") + actual override fun digestValue(): UInt { + val bytes = delegate.digest() + return ((bytes[0].toUInt() and 0xffu) shl 24) or + ((bytes[1].toUInt() and 0xffu) shl 16) or + ((bytes[2].toUInt() and 0xffu) shl 8) or + (bytes[3].toUInt() and 0xffu) } - actual override fun reset() { - TODO("Not yet implemented") - } + actual override fun update(input: ByteArray, offset: Int, length: Int): Unit = delegate.update(input, offset, length) + actual override fun reset(): Unit = delegate.reset() } diff --git a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Md5Native.kt b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Md5Native.kt index 9614543dad..efff134fc8 100644 --- a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Md5Native.kt +++ b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Md5Native.kt @@ -5,21 +5,15 @@ package aws.smithy.kotlin.runtime.hashing import aws.smithy.kotlin.runtime.InternalApi +import aws.sdk.kotlin.crt.util.hashing.Md5 as CrtMd5 /** * Implementation of RFC1321 MD5 digest */ @InternalApi public actual class Md5 actual constructor() : Md5Base() { - actual override fun update(input: ByteArray, offset: Int, length: Int) { - TODO("Not yet implemented") - } - - actual override fun digest(): ByteArray { - TODO("Not yet implemented") - } - - actual override fun reset() { - TODO("Not yet implemented") - } + private val delegate = CrtMd5() + actual override fun update(input: ByteArray, offset: Int, length: Int): Unit = delegate.update(input, offset, length) + actual override fun digest(): ByteArray = delegate.digest() + actual override fun reset(): Unit = delegate.reset() } diff --git a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Sha1Native.kt b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Sha1Native.kt index 6a4f4e1abc..541b25246f 100644 --- a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Sha1Native.kt +++ b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Sha1Native.kt @@ -5,21 +5,16 @@ package aws.smithy.kotlin.runtime.hashing import aws.smithy.kotlin.runtime.InternalApi +import aws.sdk.kotlin.crt.util.hashing.Sha1 as CrtSha1 /** * Implementation of SHA-1 (Secure Hash Algorithm 1) hash function. See: https://csrc.nist.gov/projects/hash-functions */ @InternalApi public actual class Sha1 actual constructor() : Sha1Base() { - actual override fun update(input: ByteArray, offset: Int, length: Int) { - TODO("Not yet implemented") - } + private val delegate = CrtSha1() - actual override fun digest(): ByteArray { - TODO("Not yet implemented") - } - - actual override fun reset() { - TODO("Not yet implemented") - } + actual override fun update(input: ByteArray, offset: Int, length: Int): Unit = delegate.update(input, offset, length) + actual override fun digest(): ByteArray = delegate.digest() + actual override fun reset(): Unit = delegate.reset() } diff --git a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Sha256Native.kt b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Sha256Native.kt index 6c85dfccea..69a82d4664 100644 --- a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Sha256Native.kt +++ b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/hashing/Sha256Native.kt @@ -5,10 +5,12 @@ package aws.smithy.kotlin.runtime.hashing import aws.smithy.kotlin.runtime.InternalApi +import aws.sdk.kotlin.crt.util.hashing.Sha256 as CrtSha256 @InternalApi public actual class Sha256 : Sha256Base() { - actual override fun update(input: ByteArray, offset: Int, length: Int): Unit = TODO("native not supported") - actual override fun digest(): ByteArray = TODO("native not supported") - actual override fun reset(): Unit = TODO("native not supported") + private val delegate = CrtSha256() + actual override fun update(input: ByteArray, offset: Int, length: Int): Unit = delegate.update(input, offset, length) + actual override fun digest(): ByteArray = delegate.digest() + actual override fun reset(): Unit = delegate.reset() } diff --git a/settings.gradle.kts b/settings.gradle.kts index ac7f398bc4..bfd379d2ec 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -46,7 +46,7 @@ val compositeProjectList = try { } } } catch (e: Throwable) { - logger.error("Failed to load composite project paths from local.properties") + logger.error("Could not load composite project paths from local.properties") listOf(file("../aws-crt-kotlin")) }