2017-12-29 16:37:09 +00:00
|
|
|
package selfupdate
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/blang/semver"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
2017-12-30 04:41:34 +00:00
|
|
|
"runtime"
|
2017-12-29 16:37:09 +00:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
func setupTestBinary() {
|
|
|
|
if err := exec.Command("go", "build", "./testdata/github-release-test/").Run(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func teardownTestBinary() {
|
2017-12-30 04:41:34 +00:00
|
|
|
bin := "github-release-test"
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
bin = "github-release-test.exe"
|
|
|
|
}
|
|
|
|
if err := os.Remove(bin); err != nil {
|
2017-12-29 16:37:09 +00:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdateCommand(t *testing.T) {
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("skip tests in short mode.")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, slug := range []string{
|
|
|
|
"rhysd-test/test-release-zip",
|
|
|
|
"rhysd-test/test-release-tar",
|
|
|
|
"rhysd-test/test-release-gzip",
|
2017-12-31 04:35:22 +00:00
|
|
|
"rhysd-test/test-release-tar-xz",
|
|
|
|
"rhysd-test/test-release-xz",
|
2018-01-03 10:06:33 +00:00
|
|
|
"rhysd-test/test-release-contain-version",
|
2017-12-29 16:37:09 +00:00
|
|
|
} {
|
|
|
|
t.Run(slug, func(t *testing.T) {
|
|
|
|
setupTestBinary()
|
|
|
|
defer teardownTestBinary()
|
|
|
|
latest := semver.MustParse("1.2.3")
|
|
|
|
prev := semver.MustParse("1.2.2")
|
|
|
|
rel, err := UpdateCommand("github-release-test", prev, slug)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if rel.Version.NE(latest) {
|
|
|
|
t.Error("Version is not latest", rel.Version)
|
|
|
|
}
|
|
|
|
bytes, err := exec.Command(filepath.FromSlash("./github-release-test")).Output()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal("Failed to run test binary after update:", err)
|
|
|
|
}
|
|
|
|
out := string(bytes)
|
|
|
|
if out != "v1.2.3\n" {
|
|
|
|
t.Error("Output from test binary after update is unexpected:", out)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-03 14:01:33 +00:00
|
|
|
func TestUpdateViaSymlink(t *testing.T) {
|
2018-01-03 14:13:23 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("skip tests in short mode.")
|
|
|
|
}
|
2018-01-03 14:16:28 +00:00
|
|
|
if runtime.GOOS == "windows" && os.Getenv("APPVEYOR") == "" {
|
2018-01-03 14:13:23 +00:00
|
|
|
t.Skip("skipping because creating symlink on windows requires the root privilege")
|
|
|
|
}
|
|
|
|
|
2018-01-03 14:01:33 +00:00
|
|
|
setupTestBinary()
|
|
|
|
defer teardownTestBinary()
|
2018-01-03 14:16:28 +00:00
|
|
|
exePath := "github-release-test"
|
|
|
|
symPath := "github-release-test-sym"
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
exePath = "github-release-test.exe"
|
|
|
|
symPath = "github-release-test-sym.exe"
|
|
|
|
}
|
|
|
|
if err := os.Symlink(exePath, symPath); err != nil {
|
2018-01-03 14:01:33 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-01-03 14:16:28 +00:00
|
|
|
defer os.Remove(symPath)
|
2018-01-03 14:01:33 +00:00
|
|
|
|
|
|
|
latest := semver.MustParse("1.2.3")
|
|
|
|
prev := semver.MustParse("1.2.2")
|
2018-01-03 14:16:28 +00:00
|
|
|
rel, err := UpdateCommand(symPath, prev, "rhysd-test/test-release-zip")
|
2018-01-03 14:01:33 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if rel.Version.NE(latest) {
|
|
|
|
t.Error("Version is not latest", rel.Version)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test not symbolic link, but actual physical executable
|
|
|
|
bytes, err := exec.Command(filepath.FromSlash("./github-release-test")).Output()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal("Failed to run test binary after update:", err)
|
|
|
|
}
|
|
|
|
out := string(bytes)
|
|
|
|
if out != "v1.2.3\n" {
|
|
|
|
t.Error("Output from test binary after update is unexpected:", out)
|
|
|
|
}
|
|
|
|
|
2018-01-03 14:16:28 +00:00
|
|
|
s, err := os.Lstat(symPath)
|
2018-01-03 14:01:33 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if s.Mode()&os.ModeSymlink == 0 {
|
2018-01-03 14:16:28 +00:00
|
|
|
t.Fatalf("%s is not a symlink.", symPath)
|
2018-01-03 14:01:33 +00:00
|
|
|
}
|
2018-01-03 14:16:28 +00:00
|
|
|
p, err := filepath.EvalSymlinks(symPath)
|
2018-01-03 14:01:33 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-01-03 14:16:28 +00:00
|
|
|
if p != exePath {
|
2018-01-03 14:01:33 +00:00
|
|
|
t.Fatalf("Created symlink no loger points the executable")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdateBrokenSymlinks(t *testing.T) {
|
2018-01-03 14:16:28 +00:00
|
|
|
if runtime.GOOS == "windows" && os.Getenv("APPVEYOR") == "" {
|
2018-01-03 14:13:23 +00:00
|
|
|
t.Skip("skipping because creating symlink on windows requires the root privilege")
|
|
|
|
}
|
|
|
|
|
2018-01-03 14:01:33 +00:00
|
|
|
// unknown-xxx -> unknown-yyy -> {not existing}
|
2018-01-03 14:16:28 +00:00
|
|
|
xxx := "unknown-xxx"
|
|
|
|
yyy := "unknown-yyy"
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
xxx = "unknown-xxx.exe"
|
|
|
|
yyy = "unknown-yyy.exe"
|
|
|
|
}
|
|
|
|
if err := os.Symlink("not-existing", yyy); err != nil {
|
2018-01-03 14:01:33 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-01-03 14:16:28 +00:00
|
|
|
defer os.Remove(yyy)
|
|
|
|
if err := os.Symlink(yyy, xxx); err != nil {
|
2018-01-03 14:01:33 +00:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-01-03 14:16:28 +00:00
|
|
|
defer os.Remove(xxx)
|
2018-01-03 14:01:33 +00:00
|
|
|
|
|
|
|
v := semver.MustParse("1.2.2")
|
2018-01-03 14:16:28 +00:00
|
|
|
for _, p := range []string{yyy, xxx} {
|
|
|
|
_, err := UpdateCommand(yyy, v, "owner/repo")
|
2018-01-03 14:01:33 +00:00
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Error should occur for unlinked symlink", p)
|
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), "Failed to resolve symlink") {
|
|
|
|
t.Fatal("Unexpected error for broken symlink", p, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNotExistingCommandPath(t *testing.T) {
|
|
|
|
_, err := UpdateCommand("not-existing-command-path", semver.MustParse("1.2.2"), "owner/repo")
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Not existing command path should cause an error")
|
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), "File may not exist") {
|
|
|
|
t.Fatal("Unexpected error for not existing command path", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-29 16:37:09 +00:00
|
|
|
func TestNoReleaseFoundForUpdate(t *testing.T) {
|
|
|
|
v := semver.MustParse("1.0.0")
|
2018-01-03 14:13:23 +00:00
|
|
|
fake := filepath.FromSlash("./testdata/fake-executable")
|
|
|
|
rel, err := UpdateCommand(fake, v, "rhysd/misc")
|
2017-12-29 16:37:09 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal("No release should not make an error:", err)
|
|
|
|
}
|
|
|
|
if rel.Version.NE(v) {
|
|
|
|
t.Error("No release should return the current version as the latest:", rel.Version)
|
|
|
|
}
|
|
|
|
if rel.URL != "" {
|
|
|
|
t.Error("Browse URL should be empty when no release found:", rel.URL)
|
|
|
|
}
|
|
|
|
if rel.AssetURL != "" {
|
|
|
|
t.Error("Asset URL should be empty when no release found:", rel.AssetURL)
|
|
|
|
}
|
|
|
|
if rel.ReleaseNotes != "" {
|
|
|
|
t.Error("Release notes should be empty when no release found:", rel.ReleaseNotes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCurrentIsTheLatest(t *testing.T) {
|
2018-01-03 14:13:23 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("skip tests in short mode.")
|
|
|
|
}
|
|
|
|
setupTestBinary()
|
|
|
|
defer teardownTestBinary()
|
|
|
|
|
2017-12-29 16:37:09 +00:00
|
|
|
v := semver.MustParse("1.2.3")
|
|
|
|
rel, err := UpdateCommand("github-release-test", v, "rhysd-test/test-release-zip")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if rel.Version.NE(v) {
|
|
|
|
t.Error("v1.2.3 should be the latest:", rel.Version)
|
|
|
|
}
|
|
|
|
if rel.URL == "" {
|
|
|
|
t.Error("Browse URL should not be empty when release found:", rel.URL)
|
|
|
|
}
|
|
|
|
if rel.AssetURL == "" {
|
|
|
|
t.Error("Asset URL should not be empty when release found:", rel.AssetURL)
|
|
|
|
}
|
|
|
|
if rel.ReleaseNotes == "" {
|
|
|
|
t.Error("Release notes should not be empty when release found:", rel.ReleaseNotes)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBrokenBinaryUpdate(t *testing.T) {
|
2017-12-31 04:35:22 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("skip tests in short mode.")
|
|
|
|
}
|
|
|
|
|
2018-01-03 14:13:23 +00:00
|
|
|
fake := filepath.FromSlash("./testdata/fake-executable")
|
|
|
|
_, err := UpdateCommand(fake, semver.MustParse("1.2.2"), "rhysd-test/test-incorrect-release")
|
2017-12-29 16:37:09 +00:00
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Error should occur for broken package")
|
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), "Failed to uncompress .tar.gz file") {
|
|
|
|
t.Fatal("Unexpected error:", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInvalidSlugForUpdate(t *testing.T) {
|
2018-01-03 14:13:23 +00:00
|
|
|
fake := filepath.FromSlash("./testdata/fake-executable")
|
|
|
|
_, err := UpdateCommand(fake, semver.MustParse("1.0.0"), "rhysd/")
|
2017-12-29 16:37:09 +00:00
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Unknown repo should cause an error")
|
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), "Invalid slug format") {
|
|
|
|
t.Fatal("Unexpected error:", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInvalidAssetURL(t *testing.T) {
|
|
|
|
err := UpdateTo("https://github.com/rhysd/non-existing-repo/releases/download/v1.2.3/foo.zip", "foo")
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Error should occur for URL not found")
|
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), "Failed to download a release file") {
|
|
|
|
t.Fatal("Unexpected error:", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBrokenAsset(t *testing.T) {
|
|
|
|
asset := "https://github.com/rhysd-test/test-incorrect-release/releases/download/invalid/broken-zip.zip"
|
|
|
|
err := UpdateTo(asset, "foo")
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Error should occur for URL not found")
|
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), "Failed to uncompress zip file") {
|
|
|
|
t.Fatal("Unexpected error:", err)
|
|
|
|
}
|
|
|
|
}
|