go-github-selfupdate/selfupdate/update_test.go

407 lines
11 KiB
Go

package selfupdate
import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/blang/semver"
)
func setupTestBinary(name ...string) {
var options []string
var output string
if len(name) == 0 {
options = []string{"build", "./testdata/github-release-test/"}
} else {
output = name[0]
if runtime.GOOS == "windows" {
output += ".exe"
}
options = []string{"build", "-o", output, "./testdata/github-release-test/"}
}
if err := exec.Command("go", options...).Run(); err != nil {
panic(err)
}
}
func teardownTestBinary(name ...string) {
var bin string
if len(name) == 0 {
bin = "github-release-test"
} else {
bin = name[0]
}
if runtime.GOOS == "windows" {
bin += ".exe"
}
if err := os.Remove(bin); err != nil {
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",
"rhysd-test/test-release-tar-xz",
"rhysd-test/test-release-xz",
"rhysd-test/test-release-contain-version",
} {
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)
}
})
}
}
func TestUpdateWithDifferentBinaryName(t *testing.T) {
setupTestBinary("gh-release-test")
defer teardownTestBinary("gh-release-test")
latest := semver.MustParse("1.2.3")
prev := semver.MustParse("1.2.2")
_, err := UpdateCommand("gh-release-test", prev, "rhysd-test/test-release-zip")
if err == nil {
t.Fatal("Error should occur for broken package")
}
if !strings.Contains(err.Error(), "the command is not found") {
t.Fatal("Unexpected error:", err)
}
up, err := NewUpdater(Config{BinaryName: "github-release-test", Filters: []string{"github-release-test"}})
if err != nil {
t.Fatal(err)
}
rel, err := up.UpdateCommand("gh-release-test", prev, "rhysd-test/test-release-zip")
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("./gh-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)
}
}
func TestUpdateViaSymlink(t *testing.T) {
if testing.Short() {
t.Skip("skip tests in short mode.")
}
if runtime.GOOS == "windows" && os.Getenv("APPVEYOR") == "" {
t.Skip("skipping because creating symlink on windows requires the root privilege")
}
setupTestBinary()
defer teardownTestBinary()
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 {
t.Fatal(err)
}
defer os.Remove(symPath)
latest := semver.MustParse("1.2.3")
prev := semver.MustParse("1.2.2")
rel, err := UpdateCommand(symPath, prev, "rhysd-test/test-release-zip")
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)
}
s, err := os.Lstat(symPath)
if err != nil {
t.Fatal(err)
}
if s.Mode()&os.ModeSymlink == 0 {
t.Fatalf("%s is not a symlink.", symPath)
}
p, err := filepath.EvalSymlinks(symPath)
if err != nil {
t.Fatal(err)
}
if p != exePath {
t.Fatal("Created symlink no loger points the executable:", p)
}
}
func TestUpdateBrokenSymlinks(t *testing.T) {
if runtime.GOOS == "windows" && os.Getenv("APPVEYOR") == "" {
t.Skip("skipping because creating symlink on windows requires the root privilege")
}
// unknown-xxx -> unknown-yyy -> {not existing}
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 {
t.Fatal(err)
}
defer os.Remove(yyy)
if err := os.Symlink(yyy, xxx); err != nil {
t.Fatal(err)
}
defer os.Remove(xxx)
v := semver.MustParse("1.2.2")
for _, p := range []string{yyy, xxx} {
_, err := UpdateCommand(p, v, "owner/repo")
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)
}
}
func TestNoReleaseFoundForUpdate(t *testing.T) {
v := semver.MustParse("1.0.0")
fake := filepath.FromSlash("./testdata/fake-executable")
rel, err := UpdateCommand(fake, v, "rhysd/misc")
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) {
if testing.Short() {
t.Skip("skip tests in short mode.")
}
setupTestBinary()
defer teardownTestBinary()
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) {
if testing.Short() {
t.Skip("skip tests in short mode.")
}
fake := filepath.FromSlash("./testdata/fake-executable")
_, err := UpdateCommand(fake, semver.MustParse("1.2.2"), "rhysd-test/test-incorrect-release")
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) {
fake := filepath.FromSlash("./testdata/fake-executable")
_, err := UpdateCommand(fake, semver.MustParse("1.0.0"), "rhysd/")
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)
}
}
func TestBrokenGitHubEnterpriseURL(t *testing.T) {
up, err := NewUpdater(Config{APIToken: "hogehoge", EnterpriseBaseURL: "https://example.com"})
if err != nil {
t.Fatal(err)
}
err = up.UpdateTo(&Release{AssetURL: "https://example.com"}, "foo")
if err == nil {
t.Fatal("Invalid GitHub Enterprise base URL should raise an error")
}
if !strings.Contains(err.Error(), "Failed to call GitHub Releases API for getting an asset") {
t.Error("Unexpected error occurred:", err)
}
}
func TestUpdateFromGitHubEnterprise(t *testing.T) {
token := os.Getenv("GITHUB_ENTERPRISE_TOKEN")
base := os.Getenv("GITHUB_ENTERPRISE_BASE_URL")
repo := os.Getenv("GITHUB_ENTERPRISE_REPO")
if token == "" {
t.Skip("because token for GHE is not found")
}
if base == "" {
t.Skip("because base URL for GHE is not found")
}
if repo == "" {
t.Skip("because repo slug for GHE is not found")
}
setupTestBinary()
defer teardownTestBinary()
up, err := NewUpdater(Config{APIToken: token, EnterpriseBaseURL: base})
if err != nil {
t.Fatal(err)
}
latest := semver.MustParse("1.2.3")
prev := semver.MustParse("1.2.2")
rel, err := up.UpdateCommand("github-release-test", prev, repo)
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)
}
}
func TestUpdateFromGitHubPrivateRepo(t *testing.T) {
token := os.Getenv("GITHUB_PRIVATE_TOKEN")
if token == "" {
t.Skip("because GITHUB_PRIVATE_TOKEN is not set")
}
setupTestBinary()
defer teardownTestBinary()
up, err := NewUpdater(Config{APIToken: token})
if err != nil {
t.Fatal(err)
}
latest := semver.MustParse("1.2.3")
prev := semver.MustParse("1.2.2")
rel, err := up.UpdateCommand("github-release-test", prev, "rhysd/private-release-test")
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)
}
}