Skip to content

Add unit tests for util/util.go - #995

Open
bromivipo wants to merge 17 commits into
GoogleCloudPlatform:masterfrom
bromivipo:util
Open

Add unit tests for util/util.go#995
bromivipo wants to merge 17 commits into
GoogleCloudPlatform:masterfrom
bromivipo:util

Conversation

@bromivipo

@bromivipo bromivipo commented May 26, 2026

Copy link
Copy Markdown
Contributor

This PR contains unit tests for util.go
Initial coverage: 3.3%, current coverage 78.7%

@google-oss-prow

Copy link
Copy Markdown

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 /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

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.

@bromivipo
bromivipo marked this pull request as ready for review May 27, 2026 11:29
@google-oss-prow
google-oss-prow Bot requested a review from savija-tv May 27, 2026 11:29
Comment thread util/util_test.go Outdated
}
if err == nil {
utiltest.AssertFileContents(t, tt.input, string(tt.content))
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can we use here

utiltest.AssertErrorMatch(t, err, tt.wantErr)
utiltest.AssertFileContents(t, tt.input, string(tt.content))

Comment thread util/util_test.go Outdated

if err == nil {
utiltest.AssertFileContents(t, tt.input, tt.content)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can we use here AssertErrorMatch, AssertEquals and AssertFileContents without conditions? these functions should handle empty input

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

AssertErrorMatch could be used without conditions, but AssertFileContents fails if a file does not exist. So I moved error cases to separate tests.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Comment thread util/util_test.go Outdated
os.Exit(1)
}
fmt.Fprint(os.Stdout, "success msg")
os.Exit(0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not sure if this test validates anything useful, probably we don't need it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

it does not validate anything itself. But it is used as a separate process to validate DefaultRunner.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I agree with Ilia, there is no reason to keep the test that is not clear what it test to

@google-oss-prow

Copy link
Copy Markdown

New changes are detected. LGTM label has been removed.

@burov

burov commented Jul 2, 2026

Copy link
Copy Markdown
Member

/gcbrun

1 similar comment
@burov

burov commented Jul 2, 2026

Copy link
Copy Markdown
Member

/gcbrun

@burov burov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see there differen

Comment thread util/util_test.go Outdated
os.Exit(1)
}
fmt.Fprint(os.Stdout, "success msg")
os.Exit(0)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I agree with Ilia, there is no reason to keep the test that is not clear what it test to

Comment thread util/util_test.go Outdated
Comment on lines +227 to +258
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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Comment thread util/util_test.go Outdated
}
}

func TestAtomicWriteFileStream_Error(t *testing.T) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same comment as below, please refactor tests to have one test and table testing should cover all success and failure cases

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

Comment thread util/util_test.go
os.Exit(0)
}

func TestDefaultRunnerRun(t *testing.T) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What this test is actually testing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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?

Comment thread util/util_test.go Outdated
cmd: testSuccessCmd(),
wantStdout: "success msg",
wantStderr: "",
wantErr: "^<nil>$",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

wantErr by convention should be an error rather then regexp, we should avoid doing regexp comparison for errors as much as possible.

Comment thread util/util_test.go Outdated

if err == nil {
utiltest.AssertFileContents(t, tt.input, tt.content)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

@google-oss-prow

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: bromivipo, iliatsuprik
Once this PR has been reviewed and has the lgtm label, please ask for approval from burov. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details 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

@bromivipo
bromivipo requested a review from burov July 15, 2026 16:21
@bromivipo

Copy link
Copy Markdown
Contributor Author

AssertErrorMatch now accepts custom cmp.Option parameters. Added utiltest.EquateErrorMessage for exact string equality and utiltest.EquateErrorMessagePrefix for matching errors with dynamic suffixes (such as temporary filenames or path errors), so we no longer use regexps for this.

Hopefully, I understood the intent correctly.

Comment thread util/utiltest/utiltest.go Outdated
// 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)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Both directions are checked to satisfy cmp.Diff's symmetry requirement.

Comment thread util/utiltest/utiltest.go Outdated
}))

// 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 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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 ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sure

Comment thread util/utiltest/utiltest.go Outdated
Comment on lines 164 to 176

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess we need to refactor usage of AssertError.* to avoid duplicating check, just add required options where it is required.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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

Comment thread util/util_test.go Outdated
reader := strings.NewReader(tt.content)
gotChecksum, gotErr := AtomicWriteFileStream(reader, tt.checksum, tt.input, tt.mode)

utiltest.AssertErrorMatchAndSkip(t, gotErr, tt.wantErr, utiltest.EquateErrorMessagePrefix)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess that can be refactored to use exact error match, if not please explain why

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

replied above

@bromivipo
bromivipo requested a review from burov July 21, 2026 11:29
@burov

burov commented Jul 21, 2026

Copy link
Copy Markdown
Member

/gcbrun

@burov

burov commented Aug 11, 2026

Copy link
Copy Markdown
Member

/gcbrun

@burov

burov commented Aug 19, 2026

Copy link
Copy Markdown
Member

/gcbrun

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants