Add support for mocking rpmmd

We want to test API methods which calls dnf. Unfortunately, calling dnf
is expensive operation - it requires network access and downloading
a lot of (meta)data. This commit changes the rpmmd implementation
so that it can be mocked.
This commit is contained in:
Ondřej Budai 2019-11-12 20:14:32 +01:00 committed by Tom Gundersen
parent 9970150ed5
commit 495f5b558b
6 changed files with 97 additions and 23 deletions

View file

@ -38,7 +38,9 @@ func main() {
Metalink: "https://mirrors.fedoraproject.org/metalink?repo=fedora-30&arch=x86_64",
}
packages, err := rpmmd.FetchPackageList([]rpmmd.RepoConfig{repo})
rpm := rpmmd.NewRPMMD()
packages, err := rpm.FetchPackageList([]rpmmd.RepoConfig{repo})
if err != nil {
panic(err)
}
@ -56,7 +58,7 @@ func main() {
store := store.New(&stateFile)
jobAPI := jobqueue.New(logger, store)
weldrAPI := weldr.New(repo, packages, logger, store)
weldrAPI := weldr.New(rpm, repo, packages, logger, store)
go jobAPI.Serve(jobListener)
weldrAPI.Serve(weldrListener)

View file

@ -0,0 +1,19 @@
package rpmmd_mock
import (
"github.com/osbuild/osbuild-composer/internal/rpmmd"
)
var BaseFixture = Fixture{
fetchPackageList{
rpmmd.PackageList{
{Name: "package1"},
{Name: "package2"},
},
nil,
},
depsolve{
nil,
nil,
},
}

View file

@ -0,0 +1,33 @@
package rpmmd_mock
import "github.com/osbuild/osbuild-composer/internal/rpmmd"
type fetchPackageList struct {
ret rpmmd.PackageList
err error
}
type depsolve struct {
ret []rpmmd.PackageSpec
err error
}
type Fixture struct {
fetchPackageList
depsolve
}
type rpmmdMock struct {
Fixture Fixture
}
func NewRPMMDMock(fixture Fixture) rpmmd.RPMMD {
return &rpmmdMock{Fixture: fixture}
}
func (r *rpmmdMock) FetchPackageList(repos []rpmmd.RepoConfig) (rpmmd.PackageList, error) {
return r.Fixture.fetchPackageList.ret, r.Fixture.fetchPackageList.err
}
func (r *rpmmdMock) Depsolve(specs []string, repos []rpmmd.RepoConfig) ([]rpmmd.PackageSpec, error) {
return r.Fixture.depsolve.ret, r.Fixture.depsolve.err
}

View file

@ -39,6 +39,11 @@ type PackageSpec struct {
Arch string `json:"arch,omitempty"`
}
type RPMMD interface {
FetchPackageList(repos []RepoConfig) (PackageList, error)
Depsolve(specs []string, repos []RepoConfig) ([]PackageSpec, error)
}
func runDNF(command string, arguments interface{}, result interface{}) error {
var call = struct {
Command string `json:"command"`
@ -80,7 +85,13 @@ func runDNF(command string, arguments interface{}, result interface{}) error {
return cmd.Wait()
}
func FetchPackageList(repos []RepoConfig) (PackageList, error) {
type rpmmdImpl struct{}
func NewRPMMD() RPMMD {
return &rpmmdImpl{}
}
func (*rpmmdImpl) FetchPackageList(repos []RepoConfig) (PackageList, error) {
var arguments = struct {
Repos []RepoConfig `json:"repos"`
}{repos}
@ -92,7 +103,7 @@ func FetchPackageList(repos []RepoConfig) (PackageList, error) {
return packages, err
}
func Depsolve(specs []string, repos []RepoConfig) ([]PackageSpec, error) {
func (*rpmmdImpl) Depsolve(specs []string, repos []RepoConfig) ([]PackageSpec, error) {
var arguments = struct {
PackageSpecs []string `json:"package-specs"`
Repos []RepoConfig `json:"repos"`

View file

@ -24,6 +24,7 @@ import (
type API struct {
store *store.Store
rpmmd rpmmd.RPMMD
repo rpmmd.RepoConfig
packages rpmmd.PackageList
@ -31,11 +32,12 @@ type API struct {
router *httprouter.Router
}
func New(repo rpmmd.RepoConfig, packages rpmmd.PackageList, logger *log.Logger, store *store.Store) *API {
func New(rpmmd rpmmd.RPMMD, repo rpmmd.RepoConfig, packages rpmmd.PackageList, logger *log.Logger, store *store.Store) *API {
// This needs to be shared with the worker API so that they can communicate with each other
// builds := make(chan queue.Build, 200)
api := &API{
store: store,
rpmmd: rpmmd,
repo: repo,
packages: packages,
logger: logger,
@ -467,7 +469,7 @@ func (api *API) modulesInfoHandler(writer http.ResponseWriter, request *http.Req
}
if modulesRequested {
project.Dependencies, _ = rpmmd.Depsolve([]string{pkg.Name}, []rpmmd.RepoConfig{api.repo})
project.Dependencies, _ = api.rpmmd.Depsolve([]string{pkg.Name}, []rpmmd.RepoConfig{api.repo})
}
projects = append(projects, project)
@ -610,7 +612,7 @@ func (api *API) blueprintsDepsolveHandler(writer http.ResponseWriter, request *h
specs[i] += "-*-*.*"
}
}
dependencies, _ := rpmmd.Depsolve(specs, []rpmmd.RepoConfig{api.repo})
dependencies, _ := api.rpmmd.Depsolve(specs, []rpmmd.RepoConfig{api.repo})
blueprints = append(blueprints, entry{blueprint, dependencies})
}

View file

@ -16,6 +16,7 @@ import (
"testing"
"time"
"github.com/osbuild/osbuild-composer/internal/mocks/rpmmd"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/store"
"github.com/osbuild/osbuild-composer/internal/weldr"
@ -27,11 +28,6 @@ var repo = rpmmd.RepoConfig{
BaseURL: "http://example.com/test/os",
}
var packages = rpmmd.PackageList{
{Name: "package1"},
{Name: "package2"},
}
func externalRequest(method, path, body string) *http.Response {
client := http.Client{
Transport: &http.Transport{
@ -161,6 +157,18 @@ func testRoute(t *testing.T, api *weldr.API, external bool, method, path, body s
}
}
func createWeldrAPI(fixture rpmmd_mock.Fixture) (*weldr.API, *store.Store) {
s := store.New(nil)
rpm := rpmmd_mock.NewRPMMDMock(fixture)
packageList, err := rpm.FetchPackageList([]rpmmd.RepoConfig{repo})
if err != nil {
panic(err)
}
return weldr.New(rpm, repo, packageList, nil, s), s
}
func TestBasic(t *testing.T) {
var cases = []struct {
Path string
@ -197,7 +205,7 @@ func TestBasic(t *testing.T) {
}
for _, c := range cases {
api := weldr.New(repo, packages, nil, store.New(nil))
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
testRoute(t, api, true, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedJSON)
}
}
@ -214,7 +222,7 @@ func TestBlueprintsNew(t *testing.T) {
}
for _, c := range cases {
api := weldr.New(repo, packages, nil, store.New(nil))
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
testRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
}
}
@ -231,7 +239,7 @@ func TestBlueprintsWorkspace(t *testing.T) {
}
for _, c := range cases {
api := weldr.New(repo, packages, nil, store.New(nil))
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
sendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
testRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
}
@ -252,7 +260,7 @@ func TestBlueprintsInfo(t *testing.T) {
}
for _, c := range cases {
api := weldr.New(repo, packages, nil, store.New(nil))
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
sendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"test1","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
sendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"test2","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
sendHTTP(api, true, "POST", "/api/v0/blueprints/workspace", `{"name":"test2","description":"Test","packages":[{"name":"systemd","version":"123"}],"version":"0.0.0"}`)
@ -274,7 +282,7 @@ func TestBlueprintsDiff(t *testing.T) {
}
for _, c := range cases {
api := weldr.New(repo, packages, nil, store.New(nil))
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
sendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
sendHTTP(api, true, "POST", "/api/v0/blueprints/workspace", `{"name":"test","description":"Test","packages":[{"name":"systemd","version":"123"}],"version":"0.0.0"}`)
testRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
@ -294,7 +302,7 @@ func TestBlueprintsDelete(t *testing.T) {
}
for _, c := range cases {
api := weldr.New(repo, packages, nil, store.New(nil))
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
sendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
testRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
sendHTTP(api, true, "DELETE", "/api/v0/blueprints/delete/test", ``)
@ -331,7 +339,7 @@ func TestCompose(t *testing.T) {
}
for _, c := range cases {
api := weldr.New(repo, packages, nil, store.New(nil))
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
sendHTTP(api, c.External, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
testRoute(t, api, c.External, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON, c.IgnoreFields...)
sendHTTP(api, c.External, "DELETE", "/api/v0/blueprints/delete/test", ``)
@ -355,8 +363,7 @@ func TestComposeQueue(t *testing.T) {
}
for _, c := range cases {
s := store.New(nil)
api := weldr.New(repo, packages, nil, s)
api, s := createWeldrAPI(rpmmd_mock.BaseFixture)
sendHTTP(api, false, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
// create job and leave it waiting
sendHTTP(api, false, "POST", "/api/v0/compose", `{"blueprint_name": "test","compose_type": "tar","branch": "master"}`)
@ -390,7 +397,7 @@ func TestSourcesNew(t *testing.T) {
}
for _, c := range cases {
api := weldr.New(repo, packages, nil, store.New(nil))
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
testRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
sendHTTP(api, true, "DELETE", "/api/v0/projects/source/delete/fish", ``)
}
@ -409,7 +416,7 @@ func TestSourcesDelete(t *testing.T) {
}
for _, c := range cases {
api := weldr.New(repo, packages, nil, store.New(nil))
api, _ := createWeldrAPI(rpmmd_mock.BaseFixture)
sendHTTP(api, true, "POST", "/api/v0/projects/source/new", `{"name": "fish","url": "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","type": "yum-baseurl","check_ssl": false,"check_gpg": false}`)
testRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
sendHTTP(api, true, "DELETE", "/api/v0/projects/source/delete/fish", ``)