1
0
mirror of https://github.com/taigrr/go-selfupdate synced 2025-01-18 04:33:12 -08:00

Update to go mod and parameterize check time and randomize time

This commit is contained in:
Kyle Williams
2020-12-08 20:38:04 -07:00
parent f041b81ae5
commit f247155ad6
29 changed files with 101 additions and 1823 deletions

View File

@@ -83,6 +83,8 @@ type Updater struct {
DiffURL string // Base URL for diff downloads.
Dir string // Directory to store selfupdate state.
ForceCheck bool // Check for update regardless of cktime timestamp
CheckTime int // Time in hours before next check
RandomizeTime int // Time in hours to randomize with CheckTime
Requester Requester //Optional parameter to override existing http request handler
Info struct {
Version string
@@ -102,34 +104,62 @@ func (u *Updater) BackgroundRun() error {
// fail
return err
}
if u.wantUpdate() {
if u.WantUpdate() {
if err := up.CanUpdate(); err != nil {
// fail
return err
}
u.SetUpdateTime()
//self, err := osext.Executable()
//if err != nil {
// fail update, couldn't figure out path to self
//return
//}
// TODO(bgentry): logger isn't on Windows. Replace w/ proper error reports.
if err := u.update(); err != nil {
if err := u.Update(); err != nil {
return err
}
}
return nil
}
func (u *Updater) wantUpdate() bool {
path := u.getExecRelativeDir(u.Dir + upcktimePath)
if u.CurrentVersion == "dev" || (!u.ForceCheck && readTime(path).After(time.Now())) {
// WantUpdate returns boolean designating if an update is desired
func (u *Updater) WantUpdate() bool {
if u.CurrentVersion == "dev" || (!u.ForceCheck && u.NextUpdate().After(time.Now())) {
return false
}
wait := 24*time.Hour + randDuration(24*time.Hour)
return writeTime(path, time.Now().Add(wait))
return true
}
func (u *Updater) update() error {
// NextUpdate returns the next time update should be checked
func (u *Updater) NextUpdate() time.Time {
path := u.getExecRelativeDir(u.Dir + upcktimePath)
nextTime := readTime(path)
return nextTime
}
// SetUpdateTime writes the next update time to the state file
func (u *Updater) SetUpdateTime() bool {
path := u.getExecRelativeDir(u.Dir + upcktimePath)
wait := time.Duration(u.CheckTime) * time.Hour
// Add 1 to random time since max is not included
waitrand := time.Duration(rand.Intn(u.RandomizeTime+1)) * time.Hour
return writeTime(path, time.Now().Add(wait+waitrand))
}
// ClearUpdateState writes current time to state file
func (u *Updater) ClearUpdateState() {
path := u.getExecRelativeDir(u.Dir + upcktimePath)
os.Remove(path)
}
// Update initiates the self update process
func (u *Updater) Update() error {
path, err := osext.Executable()
if err != nil {
return err
@@ -250,11 +280,6 @@ func (u *Updater) fetchBin() ([]byte, error) {
return buf.Bytes(), nil
}
// returns a random duration in [0,n).
func randDuration(n time.Duration) time.Duration {
return time.Duration(rand.Int63n(int64(n)))
}
func (u *Updater) fetch(url string) (io.ReadCloser, error) {
if u.Requester == nil {
return defaultHTTPRequester.Fetch(url)

View File

@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"testing"
"time"
)
var testHash = sha256.New()
@@ -17,7 +18,11 @@ func TestUpdaterFetchMustReturnNonNilReaderCloser(t *testing.T) {
return nil, nil
})
updater := createUpdater(mr)
updater.CheckTime = 24
updater.RandomizeTime = 24
err := updater.BackgroundRun()
if err != nil {
equals(t, "Fetch was expected to return non-nil ReadCloser", err.Error())
} else {
@@ -34,6 +39,8 @@ func TestUpdaterWithEmptyPayloadNoErrorNoUpdate(t *testing.T) {
return newTestReaderCloser("{}"), nil
})
updater := createUpdater(mr)
updater.CheckTime = 24
updater.RandomizeTime = 24
err := updater.BackgroundRun()
if err != nil {
@@ -41,6 +48,46 @@ func TestUpdaterWithEmptyPayloadNoErrorNoUpdate(t *testing.T) {
}
}
func TestUpdaterCheckTime(t *testing.T) {
mr := &mockRequester{}
mr.handleRequest(
func(url string) (io.ReadCloser, error) {
equals(t, "http://updates.yourdomain.com/myapp/darwin-amd64.json", url)
return newTestReaderCloser("{}"), nil
})
// Run test with various time
runTestTimeChecks(t, mr, 0, 0, false)
runTestTimeChecks(t, mr, 0, 5, true)
runTestTimeChecks(t, mr, 1, 0, true)
runTestTimeChecks(t, mr, 100, 100, true)
}
// Helper function to run check time tests
func runTestTimeChecks(t *testing.T, mr *mockRequester, checkTime int, randomizeTime int, expectUpdate bool) {
updater := createUpdater(mr)
updater.ClearUpdateState()
updater.CheckTime = checkTime
updater.RandomizeTime = randomizeTime
updater.BackgroundRun()
if updater.WantUpdate() == expectUpdate {
t.Errorf("WantUpdate returned %v; want %v", updater.WantUpdate(), expectUpdate)
}
maxHrs := time.Duration(updater.CheckTime+updater.RandomizeTime) * time.Hour
maxTime := time.Now().Add(maxHrs)
if !updater.NextUpdate().Before(maxTime) {
t.Errorf("NextUpdate should less than %s hrs (CheckTime + RandomizeTime) from now; now %s; next update %s", maxHrs, time.Now(), updater.NextUpdate())
}
if maxHrs > 0 && !updater.NextUpdate().After(time.Now()) {
t.Errorf("NextUpdate should be after now")
}
}
func TestUpdaterWithEmptyPayloadNoErrorNoUpdateEscapedPath(t *testing.T) {
mr := &mockRequester{}
mr.handleRequest(

1
selfupdate/update/cktime Normal file
View File

@@ -0,0 +1 @@
2020-12-08T21:11:49-07:00