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

chore(linters): Fix findings found by testifylint: go-require forinstrumental and parsers/processors #15887

Merged

Conversation

zak-pawel
Copy link
Collaborator

@zak-pawel zak-pawel commented Sep 15, 2024

Summary

This is only the first part of a larger effort to address the findings identified by testifylint: go-require: #15535
Once all the findings have been addressed, testifylint: go-require can be enabled in .golangci.yml.

In this PR, I’m focusing on parser/processors tests and instrumental_test.go. While fixing the parser/processors tests is quite straightforward, it seems that the approach to testing the simulation of the TCP Server's response in a separate goroutine requires discussion – because there are quite a few such tests in Telegraf’s test code, and it would be great to have a consistent approach in future PRs.

Here are the findings that this PR addresses:

plugins/outputs/instrumental/instrumental_test.go:92:3        testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:94:3        testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:99:3        testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:100:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:102:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:103:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:105:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:108:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:109:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:111:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:112:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:115:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:117:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:122:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:123:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:125:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:126:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:128:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:131:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:132:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:135:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:136:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:139:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:140:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:143:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:144:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/outputs/instrumental/instrumental_test.go:147:3       testifylint  go-require: require must only be used in the goroutine running the test function
plugins/parsers/influx/influx_upstream/parser_test.go:1011:3  testifylint  go-require: require must only be used in the goroutine running the test function
plugins/parsers/influx/parser_test.go:978:3                   testifylint  go-require: require must only be used in the goroutine running the test function
plugins/processors/ifname/ifname_test.go:129:4                testifylint  go-require: require must only be used in the goroutine running the test function
plugins/processors/ifname/ifname_test.go:130:4                testifylint  go-require: require must only be used in the goroutine running the test function
plugins/processors/ifname/ifname_test.go:131:4                testifylint  go-require: require must only be used in the goroutine running the test function
plugins/processors/reverse_dns/rdnscache_test.go:55:3         testifylint  go-require: require must only be used in the goroutine running the test function
plugins/processors/reverse_dns/rdnscache_test.go:61:3         testifylint  go-require: require must only be used in the goroutine running the test function

Checklist

  • No AI generated code was used in this PR

@telegraf-tiger telegraf-tiger bot added the chore label Sep 15, 2024
@zak-pawel zak-pawel changed the title chore(linters): Fix findings found by testifylint: go-require forinstrumental and parsers chore(linters): Fix findings found by testifylint: go-require forinstrumental and parsers/processors Sep 15, 2024
@zak-pawel
Copy link
Collaborator Author

I see the following options for handling multiple errors in the code simulating the TCP Server in a separate goroutine:

  1. (presented in the first commit of this PR): Introducing buffered channels (unbuffered channels are not the best idea here because they block until a receiver receives the sent message) for transmitting potential errors and exiting (return) from the goroutine after each error. Since at least one error (which should be nil) is always sent, and thanks to the fact that the error receiver reads them in a deferred function, we can get rid of WaitGroup (synchronization will happen after sending at least one error).
    Cons: Non-trivial code, prone to mistakes, no information about which line in the goroutine caused the error, need to remember to implement various defers.
  2. From point 1, channels can be removed, and WaitGroup can be restored (as it was before). Instead of sending errors to a channel, they can be logged using the t.Error(f) function, which marks the test as failed but doesn’t immediately stop it (so goroutine should be exited manually after every problem (return)).
    Pros: fewer defers, no channels which need to be handled carefully, information about the line where the problem occurred (in the log)
  3. Similar to point 2, but using assert.XXX instead of t.Error(f).
    Pros: less boilerplate than in points 1 and 2 (fewer if statements – assert functions check the failure condition themselves).
    Cons: it's assert, which we've been phasing out of the test code over the past few years.

@srebhan @DStrand1
What do you think? Or maybe you have some other suggestions?

@srebhan
Copy link
Member

srebhan commented Sep 16, 2024

@zak-pawel is there any reason to not collect errors in the TCPServer instance? We then can simply use require outside of the go-routine without channels and other fu...

@zak-pawel
Copy link
Collaborator Author

@srebhan
If I understand you correctly, you are proposing to wrap TCPServer in a structure that would store potential errors and handle them after the goroutine has finished, right?

I think I prefer option number 2 (t.Error(f)), where there is no need for channels, wrappers, and the exact line where the error occurred will be known.

@srebhan
Copy link
Member

srebhan commented Sep 16, 2024

@zak-pawel exactly, if we do store the errors we can then also check the error messages, types etc. But option 2 also works for me, just make sure the test doesn't sit and wait for the test-timeout (10min) to be hit...

@zak-pawel
Copy link
Collaborator Author

@srebhan Please, check t.Error(f) version.

Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

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

The code is ok even though I don't like the channel stuff in the influx parser... But it's better than breaking things. IMO we are still better off if we are implementing mock-server stuff for instrumental and check the errors/metrics outside of the go-routine.

Anyway, thanks for your work @zak-pawel!

@srebhan srebhan added the ready for final review This pull request has been reviewed and/or tested by multiple users and is ready for a final review. label Sep 16, 2024
@srebhan srebhan removed their assignment Sep 16, 2024
@zak-pawel
Copy link
Collaborator Author

IMO we are still better off if we are implementing mock-server stuff for instrumental and check the errors/metrics outside of the go-routine.

@srebhan I would like to understand why you would prefer it that way.
The Go convention (and common sense 😉) suggest that if someone returns an error to us (or a situation occurs that requires the creation of this error), we check it and decide what to do next. Because in the vast majority of situations, it makes no sense to continue the execution when an error occurs.
So far the error was checked by require (which should not be run in goroutines), and in your proposal with the mock-server we would still have to do it with ifs (just like in my proposal).

The only difference is the place where we "mark" the test as failed. If we do it outside the goroutine, we will lose very valuable information about exactly which line the error occurred - we will have to guess it based on the content of the message...

@srebhan
Copy link
Member

srebhan commented Sep 16, 2024

Well sometimes we want to test that an error occurs e.g. if providing bad configuration settings etc. So my take is, returning an error via the normal communication means would be the best option (e.g. return a HTTP error code on http connections).

Alternatively, implement a mockup server that can trace issues during communication (as I proposed), this way we can test expected error cases as well as comparing results on the server side to what we expect ends up on the server in the unit-test. This also adds the flexibility to adapt metrics in the test cases as input and expected output are in one place.

The least preferable option in my view is to check the result directly on the server side as it creates a rigid structure where the input needs to be known in the unit-test function as-well-as in the mocked server side. Furthermore, it will provide no means to stepwise test code and react on the unit-test side without a lot of synchronization-fu.

But just my 2 cent...

@DStrand1 DStrand1 merged commit ee9c47c into influxdata:master Sep 17, 2024
27 checks passed
@github-actions github-actions bot added this to the v1.32.1 milestone Sep 17, 2024
srebhan pushed a commit that referenced this pull request Oct 7, 2024
…`instrumental` and parsers/processors (#15887)

(cherry picked from commit ee9c47c)
asaharn pushed a commit to asaharn/telegraf that referenced this pull request Oct 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
chore linter ready for final review This pull request has been reviewed and/or tested by multiple users and is ready for a final review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants