Add unit tests for util/util.go - #995
Conversation
|
Hi @bromivipo. Thanks for your PR. I'm waiting for a GoogleCloudPlatform member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions 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. |
| } | ||
| if err == nil { | ||
| utiltest.AssertFileContents(t, tt.input, string(tt.content)) | ||
| } |
There was a problem hiding this comment.
can we use here
utiltest.AssertErrorMatch(t, err, tt.wantErr)
utiltest.AssertFileContents(t, tt.input, string(tt.content))
|
|
||
| if err == nil { | ||
| utiltest.AssertFileContents(t, tt.input, tt.content) | ||
| } |
There was a problem hiding this comment.
can we use here AssertErrorMatch, AssertEquals and AssertFileContents without conditions? these functions should handle empty input
There was a problem hiding this comment.
AssertErrorMatch could be used without conditions, but AssertFileContents fails if a file does not exist. So I moved error cases to separate tests.
There was a problem hiding this comment.
AssertErrorMatch can be customized to accept options than custom comparer can help you to archive the thing you want, you can create custom comparer to compare errors by return value of Error() only. Keep in mind that you might need to craft custom filter as well to ensure it does not use exact type, but compatibility with error interface.
| os.Exit(1) | ||
| } | ||
| fmt.Fprint(os.Stdout, "success msg") | ||
| os.Exit(0) |
There was a problem hiding this comment.
not sure if this test validates anything useful, probably we don't need it
There was a problem hiding this comment.
it does not validate anything itself. But it is used as a separate process to validate DefaultRunner.
There was a problem hiding this comment.
I agree with Ilia, there is no reason to keep the test that is not clear what it test to
|
New changes are detected. LGTM label has been removed. |
|
/gcbrun |
1 similar comment
|
/gcbrun |
| os.Exit(1) | ||
| } | ||
| fmt.Fprint(os.Stdout, "success msg") | ||
| os.Exit(0) |
There was a problem hiding this comment.
I agree with Ilia, there is no reason to keep the test that is not clear what it test to
| func TestAtomicWrite_Success(t *testing.T) { | ||
| tmpDir := t.TempDir() | ||
|
|
||
| tests := []struct { | ||
| name string | ||
| input string | ||
| content []byte | ||
| mode os.FileMode | ||
| }{ | ||
| { | ||
| name: "valid file path, expect success", | ||
| input: filepath.Join(tmpDir, "test-write-1.txt"), | ||
| content: []byte("test content"), | ||
| mode: 0644, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| err := AtomicWrite(tt.input, tt.content, tt.mode) | ||
| utiltest.AssertErrorMatch(t, err, nil) | ||
| utiltest.AssertFileContents(t, tt.input, string(tt.content)) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestAtomicWrite_Error(t *testing.T) { | ||
| tmpDir := t.TempDir() | ||
|
|
||
| tests := []struct { | ||
| name string | ||
| input string |
There was a problem hiding this comment.
Please refactor TestAtomicWrite to the single tests, there is no reason to have two table tests with only one case, testing the same function. It is complete against the purpose of the approach.
| } | ||
| } | ||
|
|
||
| func TestAtomicWriteFileStream_Error(t *testing.T) { |
There was a problem hiding this comment.
Same comment as below, please refactor tests to have one test and table testing should cover all success and failure cases
| os.Exit(0) | ||
| } | ||
|
|
||
| func TestDefaultRunnerRun(t *testing.T) { |
There was a problem hiding this comment.
What this test is actually testing?
There was a problem hiding this comment.
It verifies that DefaultRunner.Run captures stdout and stderr from the executed command and propagates execution errors. I've replaced the custom helper process with standard system commands to make it clearer.
Is there anything else you think this test should be checking?
| cmd: testSuccessCmd(), | ||
| wantStdout: "success msg", | ||
| wantStderr: "", | ||
| wantErr: "^<nil>$", |
There was a problem hiding this comment.
wantErr by convention should be an error rather then regexp, we should avoid doing regexp comparison for errors as much as possible.
|
|
||
| if err == nil { | ||
| utiltest.AssertFileContents(t, tt.input, tt.content) | ||
| } |
There was a problem hiding this comment.
AssertErrorMatch can be customized to accept options than custom comparer can help you to archive the thing you want, you can create custom comparer to compare errors by return value of Error() only. Keep in mind that you might need to craft custom filter as well to ensure it does not use exact type, but compatibility with error interface.
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: bromivipo, iliatsuprik The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
AssertErrorMatch now accepts custom cmp.Option parameters. Added Hopefully, I understood the intent correctly. |
| // EquateErrorMessagePrefix is a cmp.Option that compares errors by checking if either error string is a prefix of the other. | ||
| var EquateErrorMessagePrefix = cmp.FilterValues(filterErrors, cmp.Comparer(func(got, want any) bool { | ||
| gotErr, wantErr := got.(error).Error(), want.(error).Error() | ||
| return strings.HasPrefix(gotErr, wantErr) || strings.HasPrefix(wantErr, gotErr) |
There was a problem hiding this comment.
Both directions are checked to satisfy cmp.Diff's symmetry requirement.
| })) | ||
|
|
||
| // EquateErrorMessagePrefix is a cmp.Option that compares errors by checking if either error string is a prefix of the other. | ||
| var EquateErrorMessagePrefix = cmp.FilterValues(filterErrors, cmp.Comparer(func(got, want any) bool { |
There was a problem hiding this comment.
I suggest avoiding using Prefix matching for errors, that bring us a risk of hiding problems rather than showing the exact failure reason.
Could you explain why we cannot check exact error here ?
There was a problem hiding this comment.
AtomicWrite functions append a randomized integer suffix based on time.Now() to the tmp file path and the errors contain those paths in .Error(), so the error messages are not predetermined. I could not find a way to compare exact errors without using regexp or prefix matching, so I think it's better to remove those two cases to avoid breaking the testing guidelines. I don't think we'll lose much coverage here, as those test cases were essentially just checking error propagation from syscall failures. Additionally, I've added a positive edge case to both tests instead.
There was a problem hiding this comment.
I guess we need to refactor usage of AssertError.* to avoid duplicating check, just add required options where it is required.
There was a problem hiding this comment.
I've moved base assertion logic into an option which is now used by default when no other options are provided. Hope I understood your point correctly
| reader := strings.NewReader(tt.content) | ||
| gotChecksum, gotErr := AtomicWriteFileStream(reader, tt.checksum, tt.input, tt.mode) | ||
|
|
||
| utiltest.AssertErrorMatchAndSkip(t, gotErr, tt.wantErr, utiltest.EquateErrorMessagePrefix) |
There was a problem hiding this comment.
I guess that can be refactored to use exact error match, if not please explain why
|
/gcbrun |
|
/gcbrun |
|
/gcbrun |
This PR contains unit tests for util.go
Initial coverage: 3.3%, current coverage 78.7%