debian-forge-composer/internal/rpmmd/repository_internal_test.go
Tomas Hozza d48da99a12 rpmmd/dnf-json: support chain dependency solving
Add a new `rpmmdImpl` method `chainDepsolve`, which is able to
depsolve multiple chained package sets as separate DNF transactions
layered on top of each other.

This new method allows to depsolve the `blueprint` package set on top of
the base image package set (usually called `packages`).

Introduce a helper function `chainPackageSets` for constructing
arguments to the `chainDepsolve` method based on the provided arguments:
 - slice of package set names to chain as transactions
 - map of package sets
 - slice of system repositories used by all package sets
 - map of package-set-specific repositories

Extend `dnf-json` with a new command `chain-depsolve` allowing to
depsolve multiple transaction in a row, layered on top of each other.

Add unit tests where appropriate.
2022-04-28 14:42:49 +02:00

396 lines
8.7 KiB
Go

package rpmmd
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestChainPackageSets(t *testing.T) {
tests := []struct {
packageSetsChain []string
packageSets map[string]PackageSet
repos []RepoConfig
packageSetsRepos map[string][]RepoConfig
wantChainPkgSets []chainPackageSet
wantRepos []RepoConfig
err bool
}{
// single transaction
{
packageSetsChain: []string{"os"},
packageSets: map[string]PackageSet{
"os": {
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
},
repos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
},
wantChainPkgSets: []chainPackageSet{
{
PackageSet: PackageSet{
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
Repos: []int{0, 1},
},
},
wantRepos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
},
},
// 2 transactions + package set specific repo
{
packageSetsChain: []string{"os", "blueprint"},
packageSets: map[string]PackageSet{
"os": {
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
"blueprint": {
Include: []string{"pkg3"},
},
},
repos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
},
packageSetsRepos: map[string][]RepoConfig{
"blueprint": {
{
Name: "user-repo",
BaseURL: "https://example.org/user-repo",
},
},
},
wantChainPkgSets: []chainPackageSet{
{
PackageSet: PackageSet{
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
Repos: []int{0, 1},
},
{
PackageSet: PackageSet{
Include: []string{"pkg3"},
},
Repos: []int{0, 1, 2},
},
},
wantRepos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
{
Name: "user-repo",
BaseURL: "https://example.org/user-repo",
},
},
},
// 2 transactions + no package set specific repos
{
packageSetsChain: []string{"os", "blueprint"},
packageSets: map[string]PackageSet{
"os": {
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
"blueprint": {
Include: []string{"pkg3"},
},
},
repos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
},
wantChainPkgSets: []chainPackageSet{
{
PackageSet: PackageSet{
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
Repos: []int{0, 1},
},
{
PackageSet: PackageSet{
Include: []string{"pkg3"},
},
Repos: []int{0, 1},
},
},
wantRepos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
},
},
// 3 transactions + package set specific repo used by 2nd and 3rd transaction
{
packageSetsChain: []string{"os", "blueprint", "blueprint2"},
packageSets: map[string]PackageSet{
"os": {
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
"blueprint": {
Include: []string{"pkg3"},
},
"blueprint2": {
Include: []string{"pkg4"},
},
},
repos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
},
packageSetsRepos: map[string][]RepoConfig{
"blueprint": {
{
Name: "user-repo",
BaseURL: "https://example.org/user-repo",
},
},
"blueprint2": {
{
Name: "user-repo",
BaseURL: "https://example.org/user-repo",
},
},
},
wantChainPkgSets: []chainPackageSet{
{
PackageSet: PackageSet{
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
Repos: []int{0, 1},
},
{
PackageSet: PackageSet{
Include: []string{"pkg3"},
},
Repos: []int{0, 1, 2},
},
{
PackageSet: PackageSet{
Include: []string{"pkg4"},
},
Repos: []int{0, 1, 2},
},
},
wantRepos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
{
Name: "user-repo",
BaseURL: "https://example.org/user-repo",
},
},
},
// 3 transactions + package set specific repo used by 2nd and 3rd transaction
// + 3rd transaction using another repo
{
packageSetsChain: []string{"os", "blueprint", "blueprint2"},
packageSets: map[string]PackageSet{
"os": {
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
"blueprint": {
Include: []string{"pkg3"},
},
"blueprint2": {
Include: []string{"pkg4"},
},
},
repos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
},
packageSetsRepos: map[string][]RepoConfig{
"blueprint": {
{
Name: "user-repo",
BaseURL: "https://example.org/user-repo",
},
},
"blueprint2": {
{
Name: "user-repo",
BaseURL: "https://example.org/user-repo",
},
{
Name: "user-repo-2",
BaseURL: "https://example.org/user-repo-2",
},
},
},
wantChainPkgSets: []chainPackageSet{
{
PackageSet: PackageSet{
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
Repos: []int{0, 1},
},
{
PackageSet: PackageSet{
Include: []string{"pkg3"},
},
Repos: []int{0, 1, 2},
},
{
PackageSet: PackageSet{
Include: []string{"pkg4"},
},
Repos: []int{0, 1, 2, 3},
},
},
wantRepos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
{
Name: "user-repo",
BaseURL: "https://example.org/user-repo",
},
{
Name: "user-repo-2",
BaseURL: "https://example.org/user-repo-2",
},
},
},
// Error: 3 transactions + 3rd one not using repo used by 2nd one
{
packageSetsChain: []string{"os", "blueprint", "blueprint2"},
packageSets: map[string]PackageSet{
"os": {
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
"blueprint": {
Include: []string{"pkg3"},
},
"blueprint2": {
Include: []string{"pkg4"},
},
},
repos: []RepoConfig{
{
Name: "baseos",
BaseURL: "https://example.org/baseos",
},
{
Name: "appstream",
BaseURL: "https://example.org/appstream",
},
},
packageSetsRepos: map[string][]RepoConfig{
"blueprint": {
{
Name: "user-repo",
BaseURL: "https://example.org/user-repo",
},
},
"blueprint2": {
{
Name: "user-repo2",
BaseURL: "https://example.org/user-repo2",
},
},
},
err: true,
},
// Error: requested package set name to chain not defined in provided pkg sets
{
packageSetsChain: []string{"os", "blueprint"},
packageSets: map[string]PackageSet{
"os": {
Include: []string{"pkg1"},
Exclude: []string{"pkg2"},
},
},
err: true,
},
}
for idx, tt := range tests {
t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) {
gotChainPackageSets, gotRepos, err := chainPackageSets(tt.packageSetsChain, tt.packageSets, tt.repos, tt.packageSetsRepos)
if tt.err {
assert.NotNilf(t, err, "expected an error, but got 'nil' instead")
assert.Nilf(t, gotChainPackageSets, "got non-nill []rpmmd.ChainPackageSet, but expected an error")
assert.Nilf(t, gotRepos, "got non-nill []rpmmd.RepoConfig, but expected an error")
} else {
assert.Nilf(t, err, "expected 'nil', but got error instead")
assert.NotNilf(t, gotChainPackageSets, "expected non-nill []rpmmd.ChainPackageSet, but got 'nil' instead")
assert.NotNilf(t, gotRepos, "expected non-nill []rpmmd.RepoConfig, but got 'nil' instead")
assert.Equal(t, tt.wantChainPkgSets, gotChainPackageSets)
assert.Equal(t, tt.wantRepos, gotRepos)
}
})
}
}