Skip to content

Commit 915c41e

Browse files
cmd/image-builder: add mockable pkgSearcher and command tests
Extract the solver call into a pkgSearcher variable so tests can replace it with a fake. Add table-driven integration tests covering the full command flow with and without --type, error cases for invalid distro/type/format.
1 parent a465005 commit 915c41e

3 files changed

Lines changed: 124 additions & 2 deletions

File tree

cmd/image-builder/export_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import (
88
"github.com/osbuild/image-builder/pkg/bootc"
99
"github.com/osbuild/image-builder/pkg/cloud"
1010
"github.com/osbuild/image-builder/pkg/cloud/awscloud"
11+
"github.com/osbuild/image-builder/pkg/distro"
1112
"github.com/osbuild/image-builder/pkg/manifestgen"
1213
"github.com/osbuild/image-builder/pkg/reporegistry"
14+
"github.com/osbuild/image-builder/pkg/rpmmd"
1315
)
1416

1517
var (
@@ -110,3 +112,11 @@ func MockManifestgenDepsolver(new manifestgen.DepsolveFunc) (restore func()) {
110112
manifestgenDepsolver = saved
111113
}
112114
}
115+
116+
func MockPkgSearcher(f func(distro.Distro, string, string, []rpmmd.RepoConfig, []string) (rpmmd.PackageList, error)) (restore func()) {
117+
saved := pkgSearcher
118+
pkgSearcher = f
119+
return func() {
120+
pkgSearcher = saved
121+
}
122+
}

cmd/image-builder/pkgsearch.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ func (*jsonPkgFormatter) Output(w io.Writer, pkgs rpmmd.PackageList) error {
5656
return enc.Encode(result)
5757
}
5858

59+
// pkgSearcher performs the actual package search. It is a variable so
60+
// tests can replace it with a fake that doesn't require osbuild-depsolve-dnf.
61+
var pkgSearcher = func(d distro.Distro, archStr, cacheDir string, repos []rpmmd.RepoConfig, packages []string) (rpmmd.PackageList, error) {
62+
solver := depsolvednf.NewSolver(d.ModulePlatformID(), d.Releasever(), archStr, d.Name(), cacheDir)
63+
return solver.SearchMetadata(repos, packages)
64+
}
65+
5966
func cmdPkgSearch(cmd *cobra.Command, args []string) error {
6067
format, err := cmd.Flags().GetString("format")
6168
if err != nil {
@@ -144,8 +151,7 @@ func cmdPkgSearch(cmd *cobra.Command, args []string) error {
144151
if cacheDir == "" {
145152
cacheDir = defaultCacheDir()
146153
}
147-
solver := depsolvednf.NewSolver(d.ModulePlatformID(), d.Releasever(), archString, d.Name(), cacheDir)
148-
results, err := solver.SearchMetadata(searchRepos, args)
154+
results, err := pkgSearcher(d, archString, cacheDir, searchRepos, args)
149155
if err != nil {
150156
return err
151157
}

cmd/image-builder/pkgsearch_test.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import (
88
"github.com/stretchr/testify/assert"
99
"github.com/stretchr/testify/require"
1010

11+
"github.com/osbuild/image-builder/pkg/distro"
1112
"github.com/osbuild/image-builder/pkg/rpmmd"
13+
testrepos "github.com/osbuild/image-builder/test/data/repositories"
1214

1315
main "github.com/osbuild/image-builder/cmd/image-builder"
1416
)
@@ -46,6 +48,110 @@ func TestNewPkgSearchFormatter(t *testing.T) {
4648
}
4749
}
4850

51+
var lastCapturedCacheDir string
52+
53+
func fakePkgSearcher(_ distro.Distro, _, cacheDir string, _ []rpmmd.RepoConfig, _ []string) (rpmmd.PackageList, error) {
54+
lastCapturedCacheDir = cacheDir
55+
return rpmmd.PackageList{
56+
{Name: "bash", Version: "5.1.8", Release: "2.el9", Arch: "x86_64"},
57+
{Name: "zsh", Version: "5.8", Release: "7.el9", Arch: "x86_64"},
58+
}, nil
59+
}
60+
61+
func TestCmdPkgSearch(t *testing.T) {
62+
restorePkgSearcher := main.MockPkgSearcher(fakePkgSearcher)
63+
defer restorePkgSearcher()
64+
65+
restoreRepoRegistry := main.MockNewRepoRegistry(testrepos.New)
66+
defer restoreRepoRegistry()
67+
68+
for _, tc := range []struct {
69+
name string
70+
args []string
71+
expectedPkgs int
72+
expectedErr string
73+
expectedCacheDir string
74+
}{
75+
{
76+
name: "with type",
77+
args: []string{"pkgsearch", "bash", "--distro=centos-9", "--arch=x86_64", "--type=qcow2"},
78+
expectedPkgs: 2,
79+
},
80+
{
81+
name: "without type",
82+
args: []string{"pkgsearch", "bash", "--distro=centos-9", "--arch=x86_64"},
83+
expectedPkgs: 2,
84+
},
85+
{
86+
name: "with json format",
87+
args: []string{"pkgsearch", "bash", "--distro=centos-9", "--arch=x86_64", "--format=json"},
88+
expectedPkgs: 2,
89+
},
90+
{
91+
name: "multiple packages",
92+
args: []string{"pkgsearch", "bash", "zsh", "--distro=centos-9", "--arch=x86_64"},
93+
expectedPkgs: 2,
94+
},
95+
{
96+
name: "unsupported format",
97+
args: []string{"pkgsearch", "bash", "--distro=centos-9", "--arch=x86_64", "--format=text"},
98+
expectedErr: "unsupported",
99+
},
100+
{
101+
name: "invalid distro",
102+
args: []string{"pkgsearch", "bash", "--distro=not-a-distro", "--arch=x86_64"},
103+
expectedErr: "not-a-distro",
104+
},
105+
{
106+
name: "invalid type",
107+
args: []string{"pkgsearch", "bash", "--distro=centos-9", "--arch=x86_64", "--type=not-a-type"},
108+
expectedErr: "not-a-type",
109+
},
110+
{
111+
name: "zero args (no packages)",
112+
args: []string{"pkgsearch", "--distro=centos-9", "--arch=x86_64"},
113+
expectedPkgs: 2,
114+
},
115+
{
116+
name: "with rpmmd-cache",
117+
args: []string{"pkgsearch", "bash", "--distro=centos-9", "--arch=x86_64", "--rpmmd-cache=/tmp/test-cache"},
118+
expectedPkgs: 2,
119+
expectedCacheDir: "/tmp/test-cache",
120+
},
121+
} {
122+
t.Run(tc.name, func(t *testing.T) {
123+
restore := main.MockOsArgs(tc.args)
124+
defer restore()
125+
126+
var fakeStdout bytes.Buffer
127+
restore = main.MockOsStdout(&fakeStdout)
128+
defer restore()
129+
130+
err := main.Run()
131+
if tc.expectedErr != "" {
132+
require.Error(t, err)
133+
assert.ErrorContains(t, err, tc.expectedErr)
134+
return
135+
}
136+
137+
require.NoError(t, err)
138+
139+
var result struct {
140+
Packages []struct {
141+
Name string `json:"name"`
142+
} `json:"packages"`
143+
}
144+
err = json.Unmarshal(fakeStdout.Bytes(), &result)
145+
require.NoError(t, err)
146+
assert.Len(t, result.Packages, tc.expectedPkgs)
147+
148+
if tc.expectedCacheDir != "" {
149+
assert.Equal(t, tc.expectedCacheDir, lastCapturedCacheDir)
150+
}
151+
})
152+
}
153+
}
154+
49155
func TestPkgSearchFormatterJSONOutput(t *testing.T) {
50156
for _, tc := range []struct {
51157
name string

0 commit comments

Comments
 (0)