Skip to content

Commit

Permalink
Add PythonServerTypesTest
Browse files Browse the repository at this point in the history
  • Loading branch information
unexge committed Jan 23, 2023
1 parent 197afcb commit 76379d9
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.rust.codegen.server.python.smithy.testutil

import software.amazon.smithy.build.PluginContext
import software.amazon.smithy.model.Model
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeCrateLocation
import software.amazon.smithy.rust.codegen.core.testutil.generatePluginContext
import software.amazon.smithy.rust.codegen.core.util.runCommand
import software.amazon.smithy.rust.codegen.server.python.smithy.PythonServerCodegenVisitor
import software.amazon.smithy.rust.codegen.server.python.smithy.customizations.DECORATORS
import software.amazon.smithy.rust.codegen.server.smithy.customizations.ServerRequiredCustomizations
import software.amazon.smithy.rust.codegen.server.smithy.customize.CombinedServerCodegenDecorator
import java.io.File
import java.nio.file.Path

val TestRuntimeConfig =
RuntimeConfig(runtimeCrateLocation = RuntimeCrateLocation.Path(File("../../rust-runtime").absolutePath))

fun generatePythonServerPluginContext(model: Model) =
generatePluginContext(model, runtimeConfig = TestRuntimeConfig)

fun executePythonServerCodegenVisitor(pluginCtx: PluginContext) {
val codegenDecorator: CombinedServerCodegenDecorator =
CombinedServerCodegenDecorator.fromClasspath(
pluginCtx,
CombinedServerCodegenDecorator(DECORATORS + ServerRequiredCustomizations()),
)
PythonServerCodegenVisitor(pluginCtx, codegenDecorator).execute()
}

fun cargoTest(workdir: Path) =
// `--no-default-features` is required to disable `pyo3/extension-module` which causes linking errors
// see `PyO3ExtensionModuleDecorator`'s comments fore more detail.
"cargo test --no-default-features".runCommand(workdir, mapOf(
// Those are required to run tests on macOS, see: https://pyo3.rs/main/building_and_distribution#macos
"CARGO_TARGET_X86_64_APPLE_DARWIN_RUSTFLAGS" to "-C link-arg=-undefined -C link-arg=dynamic_lookup",
"CARGO_TARGET_AARCH64_APPLE_DARWIN_RUSTFLAGS" to "-C link-arg=-undefined -C link-arg=dynamic_lookup"
))
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.rust.codegen.server.python.smithy.generators

import org.junit.jupiter.api.Test
import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter
import software.amazon.smithy.rust.codegen.core.rustlang.rust
import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel
import software.amazon.smithy.rust.codegen.core.testutil.tokioTest
import software.amazon.smithy.rust.codegen.core.util.dq
import software.amazon.smithy.rust.codegen.server.python.smithy.testutil.cargoTest
import software.amazon.smithy.rust.codegen.server.python.smithy.testutil.executePythonServerCodegenVisitor
import software.amazon.smithy.rust.codegen.server.python.smithy.testutil.generatePythonServerPluginContext
import kotlin.io.path.appendText

internal class PythonServerTypesTest {
@Test
fun `document type`() {
val model = """
namespace test
use aws.protocols#restJson1
@restJson1
service Service {
operations: [
Echo,
],
}
@http(method: "POST", uri: "/echo")
operation Echo {
input: EchoInput,
output: EchoOutput,
}
structure EchoInput {
value: Document,
}
structure EchoOutput {
value: Document,
}
""".asSmithyModel()

val (pluginCtx, testDir) = generatePythonServerPluginContext(model)
executePythonServerCodegenVisitor(pluginCtx)

val testCases = listOf(
Pair(
""" { "value": 42 } """,
"""
assert input.value == 42
output = EchoOutput(value=input.value)
"""
),
Pair(
""" { "value": "foobar" } """,
"""
assert input.value == "foobar"
output = EchoOutput(value=input.value)
"""
),
Pair(
"""
{
"value": [
true,
false,
42,
42.0,
-42,
{
"nested": "value"
},
{
"nested": [1, 2, 3]
}
]
}
""",
"""
assert input.value == [True, False, 42, 42.0, -42, dict(nested="value"), dict(nested=[1, 2, 3])]
output = EchoOutput(value=input.value)
"""
),
)

val writer = RustWriter.forModule("service")
writer.tokioTest("document_type") {
rust(
"""
use tower::Service as _;
use pyo3::{types::IntoPyDict, IntoPy, Python};
use hyper::{Body, Request, body};
use crate::{input, output};
pyo3::prepare_freethreaded_python();
""".trimIndent()
)

testCases.forEach {
val payload = it.first.replace(" ", "").replace("\n", "")
val pythonHandler = it.second.trimIndent()
rust(
"""
let mut service = Service::builder_without_plugins()
.echo(|input: input::EchoInput| async {
Ok(Python::with_gil(|py| {
let globals = [("EchoOutput", py.get_type::<output::EchoOutput>())].into_py_dict(py);
let locals = [("input", input.into_py(py))].into_py_dict(py);
py.run(${pythonHandler.dq()}, Some(globals), Some(locals)).unwrap();
locals
.get_item("output")
.unwrap()
.extract::<output::EchoOutput>()
.unwrap()
}))
})
.build()
.unwrap();
let req = Request::builder()
.method("POST")
.uri("/echo")
.body(Body::from(${payload.dq()}))
.unwrap();
let res = service.call(req).await.unwrap();
let body = body::to_bytes(res.into_body()).await.unwrap();
assert_eq!(body, ${payload.dq()});
""".trimIndent()
)
}
}

testDir.resolve("src/service.rs").appendText(writer.toString())

cargoTest(testDir)
}
}

0 comments on commit 76379d9

Please sign in to comment.