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

EqualExportedValues: Handle nested pointer, slice and map fields #1379

Conversation

HaraldNordgren
Copy link
Contributor

@HaraldNordgren HaraldNordgren commented Apr 24, 2023

The current implementation of ObjectsExportedFieldsAreEqual does not handle (nested) pointer or slices fields. This means it doesn't work for comparing e.g. any Protobuf struct if there is any of these on the Protobuf message.

Here, I am hoisting the reflect.Kind() checking from inside the loop to earlier in the logic. This allows me to take better advantage of the recursiveness of the function for checking equality for different types of structs. All while still maintaining the original functionality, as seen by the fact that the original tests are not altered.

I added a lot of tests cove different cases. It may seems like a lot of tests for this feature, but I used them when developing and since the reflection logic is pretty brittle in general, they were quite necessary for me to be able to refactor with any kind of confidence.

Thanks a bunch to @mchlp for the original implementation, this function is very needed for using Testify together with Protobuf! 🙌🏻

@HaraldNordgren HaraldNordgren changed the title EqualExportedValues: Handle pointer and slice fields EqualExportedValues: Handle nested pointer and slice fields Apr 24, 2023
@HaraldNordgren
Copy link
Contributor Author

Ping @boyan-soubachov @mchlp @feidtmb

Copy link
Contributor

@mchlp mchlp left a comment

Choose a reason for hiding this comment

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

Just a question about handling of map. Looks good otherwise!

assert/assertions.go Show resolved Hide resolved
assert/assertions.go Outdated Show resolved Hide resolved
Copy link

@feidtmb feidtmb left a comment

Choose a reason for hiding this comment

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

I like this approach! I left a few nits but it looks good to me otherwise.

assert/assertions.go Outdated Show resolved Hide resolved
assert/assertions.go Outdated Show resolved Hide resolved
@HaraldNordgren HaraldNordgren changed the title EqualExportedValues: Handle nested pointer and slice fields EqualExportedValues: Handle nested pointer, slice and map fields Apr 28, 2023
@HaraldNordgren
Copy link
Contributor Author

@mchlp @feidtmb I added support for maps now, and I think I address all of your comments as well! 🤗

feidtmb
feidtmb previously approved these changes Apr 28, 2023
Copy link

@feidtmb feidtmb left a comment

Choose a reason for hiding this comment

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

It doesn't look like ObjectsExportedFieldsAreEqual is actually used anymore beyond tests, so we might want to remove it. Other than that though ✅ . (And thanks for adding map support!)

edit: I think a data structure that references itself would cause an infinite loop (example test case from a different PR). IMO this is acceptable for a test helper package like testify, but I think it would be worth noting in the function comment on EqualExportedValues.

mchlp
mchlp previously approved these changes Apr 28, 2023
Copy link
Contributor

@mchlp mchlp left a comment

Choose a reason for hiding this comment

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

Looks good! Thanks for adding support for maps - I think this covers all of the composite data types.

@HaraldNordgren
Copy link
Contributor Author

Thanks again!

@feidtmb, I added a comment about infinite recursion to your PR: #1373

@HaraldNordgren
Copy link
Contributor Author

Hi again @boyan-soubachov, would you have some time to look at this?

result := reflect.New(expectedType).Elem()
for i := 0; i < expectedType.NumField(); i++ {
field := expectedType.Field(i)
isExported := field.PkgPath == "" // should use field.IsExported() but it's not available in Go 1.16.5
Copy link
Collaborator

Choose a reason for hiding this comment

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

We probably shouldn't support Go 1.16 any more since it's not officially supported anyways.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Feel free to change the build to only support 1.20, 1.19, and 1.18 -- you can then change this code to not consider Go 1.16

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@boyan-soubachov Updated!

Be aware the the auto-formatting rules seem to have changed for Go versions >= 1.19. I'm re-formatting the files and committing the new ones as well.

And we are now skipping that part of the build job for 1.18 because it otherwise fails because of formatting issues.

@HaraldNordgren HaraldNordgren dismissed stale reviews from mchlp and feidtmb via 255f82e May 9, 2023 18:04
@HaraldNordgren HaraldNordgren force-pushed the nested_pointer_fields_format_diffs_correctly branch 12 times, most recently from da2f494 to b39be5d Compare May 9, 2023 18:43
- run: ./.ci.gogenerate.sh
- run: ./.ci.gofmt.sh
- name: Go generate
if: ${{ matrix.go_version != 1.18 }}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are we excluding gogenerate.sh and gofmt.sh from running if it's Go 1.18?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's because it failed. I wrote a comment about it here: #1379 (comment)

If we don't want this extra logic, we could also drop support for 1.18, maybe it's old enough at this point?

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's fair -> https://endoflife.date/go

We can drop 1.18 support.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@boyan-soubachov Updated to drop 1.18!

@HaraldNordgren HaraldNordgren force-pushed the nested_pointer_fields_format_diffs_correctly branch from b39be5d to 0a7ed06 Compare May 10, 2023 06:38
@HaraldNordgren HaraldNordgren force-pushed the nested_pointer_fields_format_diffs_correctly branch from 0a7ed06 to ae7aab5 Compare May 10, 2023 06:43
@HaraldNordgren HaraldNordgren force-pushed the nested_pointer_fields_format_diffs_correctly branch from ae7aab5 to 9c3edea Compare May 10, 2023 06:43
Copy link
Collaborator

@boyan-soubachov boyan-soubachov left a comment

Choose a reason for hiding this comment

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

Thank you :)

@boyan-soubachov boyan-soubachov merged commit 4c93d8f into stretchr:master May 10, 2023
2 checks passed
@HaraldNordgren HaraldNordgren deleted the nested_pointer_fields_format_diffs_correctly branch May 11, 2023 11:24
@nars1
Copy link

nars1 commented May 15, 2023

@HaraldNordgren : Hi. We have a Go application that uses the stretchry/testify package. It was working fine on various systems with different go versions. But for the past 4 days, our nightly pipelines have been failing when run with go 1.13.8.

$ go version
go version go1.13.8 linux/amd64

The failure symptom is the following (pasted from https://gitlab.com/YottaDB/Lang/YDBGo/-/jobs/4268493955)

$ go test -short $(go list ./... | grep -v /vendor/)
# github.com/stretchr/testify/assert
/go/src/github.com/stretchr/testify/assert/assertions.go:94:23: field.IsExported undefined (type reflect.StructField has no field or method IsExported)

The same application also fails on a system with go version go1.15.15 linux/amd64 but passes on a system with go version go1.18.1 linux/amd64.

4c93d8f changed assertions.go to add the field.isExported call. But looks like that call is only supported by recent versions of go.

Is this seeming regression expected? Thanks.

@HaraldNordgren
Copy link
Contributor Author

HaraldNordgren commented May 15, 2023

Hi @nars1!

In general I would definitely advise against using the 'master' build of any library. You are better off pinning the version to testify@v1.8.2 and you would avoid this issue.

This repo has been updated to only support Go versions >=1.18.

Be aware the the Go versions you are using are not officially supported anymore: https://endoflife.date/go. It would also be a good idea to upgrade your Go versions 🤗

@nars1
Copy link

nars1 commented May 15, 2023

@HaraldNordgren : Will pin the version like you suggest and try to upgrade our Go versions. Thank you for the prompt response.

@nars1
Copy link

nars1 commented May 15, 2023

@HaraldNordgren : How do I pin the version like you suggest. My project go.mod file looks as follows.

module lang.yottadb.com/go/yottadb

go 1.13

require github.com/stretchr/testify v1.4.0

How do I say don't go more than 1.8.2? I tried searching for pinning but could not find any references. Hoping you can point me in the right direction. Thanks.

nars1 added a commit to YottaDB/YDBGo that referenced this pull request May 17, 2023
…hr/testify/assert package)

Background
----------
* Below is pasted from stretchr/testify#1379 (comment)
  where I had asked a question on a recent failure we saw in the YDBGo pipelines (and in
  the YDBTest/go/unit_test subtest failures in in-house systems which had go 1.13 and 1.15).

  @HaraldNordgren : Hi. We have a Go application that uses the `stretchry/testify` package. It was
  working fine on various systems with different go versions. But for the past 4 days, our nightly
  pipelines have been failing when run with go 1.13.8.

  ```sh
  $ go version
  go version go1.13.8 linux/amd64
  ```

  The failure symptom is the following (pasted from https://gitlab.com/YottaDB/Lang/YDBGo/-/jobs/4268493955)

  ```sh
  $ go test -short $(go list ./... | grep -v /vendor/)
  # github.com/stretchr/testify/assert
  /go/src/github.com/stretchr/testify/assert/assertions.go:94:23: field.IsExported undefined (type reflect.StructField has no field or method IsExported)
  ```

  The same application also fails on a system with `go version go1.15.15 linux/amd64` but passes on a
  system with `go version go1.18.1 linux/amd64`.

  4c93d8f changed `assertions.go` to add the `field.isExported` call. But looks like that call is only
  supported by recent versions of go.

  Is this seeming regression expected? Thanks.

* And below was the response (pasted from stretchr/testify#1379 (comment))

  In general I would definitely advise against using the 'master' build of any library. You are better
  off pinning the version to testify@v1.8.2 and you would avoid this issue.

  This repo has been updated to only support Go versions >=1.18.

  Be aware the the Go versions you are using are not officially supported anymore:
  https://endoflife.date/go. It would also be a good idea to upgrade your Go versions.

Fix
---
* I tried pinning the version like was suggested. I tried updating go.mod as follows.

  ```diff
  $ git diff go.mod
  @@ -4,2 +4,3 @@ go 1.13

  -require github.com/stretchr/testify v1.4.0
  +require github.com/stretchr/testify v1.8.2
  +replace github.com/stretchr/testify => github.com/stretchr/testify v1.8.2
  ```

  But the YDBGo pipeline still failed as before when it used go 1.13 or go 1.15.

* I then tried the following change.

  ```diff
  $ git diff go.mod
  @@ -4,2 +4,3 @@ go 1.13

  -require github.com/stretchr/testify v1.8.2
  +require github.com/stretchr/testify v1.4.0
  +replace github.com/stretchr/testify => github.com/stretchr/testify v1.8.2
  ```

  This one failed the same way as well.

* Finally decided to bump the go version required by the pipeline to 1.18 as suggested above.
  Searched for all references of `1.13` in the YDBGo repository in the `develop` branch and
  changed all of them to be `1.18`. In some cases, used `1.18.10` as that was the latest
  golang version in the 1.18 series.

  And regenerated `go.mod` using the following steps. This auto-generated go.mod file is
  included in this commit.

  ```sh
  $ cd YDBGo
  $ echo "module lang.yottadb.com/go/yottadb" > go.mod
  $ go get -t
  go: added github.com/davecgh/go-spew v1.1.1
  go: added github.com/pmezard/go-difflib v1.0.0
  go: added github.com/stretchr/testify v1.8.2
  go: added gopkg.in/yaml.v3 v3.0.1
  ```

* And in the in-house systems that have go 1.13 (Ubuntu 20.04) and go 1.15 (Debian 11), decided
  to install the latest Go version using snap instead of using the old go version from the package
  manager. The install worked fine on x86_64, AARCH64 and ARM32 architectures. With those changes,
  the `go/unit_tests` subtest passes fine on all those architectures when it previously reliably failed.
@SuperQ
Copy link
Contributor

SuperQ commented Jun 2, 2023

This change has set the Go minimum version hint to 1.20 in go.mod, but continues to test with 1.19. This is confusing for downstream users.

@HaraldNordgren
Copy link
Contributor Author

Hi @SuperQ, it’s testing both for 1.19 and 1.20.

@SuperQ
Copy link
Contributor

SuperQ commented Jun 2, 2023

Fix for go.mod: #1394

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants