1010
1111Protocol files: ` codegen-{core,server}/.../protocols/ `
1212
13+ ## Protocol Tests
14+
15+ Protocol tests validate that generated code correctly implements Smithy protocols (like restJson1, awsJson1_1, etc.).
16+
17+ ### Adding Protocol Tests
18+
19+ Protocol tests are defined in Smithy model files using ` @httpRequestTests ` and ` @httpResponseTests ` traits:
20+
21+ ```
22+ @http(uri: "/my-operation", method: "GET")
23+ @httpRequestTests([
24+ {
25+ id: "MyOperationRequest",
26+ documentation: "Test description",
27+ protocol: "aws.protocols#restJson1",
28+ method: "GET",
29+ uri: "/my-operation",
30+ queryParams: ["param1=value1", "param2=value2"],
31+ params: {
32+ queryMap: {
33+ "param1": "value1",
34+ "param2": "value2"
35+ }
36+ },
37+ appliesTo: "client",
38+ }
39+ ])
40+ operation MyOperation {
41+ input: MyOperationInput,
42+ }
43+ ```
44+
45+ ### Key Protocol Test Locations
46+
47+ - ** ` codegen-core/common-test-models/rest-json-extras.smithy ` ** - restJson1 protocol tests
48+ - ** ` codegen-core/common-test-models/constraints.smithy ` ** - Constraint validation tests with restJson1
49+ - ** ` codegen-client-test/model/main.smithy ` ** - awsJson1_1 protocol tests
50+
1351## preludeScope: Rust Prelude Types
1452
1553** Always use ` preludeScope ` for Rust prelude types:**
@@ -28,6 +66,7 @@ rustTemplate(
2866## RuntimeType and Dependencies
2967
3068` RuntimeType ` objects contain:
69+
3170- ** ` path ` ** : Rust path (e.g., ` "::mime::Mime" ` )
3271- ** ` dependency ` ** : ` CargoDependency ` or ` InlineDependency `
3372
@@ -49,6 +88,20 @@ val smithyTypes = RuntimeType.smithyTypes(runtimeConfig)
4988❌ Wrong: ` rust("const MIME: ::mime::Mime = ::mime::APPLICATION_JSON;") `
5089✅ Correct: ` rustTemplate("const MIME: #{Mime}::Mime = #{Mime}::APPLICATION_JSON;", "Mime" to RuntimeType.Mime) `
5190
91+ ### String Interpolation in Templates
92+
93+ ** For RuntimeTypes and complex objects** : Use ` #{name} ` syntax. NOTE: you do not need to use ` #{name:W} ` . This is now
94+ the default. You may see old code with this pattern.
95+ ** For simple strings** : Use ` $ ` with ` .dq() ` for double-quoted strings
96+
97+ ``` kotlin
98+ // ❌ Wrong - causes "Invalid type provided to RustSymbolFormatter"
99+ rustTemplate(" let content_type = \" #{content_type}\" ;" , " content_type" to " application/json" )
100+
101+ // ✅ Correct - use $ interpolation for strings
102+ rustTemplate(" let content_type = ${contentType.dq()} ;" )
103+ ```
104+
52105## RuntimeType.forInlineFun: Lazy Generation
53106
54107Code is only generated if used. ` forInlineFun ` enables lazy generation:
@@ -64,22 +117,91 @@ val mimeType = RuntimeType.forInlineFun("APPLICATION_JSON", module) {
64117
65118⚠️ ** Footgun** : Name collisions mean only one implementation gets generated.
66119
120+ ## GitHub CLI Integration
121+
122+ ** View issues and PRs:**
123+
124+ ``` bash
125+ gh issue view < number> --repo smithy-lang/smithy-rs
126+ gh pr view < number> --repo smithy-lang/smithy-rs
127+ gh pr diff < number> --repo smithy-lang/smithy-rs
128+ ```
129+
130+ ** Add comments (use single quotes for complex markdown):**
131+
132+ ``` bash
133+ gh issue comment < number> --repo smithy-lang/smithy-rs --body ' markdown content with `backticks` and special chars'
134+ ```
135+
136+ ** Comment Guidelines:**
137+ - Always ask for confirmation before posting comments
138+ - Always start comments with ` *Comment from Claude* ` in italics
139+
140+ ** Run PR Bot and Canary workflows:**
141+
142+ ``` bash
143+ # Get PR info first
144+ gh pr view < PR_NUMBER> --repo smithy-lang/smithy-rs --json headRefOid,number
145+
146+ # Run PR Bot (generates codegen diff and doc preview)
147+ gh workflow run " Invoke PR Bot as Maintainer" --repo smithy-lang/smithy-rs \
148+ -f pull_number=< PR_NUMBER> -f commit_sha=< HEAD_SHA>
149+
150+ # Run Canary (tests SDK generation and integration)
151+ gh workflow run " Invoke Canary as Maintainer" --repo smithy-lang/smithy-rs \
152+ -f pull_request_number=< PR_NUMBER> -f commit_sha=< HEAD_SHA>
153+ ```
154+
155+ ## Investigation Patterns
156+
157+ ** Before implementing changes:**
158+
159+ 1 . ** Research existing work** - Check related PRs/issues first
160+ 2 . ** Build and examine generated code** - ` ./gradlew codegen-server-test:assemble --quiet `
161+ 3 . ** Generated code location** - ` codegen-server-test/build/smithyprojections/codegen-server-test/ `
162+ 4 . ** Key generated files** - ` src/protocol_serde/shape_*.rs ` , ` src/event_stream_serde.rs `
163+ 5 . ** Look for patterns** - Client vs server codegen often mirrors each other
164+ 6 . ** Identify minimal change** - Understand current behavior before modifying codegen
165+
166+ ** Single Protocol Development:**
167+
168+ - When working on a single protocol, uncomment the filter line in ` codegen-server-test/build.gradle.kts:111 `
169+ - This speeds up builds by only generating code for the protocol you're working on
170+
171+ ** Client/Server Symmetry:**
172+
173+ Client changes often show the pattern for server-side implementation
174+
175+ ** Configuration Debugging:**
176+ - Server codegen settings go under ` "codegen" ` not ` "codegenConfig" ` in smithy-build.json
177+ - When settings aren't working, check the generated smithy-build.json structure first
178+ - Settings placement matters - wrong nesting means settings are ignored silently
179+ - Always verify actual generated configuration matches expectations
180+
181+ ** Testing Configuration Settings:**
182+ - Create separate services with different settings to test configuration behavior
183+ - Use integration tests that verify actual generated code behavior, not just compilation
184+ - Test both enabled and disabled states to ensure the setting actually controls behavior
185+
67186## Testing
68187
69188### Integration Tests
189+
70190Test actual generated code, not just codegen logic:
71191
72192``` kotlin
73193serverIntegrationTest(model) { codegenContext, rustCrate ->
74194 rustCrate.testModule {
75195 tokioTest(" test_accept_header" ) {
76- rustTemplate("""
196+ rustTemplate(
197+ """
77198 let request = ::http::Request::builder()
78199 .header("Accept", "application/cbor")
79200 .body(Body::empty()).unwrap();
80201 let result = MyInput::from_request(request).await;
81202 result.expect("should accept valid header");
82- """ )
203+ """
204+ )
83205 }
84206 }
85207}
@@ -88,12 +210,14 @@ serverIntegrationTest(model) { codegenContext, rustCrate ->
88210### Running Tests
89211
90212** Codegen tests:**
213+
91214``` bash
92215./gradlew test --tests " *MyTest*"
93216./gradlew codegen-server-test:assemble --quiet
94217```
95218
96219** Debug failing tests:**
220+
97221``` bash
98222# Remove --quiet to see failure details
99223./gradlew :codegen-core:test --tests " *InlineDependencyTest*"
@@ -102,29 +226,37 @@ grep -A 5 "AssertionError\|Exception" codegen-core/build/reports/tests/test/clas
102226```
103227
104228** Runtime tests:**
229+
105230``` bash
106231cd rust-runtime && cargo test --quiet -p aws-smithy-types
107232```
108233
109234** Protocol tests:**
235+
110236``` bash
111237./gradlew codegen-client-test:assemble --quiet
112238cd codegen-client-test/build/smithyprojections/codegen-client-test/rest_xml_extras/rust-client-codegen
113239cargo test --quiet
114240```
115241
242+ ** Note: Always use ` --quiet ` with cargo commands to reduce noise and focus on actual errors.**
243+
116244## Viewing Generated Code
117245
118246Generated code appears in:
247+
119248```
120249codegen-server-test/build/smithyprojections/codegen-server-test/SERVICE_NAME/rust-server-codegen/
121250```
122251
123252Enable debug comments:
253+
124254``` kotlin
125- serverIntegrationTest(model, IntegrationTestParams (
126- additionalSettings = ServerAdditionalSettings .builder()
127- .generateCodegenComments() // Adds Kotlin source line comments
128- .toObjectNode()
129- )) { /* test code */ }
255+ serverIntegrationTest(
256+ model, IntegrationTestParams (
257+ additionalSettings = ServerAdditionalSettings .builder()
258+ .generateCodegenComments() // Adds Kotlin source line comments
259+ .toObjectNode()
260+ )
261+ ) { /* test code */ }
130262```
0 commit comments