Skip to content

Commit c55e822

Browse files
authored
Merge pull request #688 from jlbutler/fix-union-original-shape-name
Fix OriginalShapeName handling for union types
2 parents 60fc9a5 + 7f2bbc1 commit c55e822

6 files changed

Lines changed: 197 additions & 1 deletion

File tree

pkg/api/passes_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,3 +974,91 @@ func TestValidateShapeNameMethod(t *testing.T) {
974974
})
975975
}
976976
}
977+
978+
// TestRenamedUnionShapePreservesOriginalName verifies that when a union
979+
// shape is renamed (e.g. MemoryStrategyInput -> MemoryStrategyInput_) by
980+
// renameIOSuffixedShapeNames, the OriginalShapeName is preserved. The
981+
// downstream SDK code generation functions (setSDKForUnion,
982+
// setResourceForUnion, varEmptyConstructorSDKType) use OriginalShapeName
983+
// to emit correct SDK type references.
984+
func TestRenamedUnionShapePreservesOriginalName(t *testing.T) {
985+
a := &API{
986+
name: "testapi",
987+
Metadata: Metadata{
988+
APIVersion: "0000-00-00",
989+
EndpointPrefix: "testapi",
990+
JSONVersion: "1.1",
991+
Protocol: "json",
992+
ServiceAbbreviation: "TestAPI",
993+
ServiceFullName: "Test API",
994+
SignatureVersion: "v4",
995+
},
996+
Operations: map[string]*Operation{
997+
"CreateMemory": {
998+
Name: "CreateMemory",
999+
InputRef: ShapeRef{ShapeName: "CreateMemoryInput"},
1000+
OutputRef: ShapeRef{ShapeName: "CreateMemoryOutput"},
1001+
},
1002+
},
1003+
Shapes: map[string]*Shape{
1004+
"CreateMemoryInput": {
1005+
ShapeName: "CreateMemoryInput",
1006+
Type: "structure",
1007+
MemberRefs: map[string]*ShapeRef{
1008+
"Strategies": {ShapeName: "MemoryStrategyInputList"},
1009+
},
1010+
},
1011+
"CreateMemoryOutput": {
1012+
ShapeName: "CreateMemoryOutput",
1013+
Type: "structure",
1014+
},
1015+
"MemoryStrategyInputList": {
1016+
ShapeName: "MemoryStrategyInputList",
1017+
Type: "list",
1018+
MemberRef: ShapeRef{ShapeName: "MemoryStrategyInput"},
1019+
},
1020+
"MemoryStrategyInput": {
1021+
ShapeName: "MemoryStrategyInput",
1022+
Type: "structure",
1023+
RealType: "union",
1024+
},
1025+
},
1026+
}
1027+
1028+
// Wire up shape refs
1029+
for _, op := range a.Operations {
1030+
op.InputRef.API = a
1031+
op.InputRef.Shape = a.Shapes[op.InputRef.ShapeName]
1032+
op.OutputRef.API = a
1033+
op.OutputRef.Shape = a.Shapes[op.OutputRef.ShapeName]
1034+
}
1035+
for _, s := range a.Shapes {
1036+
s.API = a
1037+
for k := range s.MemberRefs {
1038+
ref := s.MemberRefs[k]
1039+
ref.API = a
1040+
ref.Shape = a.Shapes[ref.ShapeName]
1041+
s.MemberRefs[k] = ref
1042+
}
1043+
if s.MemberRef.ShapeName != "" {
1044+
s.MemberRef.API = a
1045+
s.MemberRef.Shape = a.Shapes[s.MemberRef.ShapeName]
1046+
}
1047+
}
1048+
1049+
unionShape := a.Shapes["MemoryStrategyInput"]
1050+
if unionShape.OriginalShapeName != "" {
1051+
t.Fatalf("expected empty OriginalShapeName before rename, got %q", unionShape.OriginalShapeName)
1052+
}
1053+
1054+
a.renameIOSuffixedShapeNames()
1055+
1056+
// ShapeName gets underscore suffix, OriginalShapeName preserves the
1057+
// pre-rename value for downstream SDK code generation.
1058+
if unionShape.ShapeName != "MemoryStrategyInput_" {
1059+
t.Fatalf("expected ShapeName %q after rename, got %q", "MemoryStrategyInput_", unionShape.ShapeName)
1060+
}
1061+
if unionShape.OriginalShapeName != "MemoryStrategyInput" {
1062+
t.Fatalf("expected OriginalShapeName %q after rename, got %q", "MemoryStrategyInput", unionShape.OriginalShapeName)
1063+
}
1064+
}

pkg/generate/code/set_resource.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2454,6 +2454,11 @@ func setResourceForUnion(
24542454

24552455
sdkGoType := sourceShape.GoTypeWithPkgName()
24562456
sdkGoType = model.ReplacePkgName(sdkGoType, r.SDKAPIPackageName(), "svcsdktypes", true)
2457+
// Use the original shape name for SDK type references when the shape
2458+
// was renamed (e.g. Input/Output suffix collision avoidance).
2459+
if sourceShape.OriginalShapeName != "" {
2460+
sdkGoType = "*svcsdktypes." + sourceShape.OriginalShapeName
2461+
}
24572462

24582463
out += fmt.Sprintf("%sswitch %s.(type) {\n", indent, sourceVarName)
24592464
for _, targetMemberName := range targetShape.MemberNames() {

pkg/generate/code/set_resource_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5579,3 +5579,31 @@ func TestSetResource_BedrockAgentCoreControl_GatewayTarget_NestedUnionTypeSwitch
55795579
assert.Contains(got, "case *svcsdktypes.ApiSchemaConfigurationMemberInlinePayload:")
55805580
assert.Contains(got, "case *svcsdktypes.ApiSchemaConfigurationMemberS3:")
55815581
}
5582+
5583+
// TestSetResource_BedrockAgentCoreControl_Memory_InputSuffixUnion tests that
5584+
// union types whose names end in "Input" (e.g. MemoryStrategyInput) use the
5585+
// original SDK shape name in generated set-output code, not the renamed
5586+
// version with an underscore suffix (MemoryStrategyInput_).
5587+
func TestSetResource_BedrockAgentCoreControl_Memory_InputSuffixUnion(t *testing.T) {
5588+
assert := assert.New(t)
5589+
require := require.New(t)
5590+
5591+
g := testutil.NewModelForServiceWithOptions(t, "bedrock-agentcore-control", &testutil.TestingModelOptions{
5592+
GeneratorConfigFile: "generator-with-input-suffix-union.yaml",
5593+
})
5594+
5595+
crd := testutil.GetCRDByName(t, g, "Memory")
5596+
require.NotNil(crd)
5597+
assert.NotNil(crd.Ops.ReadOne)
5598+
5599+
got, err := code.SetResource(crd.Config(), crd, model.OpTypeGet, "resp", "ko", 1)
5600+
require.NoError(err)
5601+
5602+
// On the read path, union type switches must use the original SDK name
5603+
assert.NotContains(got, "MemoryStrategyInput_",
5604+
"Should use original SDK shape name MemoryStrategyInput, not renamed MemoryStrategyInput_")
5605+
assert.NotContains(got, "CustomConfigurationInput_",
5606+
"Should use original SDK shape name CustomConfigurationInput, not renamed version")
5607+
assert.NotContains(got, "TriggerConditionInput_",
5608+
"Should use original SDK shape name TriggerConditionInput, not renamed version")
5609+
}

pkg/generate/code/set_sdk.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1533,7 +1533,7 @@ func varEmptyConstructorSDKType(
15331533
// For SDK types, we need to use the original shape name (before stutter
15341534
// removal) since the AWS SDK uses the original names. The stutter removal
15351535
// renames are only for CRD types.
1536-
if shape.Type == "structure" && shape.OriginalShapeName != "" {
1536+
if (shape.Type == "structure" || shape.RealType == "union") && shape.OriginalShapeName != "" {
15371537
// Replace the renamed shape name with the original SDK shape name
15381538
goType = "svcsdktypes." + shape.OriginalShapeName
15391539
}
@@ -1863,6 +1863,11 @@ func setSDKForUnion(
18631863

18641864
sdkGoType := targetShape.GoTypeWithPkgName()
18651865
sdkGoType = model.ReplacePkgName(sdkGoType, r.SDKAPIPackageName(), "svcsdktypes", false)
1866+
// Use the original shape name for SDK type references when the shape
1867+
// was renamed (e.g. Input/Output suffix collision avoidance).
1868+
if targetShape.OriginalShapeName != "" {
1869+
sdkGoType = "svcsdktypes." + targetShape.OriginalShapeName
1870+
}
18661871

18671872
out += fmt.Sprintf("%sisInterfaceSet := false\n", indent)
18681873

pkg/generate/code/set_sdk_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6769,3 +6769,40 @@ func TestSetSDK_BedrockAgentCoreControl_GatewayTarget_NestedUnionNoDereference(t
67696769
// dereferenced (e.g., ApiGatewayTargetConfiguration is a regular struct)
67706770
assert.Contains(got, "f7f0f0Parent.Value = *f7f0f0\n")
67716771
}
6772+
6773+
// TestSetSDK_BedrockAgentCoreControl_Memory_InputSuffixUnion tests that
6774+
// union types whose names end in "Input" (e.g. MemoryStrategyInput) use
6775+
// the original SDK shape name in generated code, not the renamed version
6776+
// with an underscore suffix (MemoryStrategyInput_). The rename pass adds
6777+
// the underscore to avoid collisions with operation input types, but SDK
6778+
// type references must use the original name.
6779+
func TestSetSDK_BedrockAgentCoreControl_Memory_InputSuffixUnion(t *testing.T) {
6780+
assert := assert.New(t)
6781+
require := require.New(t)
6782+
6783+
g := testutil.NewModelForServiceWithOptions(t, "bedrock-agentcore-control", &testutil.TestingModelOptions{
6784+
GeneratorConfigFile: "generator-with-input-suffix-union.yaml",
6785+
})
6786+
6787+
crd := testutil.GetCRDByName(t, g, "Memory")
6788+
require.NotNil(crd)
6789+
assert.NotNil(crd.Ops.Create)
6790+
6791+
got, err := code.SetSDK(crd.Config(), crd, model.OpTypeCreate, "r.ko", "res", 1)
6792+
require.NoError(err)
6793+
6794+
// MemoryStrategyInput is a union whose name ends in "Input". The code-gen
6795+
// renames it to MemoryStrategyInput_ to avoid collision with operation
6796+
// input types. SDK references must use the original name.
6797+
assert.Contains(got, "svcsdktypes.MemoryStrategyInput")
6798+
assert.NotContains(got, "MemoryStrategyInput_",
6799+
"Should use original SDK shape name MemoryStrategyInput, not renamed MemoryStrategyInput_")
6800+
6801+
// CustomConfigurationInput is also a union ending in "Input"
6802+
assert.NotContains(got, "CustomConfigurationInput_",
6803+
"Should use original SDK shape name CustomConfigurationInput, not renamed version")
6804+
6805+
// TriggerConditionInput is also a union ending in "Input"
6806+
assert.NotContains(got, "TriggerConditionInput_",
6807+
"Should use original SDK shape name TriggerConditionInput, not renamed version")
6808+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
ignore:
2+
resource_names:
3+
- AgentRuntime
4+
- AgentRuntimeEndpoint
5+
- ApiKeyCredentialProvider
6+
- Browser
7+
- BrowserProfile
8+
- CodeInterpreter
9+
- Evaluator
10+
- Gateway
11+
- GatewayTarget
12+
# Memory
13+
- Oauth2CredentialProvider
14+
- OnlineEvaluationConfig
15+
- WorkloadIdentity
16+
- Policy
17+
- PolicyEngine
18+
field_paths:
19+
- MemoryStrategy.Configuration
20+
- CreateMemoryInput.ClientToken
21+
- UpdateMemoryInput.ClientToken
22+
- DeleteMemoryInput.ClientToken
23+
sdk_names:
24+
model_name: bedrock-agentcore-control
25+
26+
resources:
27+
Memory:
28+
ignore_idempotency_token: true
29+
fields:
30+
MemoryId:
31+
is_primary_key: true
32+
tags:
33+
ignore: true

0 commit comments

Comments
 (0)