193 lines
6.3 KiB
Go
193 lines
6.3 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestCompareVersions(t *testing.T) {
|
|
cases := []struct {
|
|
a, b string
|
|
want int
|
|
}{
|
|
{"0.9.2", "0.9.1", 1},
|
|
{"v1.0.0", "0.9.9", 1},
|
|
{"0.9.2", "0.9.2", 0},
|
|
{"0.9.1", "0.9.2", -1},
|
|
{"0.9.2-1", "0.9.2", 0},
|
|
}
|
|
for _, tc := range cases {
|
|
got := compareVersions(tc.a, tc.b)
|
|
if got != tc.want {
|
|
t.Fatalf("compareVersions(%q,%q)=%d want %d", tc.a, tc.b, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReleaseAssetForDeb(t *testing.T) {
|
|
a, _ := newApp()
|
|
r := githubRelease{TagName: "v0.9.2", Assets: []githubAsset{
|
|
{Name: "citizen-launcher-0.9.2-linux-amd64.tar.gz"},
|
|
{Name: "citizen-launcher_0.9.2_amd64.deb", Digest: "sha256:abc"},
|
|
}}
|
|
asset, err := a.releaseAssetForMode(r, "0.9.2", "deb")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if asset.Name != "citizen-launcher_0.9.2_amd64.deb" {
|
|
t.Fatalf("wrong asset: %s", asset.Name)
|
|
}
|
|
}
|
|
|
|
func TestVerifyDebPackageMetadata(t *testing.T) {
|
|
if _, err := exec.LookPath("dpkg-deb"); err != nil {
|
|
t.Skip("dpkg-deb unavailable")
|
|
}
|
|
root := t.TempDir()
|
|
pkg := filepath.Join(root, "pkg")
|
|
if err := os.MkdirAll(filepath.Join(pkg, "DEBIAN"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
control := "Package: citizen-launcher\nVersion: 0.9.2\nArchitecture: amd64\nMaintainer: test\nDescription: test\n"
|
|
if err := os.WriteFile(filepath.Join(pkg, "DEBIAN", "control"), []byte(control), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
deb := filepath.Join(root, "citizen-launcher_0.9.2_amd64.deb")
|
|
cmd := exec.Command("dpkg-deb", "--build", "--root-owner-group", pkg, deb)
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
t.Fatalf("dpkg-deb: %v: %s", err, out)
|
|
}
|
|
if err := verifyDebPackage(deb, "0.9.2"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestVerifyDebPackageRejectsMismatchedNewerVersion(t *testing.T) {
|
|
if _, err := exec.LookPath("dpkg-deb"); err != nil {
|
|
t.Skip("dpkg-deb unavailable")
|
|
}
|
|
root := t.TempDir()
|
|
pkg := filepath.Join(root, "pkg")
|
|
if err := os.MkdirAll(filepath.Join(pkg, "DEBIAN"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
control := "Package: citizen-launcher\nVersion: 9.9.9\nArchitecture: amd64\nMaintainer: test\nDescription: test\n"
|
|
if err := os.WriteFile(filepath.Join(pkg, "DEBIAN", "control"), []byte(control), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
deb := filepath.Join(root, "citizen-launcher_1.0.0_amd64.deb")
|
|
if out, err := exec.Command("dpkg-deb", "--build", "--root-owner-group", pkg, deb).CombinedOutput(); err != nil {
|
|
t.Fatalf("dpkg-deb: %v: %s", err, out)
|
|
}
|
|
if err := verifyDebPackage(deb, "1.0.0"); err == nil {
|
|
t.Fatal("mismatched package version was accepted")
|
|
}
|
|
}
|
|
|
|
func TestReleaseAssetsForAllNativeModes(t *testing.T) {
|
|
a, _ := newApp()
|
|
r := githubRelease{TagName: "v1.1.1", Assets: []githubAsset{
|
|
{Name: "citizen-launcher_1.1.1_amd64.deb"},
|
|
{Name: "citizen-launcher-1.1.1-1.linux.x86_64.rpm"},
|
|
{Name: "citizen-launcher-1.1.1-1-x86_64.pkg.tar.zst"},
|
|
{Name: "citizen-launcher-1.1.1-linux-amd64.tar.gz"},
|
|
}}
|
|
want := map[string]string{
|
|
"deb": "citizen-launcher_1.1.1_amd64.deb",
|
|
"rpm": "citizen-launcher-1.1.1-1.linux.x86_64.rpm",
|
|
"arch": "citizen-launcher-1.1.1-1-x86_64.pkg.tar.zst",
|
|
"user": "citizen-launcher-1.1.1-linux-amd64.tar.gz",
|
|
}
|
|
for mode, name := range want {
|
|
asset, err := a.releaseAssetForMode(r, "1.1.1", mode)
|
|
if err != nil {
|
|
t.Fatalf("%s: %v", mode, err)
|
|
}
|
|
if asset.Name != name {
|
|
t.Fatalf("%s: got %q want %q", mode, asset.Name, name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestVerifyPackageIdentityAcceptsNativeReleaseSuffixes(t *testing.T) {
|
|
cases := []struct{ version, arch, wantArch string }{
|
|
{"1.1.0", "amd64", "amd64"},
|
|
{"1.1.0-1", "x86_64", "x86_64"},
|
|
{"1.1.0", "x86_64", "x86_64"},
|
|
}
|
|
for _, tc := range cases {
|
|
if err := verifyPackageIdentity("citizen-launcher", tc.version, tc.arch, "1.1.0", tc.wantArch); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := verifyPackageIdentity("evil", "1.1.0", "x86_64", "1.1.0", "x86_64"); err == nil {
|
|
t.Fatal("wrong package name accepted")
|
|
}
|
|
}
|
|
|
|
func TestNativePackageDatabaseParsers(t *testing.T) {
|
|
root := t.TempDir()
|
|
write := func(name, body string) {
|
|
p := filepath.Join(root, name)
|
|
if err := os.WriteFile(p, []byte("#!/bin/sh\n"+body+"\n"), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
write("dpkg-query", "printf 'install ok installed\\n1.1.0\\n'")
|
|
write("rpm", "printf '1.1.0\\n'")
|
|
write("pacman", "printf 'citizen-launcher 1.1.0-1\\n'")
|
|
t.Setenv("PATH", root)
|
|
|
|
for mode, want := range map[string]string{"deb": "1.1.0", "rpm": "1.1.0", "arch": "1.1.0-1"} {
|
|
pkg := queryInstalledPackage(mode)
|
|
if pkg.Mode != mode || pkg.Version != want {
|
|
t.Fatalf("%s parser: %#v want version %s", mode, pkg, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseLauncherReleaseSource(t *testing.T) {
|
|
cases := []struct {
|
|
in, kind string
|
|
ok bool
|
|
}{
|
|
{"owner/repo", "github", true},
|
|
{"github:owner/repo", "github", true},
|
|
{"gitea:https://git.example.test/api/v1/repos/owner/repo", "gitea", true},
|
|
{"gitea:https://git.example.test/sub/path/api/v1/repos/owner/repo", "gitea", true},
|
|
{"gitea:https://git.example.test/api/v1/repos/owner/repo/", "gitea", true},
|
|
{"gitea:http://git.example.test/api/v1/repos/owner/repo", "", false},
|
|
{"gitea:https://user:pass@git.example.test/api/v1/repos/owner/repo", "", false},
|
|
{"gitea:https://git.example.test/owner/repo", "", false},
|
|
{"../evil", "", false},
|
|
}
|
|
for _, tc := range cases {
|
|
src, ok := parseLauncherReleaseSource(tc.in)
|
|
if ok != tc.ok {
|
|
t.Fatalf("parseLauncherReleaseSource(%q) ok=%v want %v", tc.in, ok, tc.ok)
|
|
}
|
|
if ok && src.Kind != tc.kind {
|
|
t.Fatalf("parseLauncherReleaseSource(%q) kind=%q want %q", tc.in, src.Kind, tc.kind)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestParseSHA256SUMS(t *testing.T) {
|
|
body := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa citizen-launcher_1.1.1_amd64.deb\n" +
|
|
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb *citizen-launcher-1.1.1-linux-amd64.tar.gz\n" +
|
|
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc ../escape.deb\n" +
|
|
"not-a-hash ignored\n"
|
|
got := parseSHA256SUMS(body)
|
|
if got["citizen-launcher_1.1.1_amd64.deb"] != "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" {
|
|
t.Fatal("deb checksum missing")
|
|
}
|
|
if got["citizen-launcher-1.1.1-linux-amd64.tar.gz"] != "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" {
|
|
t.Fatal("tarball checksum missing")
|
|
}
|
|
if _, ok := got["escape.deb"]; ok {
|
|
t.Fatal("path-traversal checksum entry accepted")
|
|
}
|
|
}
|