Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ See [`docs/PLAN.md`](docs/PLAN.md) for the full phased plan and
| 2 | Codegen plugin + type generation | ✅ Done — types generated for both fixtures, golden+compile+behavior tested ([docs/design/codegen-architecture.md](docs/design/codegen-architecture.md)) |
| 3 | Client generation (restJson1 + rpcv2Cbor) | ✅ Done — serde + clients for both protocols with typed errors ([docs/generated-types.md](docs/generated-types.md)); ~240 official protocol conformance cases green (documented exclusions) |
| 4 | Server generation (restJson1 + rpcv2Cbor) | ✅ Done — handlers, routing, serde, all HTTP bindings incl. `@httpPayload`/`@httpPrefixHeaders`, constraint validation, parser strictness, content negotiation; ~1,175 official conformance cases green ([docs/server-guide.md](docs/server-guide.md)) |
| 5 | Generated-client ↔ generated-server integration harness | Not started |
| 5 | Generated-client ↔ generated-server integration harness | ✅ Done — every fixture ships a generated integration suite: seeded random round-trips over loopback and real sockets, per-error mapping, unknown-member tolerance, mutation-checked ([docs/design/integration-testing.md](docs/design/integration-testing.md)) |
| 6 | Bazel rules, CLI, packaging (BCR + Maven Central), docs site | Not started |
| 7 | Hardening, fuzzing, v0.1.0 | Not started |
| 8 | Bidirectional streaming (event streams, WebSockets) | Not started |
Expand Down
26 changes: 25 additions & 1 deletion codegen/smithy-cpp-codegen/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ fun registerFixtureTask(
"--runtime-target", "//runtime:core",
"--output", File(repoRoot, outputPath).absolutePath,
"--tests-package", "//" + outputPath,
"--integration-tests", "true",
)
doFirst {
project.delete(File(repoRoot, outputPath))
Expand All @@ -42,6 +43,24 @@ val generateCafeFixture = registerFixtureTask(
"examples/cafe/generated",
)

// The kitchen-sink round-trip fixture: one model, two protocol variants, so the
// Phase 5 integration matrix covers REST and RPC with the same shapes.
val generateRoundTripRestFixture = registerFixtureTask(
"generateRoundTripRestFixture",
"examples/roundtrip/model/roundtrip.smithy",
"example.roundtrip#RoundTripRest",
"example::roundtrip::rest",
"examples/roundtrip/rest/generated",
)

val generateRoundTripRpcFixture = registerFixtureTask(
"generateRoundTripRpcFixture",
"examples/roundtrip/model/roundtrip.smithy",
"example.roundtrip#RoundTripRpc",
"example::roundtrip::rpc",
"examples/roundtrip/rpc/generated",
)

// The official protocol-test suite models, kept off the main runtime classpath
// so ordinary fixture generation doesn't assemble them.
val protocolTestModels: Configuration by configurations.creating
Expand Down Expand Up @@ -131,7 +150,12 @@ tasks.register("generateProtocolTests") {
tasks.register("generateFixtures") {
group = "smithy-cpp"
description = "Regenerates all checked-in generated code under examples/ (the goldens)"
dependsOn(generateWeatherFixture, generateCafeFixture)
dependsOn(
generateWeatherFixture,
generateCafeFixture,
generateRoundTripRestFixture,
generateRoundTripRpcFixture,
)
}

tasks.withType<Test>().configureEach {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public static void main(String[] args) {
String output = null;
String testsPackage = null;
boolean malformedTests = false;
boolean integrationTests = false;
List<String> omitOperations = new ArrayList<>();
for (int i = 0; i + 1 < args.length; i += 2) {
switch (args[i]) {
Expand All @@ -52,6 +53,7 @@ public static void main(String[] args) {
case "--tests-package" -> testsPackage = args[i + 1];
case "--omit-operation" -> omitOperations.add(args[i + 1]);
case "--malformed-tests" -> malformedTests = Boolean.parseBoolean(args[i + 1]);
case "--integration-tests" -> integrationTests = Boolean.parseBoolean(args[i + 1]);
default -> throw new IllegalArgumentException("unknown argument: " + args[i]);
}
}
Expand Down Expand Up @@ -87,6 +89,9 @@ public static void main(String[] args) {
if (malformedTests) {
settings.withMember("malformedTests", true);
}
if (integrationTests) {
settings.withMember("integrationTests", true);
}

PluginContext context =
PluginContext.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,21 @@ public final class CppSettings {
private final String runtimeTarget;
private final String testsPackage;
private final boolean malformedTests;
private final boolean integrationTests;

private CppSettings(
ShapeId service,
String namespace,
String runtimeTarget,
String testsPackage,
boolean malformedTests) {
boolean malformedTests,
boolean integrationTests) {
this.service = service;
this.namespace = namespace;
this.runtimeTarget = runtimeTarget;
this.testsPackage = testsPackage;
this.malformedTests = malformedTests;
this.integrationTests = integrationTests;
}

public static CppSettings fromNode(ObjectNode node) {
Expand All @@ -43,11 +46,13 @@ public static CppSettings fromNode(ObjectNode node) {
node.getStringMemberOrDefault("runtimeTarget", "@smithy_cpp//runtime:core");
String testsPackage = node.getStringMemberOrDefault("testsPackage", null);
boolean malformedTests = node.getBooleanMemberOrDefault("malformedTests", false);
boolean integrationTests = node.getBooleanMemberOrDefault("integrationTests", false);
if (!namespace.matches("[A-Za-z_][A-Za-z0-9_]*(::[A-Za-z_][A-Za-z0-9_]*)*")) {
throw new IllegalArgumentException(
"cpp-codegen: 'namespace' must be a C++ namespace like a::b, got: " + namespace);
}
return new CppSettings(service, namespace, runtimeTarget, testsPackage, malformedTests);
return new CppSettings(
service, namespace, runtimeTarget, testsPackage, malformedTests, integrationTests);
}

public ShapeId service() {
Expand Down Expand Up @@ -110,6 +115,15 @@ public boolean malformedTests() {
return malformedTests;
}

/**
* Whether to generate tests/integration_test.cc: generated client vs generated server over
* loopback and real sockets with random round-trips (PLAN Phase 5). Per-module, like the
* conformance suites.
*/
public boolean integrationTests() {
return integrationTests;
}

@Override
public boolean equals(Object other) {
if (!(other instanceof CppSettings that)) {
Expand All @@ -119,11 +133,13 @@ public boolean equals(Object other) {
&& namespace.equals(that.namespace)
&& runtimeTarget.equals(that.runtimeTarget)
&& Objects.equals(testsPackage, that.testsPackage)
&& malformedTests == that.malformedTests;
&& malformedTests == that.malformedTests
&& integrationTests == that.integrationTests;
}

@Override
public int hashCode() {
return Objects.hash(service, namespace, runtimeTarget, testsPackage, malformedTests);
return Objects.hash(
service, namespace, runtimeTarget, testsPackage, malformedTests, integrationTests);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,12 @@ public void generateService(GenerateServiceDirective<CppContext, CppSettings> di
hasMalformedTests)
.run();
}
TestsBuildFileGenerator.run(directive.context(), hasProtocolTests, hasMalformedTests);
boolean hasIntegrationTests = directive.settings().integrationTests();
if (hasIntegrationTests) {
new IntegrationTestGenerator(directive.context(), service, protocol, operations).run();
}
TestsBuildFileGenerator.run(
directive.context(), hasProtocolTests, hasMalformedTests, hasIntegrationTests);
}
}
}
Expand Down
Loading
Loading