mirror of
https://github.com/rclone/rclone.git
synced 2024-11-23 00:43:49 +01:00
5d6b8141ec
As of Go 1.16, the same functionality is now provided by package io or package os, and those implementations should be preferred in new code.
202 lines
5.4 KiB
Go
202 lines
5.4 KiB
Go
//go:build !noselfupdate
|
|
// +build !noselfupdate
|
|
|
|
package selfupdate
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/rclone/rclone/fs"
|
|
"github.com/rclone/rclone/fstest/testy"
|
|
"github.com/rclone/rclone/lib/file"
|
|
"github.com/rclone/rclone/lib/random"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestGetVersion(t *testing.T) {
|
|
testy.SkipUnreliable(t)
|
|
|
|
ctx := context.Background()
|
|
|
|
// a beta version can only have "v" prepended
|
|
resultVer, _, err := GetVersion(ctx, true, "1.2.3.4")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "v1.2.3.4", resultVer)
|
|
|
|
// but a stable version syntax should be checked
|
|
_, _, err = GetVersion(ctx, false, "1")
|
|
assert.Error(t, err)
|
|
_, _, err = GetVersion(ctx, false, "1.")
|
|
assert.Error(t, err)
|
|
_, _, err = GetVersion(ctx, false, "1.2.")
|
|
assert.Error(t, err)
|
|
_, _, err = GetVersion(ctx, false, "1.2.3.4")
|
|
assert.Error(t, err)
|
|
|
|
// incomplete stable version should have micro release added
|
|
resultVer, _, err = GetVersion(ctx, false, "1.52")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "v1.52.3", resultVer)
|
|
}
|
|
|
|
func makeTestDir() (testDir string, err error) {
|
|
const maxAttempts = 5
|
|
testDirBase := filepath.Join(os.TempDir(), "rclone-test-selfupdate.")
|
|
|
|
for attempt := 0; attempt < maxAttempts; attempt++ {
|
|
testDir = testDirBase + random.String(4)
|
|
err = file.MkdirAll(testDir, os.ModePerm)
|
|
if err == nil {
|
|
break
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func TestInstallOnLinux(t *testing.T) {
|
|
testy.SkipUnreliable(t)
|
|
if runtime.GOOS != "linux" {
|
|
t.Skip("this is a Linux only test")
|
|
}
|
|
|
|
// Prepare for test
|
|
ctx := context.Background()
|
|
testDir, err := makeTestDir()
|
|
assert.NoError(t, err)
|
|
path := filepath.Join(testDir, "rclone")
|
|
defer func() {
|
|
_ = os.Chmod(path, 0644)
|
|
_ = os.RemoveAll(testDir)
|
|
}()
|
|
|
|
regexVer := regexp.MustCompile(`v[0-9]\S+`)
|
|
|
|
betaVer, _, err := GetVersion(ctx, true, "")
|
|
assert.NoError(t, err)
|
|
|
|
// Must do nothing if version isn't changing
|
|
assert.NoError(t, InstallUpdate(ctx, &Options{Beta: true, Output: path, Version: fs.Version}))
|
|
|
|
// Must fail on non-writable file
|
|
assert.NoError(t, os.WriteFile(path, []byte("test"), 0644))
|
|
assert.NoError(t, os.Chmod(path, 0000))
|
|
err = (InstallUpdate(ctx, &Options{Beta: true, Output: path}))
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "run self-update as root")
|
|
|
|
// Must keep non-standard permissions
|
|
assert.NoError(t, os.Chmod(path, 0644))
|
|
assert.NoError(t, InstallUpdate(ctx, &Options{Beta: true, Output: path}))
|
|
|
|
info, err := os.Stat(path)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, os.FileMode(0644), info.Mode().Perm())
|
|
|
|
// Must remove temporary files
|
|
files, err := os.ReadDir(testDir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, len(files))
|
|
|
|
// Must contain valid executable
|
|
assert.NoError(t, os.Chmod(path, 0755))
|
|
cmd := exec.Command(path, "version")
|
|
output, err := cmd.CombinedOutput()
|
|
assert.NoError(t, err)
|
|
assert.True(t, cmd.ProcessState.Success())
|
|
assert.Equal(t, betaVer, regexVer.FindString(string(output)))
|
|
}
|
|
|
|
func TestRenameOnWindows(t *testing.T) {
|
|
testy.SkipUnreliable(t)
|
|
if runtime.GOOS != "windows" {
|
|
t.Skip("this is a Windows only test")
|
|
}
|
|
|
|
// Prepare for test
|
|
ctx := context.Background()
|
|
|
|
testDir, err := makeTestDir()
|
|
assert.NoError(t, err)
|
|
defer func() {
|
|
_ = os.RemoveAll(testDir)
|
|
}()
|
|
|
|
path := filepath.Join(testDir, "rclone.exe")
|
|
regexVer := regexp.MustCompile(`v[0-9]\S+`)
|
|
|
|
stableVer, _, err := GetVersion(ctx, false, "")
|
|
assert.NoError(t, err)
|
|
|
|
betaVer, _, err := GetVersion(ctx, true, "")
|
|
assert.NoError(t, err)
|
|
|
|
// Must not create temporary files when target doesn't exist
|
|
assert.NoError(t, InstallUpdate(ctx, &Options{Beta: true, Output: path}))
|
|
|
|
files, err := os.ReadDir(testDir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, len(files))
|
|
|
|
// Must save running executable as the "old" file
|
|
cmdWait := exec.Command(path, "config")
|
|
stdinWait, err := cmdWait.StdinPipe() // Make it run waiting for input
|
|
assert.NoError(t, err)
|
|
assert.NoError(t, cmdWait.Start())
|
|
|
|
assert.NoError(t, InstallUpdate(ctx, &Options{Beta: false, Output: path}))
|
|
files, err = os.ReadDir(testDir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, len(files))
|
|
|
|
pathOld := filepath.Join(testDir, "rclone.old.exe")
|
|
_, err = os.Stat(pathOld)
|
|
assert.NoError(t, err)
|
|
|
|
cmd := exec.Command(path, "version")
|
|
output, err := cmd.CombinedOutput()
|
|
assert.NoError(t, err)
|
|
assert.True(t, cmd.ProcessState.Success())
|
|
assert.Equal(t, stableVer, regexVer.FindString(string(output)))
|
|
|
|
cmdOld := exec.Command(pathOld, "version")
|
|
output, err = cmdOld.CombinedOutput()
|
|
assert.NoError(t, err)
|
|
assert.True(t, cmdOld.ProcessState.Success())
|
|
assert.Equal(t, betaVer, regexVer.FindString(string(output)))
|
|
|
|
// Stop previous waiting executable, run new and saved executables
|
|
_ = stdinWait.Close()
|
|
_ = cmdWait.Wait()
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
cmdWait = exec.Command(path, "config")
|
|
stdinWait, err = cmdWait.StdinPipe()
|
|
assert.NoError(t, err)
|
|
assert.NoError(t, cmdWait.Start())
|
|
|
|
cmdWaitOld := exec.Command(pathOld, "config")
|
|
stdinWaitOld, err := cmdWaitOld.StdinPipe()
|
|
assert.NoError(t, err)
|
|
assert.NoError(t, cmdWaitOld.Start())
|
|
|
|
// Updating when the "old" executable is running must produce a random "old" file
|
|
assert.NoError(t, InstallUpdate(ctx, &Options{Beta: true, Output: path}))
|
|
files, err = os.ReadDir(testDir)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 3, len(files))
|
|
|
|
// Stop all waiting executables
|
|
_ = stdinWait.Close()
|
|
_ = cmdWait.Wait()
|
|
_ = stdinWaitOld.Close()
|
|
_ = cmdWaitOld.Wait()
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|