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

[e2e] Dump the stacktrace while an error occurs #80979

Merged
merged 1 commit into from
Aug 22, 2019

Conversation

jiatongw
Copy link

@jiatongw jiatongw commented Aug 5, 2019

What type of PR is this?

/kind cleanup

What this PR does / why we need it:

It's difficult to navigate when the error is generic, so dumping the stacktrace is worthwhile.
Reference: #34059

Does this PR introduce a user-facing change?:

NONE

@k8s-ci-robot k8s-ci-robot added release-note-none Denotes a PR that doesn't merit a release note. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. needs-priority Indicates a PR lacks a `priority/foo` label and requires one. labels Aug 5, 2019
@jiatongw
Copy link
Author

jiatongw commented Aug 5, 2019

/assign @timothysc @alejandrox1

@jiatongw
Copy link
Author

jiatongw commented Aug 5, 2019

/area e2e-test-framework
/area test
/sig testing

@k8s-ci-robot k8s-ci-robot added area/e2e-test-framework Issues or PRs related to refactoring the kubernetes e2e test framework area/test sig/testing Categorizes an issue or PR as relevant to SIG Testing. and removed needs-sig Indicates an issue or PR lacks a `sig/foo` label and requires one. labels Aug 5, 2019
@@ -1327,6 +1328,8 @@ func ExpectNoError(err error, explain ...interface{}) {
func ExpectNoErrorWithOffset(offset int, err error, explain ...interface{}) {
if err != nil {
e2elog.Logf("Unexpected error occurred: %v", err)
// Dump the stacktrace while an error occurs
debug.PrintStack()
}
Copy link
Author

Choose a reason for hiding this comment

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

Although panic could print the stacktrace but it will exit the program. So using debug.PrintStack() instead.

@jiatongw
Copy link
Author

jiatongw commented Aug 5, 2019

/retest

@timothysc timothysc added the priority/important-longterm Important over the long term, but may not be staffed and/or may need multiple releases to complete. label Aug 5, 2019
@k8s-ci-robot k8s-ci-robot removed the needs-priority Indicates a PR lacks a `priority/foo` label and requires one. label Aug 5, 2019
@timothysc timothysc added this to the v1.16 milestone Aug 5, 2019
Copy link
Member

@timothysc timothysc 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 it!
This will be helpful on errors.
/cc @johnSchnake
/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Aug 5, 2019
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: jiatongw, timothysc

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 /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 5, 2019
@@ -1340,6 +1343,8 @@ func ExpectNoErrorWithRetries(fn func() error, maxRetries int, explain ...interf
return
}
e2elog.Logf("(Attempt %d of %d) Unexpected error occurred: %v", i+1, maxRetries, err)
// Dump the stacktrace while an error occurs
debug.PrintStack()
Copy link
Contributor

Choose a reason for hiding this comment

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

If we're doing retries it seems like we expect errors and wouldn't want/need the stacktrace.

Can we move this down so that we only dump the trace here if we run out of retries and are actually bubbling up the error?

Copy link
Author

@jiatongw jiatongw Aug 5, 2019

Choose a reason for hiding this comment

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

My thought is that it may have different reasons to cause the retry fail each time. So for each retry I chose to print the stack.

Copy link
Author

Choose a reason for hiding this comment

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

any comments?

Copy link
Contributor

Choose a reason for hiding this comment

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

Although that can happen; it has never been the case in my experience. Usually the same error happens 5 times so only the last one matters. OR you get an "error" which was somewhat expected (like polling for a service to come up) so you see 4 errors (and now 4 entire stack traces) even though the test goes onto pass.

My preference would still be for just the trace at the end, but I don't feel that strongly if you prefer this.

Copy link
Author

Choose a reason for hiding this comment

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

This make more sense. I will move the printstack() out of the loop

Copy link
Contributor

Choose a reason for hiding this comment

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

Let me know when you've made the changes and I'll re-review and remove the hold

Copy link
Author

Choose a reason for hiding this comment

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

Ready to re-review

@@ -1327,6 +1328,8 @@ func ExpectNoError(err error, explain ...interface{}) {
func ExpectNoErrorWithOffset(offset int, err error, explain ...interface{}) {
if err != nil {
e2elog.Logf("Unexpected error occurred: %v", err)
// Dump the stacktrace while an error occurs
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I don't think the comments add any helpful information in either place. I'd just remove them.

Copy link
Author

Choose a reason for hiding this comment

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

Deleted the comment

@timothysc
Copy link
Member

/hold

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Aug 5, 2019
@timothysc timothysc removed lgtm "Looks good to me", indicates that a PR is ready to be merged. do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. labels Aug 5, 2019
@jiatongw
Copy link
Author

jiatongw commented Aug 5, 2019

/retest

Copy link
Member

@neolit123 neolit123 left a comment

Choose a reason for hiding this comment

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

i think that the PrintStack will be useful for all of our Expect wrappers - i.e. not only these two.

@@ -1342,6 +1344,7 @@ func ExpectNoErrorWithRetries(fn func() error, maxRetries int, explain ...interf
}
e2elog.Logf("(Attempt %d of %d) Unexpected error occurred: %v", i+1, maxRetries, err)
}
debug.PrintStack()
Copy link
Member

Choose a reason for hiding this comment

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

should this PrintStack call should only happen if err != nil ?

Copy link
Author

@jiatongw jiatongw Aug 7, 2019

Choose a reason for hiding this comment

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

@neolit123 For wrappers like ExpectEqual and ExpectNotEqual, we need to put the PrintStack into a condition statement to avoid it dump the stacktrace every time the wrappers be called. But gomega.Expect() has no return value. I don't have any better insights to do some change in the wrappers. But there is a potential way, similar like this: For those tests that call ExpectEqual/ExpectNotEqual, have a try..catch thing. If exception happens, then call PrintStack(). But Go doesn't have this kind of mechanism so this may involve a lot of changes. Or do you have any insights ?

Copy link
Author

Choose a reason for hiding this comment

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

Capture the stdout/stderr after ExpectEqual/ExpectNotEqual is also a potential solution. Need to implement a wrappers for the capture behavior.

Copy link
Member

Choose a reason for hiding this comment

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

sorry my comment here was about this.

should this PrintStack call should only happen if err != nil ?

if err != nil {
  debug.PrintStack()
}

otherwise we are printing a stack trace even if there is no error in the retires.

Copy link
Author

Choose a reason for hiding this comment

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

ready to re-review

@neolit123
Copy link
Member

i think that the PrintStack will be useful for all of our Expect wrappers - i.e. not only these two.

@neolit123 For wrappers like ExpectEqual and ExpectNotEqual, we need to put the PrintStack into a condition statement to avoid it dump the stacktrace every time the wrappers be called

that's what i meant.
we already perform a similar check in the Expect* functions that this PR changes.

if we add similar checks it should work e.g.

// ExpectError expects an error happens, otherwise an exception raises
func ExpectError(err error, explain ...interface{}) {
    if err == nil {
       // PrintStack
    }
    gomega.Expect(err).To(gomega.HaveOccurred(), explain...)
}

these need reflection on the interfaces to see if they are of the same type and equal.

// ExpectEqual expects the specified two are the same, otherwise an exception raises
func ExpectEqual(actual interface{}, extra interface{}, explain ...interface{}) {
	gomega.Expect(actual).To(gomega.Equal(extra), explain...)
}

@jiatongw
Copy link
Author

jiatongw commented Aug 7, 2019

these need reflection on the interfaces to see if they are of the same type and equal.

// ExpectEqual expects the specified two are the same, otherwise an exception raises
func ExpectEqual(actual interface{}, extra interface{}, explain ...interface{}) {
	gomega.Expect(actual).To(gomega.Equal(extra), explain...)
}

That's a better solution. Thanks

@k8s-ci-robot k8s-ci-robot added size/S Denotes a PR that changes 10-29 lines, ignoring generated files. and removed size/XS Denotes a PR that changes 0-9 lines, ignoring generated files. labels Aug 9, 2019
Copy link
Member

@neolit123 neolit123 left a comment

Choose a reason for hiding this comment

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

thanks for the update @jiatongw
/lgtm
but i'd prefer if someone else has a look too.
/assign @johnSchnake
/hold

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Aug 9, 2019
@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Aug 9, 2019
@jiatongw
Copy link
Author

jiatongw commented Aug 9, 2019

/retest

if reflect.TypeOf(actual) != reflect.TypeOf(extra) {
e2elog.Logf("Unexpected unequal occurred: %v and %v", actual, extra)
debug.PrintStack()
} else if reflect.ValueOf(actual) != reflect.ValueOf(extra) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not the type of comparison you want. From the godocs:

To compare two Values, compare the results of the Interface method. Using == on two Values does not compare the underlying values they represent.

I wouldn't even use the Interface since it gets confusing to anyone about when/how they can use certain reflect methods.

It seems like in these two cases we should be using the actual match that ginkgo will do, just leverage those without the Expect:

if isEqual, _ := gomega.Equal(extra).Match(actual); isEqual{
...
}

Double-check me on that syntax but I think thats the way it would be written.

Copy link
Author

Choose a reason for hiding this comment

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

Hi @johnSchnake , based on the doc https://onsi.github.io/gomega/#provided-matchers, I can't find a use like gomega.Equal(extra).Match(actual) but I think I can use reflect.DeepEqual to compare ACTUAL with EXPECTED, which is the gomega.Equal implementation.

Copy link
Contributor

Choose a reason for hiding this comment

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

They are all exported types/interfaces so we should just leverage what they've already written. For instance, they dont just do reflect.DeepEqual but have an optimization in place. I don't want to have to maintain a separate method which could drift and doesn't have any justification/benefit over using theirs.

//For details on writing custom matchers, check out: http://onsi.github.io/gomega/#adding-your-own-matchers
type GomegaMatcher interface {
    Match(actual interface{}) (success bool, err error)
    FailureMessage(actual interface{}) (message string)
...

Equal matcher implementation:
https://github.com/kubernetes/kubernetes/blob/master/vendor/github.com/onsi/gomega/matchers/equal_matcher.go#L15-L28

Copy link
Author

Choose a reason for hiding this comment

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

@johnSchnake could you re-review? Thanks!

@oomichi
Copy link
Member

oomichi commented Aug 17, 2019

/cc @oomichi

Signed-off-by: Jiatong Wang <wangjiatong@vmware.com>
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Aug 21, 2019
@johnSchnake
Copy link
Contributor

/lgtm
/hold cancel

@k8s-ci-robot k8s-ci-robot added lgtm "Looks good to me", indicates that a PR is ready to be merged. and removed do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. labels Aug 21, 2019
@k8s-ci-robot k8s-ci-robot merged commit 68d6ec9 into kubernetes:master Aug 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. area/e2e-test-framework Issues or PRs related to refactoring the kubernetes e2e test framework area/test cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. lgtm "Looks good to me", indicates that a PR is ready to be merged. priority/important-longterm Important over the long term, but may not be staffed and/or may need multiple releases to complete. release-note-none Denotes a PR that doesn't merit a release note. sig/testing Categorizes an issue or PR as relevant to SIG Testing. size/S Denotes a PR that changes 10-29 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants