Files
snack/apk/apk_integration_test.go
Tai Groot b12f956e45 test: exhaustive integration tests with codecov
- Root package unit tests: Targets, TargetNames, ApplyOptions, error sentinels
- Every provider integration test now covers:
  - All Manager interface methods (positive + negative cases)
  - GetCapabilities verification (assert expected interfaces)
  - VersionQuerier: LatestVersion, ListUpgrades, UpgradeAvailable, VersionCmp
  - Holder: Hold, ListHeld, Unhold (apt, dnf)
  - Cleaner: Autoremove, Clean
  - FileOwner: FileList, Owner (+ not-found cases)
  - RepoManager: ListRepos (apt, dnf, flatpak)
  - KeyManager: ListKeys (apt, dnf)
  - Grouper: GroupList, GroupInfo (pacman, dnf)
  - NameNormalizer: NormalizeName, ParseArch table tests (apt, dpkg, dnf, rpm)
- Containertest matrix: 5 distros (debian, alpine, arch, fedora39, fedora-latest)
- CI: coverage profiles uploaded per-job, merged in codecov job
- Added .gitignore for coverage files
2026-02-26 02:50:48 +00:00

262 lines
6.6 KiB
Go

//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()
assert.Equal(t, "apk", mgr.Name())
caps := snack.GetCapabilities(mgr)
assert.True(t, caps.VersionQuery, "apk should support VersionQuery")
assert.True(t, caps.Clean, "apk should support Clean")
assert.True(t, caps.FileOwnership, "apk should support FileOwnership")
assert.False(t, caps.Hold, "apk should not support Hold")
assert.False(t, caps.RepoManagement, "apk should not support RepoManagement")
assert.False(t, caps.KeyManagement, "apk should not support KeyManagement")
assert.False(t, caps.Groups, "apk should not support Groups")
assert.False(t, caps.NameNormalize, "apk should not support NameNormalize")
t.Run("Update", func(t *testing.T) {
require.NoError(t, mgr.Update(ctx))
})
t.Run("Search", func(t *testing.T) {
pkgs, err := mgr.Search(ctx, "curl")
require.NoError(t, err)
require.NotEmpty(t, pkgs, "search for curl should return results")
found := false
for _, p := range pkgs {
if p.Name == "curl" {
found = true
break
}
}
assert.True(t, found, "curl should appear in search results")
})
t.Run("Search_NoResults", func(t *testing.T) {
pkgs, err := mgr.Search(ctx, "xyznonexistentpackage999")
require.NoError(t, err)
assert.Empty(t, pkgs)
})
t.Run("Info_PreInstalled", func(t *testing.T) {
pkg, err := mgr.Info(ctx, "busybox")
if err != nil {
t.Skip("busybox not installed")
}
require.NotNil(t, pkg)
assert.Equal(t, "busybox", pkg.Name)
assert.NotEmpty(t, pkg.Version)
})
t.Run("Info_NotFound", func(t *testing.T) {
_, err := mgr.Info(ctx, "xyznonexistentpackage999")
assert.Error(t, err)
})
t.Run("Install_Single", func(t *testing.T) {
_ = mgr.Remove(ctx, snack.Targets("tree"))
err := mgr.Install(ctx, snack.Targets("tree"))
require.NoError(t, err)
})
t.Run("IsInstalled_True", func(t *testing.T) {
installed, err := mgr.IsInstalled(ctx, "tree")
require.NoError(t, err)
assert.True(t, installed)
})
t.Run("IsInstalled_False", func(t *testing.T) {
installed, err := mgr.IsInstalled(ctx, "xyznonexistentpackage999")
require.NoError(t, err)
assert.False(t, installed)
})
t.Run("Version_Installed", func(t *testing.T) {
ver, err := mgr.Version(ctx, "tree")
require.NoError(t, err)
assert.NotEmpty(t, ver)
t.Logf("tree version: %s", ver)
})
t.Run("Version_NotInstalled", func(t *testing.T) {
_, err := mgr.Version(ctx, "xyznonexistentpackage999")
assert.Error(t, err)
})
t.Run("List_ContainsInstalled", func(t *testing.T) {
pkgs, err := mgr.List(ctx)
require.NoError(t, err)
require.NotEmpty(t, pkgs)
found := false
for _, p := range pkgs {
if p.Name == "tree" {
found = true
assert.NotEmpty(t, p.Version)
break
}
}
assert.True(t, found, "tree should be in installed list")
})
t.Run("Info_AfterInstall", func(t *testing.T) {
pkg, err := mgr.Info(ctx, "tree")
require.NoError(t, err)
require.NotNil(t, pkg)
assert.Equal(t, "tree", pkg.Name)
assert.NotEmpty(t, pkg.Version)
})
t.Run("Install_Multiple", func(t *testing.T) {
err := mgr.Install(ctx, snack.Targets("tree", "less"))
require.NoError(t, err)
for _, pkg := range []string{"tree", "less"} {
installed, err := mgr.IsInstalled(ctx, pkg)
require.NoError(t, err)
assert.True(t, installed, "%s should be installed", pkg)
}
})
t.Run("Purge", func(t *testing.T) {
// apk purge is same as remove
err := mgr.Purge(ctx, snack.Targets("less"))
require.NoError(t, err)
installed, err := mgr.IsInstalled(ctx, "less")
require.NoError(t, err)
assert.False(t, installed)
})
t.Run("Remove", func(t *testing.T) {
err := mgr.Remove(ctx, snack.Targets("tree"))
require.NoError(t, err)
installed, err := mgr.IsInstalled(ctx, "tree")
require.NoError(t, err)
assert.False(t, installed)
})
// --- VersionQuerier ---
t.Run("VersionQuerier", func(t *testing.T) {
vq, ok := mgr.(snack.VersionQuerier)
require.True(t, ok)
t.Run("LatestVersion", func(t *testing.T) {
ver, err := vq.LatestVersion(ctx, "curl")
require.NoError(t, err)
assert.NotEmpty(t, ver)
t.Logf("curl latest: %s", ver)
})
t.Run("LatestVersion_NotFound", func(t *testing.T) {
_, err := vq.LatestVersion(ctx, "xyznonexistentpackage999")
assert.Error(t, err)
})
t.Run("ListUpgrades", func(t *testing.T) {
pkgs, err := vq.ListUpgrades(ctx)
require.NoError(t, err)
t.Logf("upgradable packages: %d", len(pkgs))
})
t.Run("UpgradeAvailable", func(t *testing.T) {
avail, err := vq.UpgradeAvailable(ctx, "busybox")
require.NoError(t, err)
_ = avail
})
t.Run("VersionCmp", func(t *testing.T) {
tests := []struct {
v1, v2 string
want int
}{
{"1.0.0-r0", "1.0.0-r1", -1},
{"2.0.0-r0", "1.0.0-r0", 1},
{"1.0.0-r0", "1.0.0-r0", 0},
}
for _, tt := range tests {
cmp, err := vq.VersionCmp(ctx, tt.v1, tt.v2)
require.NoError(t, err, "VersionCmp(%s, %s)", tt.v1, tt.v2)
assert.Equal(t, tt.want, cmp, "VersionCmp(%s, %s)", tt.v1, tt.v2)
}
})
})
// --- Cleaner ---
t.Run("Cleaner", func(t *testing.T) {
cl, ok := mgr.(snack.Cleaner)
require.True(t, ok)
t.Run("Autoremove", func(t *testing.T) {
// apk doesn't have autoremove but we exercise the path
err := cl.Autoremove(ctx)
// May or may not be supported
_ = err
})
t.Run("Clean", func(t *testing.T) {
err := cl.Clean(ctx)
require.NoError(t, err)
})
})
// --- FileOwner ---
t.Run("FileOwner", func(t *testing.T) {
fo, ok := mgr.(snack.FileOwner)
require.True(t, ok)
// Install tree for file tests
_ = mgr.Install(ctx, snack.Targets("tree"))
t.Run("FileList", func(t *testing.T) {
files, err := fo.FileList(ctx, "tree")
require.NoError(t, err)
require.NotEmpty(t, files)
t.Logf("tree files: %d", len(files))
})
t.Run("FileList_NotInstalled", func(t *testing.T) {
_, err := fo.FileList(ctx, "xyznonexistentpackage999")
assert.Error(t, err)
})
t.Run("Owner", func(t *testing.T) {
owner, err := fo.Owner(ctx, "/usr/bin/tree")
require.NoError(t, err)
assert.Contains(t, owner, "tree")
})
t.Run("Owner_NotFound", func(t *testing.T) {
_, err := fo.Owner(ctx, "/nonexistent/path/xyz")
assert.Error(t, err)
})
_ = mgr.Remove(ctx, snack.Targets("tree"))
})
// --- Upgrade ---
t.Run("Upgrade", func(t *testing.T) {
err := mgr.Upgrade(ctx)
require.NoError(t, err)
})
}