-
Notifications
You must be signed in to change notification settings - Fork 331
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
Migrate knative.dev/hack/shell to knative.dev/pkg/test/shell #2856
Conversation
@mgencur: The label(s) 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. |
Codecov ReportAll modified lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #2856 +/- ##
==========================================
- Coverage 81.83% 81.80% -0.03%
==========================================
Files 167 167
Lines 10227 10227
==========================================
- Hits 8369 8366 -3
- Misses 1612 1614 +2
- Partials 246 247 +1 ☔ View full report in Codecov by Sentry. |
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, @mgencur! This looks promising.
There are a couple of places that require changes.
TLDR: We should force passing TestingT
, and we can't fail in case of STDERR output.
test/shell/types.go
Outdated
// If true, the test will be marked as failed if this testingWriter is | ||
// ever used. | ||
markFailed bool |
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.
This is no-go. The scripts often write messages to STDERR (in unix world usually debugging output goes to STDERR). The sole fact the script/tool writes something to STDERR doesn't mean we should fail the 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.
OK
test/shell/types.go
Outdated
|
||
// testingWriter writes to the given testing.TB. | ||
type testingWriter struct { | ||
t testing.TB |
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.
Let's use our own interface. We just need one method:
type TestingT interface {
Log(args ...any)
}
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.
OK. Just curious how does this help?
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.
Helps with testing of functions, as they accept any object that suffices the interface.
This is just good practice in Golang. Here's example article on this https://www.thoughtworks.com/insights/blog/programming-languages/mistakes-to-avoid-when-coming-from-an-object-oriented-language
test/shell/executor.go
Outdated
|
||
// TestingTStreams returns Streams which writes to t.Log and marks | ||
// the test as failed if anything is written to Streams.Err. | ||
func TestingTStreams(t testing.TB) Streams { |
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.
func TestingTStreams(t testing.TB) Streams { | |
func testingTStreams(t TestingT) Streams { |
test/shell/executor.go
Outdated
var ErrNoProjectLocation = errors.New("project location isn't provided") | ||
|
||
// NewExecutor creates a new executor from given config. | ||
func NewExecutor(config ExecutorConfig) Executor { |
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.
func NewExecutor(config ExecutorConfig) Executor { | |
func NewExecutor(t TestingT, config ExecutorConfig) Executor { |
I would prefer to create an API that can't be misused. We probably want to force to pass the TestingT
, we shouldn't allow people just switch without this and continue to output to os.Stdout
, and os.Stderr
.
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.
The API shell.NewExecutor
is general. It doesn't have to be used only in upgrade tests and doesn't always have to log to testing.T. Somebody can use it to log to normal stdout and stderr. That's why I keep it optional.
I will fix using this in a few repositories, at least Serving, Eventing, EventingKafkaBroker. I don't think it's a concern that somebody will migrate to the new package but will not use this new out/err. It's a narrow set of repositories. People need to know what they're doing, I think forcing this func NewExecutor(t TestingT, config ExecutorConfig) Executor {
will just hide the fact. And it's also forcing users to pass testing.T even if they don't want to log to testing.T.
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.
This shell executor is only allowed to be used in testing, see: knative/hack#32
And if so, it doesn't make sense to log to stdout/stderr in tests, as knative/serving#14461 clearly shows.
This is why I wanted a different API, fixing the project location, at the same time. I propose to have:
type Option func(*ExecutorConfig)
func NewExecutor(t TestingT, loc ProjectLocation, opts... Option) Executor
Such API clearly says which params are required, and also allows customization if needed.
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.
Wow. So this package is deprecated from the beginning? I think we're trying to do too many things with this fix. I like the previous API. From the example above it's not clear how ExecutorConfig is passed to the NewExecutor and it's increasing the num of parameters.
There would be further improvements needed:
- actually move the "shell" package under test/pkg/upgrade because that's the only place where it can be used according to the validator code
- remove "Streams" from the ExecutorConfig because it doesn't make sense anymore
Since this API is deprecated I don't see a point in improving it much. The goal is to fix the bug with logging.
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.
There is a saying in 🇵🇱 - "Makeshift is the most durable."
The original PR was done in Nov, 2020 as a temporary solution. And it still is.
However, there is a way out of this mess. The Productivity WG is currently pushing this epic: knative/hack#254. In the process, at some point, it may be feasible to rewrite these install shell functions into proper Go-native packages. Those packages can be used directly in upgrade testing, so this package could be removed permanently, as intended.
But it will take time to get there.
So I think it's worth taking some extra steps to make it less buggy. Maybe people will start new projects and run into the same problem. If we change the API to not allow that, that would prevent those potential bugs.
I like both of your suggestions: moving the package to knative.dev/pkg/test/upgrade/shell
and removing the Streams
from ExecutorConfig
.
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.
OK. I pushed the changes. I left Streams
within ExecutorConfig because it is the place where the stream configuration is held, it's later used by the executor.
test/shell/types.go
Outdated
// ExecutorConfig holds a executor configuration options. | ||
type ExecutorConfig struct { | ||
ProjectLocation | ||
Streams |
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.
Streams |
* use own interface TestingT
It is now a required argument for NewExecutor function
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
It look
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.
It looks great.
/lgtm
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.
It looks great.
/lgtm
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: cardil, mgencur 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 |
Thanks @mgencur! |
Changes
Example usage can be seen in knative/serving#14495 . This way the logs from shell scripts are printed within test scope.
/kind
Fixes knative/serving#14461
knative/serving#14495 for knative/serving is also required to fully fix it.
Release Note
Docs