From 137d0d708c4cbc7a7da41e73afb4662df3402ed7 Mon Sep 17 00:00:00 2001 From: Stephen Lewis Date: Wed, 17 Apr 2024 11:11:49 -0700 Subject: [PATCH 1/2] Documented how to use field validation functions --- docs/content/develop/field-reference.md | 46 +++++++++++++++++++++++++ docs/content/develop/test/test.md | 11 ++++++ 2 files changed, 57 insertions(+) diff --git a/docs/content/develop/field-reference.md b/docs/content/develop/field-reference.md index b1424939d3fc..a72436a5a684 100644 --- a/docs/content/develop/field-reference.md +++ b/docs/content/develop/field-reference.md @@ -217,6 +217,11 @@ to use for this field. In many cases, a [custom flattener](https://googlecloudpl is preferred because it will allow the user to see a clearer diff when the field actually is being changed. See [Fix a permadiff]({{< ref "/develop/permadiff.md" >}}) for more information and best practices. +The function specified can be a +[provider-specific function](https://github.com/hashicorp/terraform-provider-google-beta/blob/main/google-beta/tpgresource/common_diff_suppress.go) +(for example, `tgpresource.CaseDiffSuppress`) or a function defined in resource-specific +[custom code]({{}}). + Example: ```yaml @@ -225,6 +230,44 @@ Example: diff_suppress_func: 'tpgresource.CaseDiffSuppress' ``` +### `validation` +Controls the value set for the field's [`ValidateFunc`](https://developer.hashicorp.com/terraform/plugin/sdkv2/schemas/schema-behaviors#validatefunc). + +If `validation` is set on an Enum field, it will override the default validation (that the provided value is in the Enum's [`values`](#values)). + +This property has two mutually exclusive child properties: + +- `function`: The name of a + [validation function](https://developer.hashicorp.com/terraform/plugin/sdkv2/schemas/schema-behaviors#validatefunc) + to use for validation. The function can be a + [Terraform-provided function](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/helper/validation) + (for example, `validation.IntAtLeast(0)`), a + [provider-specific function](https://github.com/hashicorp/terraform-provider-google-beta/blob/main/google-beta/verify/validation.go) + (for example, `verify.ValidateBase64String`), or a function defined in + resource-specific + [custom code]({{}}). +- `regex`: A regex string to check values against. This can only be used on simple + String fields. It is equivalent to + [`function: verify.ValidateRegexp(REGEX_STRING)`](https://github.com/hashicorp/terraform-provider-google-beta/blob/0ef51142a4dd1c1a4fc308c1eb09dce307ebe5f5/google-beta/verify/validation.go#L425). + +Example: Provider-specific function + +```yaml +- !ruby/object:Api::Type::String + name: 'fieldOne' + validation: !ruby/object:Provider::Terraform::Validation + function: 'verify.ValidateBase64String' +``` + +Example: Regex + +```yaml +- !ruby/object:Api::Type::String + name: 'fieldOne' + validation: !ruby/object:Provider::Terraform::Validation + regex: '^[a-zA-Z][a-zA-Z0-9_]*$' +``` + ### `api_name` Specifies a name to use for communication with the API that is different than the name of the field in Terraform. In general, setting an `api_name` is not @@ -246,6 +289,9 @@ to allow better forwards-compatibility, and link to API documentation stating the current allowed values in the String field's description. Do not include UNSPECIFIED values in this list. +Enums will validate that the provided field is in the allowed list unless a +custom [`validation`](#validation) is provided. + Example: ```yaml diff --git a/docs/content/develop/test/test.md b/docs/content/develop/test/test.md index 827b94407046..55d5272d4f72 100644 --- a/docs/content/develop/test/test.md +++ b/docs/content/develop/test/test.md @@ -222,6 +222,17 @@ An update test is a test that creates the target resource and then makes updates {{< /tab >}} {{< /tabs >}} +## Add unit tests + +A unit test verifies functionality that is not related to interactions with the API, such as +[diff suppress functions]({{}})), +[validation functions]({{}}), +CustomizeDiff functions, and so on. + +Unit tests should be added to the appropriate folder in [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services) in the file called `resource_PRODUCT_RESOURCE_test.go`. (You may need to create this file if it does not already exist. Replace PRODUCT with the product name and RESOURCE with the resource name; it should match the name of the generated resource file.) + +Unit tests should be named like `TestFunctionName` - for example, `TestDiskImageDiffSuppress` tests the `DiskImageDiffSuppress` function. + ## What's next? - [Run your tests]({{< ref "/develop/test/run-tests.md" >}}) From f12e96cdf79e78ffe088bf5a4acf12a8634604ff Mon Sep 17 00:00:00 2001 From: Stephen Lewis Date: Wed, 17 Apr 2024 14:28:16 -0700 Subject: [PATCH 2/2] Added a unit test example --- docs/content/develop/test/test.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/content/develop/test/test.md b/docs/content/develop/test/test.md index 55d5272d4f72..bbec189143b6 100644 --- a/docs/content/develop/test/test.md +++ b/docs/content/develop/test/test.md @@ -231,7 +231,31 @@ CustomizeDiff functions, and so on. Unit tests should be added to the appropriate folder in [`magic-modules/mmv1/third_party/terraform/services`](https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services) in the file called `resource_PRODUCT_RESOURCE_test.go`. (You may need to create this file if it does not already exist. Replace PRODUCT with the product name and RESOURCE with the resource name; it should match the name of the generated resource file.) -Unit tests should be named like `TestFunctionName` - for example, `TestDiskImageDiffSuppress` tests the `DiskImageDiffSuppress` function. +Unit tests should be named like `TestFunctionName` - for example, `TestDiskImageDiffSuppress` would contain tests for the `DiskImageDiffSuppress` function. + +Example: + +```go +func TestSignatureAlgorithmDiffSuppress(t *testing.T) { + cases := map[string]struct { + Old, New string + ExpectDiffSuppress bool + }{ + "ECDSA_P256 equivalent": { + Old: "ECDSA_P256_SHA256", + New: "EC_SIGN_P256_SHA256", + ExpectDiffSuppress: true, + }, + // Additional cases excluded for brevity + } + + for tn, tc := range cases { + if signatureAlgorithmDiffSuppress("signature_algorithm", tc.Old, tc.New, nil) != tc.ExpectDiffSuppress { + t.Errorf("bad: %s, %q => %q expect DiffSuppress to return %t", tn, tc.Old, tc.New, tc.ExpectDiffSuppress) + } + } +} +``` ## What's next?