Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Validate() to all collections #481

Merged
merged 13 commits into from Sep 15, 2022
Merged

Add Validate() to all collections #481

merged 13 commits into from Sep 15, 2022

Conversation

Doridian
Copy link
Contributor

@Doridian Doridian commented Sep 14, 2022

This also fixes a bug in internal/reflect/map.go where it used the map's own type to Validate elements, which does not seem correct at all.

Fixes #467

@Doridian Doridian requested a review from a team as a code owner September 14, 2022 05:10
@hashicorp-cla
Copy link

hashicorp-cla commented Sep 14, 2022

CLA assistant check
All committers have signed the CLA.

@bflad bflad added the bug Something isn't working label Sep 14, 2022
Copy link
Member

@bflad bflad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Doridian 👋 Thank you for submitting this. Overall this is looking pretty good, it could just use some additional unit testing and small adjustments. If you have any questions about adding that testing, please reach out.

Also, if you could, it would be great to include a changelog entry which can be done by adding a .changelog/481.txt file with contents such as:

```release-note:bug
types: Ensured `List`, `Map`, and `Set` types with `xattr.TypeWithValidate` elements run validation on those elements
```

types/list.go Show resolved Hide resolved
types/set.go Outdated Show resolved Hide resolved
types/map.go Show resolved Hide resolved
@@ -148,15 +148,23 @@ func (st SetType) Validate(ctx context.Context, in tftypes.Value, path path.Path
return diags
}

validatableType, isValidatable := st.ElemType.(xattr.TypeWithValidate)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should ensure there is a covering unit test for this change. 👍

return diags
}

if !in.Type().Is(tftypes.Map{}) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should ensure there is a covering unit test for this new conditional. 👍

Doridian and others added 5 commits September 14, 2022 07:13
Co-authored-by: Brian Flad <bflad417@gmail.com>
Co-authored-by: Brian Flad <bflad417@gmail.com>
Co-authored-by: Brian Flad <bflad417@gmail.com>
@Doridian
Copy link
Contributor Author

Addresses all suggestions but unit tests.

I was looking at the unit tests and could not really find any that seem to test the current validation framework, so I was unsure how or where to add those.

I also saw tests for collections spread over the local list_test/map_test and then the big struct_test file.

I will gladly take any suggestion for where to best add those tests and if I maybe just missed validation tests I could base off of.

@Doridian
Copy link
Contributor Author

Doridian commented Sep 14, 2022

It seems that AtSetValue expects an attr.Value, not tftypes.Value. Pushed a fix for that.

@bflad
Copy link
Member

bflad commented Sep 14, 2022

@Doridian since we are adding a method onto the type, we can unit test the method itself, e.g.

func TestListTypeValidate(t *testing.T) {
	t.Parallel()

	testCases := map[string]struct {
		listType      ListType
		tfValue       tftypes.Value
		path          path.Path
		expectedDiags diag.Diagnostics
	}{
		"wrong-value-type": {
			listType: ListType{
				ElemType: StringType,
			},
			tfValue: tftypes.NewValue(tftypes.Set{
				ElementType: tftypes.String,
			}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "testvalue"),
			}),
			path: path.Root("test"),
			expectedDiags: diag.Diagnostics{
				diag.NewAttributeErrorDiagnostic(
					path.Root("test"),
					"List Type Validation Error",
					"An unexpected error was encountered trying to validate an attribute value. This is always an error in the provider. Please report the following to the provider developer:\n\n"+
						"expected List value, received tftypes.Value with value: tftypes.Set[tftypes.String]<tftypes.String<\"testvalue\">>",
				),
			},
		},
		"no-validation": {
			listType: ListType{
				ElemType: StringType,
			},
			tfValue: tftypes.NewValue(tftypes.List{
				ElementType: tftypes.String,
			}, []tftypes.Value{
				tftypes.NewValue(tftypes.String, "testvalue"),
			}),
			path: path.Root("test"),
		},
	}

	for name, testCase := range testCases {
		name, testCase := name, testCase

		t.Run(name, func(t *testing.T) {
			t.Parallel()

			diags := testCase.listType.Validate(context.Background(), testCase.tfValue, testCase.path)

			if diff := cmp.Diff(diags, testCase.expectedDiags); diff != "" {
				t.Errorf("unexpected diagnostics difference: %s", diff)
			}
		})
	}
}

Rinse and repeat for MapType and SetType.

This is okay for now as it would unfortunately take a lot more effort to import the existing internal/testing/types.StringTypeWithValidateError to verify the element validation diagnostics are passed back, as importing that right now would cause an import cycle and updating the testing file to package types_test and putting types. in front of everything in the types package is a lot to ask. 😅

@bflad
Copy link
Member

bflad commented Sep 14, 2022

(We could also create an unexported type with validation errors in the test files too, but it is totally fine.)

@Doridian
Copy link
Contributor Author

I have added tests for list and map exactly as you described.
For map, as it already was validatable, I have just appended the wrong-value-type test case.

@Doridian
Copy link
Contributor Author

This is okay for now as it would unfortunately take a lot more effort to import the existing internal/testing/types.StringTypeWithValidateError to verify the element validation diagnostics are passed back, as importing that right now would cause an import cycle and updating the testing file to package types_test and putting types. in front of everything in the types package is a lot to ask. 😅

Maybe in another PR if I find the time 😉

@Doridian Doridian requested a review from bflad September 15, 2022 03:28
@bflad bflad added this to the v0.13.0 milestone Sep 15, 2022
Copy link
Member

@bflad bflad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, @Doridian, thank you so much for your efforts here 🚀

@bflad bflad merged commit 5f9d3d3 into hashicorp:main Sep 15, 2022
@Doridian Doridian deleted the feat/validation-collections branch September 15, 2022 13:24
@github-actions
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

xattr.TypeWithValidate support for list elements (and possibly contents of other collections)
3 participants