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
systemd: add AtLeast() method, add mocking in systemdtest #10748
Conversation
Codecov Report
@@ Coverage Diff @@
## master #10748 +/- ##
==========================================
- Coverage 78.36% 78.34% -0.02%
==========================================
Files 888 888
Lines 100091 100109 +18
==========================================
- Hits 78433 78432 -1
- Misses 16743 16762 +19
Partials 4915 4915
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
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.
Looks nice, thank you! A few remarks/suggestions to consider
} | ||
|
||
func quotaGroupsAvailable(st *state.State) error { | ||
// check if the systemd version is too old | ||
if systemdVersion < 230 { | ||
return fmt.Errorf("systemd version too old: snap quotas requires systemd 230 and newer (currently have %d)", systemdVersion) |
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.
I wonder if not showing the detected version could bite us (e.g. if we suddenly encounter a version string we don't parse properly).
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.
Good point. I restored it, though I had to refactor things a bit.
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 for the changes, I think they look good. Still a bit unsure about the placement of mocking per my other comment (but feel free to object ;)).
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.
Nope, I simply didn't get to it yet :-)
systemd/systemdtest/systemdtest.go
Outdated
@@ -59,3 +60,14 @@ Type=simple | |||
} | |||
return output | |||
} | |||
|
|||
func MockSystemdVersion(version int) (restore func()) { |
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.
I think we typically put such functions in the respective package (systemd in this case), and then systemd.Version doesn't have to be exported?
Also, I would make it possible to mock the function with complete return value (int, error), not just hardcode one that returns (version, nil).
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.
Done! :-)
systemd/systemd.go
Outdated
// false. | ||
func AtLeast(requiredVersion int) bool { | ||
version, err := Version() | ||
return err == nil && version >= requiredVersion |
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.
I think we should log the error somewhere like we did before this change, otherwise we won't know if something went wrong.
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.
I reowrked this a little, please have another look.
systemd/systemd.go
Outdated
return err | ||
} | ||
if version < requiredVersion { | ||
return fmt.Errorf(`installed version %d is too old`, version) |
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.
Should this be a separate error type? eg.
type systemdTooOldError struct {
expected int
got int
}
func (e *systemdTooOldError) Error() string {
return fmt.Sprintf("systemd version %d is too old (expected at least %d)", e.got, e.expected)
}
Then here:
return &systemdTooOld{got: version, expected: requiredVersion}
then in quotas code you can just return:
return fmt.Errorf("cannot use quotas with incompatible systemd: %v", err)
which would produce eg. cannot use quotas with incompatible systemd: systemd version 123 is too old (expected 345)
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.
Nice suggestion, done!
ec3849c
to
8a62deb
Compare
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.
Looks fine, a suggestion about a test inline but with that I think this is a 👍
@@ -118,6 +121,17 @@ var systemctlCmd = func(args ...string) ([]byte, error) { | |||
return bs, nil | |||
} | |||
|
|||
func MockSystemdVersion(version int, injectedError error) (restore func()) { |
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 injectedError is not used yet AFAICT but AIUI this will be used in a followup PR(?). Maybe a trivial test that ithe mocking works as expected? in systemd_test.go or something?
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.
No, I don't have a plan to use it, but I might :-) It was actually Pavel who suggested to add the error, and I think it can help to test some corner cases.
I've now added a unit test for it, so it won't appear to be unused anymore :-)
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
func MockSystemdVersion(version int, injectedError error) (restore func()) { | ||
osutil.MustBeTestBinary("cannot mock systemd version outside of tests") | ||
old := Version | ||
Version = func() (int, error) { | ||
return version, injectedError | ||
} | ||
return func() { | ||
Version = old | ||
} |
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.
I had the usual MockSystemdVersion(f func() (int, err)) (restore ....
in mind, but that's fine too and maybe even more handy.
func EnsureAtLeast(requiredVersion int) error { | ||
version, err := Version() | ||
if err != nil { | ||
return err | ||
} | ||
if version < requiredVersion { | ||
return &systemdTooOldError{got: version, expected: requiredVersion} | ||
} | ||
return nil | ||
} |
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 should probably have a simple test now in systemd_test.go.
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.
Added!
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, thank you!
973ab87
to
2a1c3c1
Compare
Allow the systemd.Version() method to be mocked, and add a new AtLeast() method, as per the TODO.