From 211ee0e4b75c3bb90dab7ed7d00fff6715de0538 Mon Sep 17 00:00:00 2001 From: Ruben Hoenle Date: Wed, 28 May 2025 15:55:40 +0200 Subject: [PATCH 1/4] fix(go): prevent infinite recursion during json unmarshal of enums relates to STACKITSDK-162 --- openapi-generator-config-go.yml | 5 +++ scripts/generate-sdk/languages/go.sh | 7 ++-- templates/go/model_simple.mustache | 7 +++- templates/go/model_simple_test.mustache | 49 +++++++++++++++++++++++++ templates/go/model_test.mustache | 17 +++++++++ 5 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 openapi-generator-config-go.yml create mode 100644 templates/go/model_simple_test.mustache create mode 100644 templates/go/model_test.mustache diff --git a/openapi-generator-config-go.yml b/openapi-generator-config-go.yml new file mode 100644 index 0000000..4950638 --- /dev/null +++ b/openapi-generator-config-go.yml @@ -0,0 +1,5 @@ +templateDir: templates/go +files: + model_test.mustache: + templateType: ModelTests + destinationFilename: .go diff --git a/scripts/generate-sdk/languages/go.sh b/scripts/generate-sdk/languages/go.sh index d79f9b0..0c4cf6a 100644 --- a/scripts/generate-sdk/languages/go.sh +++ b/scripts/generate-sdk/languages/go.sh @@ -153,15 +153,16 @@ generate_go_sdk() { --input-spec ${service_json} \ --output ${SERVICES_FOLDER}/${service} \ --package-name ${service} \ - --template-dir ${ROOT_DIR}/templates/go/ \ --enable-post-process-file \ --git-host ${GIT_HOST} \ --git-user-id ${GIT_USER_ID} \ --git-repo-id ${GIT_REPO_ID} \ --global-property apis,models,modelTests=true,modelDocs=false,apiDocs=false,supportingFiles \ --additional-properties=isGoSubmodule=true,enumClassPrefix=true,generateInterfaces=true,$regional_api \ - --http-user-agent stackit-sdk-go/${service} \ - --reserved-words-mappings type=types + --http-user-agent stackit-sdk-go/${service} \ + --reserved-words-mappings type=types \ + --config openapi-generator-config-go.yml + # Remove unnecessary files rm ${SERVICES_FOLDER}/${service}/.openapi-generator-ignore rm ${SERVICES_FOLDER}/${service}/.openapi-generator/FILES diff --git a/templates/go/model_simple.mustache b/templates/go/model_simple.mustache index 7d6cecf..ee0e605 100644 --- a/templates/go/model_simple.mustache +++ b/templates/go/model_simple.mustache @@ -305,13 +305,16 @@ var Allowed{{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titl } func (v *{{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}}) UnmarshalJSON(src []byte) error { - var value {{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}} + // use a type alias to prevent infinite recursion during unmarshal, + // see https://biscuit.ninja/posts/go-avoid-an-infitine-loop-with-custom-json-unmarshallers + type TmpJson {{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}} + var value TmpJson err := json.Unmarshal(src, &value) if err != nil { return err } // Allow unmarshalling zero value for testing purposes - var zeroValue {{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}} + var zeroValue TmpJson if value == zeroValue { return nil } diff --git a/templates/go/model_simple_test.mustache b/templates/go/model_simple_test.mustache new file mode 100644 index 0000000..f6bde36 --- /dev/null +++ b/templates/go/model_simple_test.mustache @@ -0,0 +1,49 @@ +{{! NOTE: This is a custom STACKIT template which is not present in upsteam to support testing of enum models}} + +{{#vars}} +{{! special handling for enums}} +{{#isEnumRef}} +{{#isEnum}} +// isEnum + +func Test{{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}}_UnmarshalJSON(t *testing.T) { + type args struct { + src []byte + } + tests := []struct { + name string + args args + wantErr bool + }{ + {{#allowableValues}} + {{#enumVars}} + { + name: `success - possible enum value no. {{-index}}`, + args: args{ + src: []byte(`{{{value}}}`), + }, + wantErr: false, + }, + {{/enumVars}} + {{/allowableValues}} + { + name: "fail", + args: args{ + src: []byte("\"FOOBAR\""), + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := {{{classname}}}{{#lambda.titlecase}}{{nameInCamelCase}}{{/lambda.titlecase}}({{#isNumeric}}-1{{/isNumeric}}{{^isNumeric}}""{{/isNumeric}}) + if err := v.UnmarshalJSON(tt.args.src); (err != nil) != tt.wantErr { + t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +{{/isEnum}} +{{/isEnumRef}} +{{/vars}} \ No newline at end of file diff --git a/templates/go/model_test.mustache b/templates/go/model_test.mustache new file mode 100644 index 0000000..b471f42 --- /dev/null +++ b/templates/go/model_test.mustache @@ -0,0 +1,17 @@ +{{>partial_header}} +package {{packageName}} + +{{#models}} +import ( + "testing" +{{#imports}} + "{{import}}" +{{/imports}} +) + +{{#model}} +{{^isEnum}} +{{#oneOf}}{{#-first}}{{/-first}}{{/oneOf}}{{^oneOf}}{{#anyOf}}{{#-first}}{{/-first}}{{/anyOf}}{{^anyOf}}{{>model_simple_test}}{{/anyOf}}{{/oneOf}} +{{/isEnum}} +{{/model}} +{{/models}} From 78c8653cc5db30570555195d4ec66ac470d5109f Mon Sep 17 00:00:00 2001 From: Ruben Hoenle Date: Wed, 28 May 2025 16:09:52 +0200 Subject: [PATCH 2/4] move custom templates into own directory --- openapi-generator-config-go.yml | 2 +- templates/go/{ => custom}/model_simple_test.mustache | 0 templates/go/{ => custom}/model_test.mustache | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename templates/go/{ => custom}/model_simple_test.mustache (100%) rename templates/go/{ => custom}/model_test.mustache (72%) diff --git a/openapi-generator-config-go.yml b/openapi-generator-config-go.yml index 4950638..406735b 100644 --- a/openapi-generator-config-go.yml +++ b/openapi-generator-config-go.yml @@ -1,5 +1,5 @@ templateDir: templates/go files: - model_test.mustache: + custom/model_test.mustache: templateType: ModelTests destinationFilename: .go diff --git a/templates/go/model_simple_test.mustache b/templates/go/custom/model_simple_test.mustache similarity index 100% rename from templates/go/model_simple_test.mustache rename to templates/go/custom/model_simple_test.mustache diff --git a/templates/go/model_test.mustache b/templates/go/custom/model_test.mustache similarity index 72% rename from templates/go/model_test.mustache rename to templates/go/custom/model_test.mustache index b471f42..2a170be 100644 --- a/templates/go/model_test.mustache +++ b/templates/go/custom/model_test.mustache @@ -11,7 +11,7 @@ import ( {{#model}} {{^isEnum}} -{{#oneOf}}{{#-first}}{{/-first}}{{/oneOf}}{{^oneOf}}{{#anyOf}}{{#-first}}{{/-first}}{{/anyOf}}{{^anyOf}}{{>model_simple_test}}{{/anyOf}}{{/oneOf}} +{{#oneOf}}{{#-first}}{{/-first}}{{/oneOf}}{{^oneOf}}{{#anyOf}}{{#-first}}{{/-first}}{{/anyOf}}{{^anyOf}}{{>custom/model_simple_test}}{{/anyOf}}{{/oneOf}} {{/isEnum}} {{/model}} {{/models}} From 663c407cc1c1c82f236637e9272538857d4a65ee Mon Sep 17 00:00:00 2001 From: Ruben Hoenle Date: Fri, 30 May 2025 10:49:35 +0200 Subject: [PATCH 3/4] chore(go): adjust generator config to use go file naming conventions --- openapi-generator-config-go.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openapi-generator-config-go.yml b/openapi-generator-config-go.yml index 406735b..f78db9e 100644 --- a/openapi-generator-config-go.yml +++ b/openapi-generator-config-go.yml @@ -1,5 +1,7 @@ templateDir: templates/go files: custom/model_test.mustache: - templateType: ModelTests - destinationFilename: .go + # TODO: this should be 'ModelTests' instead of 'Model' + # 'Model' was used because 'ModelTests' didn't stick to golangs file naming conventions + templateType: Model + destinationFilename: _test.go From 7a32c567b409aa171d8c629c4ce17999c55d1fd8 Mon Sep 17 00:00:00 2001 From: Ruben Hoenle Date: Fri, 30 May 2025 10:50:51 +0200 Subject: [PATCH 4/4] chore(go): simplify model test template --- templates/go/custom/model_test.mustache | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/templates/go/custom/model_test.mustache b/templates/go/custom/model_test.mustache index 2a170be..65e6577 100644 --- a/templates/go/custom/model_test.mustache +++ b/templates/go/custom/model_test.mustache @@ -1,7 +1,8 @@ +{{#models}} + {{>partial_header}} package {{packageName}} -{{#models}} import ( "testing" {{#imports}} @@ -11,7 +12,9 @@ import ( {{#model}} {{^isEnum}} -{{#oneOf}}{{#-first}}{{/-first}}{{/oneOf}}{{^oneOf}}{{#anyOf}}{{#-first}}{{/-first}}{{/anyOf}}{{^anyOf}}{{>custom/model_simple_test}}{{/anyOf}}{{/oneOf}} +{{^oneOf}}{{^anyOf}} +{{>custom/model_simple_test}} +{{/anyOf}}{{/oneOf}} {{/isEnum}} {{/model}} {{/models}}