-
Notifications
You must be signed in to change notification settings - Fork 151
sanity: fix nil pointer error for IDGen when using Ginkgo suite #220
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
Conversation
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: pohly The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/assign @davidz627 |
/cc @okartau Found by Olev when updating PMEM-CSI to csi-test 2.2.0. |
@pohly: GitHub didn't allow me to request PR reviews from the following users: okartau. Note that only kubernetes-csi members and repo collaborators can review this PR, and authors cannot review their own PRs. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
pkg/sanity/util.go
Outdated
@@ -44,7 +44,7 @@ type IDGenerator interface { | |||
GenerateInvalidNodeID() string | |||
} | |||
|
|||
var _ IDGenerator = &DefaultIDGenerator{} | |||
var defaultIDGen IDGenerator = &DefaultIDGenerator{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid global variables, consider creating a "NewDefaultIDGenerator" function instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or just return &DefaultIDGenerator{}
- but that becomes mute if we don't use the accessor at all.
pkg/sanity/sanity.go
Outdated
if c.IDGen != nil { | ||
return c.IDGen | ||
} | ||
return defaultIDGen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defaulting in an accessor is a code smell. This will surprise someone eventually. Could you just provide a default ID generator in the GinkgoTest? If you want to fix it once and for all you could also make the creation of a Config
into a NewConfig
function which defaults IDGen
if not specified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A NewConfig
function is useful and would simplify the addition of new entries were the null entry isn't a sensible default. But depending on it being used to construct the Config
is an API break.
For now I'll go for a deep-copy function instead which takes the user supplied Config
and sanitizes it, like you did in Test
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copying Config
doesn't work. That the tests use the user-supplied instance is part of the API, too. In PMEM-CSI we use that to fill in some fields that depend on the current test in a BeforeEach
.
I guess we have to continue with updating the user-supplied instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pohly@8ac7c59 contains a version which updates IDGen
in both code paths.
But I am not convinced that this is actually the better solution compared to the current one with the accessor. It creates a special case just for IDGen
, everything else is checked at test runtime.
@davidz627 perhaps I can convince you that the accessor isn't so bad after all? 😐
I updated the defaulting to not use a global variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still slightly confused as to why callers (or a constructor) can't just set the IDGen
to a default when creating the Config
struct? If the Config
struct must have an IDGen
field set to function (it does) it should enforce that at creation time.
Another issue with defaulting in the accessor is now you've created an "API break" in that you MUST use the accessor. It's easy to imagine a scenario where someone adds code that doesn't use the accessor and grabs the IDGen
directly and breaks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think defaulting IDGen
either or creation or near creation of the Config
object is the correct way to do this. There's no API break and theres no unexpected behavior around accessing it.
The comment about IDGen
being optional
is probably incorrect as we can see it's being assumed + used in several places in the tests. It is actually required and should be defaulted or set by a caller.
If for some reason this doesn't work I would prefer to rev the major version by requiring a constructor (honestly requiring a constructor should never be the case - we should be able to default elsewhere where the config is "initialized") with the defaulting rather than force usage of an accessor that has implicit defaulting behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
introducing one [constructor] now is an API break
Adding a new function is generally not considered an API break. The accessor you created is also a new function, and I don't consider that to be an API break either. Both approaches fix the bug in a new API, and users will have to switch to that API to get the bug fix.
// IDGen is an optional interface for callers to provide a generator for
// valid Volume and Node IDs. Defaults to DefaultIDGenerator which generates
// generic string IDs
My interpretation is close to yours, @pohly. To me, this says "Users don't need to supply this value and anyone reading it should expect the default behavior provided by DefaultIDGenerator
". Since users are expected to create this struct directly, that means the nil value should be a useful default. If users were using a constructor, I would assume the constructor to handle defaulting.
The fact that the intention was to have this default, but no defaulting was provided in the library is a bug. However, I feel the bug lies with the API design and not its implementation. i.e. Asking users to initialize a struct directly means that the nil value should be useful, but that is not possible for interface types.
If the impact on users is comparable (minor code change to use new API) then we should focus on which API is preferable. The options I see here are,
- Add an accessor with defaulting behavior
- Add a constructor with defaulting behavior
- Document that users must explicitly provide
DefaultIDGenerator
or another generator.
Option 1 is the worst fit with the existing API. The Config type has no methods or accessors today. Defining one for a single field is likely to be missed by someone when they access every other field directly.
Option 2 provides the most forward compatibility, since a constructor function can usually adopt a functional options pattern.
Option 3 is updating the comments to describe the API implemented rather than the one intended. This may be reasonable, given how few users this library has.
Regarding DeepCopy,
That the tests use the user-supplied instance is part of the API, too.
If a behavior is observable, that does not mean it must be treated like an API. (see also, Hyrum's Law) While it is good to avoid breaking users of this library, it is also good to avoid accumulating tech debt.
Just as a side comment, the godoc for this package does not make it easy to figure out how to use this package. Is there documentation elsewhere that users should be reading? Should we link to it from the godoc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
introducing one [constructor] now is an API break
Adding a new function is generally not considered an API break.
Yes, as long as calling it is optional. But the idea was to make calling
the constructor mandatory because there new non-null values (like the
interface implementation) would be set. That would be an API break,
because current users of the API don't call it and then fail.
The fact that the intention was to have this default, but no defaulting was provided in the library is a bug. However, I feel the bug lies with the API design and not its implementation. i.e. Asking users to initialize a struct directly means that the nil value should be useful, but that is not possible for interface types.
I don't think there has been much thought spent on API design in this
package... I suppose we now try to reconstruct what the API really is
based on the exported types and how they get used in reality.
If the impact on users is comparable (minor code change to use new API) then we should focus on which API is preferable. The options I see here are,
- Add an accessor with defaulting behavior
- Add a constructor with defaulting behavior
- Document that users must explicitly provide
DefaultIDGenerator
or another generator.Option 1 is the worst fit with the existing API. The Config type has
no methods or accessors today. Defining one for a single field is
likely to be missed by someone when they access every other field
directly.Option 2 provides the most forward compatibility, since a constructor
function can usually adopt a functional
options
pattern.
That would also be my preferred solution. But let's postpone that until
we need to break the API for some other reason.
As a short-term solution let's fix the missing initialization, which is
the alternative solution that I mentioned in #220 (comment)
I've updated this PR with that code.
Option 3 is updating the comments to describe the API implemented
rather than the one intended. This may be reasonable, given how few
users this library has.Regarding DeepCopy,
That the tests use the user-supplied instance is part of the API, too.
If a behavior is observable, that does not mean it must be treated like an API. (see also, Hyrum's Law) While it is good to avoid breaking users of this library, it is also good to avoid accumulating tech debt.
True. But this aspect of the package is useful, so it should be part of
the API.
Just as a side comment, the
godoc
for this package does not make it easy to figure out how to use this
package. Is there documentation elsewhere that users should be
reading?
Unfortunately not. New users probably discover it based on usage in
other projects, which then also serves as example for how to use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the quick reply.
introducing one [constructor] now is an API break
Adding a new function is generally not considered an API break.
Yes, as long as calling it is optional. But the idea was to make calling
the constructor mandatory because there new non-null values (like the
interface implementation) would be set. That would be an API break,
because current users of the API don't call it and then fail.
My point was that adding an accessor is also a new "mandatory" function. However, I think "mandatory" is not the only way to view such a change. Any client that continues to use the existing API will experience the exact same behavior, bug and all. From that perspective, this is not a breaking API change.
The fact that the intention was to have this default, but no defaulting was provided in the library is a bug. However, I feel the bug lies with the API design and not its implementation. i.e. Asking users to initialize a struct directly means that the nil value should be useful, but that is not possible for interface types.
I don't think there has been much thought spent on API design in this
package... I suppose we now try to reconstruct what the API really is
based on the exported types and how they get used in reality.
That's a fair assessment, but I do not believe we need to be absolutely rigid with regard to the existing API. The cost of moving all callers on to a new and improved API may be worth it for said API.
If the impact on users is comparable (minor code change to use new API) then we should focus on which API is preferable. The options I see here are,
- Add an accessor with defaulting behavior
- Add a constructor with defaulting behavior
- Document that users must explicitly provide
DefaultIDGenerator
or another generator.Option 1 is the worst fit with the existing API. The Config type has
no methods or accessors today. Defining one for a single field is
likely to be missed by someone when they access every other field
directly.
Option 2 provides the most forward compatibility, since a constructor
function can usually adopt a functional
options
pattern.That would also be my preferred solution. But let's postpone that until
we need to break the API for some other reason.As a short-term solution let's fix the missing initialization, which is
the alternative solution that I mentioned in #220 (comment)I've updated this PR with that code.
Option 3 is updating the comments to describe the API implemented
rather than the one intended. This may be reasonable, given how few
users this library has.
Regarding DeepCopy,That the tests use the user-supplied instance is part of the API, too.
If a behavior is observable, that does not mean it must be treated like an API. (see also, Hyrum's Law) While it is good to avoid breaking users of this library, it is also good to avoid accumulating tech debt.
True. But this aspect of the package is useful, so it should be part of
the API.
Are you referring to the nil panic fix, or the fact that test break if you DeepCopy a Config
? I don't see how the latter is useful.
Just as a side comment, the
godoc
for this package does not make it easy to figure out how to use this
package. Is there documentation elsewhere that users should be
reading?Unfortunately not. New users probably discover it based on usage in
other projects, which then also serves as example for how to use it.
It can always be improved in the future! May also be a good-first-issue
task for a learning contributor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you referring to the nil panic fix, or the fact that test break if you DeepCopy a Config? I don't see how the latter is useful.
Shared ownership of Config with the ability to modify it later is useful in a Ginkgo suite due to the way how tests are run: there's registration of tests at init time, then code from the caller is executed (custom BeforeEach), then the code of each test runs. But that's a discussion for another time. For now let's simply ensure that code using 2.1.0 can update to 2.3.0 without having to change how the package is used (no API change).
@davidz627 can you lgtm to get this merged?
When adding IDGen, only one of the two code paths that trigger testing was updated such that it sets a default ID generator when the config doesn't already have one. GinkgoTest was not updated. As a result, existing E2E suites which use GinkgoTest and don't set the new field crash at runtime with a nil pointer error when updated to csi-test 2.2.0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
@misterikkit: changing LGTM is restricted to collaborators In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/lgtm |
test: fix golint error
227577e Merge pull request kubernetes-csi#258 from gnufied/enable-race-detection e1ceee2 Always enable race detection while running tests 988496a Merge pull request kubernetes-csi#257 from jakobmoellerdev/csi-prow-sidecar-e2e-path 028f8c6 chore: bump to Go 1.22.5 69bd71e chore: add CSI_PROW_SIDECAR_E2E_PATH f40f0cc Merge pull request kubernetes-csi#256 from solumath/master cfa9210 Instruction update 379a1bb Merge pull request kubernetes-csi#255 from humblec/sidecar-md a5667bb fix typo in sidecar release process 4967685 Merge pull request kubernetes-csi#254 from bells17/add-github-actions d9bd160 Update skip list in codespell GitHub Action adb3af9 Merge pull request kubernetes-csi#252 from bells17/update-go-version f5aebfc Add GitHub Actions workflows b82ee38 Merge pull request kubernetes-csi#253 from bells17/fix-typo c317456 Fix typo 0a78505 Bump to Go 1.22.3 edd89ad Merge pull request kubernetes-csi#251 from jsafrane/add-logcheck 043fd09 Add test-logcheck target d7535ae Merge pull request kubernetes-csi#250 from jsafrane/go-1.22 b52e7ad Update go to 1.22.2 14fdb6f Merge pull request kubernetes-csi#247 from msau42/prow dc4d0ae Merge pull request kubernetes-csi#249 from jsafrane/use-go-version e681b17 Use .go-version to get Kubernetes go version 9b4352e Update release playbook c7bb972 Fix release notes script to use fixed tags 463a0e9 Add script to update specific go modules b54c1ba Merge pull request kubernetes-csi#246 from xing-yang/go_1.21 5436c81 Change go version to 1.21.5 267b40e Merge pull request kubernetes-csi#244 from carlory/sig-storage b42e5a2 nominate self (carlory) as kubernetes-csi reviewer a17f536 Merge pull request kubernetes-csi#210 from sunnylovestiramisu/sidecar 011033d Use set -x instead of die 5deaf66 Add wrapper script for sidecar release f8c8cc4 Merge pull request kubernetes-csi#237 from msau42/prow b36b5bf Merge pull request kubernetes-csi#240 from dannawang0221/upgrade-go-version adfddcc Merge pull request kubernetes-csi#243 from pohly/git-subtree-pull-fix c465088 pull-test.sh: avoid "git subtree pull" error 7b175a1 Update csi-test version to v5.2.0 987c90c Update go version to 1.21 to match k/k 2c625d4 Add script to generate patch release notes f9d5b9c Merge pull request kubernetes-csi#236 from mowangdk/feature/bump_csi-driver-host-path_version b01fd53 Bump csi-driver-host-path version up to v1.12.0 984feec Merge pull request kubernetes-csi#234 from siddhikhapare/csi-tools 1f7e605 fixed broken links of testgrid dashboard de2fba8 Merge pull request kubernetes-csi#233 from andyzhangx/andyzhangx-patch-1 cee895e remove windows 20H2 build since it's EOL long time ago 670bb0e Merge pull request kubernetes-csi#229 from marosset/fix-codespell-errors 35d5e78 Merge pull request kubernetes-csi#219 from yashsingh74/update-registry 63473cc Merge pull request kubernetes-csi#231 from coulof/bump-go-version-1.20.5 29a5c76 Merge pull request kubernetes-csi#228 from mowangdk/chore/adopt_kubernetes_recommand_labels 8dd2821 Update cloudbuild image with go 1.20.5 1df23db Merge pull request kubernetes-csi#230 from msau42/prow 1f92b7e Add ginkgo timeout to e2e tests to help catch any stuck tests 2b8b80e fixing some codespell errors c10b678 Merge pull request kubernetes-csi#227 from coulof/check-sidecar-supported-versions 72984ec chore: adopt kubernetes recommand label b055535 Header bd0a10b typo c39d73c Add comments f6491af Script to verify EOL sidecar version 4133d1d Merge pull request kubernetes-csi#226 from msau42/cloudbuild 8d519d2 Pin buildkit to v0.10.6 to workaround v0.11 bug with docker manifest 6e04a03 Merge pull request kubernetes-csi#224 from msau42/cloudbuild 26fdfff Update cloudbuild image 6613c39 Merge pull request kubernetes-csi#223 from sunnylovestiramisu/update 0e7ae99 Update k8s image repo url 77e47cc Merge pull request kubernetes-csi#222 from xinydev/fix-dep-version 155854b Fix dep version mismatch 8f83905 Merge pull request kubernetes-csi#221 from sunnylovestiramisu/go-update 1d3f94d Update go version to 1.20 to match k/k v1.27 e322ce5 Merge pull request kubernetes-csi#220 from andyzhangx/fix-golint-error b74a512 test: fix golint error 901bcb5 Update registry k8s.gcr.io -> registry.k8s.io git-subtree-dir: release-tools git-subtree-split: 227577e
734c2b9 Merge pull request kubernetes-csi#265 from Rakshith-R/consider-main-branch f95c855 Merge pull request kubernetes-csi#262 from huww98/golang-toolchain 3c8d966 Treat main branch as equivalent to master branch e31de52 Merge pull request kubernetes-csi#261 from huww98/golang fd153a9 Bump golang to 1.23.1 a8b3d05 pull-test.sh: fix "git subtree pull" errors 6b05f0f use new GOTOOLCHAIN env to manage go version 227577e Merge pull request kubernetes-csi#258 from gnufied/enable-race-detection e1ceee2 Always enable race detection while running tests 988496a Merge pull request kubernetes-csi#257 from jakobmoellerdev/csi-prow-sidecar-e2e-path 028f8c6 chore: bump to Go 1.22.5 69bd71e chore: add CSI_PROW_SIDECAR_E2E_PATH f40f0cc Merge pull request kubernetes-csi#256 from solumath/master cfa9210 Instruction update 379a1bb Merge pull request kubernetes-csi#255 from humblec/sidecar-md a5667bb fix typo in sidecar release process 4967685 Merge pull request kubernetes-csi#254 from bells17/add-github-actions d9bd160 Update skip list in codespell GitHub Action adb3af9 Merge pull request kubernetes-csi#252 from bells17/update-go-version f5aebfc Add GitHub Actions workflows b82ee38 Merge pull request kubernetes-csi#253 from bells17/fix-typo c317456 Fix typo 0a78505 Bump to Go 1.22.3 edd89ad Merge pull request kubernetes-csi#251 from jsafrane/add-logcheck 043fd09 Add test-logcheck target d7535ae Merge pull request kubernetes-csi#250 from jsafrane/go-1.22 b52e7ad Update go to 1.22.2 14fdb6f Merge pull request kubernetes-csi#247 from msau42/prow dc4d0ae Merge pull request kubernetes-csi#249 from jsafrane/use-go-version e681b17 Use .go-version to get Kubernetes go version 9b4352e Update release playbook c7bb972 Fix release notes script to use fixed tags 463a0e9 Add script to update specific go modules b54c1ba Merge pull request kubernetes-csi#246 from xing-yang/go_1.21 5436c81 Change go version to 1.21.5 267b40e Merge pull request kubernetes-csi#244 from carlory/sig-storage b42e5a2 nominate self (carlory) as kubernetes-csi reviewer a17f536 Merge pull request kubernetes-csi#210 from sunnylovestiramisu/sidecar 011033d Use set -x instead of die 5deaf66 Add wrapper script for sidecar release f8c8cc4 Merge pull request kubernetes-csi#237 from msau42/prow b36b5bf Merge pull request kubernetes-csi#240 from dannawang0221/upgrade-go-version adfddcc Merge pull request kubernetes-csi#243 from pohly/git-subtree-pull-fix c465088 pull-test.sh: avoid "git subtree pull" error 7b175a1 Update csi-test version to v5.2.0 987c90c Update go version to 1.21 to match k/k 2c625d4 Add script to generate patch release notes f9d5b9c Merge pull request kubernetes-csi#236 from mowangdk/feature/bump_csi-driver-host-path_version b01fd53 Bump csi-driver-host-path version up to v1.12.0 984feec Merge pull request kubernetes-csi#234 from siddhikhapare/csi-tools 1f7e605 fixed broken links of testgrid dashboard de2fba8 Merge pull request kubernetes-csi#233 from andyzhangx/andyzhangx-patch-1 cee895e remove windows 20H2 build since it's EOL long time ago 670bb0e Merge pull request kubernetes-csi#229 from marosset/fix-codespell-errors 35d5e78 Merge pull request kubernetes-csi#219 from yashsingh74/update-registry 63473cc Merge pull request kubernetes-csi#231 from coulof/bump-go-version-1.20.5 29a5c76 Merge pull request kubernetes-csi#228 from mowangdk/chore/adopt_kubernetes_recommand_labels 8dd2821 Update cloudbuild image with go 1.20.5 1df23db Merge pull request kubernetes-csi#230 from msau42/prow 1f92b7e Add ginkgo timeout to e2e tests to help catch any stuck tests 2b8b80e fixing some codespell errors c10b678 Merge pull request kubernetes-csi#227 from coulof/check-sidecar-supported-versions 72984ec chore: adopt kubernetes recommand label b055535 Header bd0a10b typo c39d73c Add comments f6491af Script to verify EOL sidecar version 4133d1d Merge pull request kubernetes-csi#226 from msau42/cloudbuild 8d519d2 Pin buildkit to v0.10.6 to workaround v0.11 bug with docker manifest 6e04a03 Merge pull request kubernetes-csi#224 from msau42/cloudbuild 26fdfff Update cloudbuild image 6613c39 Merge pull request kubernetes-csi#223 from sunnylovestiramisu/update 0e7ae99 Update k8s image repo url 77e47cc Merge pull request kubernetes-csi#222 from xinydev/fix-dep-version 155854b Fix dep version mismatch 8f83905 Merge pull request kubernetes-csi#221 from sunnylovestiramisu/go-update 1d3f94d Update go version to 1.20 to match k/k v1.27 e322ce5 Merge pull request kubernetes-csi#220 from andyzhangx/fix-golint-error b74a512 test: fix golint error 901bcb5 Update registry k8s.gcr.io -> registry.k8s.io git-subtree-dir: release-tools git-subtree-split: 734c2b950c4b31f64b63052c64ffa5929d1c9b97
What type of PR is this?
/kind bug
What this PR does / why we need it:
When adding IDGen, only one of the two code paths that trigger testing
was updated such that it sets a default ID generator when the config
doesn't already have one. GinkgoTest was not updated.
As a result, existing E2E suites which use GinkgoTest and don't set the
new field crash at runtime with a nil pointer error when updated to
csi-test 2.2.0.
Updating the instance provided by the caller is also a bit
questionable because it is an undocumented side effect. It's cleaner
to treat the struct as read-only and implement the fallback in an
accessor function.
Special notes for your reviewer:
We should create a 2.2.1 with this fix...
Does this PR introduce a user-facing change?: