From b443269594dd287545e4062a41b4956d5ebb92bc Mon Sep 17 00:00:00 2001 From: Tai Groot Date: Thu, 26 Feb 2026 01:42:19 +0000 Subject: [PATCH] feat: add integration tests and GitHub Actions CI Add integration test files for all providers (apt, dpkg, pacman, apk, dnf, rpm, flatpak, snap, pkg, detect) behind the 'integration' build tag. Tests exercise real package operations: update, search, info, install, verify, list, remove, and capability interfaces. Add GitHub Actions workflow running unit tests on ubuntu-latest and integration tests on Debian, Ubuntu, Fedora, Alpine, Arch Linux, and Ubuntu+Flatpak containers/runners. --- .github/workflows/integration.yml | 118 ++++++++++++++++++++++++++++ apk/apk_integration_test.go | 104 ++++++++++++++++++++++++ apt/apt_integration_test.go | 104 ++++++++++++++++++++++++ detect/detect_integration_test.go | 29 +++++++ dnf/dnf_integration_test.go | 110 ++++++++++++++++++++++++++ dpkg/dpkg_integration_test.go | 65 +++++++++++++++ flatpak/flatpak_integration_test.go | 84 ++++++++++++++++++++ go.mod | 1 + go.sum | 2 + pacman/pacman_integration_test.go | 110 ++++++++++++++++++++++++++ pkg/pkg_integration_test.go | 80 +++++++++++++++++++ rpm/rpm_integration_test.go | 58 ++++++++++++++ snap/snap_integration_test.go | 80 +++++++++++++++++++ 13 files changed, 945 insertions(+) create mode 100644 .github/workflows/integration.yml create mode 100644 apk/apk_integration_test.go create mode 100644 apt/apt_integration_test.go create mode 100644 detect/detect_integration_test.go create mode 100644 dnf/dnf_integration_test.go create mode 100644 dpkg/dpkg_integration_test.go create mode 100644 flatpak/flatpak_integration_test.go create mode 100644 pacman/pacman_integration_test.go create mode 100644 pkg/pkg_integration_test.go create mode 100644 rpm/rpm_integration_test.go create mode 100644 snap/snap_integration_test.go diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml new file mode 100644 index 0000000..ca3d749 --- /dev/null +++ b/.github/workflows/integration.yml @@ -0,0 +1,118 @@ +name: Integration Tests +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + unit-tests: + name: Unit Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - run: go build ./... + - run: go vet ./... + - run: go test -race ./... + + debian: + name: Debian (apt) + runs-on: ubuntu-latest + container: debian:bookworm + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Setup + run: | + apt-get update + apt-get install -y sudo tree curl + - name: Integration tests + run: go test -v -tags integration -count=1 ./apt/ ./dpkg/ ./detect/ + + ubuntu: + name: Ubuntu (apt + snap) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Setup + run: | + sudo apt-get update + sudo apt-get install -y tree + sudo snap install hello-world 2>/dev/null; sudo snap remove hello-world 2>/dev/null + - name: Integration tests (apt) + run: sudo -E go test -v -tags integration -count=1 ./apt/ ./dpkg/ ./detect/ + - name: Integration tests (snap) + run: sudo -E go test -v -tags integration -count=1 ./snap/ + + fedora: + name: Fedora (dnf) + runs-on: ubuntu-latest + container: fedora:latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Setup + run: | + dnf install -y tree sudo + - name: Integration tests + run: go test -v -tags integration -count=1 ./dnf/ ./rpm/ ./detect/ + + alpine: + name: Alpine (apk) + runs-on: ubuntu-latest + container: alpine:latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Setup + run: | + apk add --no-cache sudo tree bash + - name: Integration tests + run: go test -v -tags integration -count=1 ./apk/ ./detect/ + + arch: + name: Arch Linux (pacman) + runs-on: ubuntu-latest + container: archlinux:latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Setup + run: | + pacman -Syu --noconfirm + pacman -S --noconfirm sudo tree + - name: Integration tests + run: go test -v -tags integration -count=1 ./pacman/ ./detect/ + + flatpak: + name: Ubuntu + Flatpak + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - name: Verify flatpak not installed + run: | + if command -v flatpak &>/dev/null; then echo "already installed"; else echo "not installed — good"; fi + - name: Install flatpak + run: | + sudo apt-get update + sudo apt-get install -y flatpak + sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo + - name: Integration tests + run: sudo -E go test -v -tags integration -count=1 ./flatpak/ diff --git a/apk/apk_integration_test.go b/apk/apk_integration_test.go new file mode 100644 index 0000000..f80fc4f --- /dev/null +++ b/apk/apk_integration_test.go @@ -0,0 +1,104 @@ +//go:build integration + +package apk_test + +import ( + "context" + "testing" + + "github.com/gogrlx/snack" + "github.com/gogrlx/snack/apk" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegration_Apk(t *testing.T) { + mgr := apk.New() + if !mgr.Available() { + t.Skip("apk not available") + } + ctx := context.Background() + + t.Run("Update", func(t *testing.T) { + err := mgr.Update(ctx) + require.NoError(t, err) + }) + + t.Run("Search", func(t *testing.T) { + pkgs, err := mgr.Search(ctx, "curl") + require.NoError(t, err) + require.NotEmpty(t, pkgs) + }) + + t.Run("Info", func(t *testing.T) { + pkg, err := mgr.Info(ctx, "curl") + require.NoError(t, err) + require.NotNil(t, pkg) + assert.Equal(t, "curl", pkg.Name) + }) + + t.Run("Install", func(t *testing.T) { + err := mgr.Install(ctx, snack.Targets("tree"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "tree") + require.NoError(t, err) + assert.True(t, installed) + }) + + t.Run("Version", func(t *testing.T) { + ver, err := mgr.Version(ctx, "tree") + require.NoError(t, err) + assert.NotEmpty(t, ver) + }) + + t.Run("List", func(t *testing.T) { + pkgs, err := mgr.List(ctx) + require.NoError(t, err) + found := false + for _, p := range pkgs { + if p.Name == "tree" { + found = true + break + } + } + assert.True(t, found, "tree should be in installed list") + }) + + t.Run("Remove", func(t *testing.T) { + err := mgr.Remove(ctx, snack.Targets("tree"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled_After_Remove", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "tree") + require.NoError(t, err) + assert.False(t, installed) + }) + + t.Run("Capabilities", func(t *testing.T) { + if vq, ok := mgr.(snack.VersionQuerier); ok { + ver, err := vq.LatestVersion(ctx, "curl") + require.NoError(t, err) + assert.NotEmpty(t, ver) + + upgrades, err := vq.ListUpgrades(ctx) + require.NoError(t, err) + _ = upgrades + } + + if cl, ok := mgr.(snack.Cleaner); ok { + err := cl.Clean(ctx) + require.NoError(t, err) + } + + if fo, ok := mgr.(snack.FileOwner); ok { + owner, err := fo.Owner(ctx, "/usr/bin/apk") + if err == nil { + assert.NotEmpty(t, owner) + } + } + }) +} diff --git a/apt/apt_integration_test.go b/apt/apt_integration_test.go new file mode 100644 index 0000000..b123a68 --- /dev/null +++ b/apt/apt_integration_test.go @@ -0,0 +1,104 @@ +//go:build integration + +package apt_test + +import ( + "context" + "testing" + + "github.com/gogrlx/snack" + "github.com/gogrlx/snack/apt" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegration_Apt(t *testing.T) { + mgr := apt.New() + if !mgr.Available() { + t.Skip("apt not available") + } + ctx := context.Background() + + t.Run("Update", func(t *testing.T) { + err := mgr.Update(ctx) + require.NoError(t, err) + }) + + t.Run("Search", func(t *testing.T) { + pkgs, err := mgr.Search(ctx, "curl") + require.NoError(t, err) + require.NotEmpty(t, pkgs) + }) + + t.Run("Info", func(t *testing.T) { + pkg, err := mgr.Info(ctx, "curl") + require.NoError(t, err) + require.NotNil(t, pkg) + assert.Equal(t, "curl", pkg.Name) + }) + + t.Run("Install", func(t *testing.T) { + err := mgr.Install(ctx, snack.Targets("tree"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "tree") + require.NoError(t, err) + assert.True(t, installed) + }) + + t.Run("Version", func(t *testing.T) { + ver, err := mgr.Version(ctx, "tree") + require.NoError(t, err) + assert.NotEmpty(t, ver) + }) + + t.Run("List", func(t *testing.T) { + pkgs, err := mgr.List(ctx) + require.NoError(t, err) + found := false + for _, p := range pkgs { + if p.Name == "tree" { + found = true + break + } + } + assert.True(t, found, "tree should be in installed list") + }) + + t.Run("Remove", func(t *testing.T) { + err := mgr.Remove(ctx, snack.Targets("tree"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled_After_Remove", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "tree") + require.NoError(t, err) + assert.False(t, installed) + }) + + t.Run("Capabilities", func(t *testing.T) { + if vq, ok := mgr.(snack.VersionQuerier); ok { + ver, err := vq.LatestVersion(ctx, "curl") + require.NoError(t, err) + assert.NotEmpty(t, ver) + + upgrades, err := vq.ListUpgrades(ctx) + require.NoError(t, err) + _ = upgrades + } + + if cl, ok := mgr.(snack.Cleaner); ok { + err := cl.Clean(ctx) + require.NoError(t, err) + } + + if fo, ok := mgr.(snack.FileOwner); ok { + owner, err := fo.Owner(ctx, "/usr/bin/apt") + if err == nil { + assert.NotEmpty(t, owner) + } + } + }) +} diff --git a/detect/detect_integration_test.go b/detect/detect_integration_test.go new file mode 100644 index 0000000..6bc9e55 --- /dev/null +++ b/detect/detect_integration_test.go @@ -0,0 +1,29 @@ +//go:build integration + +package detect_test + +import ( + "testing" + + "github.com/gogrlx/snack" + "github.com/gogrlx/snack/detect" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegration_Detect(t *testing.T) { + mgr, err := detect.Default() + require.NoError(t, err) + require.NotNil(t, mgr) + t.Logf("Detected: %s", mgr.Name()) + + all := detect.All() + require.NotEmpty(t, all) + for _, m := range all { + t.Logf("Available: %s", m.Name()) + } + + caps := snack.GetCapabilities(mgr) + t.Logf("Capabilities: %+v", caps) + assert.NotEmpty(t, mgr.Name()) +} diff --git a/dnf/dnf_integration_test.go b/dnf/dnf_integration_test.go new file mode 100644 index 0000000..8c60429 --- /dev/null +++ b/dnf/dnf_integration_test.go @@ -0,0 +1,110 @@ +//go:build integration + +package dnf_test + +import ( + "context" + "testing" + + "github.com/gogrlx/snack" + "github.com/gogrlx/snack/dnf" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegration_DNF(t *testing.T) { + mgr := dnf.New() + if !mgr.Available() { + t.Skip("dnf not available") + } + ctx := context.Background() + + t.Run("Update", func(t *testing.T) { + err := mgr.Update(ctx) + require.NoError(t, err) + }) + + t.Run("Search", func(t *testing.T) { + pkgs, err := mgr.Search(ctx, "curl") + require.NoError(t, err) + require.NotEmpty(t, pkgs) + }) + + t.Run("Info", func(t *testing.T) { + pkg, err := mgr.Info(ctx, "curl") + require.NoError(t, err) + require.NotNil(t, pkg) + assert.Equal(t, "curl", pkg.Name) + }) + + t.Run("Install", func(t *testing.T) { + err := mgr.Install(ctx, snack.Targets("tree"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "tree") + require.NoError(t, err) + assert.True(t, installed) + }) + + t.Run("Version", func(t *testing.T) { + ver, err := mgr.Version(ctx, "tree") + require.NoError(t, err) + assert.NotEmpty(t, ver) + }) + + t.Run("List", func(t *testing.T) { + pkgs, err := mgr.List(ctx) + require.NoError(t, err) + found := false + for _, p := range pkgs { + if p.Name == "tree" { + found = true + break + } + } + assert.True(t, found, "tree should be in installed list") + }) + + t.Run("Remove", func(t *testing.T) { + err := mgr.Remove(ctx, snack.Targets("tree"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled_After_Remove", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "tree") + require.NoError(t, err) + assert.False(t, installed) + }) + + t.Run("Capabilities", func(t *testing.T) { + if vq, ok := mgr.(snack.VersionQuerier); ok { + ver, err := vq.LatestVersion(ctx, "curl") + require.NoError(t, err) + assert.NotEmpty(t, ver) + + upgrades, err := vq.ListUpgrades(ctx) + require.NoError(t, err) + _ = upgrades + } + + if cl, ok := mgr.(snack.Cleaner); ok { + err := cl.Clean(ctx) + require.NoError(t, err) + } + + if fo, ok := mgr.(snack.FileOwner); ok { + owner, err := fo.Owner(ctx, "/usr/bin/dnf") + if err == nil { + assert.NotEmpty(t, owner) + } + } + + if g, ok := mgr.(snack.Grouper); ok { + groups, err := g.GroupList(ctx) + require.NoError(t, err) + _ = groups + } + }) +} diff --git a/dpkg/dpkg_integration_test.go b/dpkg/dpkg_integration_test.go new file mode 100644 index 0000000..9308734 --- /dev/null +++ b/dpkg/dpkg_integration_test.go @@ -0,0 +1,65 @@ +//go:build integration + +package dpkg_test + +import ( + "context" + "testing" + + "github.com/gogrlx/snack" + "github.com/gogrlx/snack/dpkg" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegration_Dpkg(t *testing.T) { + mgr := dpkg.New() + if !mgr.Available() { + t.Skip("dpkg not available") + } + ctx := context.Background() + + t.Run("List", func(t *testing.T) { + pkgs, err := mgr.List(ctx) + require.NoError(t, err) + require.NotEmpty(t, pkgs) + }) + + t.Run("IsInstalled", func(t *testing.T) { + // bash should always be installed + installed, err := mgr.IsInstalled(ctx, "bash") + require.NoError(t, err) + assert.True(t, installed) + }) + + t.Run("Version", func(t *testing.T) { + ver, err := mgr.Version(ctx, "bash") + require.NoError(t, err) + assert.NotEmpty(t, ver) + }) + + t.Run("Info", func(t *testing.T) { + pkg, err := mgr.Info(ctx, "bash") + require.NoError(t, err) + require.NotNil(t, pkg) + assert.Equal(t, "bash", pkg.Name) + }) + + t.Run("Search", func(t *testing.T) { + pkgs, err := mgr.Search(ctx, "bash") + require.NoError(t, err) + require.NotEmpty(t, pkgs) + }) + + t.Run("FileOwner", func(t *testing.T) { + if fo, ok := mgr.(snack.FileOwner); ok { + owner, err := fo.Owner(ctx, "/bin/bash") + require.NoError(t, err) + assert.NotEmpty(t, owner) + + files, err := fo.FileList(ctx, "bash") + require.NoError(t, err) + assert.NotEmpty(t, files) + } + }) +} diff --git a/flatpak/flatpak_integration_test.go b/flatpak/flatpak_integration_test.go new file mode 100644 index 0000000..c92d4d3 --- /dev/null +++ b/flatpak/flatpak_integration_test.go @@ -0,0 +1,84 @@ +//go:build integration + +package flatpak_test + +import ( + "context" + "testing" + + "github.com/gogrlx/snack" + "github.com/gogrlx/snack/flatpak" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegration_Flatpak(t *testing.T) { + mgr := flatpak.New() + if !mgr.Available() { + t.Skip("flatpak not available — install it first") + } + ctx := context.Background() + + t.Run("Update", func(t *testing.T) { + err := mgr.Update(ctx) + require.NoError(t, err) + }) + + t.Run("RepoManager", func(t *testing.T) { + rm, ok := mgr.(snack.RepoManager) + if !ok { + t.Skip("RepoManager not implemented") + } + repos, err := rm.ListRepos(ctx) + require.NoError(t, err) + found := false + for _, r := range repos { + if r.Name == "flathub" || r.ID == "flathub" { + found = true + break + } + } + assert.True(t, found, "flathub repo should be configured") + }) + + t.Run("Search", func(t *testing.T) { + pkgs, err := mgr.Search(ctx, "Flatseal") + require.NoError(t, err) + require.NotEmpty(t, pkgs) + }) + + t.Run("Install", func(t *testing.T) { + err := mgr.Install(ctx, snack.Targets("com.github.tchx84.Flatseal"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "com.github.tchx84.Flatseal") + require.NoError(t, err) + assert.True(t, installed) + }) + + t.Run("List", func(t *testing.T) { + pkgs, err := mgr.List(ctx) + require.NoError(t, err) + found := false + for _, p := range pkgs { + if p.Name == "com.github.tchx84.Flatseal" { + found = true + break + } + } + assert.True(t, found, "Flatseal should be in installed list") + }) + + t.Run("Remove", func(t *testing.T) { + err := mgr.Remove(ctx, snack.Targets("com.github.tchx84.Flatseal"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled_After_Remove", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "com.github.tchx84.Flatseal") + require.NoError(t, err) + assert.False(t, installed) + }) +} diff --git a/go.mod b/go.mod index 61f7b23..3faa4ae 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/muesli/roff v0.1.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/spf13/pflag v1.0.9 // indirect + github.com/stretchr/testify v1.11.1 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect diff --git a/go.sum b/go.sum index e9588ab..c577f67 100644 --- a/go.sum +++ b/go.sum @@ -56,6 +56,8 @@ github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= diff --git a/pacman/pacman_integration_test.go b/pacman/pacman_integration_test.go new file mode 100644 index 0000000..7f968df --- /dev/null +++ b/pacman/pacman_integration_test.go @@ -0,0 +1,110 @@ +//go:build integration + +package pacman_test + +import ( + "context" + "testing" + + "github.com/gogrlx/snack" + "github.com/gogrlx/snack/pacman" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegration_Pacman(t *testing.T) { + mgr := pacman.New() + if !mgr.Available() { + t.Skip("pacman not available") + } + ctx := context.Background() + + t.Run("Update", func(t *testing.T) { + err := mgr.Update(ctx) + require.NoError(t, err) + }) + + t.Run("Search", func(t *testing.T) { + pkgs, err := mgr.Search(ctx, "curl") + require.NoError(t, err) + require.NotEmpty(t, pkgs) + }) + + t.Run("Info", func(t *testing.T) { + pkg, err := mgr.Info(ctx, "curl") + require.NoError(t, err) + require.NotNil(t, pkg) + assert.Equal(t, "curl", pkg.Name) + }) + + t.Run("Install", func(t *testing.T) { + err := mgr.Install(ctx, snack.Targets("tree"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "tree") + require.NoError(t, err) + assert.True(t, installed) + }) + + t.Run("Version", func(t *testing.T) { + ver, err := mgr.Version(ctx, "tree") + require.NoError(t, err) + assert.NotEmpty(t, ver) + }) + + t.Run("List", func(t *testing.T) { + pkgs, err := mgr.List(ctx) + require.NoError(t, err) + found := false + for _, p := range pkgs { + if p.Name == "tree" { + found = true + break + } + } + assert.True(t, found, "tree should be in installed list") + }) + + t.Run("Remove", func(t *testing.T) { + err := mgr.Remove(ctx, snack.Targets("tree"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled_After_Remove", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "tree") + require.NoError(t, err) + assert.False(t, installed) + }) + + t.Run("Capabilities", func(t *testing.T) { + if vq, ok := mgr.(snack.VersionQuerier); ok { + ver, err := vq.LatestVersion(ctx, "curl") + require.NoError(t, err) + assert.NotEmpty(t, ver) + + upgrades, err := vq.ListUpgrades(ctx) + require.NoError(t, err) + _ = upgrades + } + + if cl, ok := mgr.(snack.Cleaner); ok { + err := cl.Clean(ctx) + require.NoError(t, err) + } + + if fo, ok := mgr.(snack.FileOwner); ok { + owner, err := fo.Owner(ctx, "/usr/bin/pacman") + if err == nil { + assert.NotEmpty(t, owner) + } + } + + if g, ok := mgr.(snack.Grouper); ok { + groups, err := g.GroupList(ctx) + require.NoError(t, err) + assert.NotEmpty(t, groups) + } + }) +} diff --git a/pkg/pkg_integration_test.go b/pkg/pkg_integration_test.go new file mode 100644 index 0000000..7eb8c53 --- /dev/null +++ b/pkg/pkg_integration_test.go @@ -0,0 +1,80 @@ +//go:build integration + +package pkg_test + +import ( + "context" + "testing" + + "github.com/gogrlx/snack" + "github.com/gogrlx/snack/pkg" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegration_Pkg(t *testing.T) { + mgr := pkg.New() + if !mgr.Available() { + t.Skip("pkg not available") + } + ctx := context.Background() + + t.Run("Update", func(t *testing.T) { + err := mgr.Update(ctx) + require.NoError(t, err) + }) + + t.Run("Search", func(t *testing.T) { + pkgs, err := mgr.Search(ctx, "curl") + require.NoError(t, err) + require.NotEmpty(t, pkgs) + }) + + t.Run("Info", func(t *testing.T) { + p, err := mgr.Info(ctx, "curl") + require.NoError(t, err) + require.NotNil(t, p) + assert.Equal(t, "curl", p.Name) + }) + + t.Run("Install", func(t *testing.T) { + err := mgr.Install(ctx, snack.Targets("tree"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "tree") + require.NoError(t, err) + assert.True(t, installed) + }) + + t.Run("Version", func(t *testing.T) { + ver, err := mgr.Version(ctx, "tree") + require.NoError(t, err) + assert.NotEmpty(t, ver) + }) + + t.Run("List", func(t *testing.T) { + pkgs, err := mgr.List(ctx) + require.NoError(t, err) + found := false + for _, p := range pkgs { + if p.Name == "tree" { + found = true + break + } + } + assert.True(t, found, "tree should be in installed list") + }) + + t.Run("Remove", func(t *testing.T) { + err := mgr.Remove(ctx, snack.Targets("tree"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled_After_Remove", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "tree") + require.NoError(t, err) + assert.False(t, installed) + }) +} diff --git a/rpm/rpm_integration_test.go b/rpm/rpm_integration_test.go new file mode 100644 index 0000000..7853afa --- /dev/null +++ b/rpm/rpm_integration_test.go @@ -0,0 +1,58 @@ +//go:build integration + +package rpm_test + +import ( + "context" + "testing" + + "github.com/gogrlx/snack" + "github.com/gogrlx/snack/rpm" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegration_RPM(t *testing.T) { + mgr := rpm.New() + if !mgr.Available() { + t.Skip("rpm not available") + } + ctx := context.Background() + + t.Run("List", func(t *testing.T) { + pkgs, err := mgr.List(ctx) + require.NoError(t, err) + require.NotEmpty(t, pkgs) + }) + + t.Run("IsInstalled", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "bash") + require.NoError(t, err) + assert.True(t, installed) + }) + + t.Run("Version", func(t *testing.T) { + ver, err := mgr.Version(ctx, "bash") + require.NoError(t, err) + assert.NotEmpty(t, ver) + }) + + t.Run("Info", func(t *testing.T) { + pkg, err := mgr.Info(ctx, "bash") + require.NoError(t, err) + require.NotNil(t, pkg) + assert.Equal(t, "bash", pkg.Name) + }) + + t.Run("FileOwner", func(t *testing.T) { + if fo, ok := mgr.(snack.FileOwner); ok { + owner, err := fo.Owner(ctx, "/bin/bash") + require.NoError(t, err) + assert.NotEmpty(t, owner) + + files, err := fo.FileList(ctx, "bash") + require.NoError(t, err) + assert.NotEmpty(t, files) + } + }) +} diff --git a/snap/snap_integration_test.go b/snap/snap_integration_test.go new file mode 100644 index 0000000..23ae4b8 --- /dev/null +++ b/snap/snap_integration_test.go @@ -0,0 +1,80 @@ +//go:build integration + +package snap_test + +import ( + "context" + "testing" + + "github.com/gogrlx/snack" + "github.com/gogrlx/snack/snap" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegration_Snap(t *testing.T) { + mgr := snap.New() + if !mgr.Available() { + t.Skip("snap not available") + } + ctx := context.Background() + + t.Run("Update", func(t *testing.T) { + err := mgr.Update(ctx) + require.NoError(t, err) + }) + + t.Run("Search", func(t *testing.T) { + pkgs, err := mgr.Search(ctx, "hello-world") + require.NoError(t, err) + require.NotEmpty(t, pkgs) + }) + + t.Run("Info", func(t *testing.T) { + pkg, err := mgr.Info(ctx, "hello-world") + require.NoError(t, err) + require.NotNil(t, pkg) + assert.Equal(t, "hello-world", pkg.Name) + }) + + t.Run("Install", func(t *testing.T) { + err := mgr.Install(ctx, snack.Targets("hello-world"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "hello-world") + require.NoError(t, err) + assert.True(t, installed) + }) + + t.Run("Version", func(t *testing.T) { + ver, err := mgr.Version(ctx, "hello-world") + require.NoError(t, err) + assert.NotEmpty(t, ver) + }) + + t.Run("List", func(t *testing.T) { + pkgs, err := mgr.List(ctx) + require.NoError(t, err) + found := false + for _, p := range pkgs { + if p.Name == "hello-world" { + found = true + break + } + } + assert.True(t, found, "hello-world should be in installed list") + }) + + t.Run("Remove", func(t *testing.T) { + err := mgr.Remove(ctx, snack.Targets("hello-world"), snack.WithSudo(), snack.WithAssumeYes()) + require.NoError(t, err) + }) + + t.Run("IsInstalled_After_Remove", func(t *testing.T) { + installed, err := mgr.IsInstalled(ctx, "hello-world") + require.NoError(t, err) + assert.False(t, installed) + }) +}