debian-forge-composer/internal/weldr/api_test.go
Gianluca Zuccarelli 4d42808b6a internal/rpmmd: RepoConfig baseurl change
Update the internal RepoConfig object to
accept a slice of baseurls rather than a
single field. This change was needed to
align RepoConfig with the dnf spec [1].

Additionally, this change adds custom json
marshal and unmarshal functions to ensure
backwards compatibility with older workers.
Add json tags to the internal rpmmd config
since this is serialized in dnfjson.
Add unit tests to check the serialization
is okay.

[1] See dnf.config
2023-04-21 17:40:00 +02:00

2230 lines
103 KiB
Go

package weldr
import (
"archive/tar"
"bytes"
"encoding/json"
"fmt"
"io"
"math/rand"
"net/http"
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"strconv"
"testing"
"time"
"github.com/osbuild/osbuild-composer/internal/blueprint"
"github.com/osbuild/osbuild-composer/internal/common"
"github.com/osbuild/osbuild-composer/internal/distro"
"github.com/osbuild/osbuild-composer/internal/distro/test_distro"
"github.com/osbuild/osbuild-composer/internal/distroregistry"
"github.com/osbuild/osbuild-composer/internal/dnfjson"
dnfjson_mock "github.com/osbuild/osbuild-composer/internal/mocks/dnfjson"
rpmmd_mock "github.com/osbuild/osbuild-composer/internal/mocks/rpmmd"
"github.com/osbuild/osbuild-composer/internal/ostree/mock_ostree_repo"
"github.com/osbuild/osbuild-composer/internal/reporegistry"
"github.com/osbuild/osbuild-composer/internal/rpmmd"
"github.com/osbuild/osbuild-composer/internal/store"
"github.com/osbuild/osbuild-composer/internal/target"
"github.com/osbuild/osbuild-composer/internal/test"
"github.com/BurntSushi/toml"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
)
var dnfjsonPath string
func setupDNFJSON() {
// compile the mock-dnf-json binary to speed up tests
tmpdir, err := os.MkdirTemp("", "")
if err != nil {
panic(err)
}
dnfjsonPath = filepath.Join(tmpdir, "mock-dnf-json")
cmd := exec.Command("go", "build", "-o", dnfjsonPath, "../../cmd/mock-dnf-json")
if err := cmd.Run(); err != nil {
panic(err)
}
}
func createWeldrAPI(tempdir string, fixtureGenerator rpmmd_mock.FixtureGenerator) (*API, *store.Store) {
// create tempdir subdirectory for store
dbpath, err := os.MkdirTemp(tempdir, "")
if err != nil {
panic(err)
}
fixture := fixtureGenerator(dbpath)
rr := reporegistry.NewFromDistrosRepoConfigs(rpmmd.DistrosRepoConfigs{
test_distro.TestDistroName: {
test_distro.TestArchName: {
{Name: "test-id", BaseURLs: []string{"http://example.com/test/os/x86_64"}, CheckGPG: true},
},
},
test_distro.TestDistro2Name: {
test_distro.TestArchName: {
{Name: "test-id-2", BaseURLs: []string{"http://example.com/test-2/os/x86_64"}, CheckGPG: true},
},
},
})
distro1 := test_distro.New()
arch, err := distro1.GetArch(test_distro.TestArchName)
if err != nil {
panic(err)
}
distro2 := test_distro.New2()
dr, err := distroregistry.New(distro1, distro1, distro2)
if err != nil {
panic(err)
}
solver := dnfjson.NewBaseSolver("") // test solver doesn't need a cache dir
// create tempdir subdirectory for solver response file
dspath, err := os.MkdirTemp(tempdir, "")
if err != nil {
panic(err)
}
respfile := fixture.ResponseGenerator(dspath)
solver.SetDNFJSONPath(dnfjsonPath, respfile)
testApi := NewTestAPI(solver, arch, dr, rr, nil, fixture.Store, fixture.Workers, "", nil)
return testApi, fixture.Store
}
// createWeldrAPI2 is an alternative function to createWeldrAPI, using different test architecture
// with more than a single image type
func createWeldrAPI2(tempdir string, fixtureGenerator rpmmd_mock.FixtureGenerator, distroImageTypeDenylist map[string][]string) (*API, *store.Store) {
// create tempdir subdirectory for store
dbpath, err := os.MkdirTemp(tempdir, "")
if err != nil {
panic(err)
}
fixture := fixtureGenerator(dbpath)
rr := reporegistry.NewFromDistrosRepoConfigs(rpmmd.DistrosRepoConfigs{
test_distro.TestDistroName: {
test_distro.TestArch2Name: {
{Name: "test-id", BaseURLs: []string{"http://example.com/test/os/x86_64"}, CheckGPG: true},
},
},
test_distro.TestDistro2Name: {
test_distro.TestArch2Name: {
{Name: "test-id-2", BaseURLs: []string{"http://example.com/test-2/os/x86_64"}, CheckGPG: true},
},
},
})
distro1 := test_distro.New()
arch, err := distro1.GetArch(test_distro.TestArch2Name)
if err != nil {
panic(err)
}
distro2 := test_distro.New2()
dr, err := distroregistry.New(distro1, distro2)
if err != nil {
panic(err)
}
// create tempdir subdirectory for solver response file
dspath, err := os.MkdirTemp(tempdir, "")
if err != nil {
panic(err)
}
solver := dnfjson.NewBaseSolver("")
respfile := fixture.ResponseGenerator(dspath)
solver.SetDNFJSONPath(dnfjsonPath, respfile)
return NewTestAPI(solver, arch, dr, rr, nil, fixture.Store, fixture.Workers, "", distroImageTypeDenylist), fixture.Store
}
func TestBasic(t *testing.T) {
var cases = []struct {
Path string
ExpectedStatus int
ExpectedJSON string
}{
{"/api/status", http.StatusOK, `{"api":"1","db_supported":true,"db_version":"0","schema_version":"0","backend":"osbuild-composer","build":"devel","msgs":[]}`},
{"/api/v0/projects/source/list", http.StatusOK, `{"sources":["test-id"]}`},
{"/api/v0/projects/source/info", http.StatusNotFound, `{"errors":[{"code":404,"id":"HTTPError","msg":"Not Found"}],"status":false}`},
{"/api/v0/projects/source/info/", http.StatusNotFound, `{"errors":[{"code":404,"id":"HTTPError","msg":"Not Found"}],"status":false}`},
{"/api/v0/projects/source/info/foo", http.StatusOK, `{"errors":[{"id":"UnknownSource","msg":"foo is not a valid source"}],"sources":{}}`},
{"/api/v0/projects/source/info/test-id", http.StatusOK, `{"sources":{"test-id":{"name":"test-id","type":"yum-baseurl","url":"http://example.com/test/os/x86_64","check_gpg":true,"check_ssl":true,"system":true}},"errors":[]}`},
{"/api/v0/projects/source/info/*", http.StatusOK, `{"sources":{"test-id":{"name":"test-id","type":"yum-baseurl","url":"http://example.com/test/os/x86_64","check_gpg":true,"check_ssl":true,"system":true}},"errors":[]}`},
{"/api/v0/blueprints/list", http.StatusOK, `{"total":1,"offset":0,"limit":1,"blueprints":["test"]}`},
{"/api/v0/blueprints/info/", http.StatusNotFound, `{"errors":[{"code":404,"id":"HTTPError","msg":"Not Found"}],"status":false}`},
{"/api/v0/blueprints/info/foo", http.StatusOK, `{"blueprints":[],"changes":[],"errors":[{"id":"UnknownBlueprint","msg":"foo: "}]}`},
{"/api/v1/distros/list", http.StatusOK, `{"distros": ["test-distro", "test-distro-2"]}`},
{"/api/v1/compose/types", http.StatusOK, `{"types": [{"enabled":true, "name":"test_ostree_type"},{"enabled":true, "name":"test_type"}]}`},
{"/api/v1/compose/types?distro=test-distro-2", http.StatusOK, `{"types": [{"enabled":true, "name":"test_ostree_type"},{"enabled":true, "name":"test_type"}]}`},
{"/api/v1/compose/types?distro=fedora-1", http.StatusBadRequest, `{"status":false,"errors":[{"id":"DistroError","msg":"Invalid distro: fedora-1"}]}`},
}
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
for _, c := range cases {
test.TestRoute(t, api, true, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedJSON)
}
}
func TestBlueprintsNew(t *testing.T) {
var cases = []struct {
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{"POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[],"version":""}`, http.StatusOK, `{"status":true}`},
{"POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`, http.StatusOK, `{"status":true}`},
{"POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages:}`, http.StatusBadRequest, `{"status":false,"errors":[{"id":"BlueprintsError","msg":"400 Bad Request: The browser (or proxy) sent a request that this server could not understand: unexpected EOF"}]}`},
{"POST", "/api/v0/blueprints/new", `{"name":"","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`, http.StatusBadRequest, `{"status":false,"errors":[{"id":"InvalidChars","msg":"Invalid characters in API path"}]}`},
{"POST", "/api/v0/blueprints/new", ``, http.StatusBadRequest, `{"status":false,"errors":[{"id":"BlueprintsError","msg":"Missing blueprint"}]}`},
{"POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","distro":"test-distro","packages":[],"version":""}`, http.StatusOK, `{"status":true}`},
{"POST", "/api/v0/blueprints/new", `{"name":"test2","description":"Test 2","distro":"test-distro-2","packages":[],"version":""}`, http.StatusOK, `{"status":true}`},
{"POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","distro":"fedora-1","packages":[],"version":""}`, http.StatusBadRequest, `{"status":false,"errors":[{"id":"BlueprintsError","msg":"'fedora-1' is not a valid distribution"}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.TestRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
}
}
func TestBlueprintsNewToml(t *testing.T) {
blueprint := `
name = "test"
description = "Test"
version = "0.0.0"
[[packages]]
name = "httpd"
version = "2.4.*"`
req := httptest.NewRequest("POST", "/api/v0/blueprints/new", bytes.NewReader([]byte(blueprint)))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusOK, r.StatusCode)
}
func TestBlueprintsEmptyToml(t *testing.T) {
req := httptest.NewRequest("POST", "/api/v0/blueprints/new", bytes.NewReader(nil))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusBadRequest, r.StatusCode)
}
func TestBlueprintsInvalidToml(t *testing.T) {
blueprint := `
name = "test"
description = "Test"
version = "0.0.0"
[[packages
name = "httpd"
version = "2.4.*"`
req := httptest.NewRequest("POST", "/api/v0/blueprints/new", bytes.NewReader([]byte(blueprint)))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusBadRequest, r.StatusCode)
}
func TestBlueprintsWorkspaceJSON(t *testing.T) {
var cases = []struct {
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{"POST", "/api/v0/blueprints/workspace", `{"name":"test","description":"Test","packages":[{"name":"systemd","version":"123"}],"version":"0.0.0"}`, http.StatusOK, `{"status":true}`},
{"POST", "/api/v0/blueprints/workspace", `{"name":"test","description":"Test","packages:}`, http.StatusBadRequest, `{"status":false,"errors":[{"id":"BlueprintsError","msg":"400 Bad Request: The browser (or proxy) sent a request that this server could not understand: unexpected EOF"}]}`},
{"POST", "/api/v0/blueprints/workspace", ``, http.StatusBadRequest, `{"status":false,"errors":[{"id":"BlueprintsError","msg":"Missing blueprint"}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.TestRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
}
}
func TestBlueprintsWorkspaceTOML(t *testing.T) {
blueprint := `
name = "test"
description = "Test"
version = "0.0.0"
[[packages]]
name = "httpd"
version = "2.4.*"`
req := httptest.NewRequest("POST", "/api/v0/blueprints/workspace", bytes.NewReader([]byte(blueprint)))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusOK, r.StatusCode)
}
func TestBlueprintsWorkspaceEmptyTOML(t *testing.T) {
req := httptest.NewRequest("POST", "/api/v0/blueprints/workspace", bytes.NewReader(nil))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusBadRequest, r.StatusCode)
}
func TestBlueprintsWorkspaceInvalidTOML(t *testing.T) {
blueprint := `
name = "test"
description = "Test"
version = "0.0.0"
[[packages
name = "httpd"
version = "2.4.*"`
req := httptest.NewRequest("POST", "/api/v0/blueprints/workspace", bytes.NewReader([]byte(blueprint)))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusBadRequest, r.StatusCode)
}
func TestBlueprintsInfo(t *testing.T) {
var cases = []struct {
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{"GET", "/api/v0/blueprints/info/test1", ``, http.StatusOK, `{"blueprints":[{"name":"test1","description":"Test","distro":"","modules":[],"packages":[{"name":"httpd","version":"2.4.*"}],"groups":[],"version":"0.0.0"}],
"changes":[{"name":"test1","changed":false}], "errors":[]}`},
{"GET", "/api/v0/blueprints/info/test2", ``, http.StatusOK, `{"blueprints":[{"name":"test2","description":"Test","distro":"","modules":[],"packages":[{"name":"systemd","version":"123"}],"groups":[],"version":"0.0.0"}],
"changes":[{"name":"test2","changed":true}], "errors":[]}`},
{"GET", "/api/v0/blueprints/info/test3-non", ``, http.StatusOK, `{"blueprints":[],"changes":[],"errors":[{"id":"UnknownBlueprint","msg":"test3-non: "}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"test1","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"test2","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/workspace", `{"name":"test2","description":"Test","packages":[{"name":"systemd","version":"123"}],"version":"0.0.0"}`)
test.TestRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
test.SendHTTP(api, true, "DELETE", "/api/v0/blueprints/delete/test2", ``)
test.SendHTTP(api, true, "DELETE", "/api/v0/blueprints/delete/test1", ``)
}
}
func TestBlueprintsInfoToml(t *testing.T) {
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"test1","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
req := httptest.NewRequest("GET", "/api/v0/blueprints/info/test1?format=toml", nil)
recorder := httptest.NewRecorder()
api.ServeHTTP(recorder, req)
resp := recorder.Result()
require.Equal(t, http.StatusOK, resp.StatusCode)
var got blueprint.Blueprint
_, err := toml.NewDecoder(resp.Body).Decode(&got)
require.NoErrorf(t, err, "error decoding toml file")
expected := blueprint.Blueprint{
Name: "test1",
Description: "Test",
Version: "0.0.0",
Distro: "",
Packages: []blueprint.Package{
{
Name: "httpd",
Version: "2.4.*"},
},
Groups: []blueprint.Group{},
Modules: []blueprint.Package{},
}
require.Equalf(t, expected, got, "received unexpected blueprint")
}
func TestBlueprintsCustomizationInfoToml(t *testing.T) {
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
// A test blueprint with all the available customizations filled in
// Converted from TOML to JSON for the POST
testBlueprint := `{
"name": "example-custom-base",
"description": "A base system with customizations",
"version": "0.0.1",
"distro": "test-distro",
"packages": [
{
"name": "tmux",
"version": "*"
},
{
"name": "git",
"version": "*"
},
{
"name": "vim-enhanced",
"version": "*"
}
],
"containers": [
{
"source": "quay.io/fedora/fedora:latest"
}
],
"customizations": {
"hostname": "custombase",
"kernel": {
"append": "nosmt=force"
},
"timezone": {
"timezone": "US/Eastern",
"ntpservers": [
"0.north-america.pool.ntp.org",
"1.north-america.pool.ntp.org"
]
},
"locale": {
"languages": [
"en_US.UTF-8"
],
"keyboard": "us"
},
"sshkey": [
{
"user": "root",
"key": "A SSH KEY FOR ROOT"
}
],
"firewall": {
"ports": [
"22:tcp",
"80:tcp",
"imap:tcp",
"53:tcp",
"53:udp"
],
"services": {
"enabled": [
"ftp",
"ntp",
"dhcp"
],
"disabled": [
"telnet"
]
}
},
"services": {
"enabled": [
"sshd",
"cockpit.socket",
"httpd"
],
"disabled": [
"postfix",
"telnetd"
]
},
"user": [
{
"name": "admin",
"description": "Widget admin account",
"password": "$6$CHO2$3rN8eviE2t50lmVyBYihTgVRHcaecmeCk31LeOUleVK/R/aeWVHVZDi26zAH.o0ywBKH9Tc0/wm7sW/q39uyd1",
"home": "/srv/widget/",
"shell": "/usr/bin/bash",
"groups": [
"widget",
"users",
"students"
],
"uid": 1200
}
],
"group": [
{
"name": "widget"
},
{
"name": "students"
}
],
"filesystem": [
{
"mountpoint": "/",
"minsize": 2147483648
}
],
"openscap": {
"datastream": "/usr/share/xml/scap/ssg/content/ssg-rhel8-ds.xml",
"profile_id": "xccdf_org.ssgproject.content_profile_cis"
}
}
}`
resp := test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", testBlueprint)
body, err := io.ReadAll(resp.Body)
require.Nil(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode, string(body))
req := httptest.NewRequest("GET", "/api/v0/blueprints/info/example-custom-base?format=toml", nil)
recorder := httptest.NewRecorder()
api.ServeHTTP(recorder, req)
resp = recorder.Result()
body, err = io.ReadAll(resp.Body)
require.Nil(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode, string(body))
var got blueprint.Blueprint
err = toml.Unmarshal(body, &got)
require.NoErrorf(t, err, "error decoding toml file")
expected := blueprint.Blueprint{
Name: "example-custom-base",
Description: "A base system with customizations",
Version: "0.0.1",
Distro: "test-distro",
Packages: []blueprint.Package{
blueprint.Package{Name: "tmux", Version: "*"},
blueprint.Package{Name: "git", Version: "*"},
blueprint.Package{Name: "vim-enhanced", Version: "*"},
},
Modules: []blueprint.Package{},
Groups: []blueprint.Group{},
Containers: []blueprint.Container{
blueprint.Container{
Source: "quay.io/fedora/fedora:latest",
},
},
Customizations: &blueprint.Customizations{
Hostname: common.ToPtr("custombase"),
Kernel: &blueprint.KernelCustomization{
Append: "nosmt=force",
},
SSHKey: []blueprint.SSHKeyCustomization{
blueprint.SSHKeyCustomization{User: "root", Key: "A SSH KEY FOR ROOT"},
},
User: []blueprint.UserCustomization{
blueprint.UserCustomization{
Name: "admin",
Description: common.ToPtr("Widget admin account"),
Password: common.ToPtr("$6$CHO2$3rN8eviE2t50lmVyBYihTgVRHcaecmeCk31LeOUleVK/R/aeWVHVZDi26zAH.o0ywBKH9Tc0/wm7sW/q39uyd1"),
Home: common.ToPtr("/srv/widget/"),
Shell: common.ToPtr("/usr/bin/bash"),
Groups: []string{"widget", "users", "students"},
UID: common.ToPtr(1200),
},
},
Group: []blueprint.GroupCustomization{
blueprint.GroupCustomization{
Name: "widget",
},
blueprint.GroupCustomization{
Name: "students",
},
},
Timezone: &blueprint.TimezoneCustomization{
Timezone: common.ToPtr("US/Eastern"),
NTPServers: []string{"0.north-america.pool.ntp.org", "1.north-america.pool.ntp.org"},
},
Locale: &blueprint.LocaleCustomization{
Languages: []string{"en_US.UTF-8"},
Keyboard: common.ToPtr("us"),
},
Firewall: &blueprint.FirewallCustomization{
Ports: []string{"22:tcp", "80:tcp", "imap:tcp", "53:tcp", "53:udp"},
Services: &blueprint.FirewallServicesCustomization{
Enabled: []string{"ftp", "ntp", "dhcp"},
Disabled: []string{"telnet"},
},
},
Services: &blueprint.ServicesCustomization{
Enabled: []string{"sshd", "cockpit.socket", "httpd"},
Disabled: []string{"postfix", "telnetd"},
},
Filesystem: []blueprint.FilesystemCustomization{
blueprint.FilesystemCustomization{
Mountpoint: "/",
MinSize: 2147483648,
},
},
OpenSCAP: &blueprint.OpenSCAPCustomization{
DataStream: "/usr/share/xml/scap/ssg/content/ssg-rhel8-ds.xml",
ProfileID: "xccdf_org.ssgproject.content_profile_cis",
},
},
}
require.Equalf(t, expected, got, string(body))
}
func TestNonExistentBlueprintsInfoToml(t *testing.T) {
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
req := httptest.NewRequest("GET", "/api/v0/blueprints/info/test3-non?format=toml", nil)
recorder := httptest.NewRecorder()
api.ServeHTTP(recorder, req)
resp := recorder.Result()
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
}
func TestSetPkgEVRA(t *testing.T) {
// Sorted list of dependencies
deps := []rpmmd.PackageSpec{
{
Name: "dep-package1",
Epoch: 0,
Version: "1.33",
Release: "2.fc30",
Arch: "x86_64",
},
{
Name: "dep-package2",
Epoch: 0,
Version: "2.9",
Release: "1.fc30",
Arch: "x86_64",
},
{
Name: "dep-package3",
Epoch: 7,
Version: "3.0.3",
Release: "1.fc30",
Arch: "x86_64",
},
}
pkgs := []blueprint.Package{
{Name: "dep-package1", Version: "*"},
{Name: "dep-package2", Version: "*"},
}
// Replace globs with dependencies
err := setPkgEVRA(deps, pkgs)
require.NoErrorf(t, err, "setPkgEVRA failed")
require.Equalf(t, "1.33-2.fc30.x86_64", pkgs[0].Version, "setPkgEVRA Unexpected pkg version")
require.Equalf(t, "2.9-1.fc30.x86_64", pkgs[1].Version, "setPkgEVRA Unexpected pkg version")
// Test that a missing package in deps returns an error
pkgs = []blueprint.Package{
{Name: "dep-package1", Version: "*"},
{Name: "dep-package0", Version: "*"},
}
err = setPkgEVRA(deps, pkgs)
require.EqualErrorf(t, err, "dep-package0 missing from depsolve results", "setPkgEVRA missing package failed to return error")
}
func TestBlueprintsFreeze(t *testing.T) {
t.Run("json", func(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Path string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "/api/v0/blueprints/freeze/test,test2", http.StatusOK, freezeTestResponse},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.SendHTTP(api, false, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"dep-package1","version":"*"},{"name":"dep-package3","version":"*"}], "modules":[{"name":"dep-package2","version":"*"}],"version":"0.0.0"}`)
test.SendHTTP(api, false, "POST", "/api/v0/blueprints/new", `{"name":"test2","description":"Test","packages":[{"name":"dep-package1","version":"*"},{"name":"dep-package3","version":"*"}], "modules":[{"name":"dep-package2","version":"*"}],"version":"0.0.0"}`)
test.TestRoute(t, api, false, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedJSON)
}
})
t.Run("toml", func(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Path string
ExpectedStatus int
ExpectedTOML string
}{
{rpmmd_mock.BaseFixture, "/api/v0/blueprints/freeze/test?format=toml", http.StatusOK, "name=\"test\"\n description=\"Test\"\n distro=\"\"\n version=\"0.0.1\"\n groups = []\n [[packages]]\n name=\"dep-package1\"\n version=\"1.33-2.fc30.x86_64\"\n [[packages]]\n name=\"dep-package3\"\n version=\"7:3.0.3-1.fc30.x86_64\"\n [[modules]]\n name=\"dep-package2\"\n version=\"2.9-1.fc30.x86_64\""},
{rpmmd_mock.BaseFixture, "/api/v0/blueprints/freeze/missing?format=toml", http.StatusOK, ""},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.SendHTTP(api, false, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"dep-package1","version":"*"},{"name":"dep-package3","version":"*"}], "modules":[{"name":"dep-package2","version":"*"}],"version":"0.0.0"}`)
test.TestTOMLRoute(t, api, false, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedTOML)
}
})
t.Run("toml-multiple", func(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Path string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "/api/v0/blueprints/freeze/test,test2?format=toml", http.StatusBadRequest, "{\"status\":false,\"errors\":[{\"id\":\"HTTPError\",\"msg\":\"toml format only supported when requesting one blueprint\"}]}"},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.SendHTTP(api, false, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"dep-package1","version":"*"},{"name":"dep-package3","version":"*"}], "modules":[{"name":"dep-package2","version":"*"}],"version":"0.0.0"}`)
test.SendHTTP(api, false, "POST", "/api/v0/blueprints/new", `{"name":"test2","description":"Test","packages":[{"name":"dep-package1","version":"*"},{"name":"dep-package3","version":"*"}], "modules":[{"name":"dep-package2","version":"*"}],"version":"0.0.0"}`)
test.TestRoute(t, api, false, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedJSON)
}
})
}
func TestBlueprintsDiff(t *testing.T) {
var cases = []struct {
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{"GET", "/api/v0/blueprints/diff/test/NEWEST/WORKSPACE", ``, http.StatusOK, `{"diff":[{"new":{"Package":{"name":"systemd","version":"123"}},"old":null},{"new":null,"old":{"Package":{"name":"httpd","version":"2.4.*"}}}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/workspace", `{"name":"test","description":"Test","packages":[{"name":"systemd","version":"123"}],"version":"0.0.0"}`)
test.TestRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
test.SendHTTP(api, true, "DELETE", "/api/v0/blueprints/delete/test", ``)
}
}
func TestBlueprintsDelete(t *testing.T) {
var cases = []struct {
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{"DELETE", "/api/v0/blueprints/delete/test", ``, http.StatusOK, `{"status":true}`},
{"DELETE", "/api/v0/blueprints/delete/test3-non", ``, http.StatusBadRequest, `{"status":false,"errors":[{"id":"BlueprintsError","msg":"Unknown blueprint: test3-non"}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
test.TestRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
test.SendHTTP(api, true, "DELETE", "/api/v0/blueprints/delete/test", ``)
}
}
func TestBlueprintsChanges(t *testing.T) {
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
rand.Seed(time.Now().UnixNano())
// math/rand is good enough in this case
/* #nosec G404 */
id := strconv.Itoa(rand.Int())
ignoreFields := []string{"commit", "timestamp"}
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"`+id+`","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
test.TestRoute(t, api, true, "GET", "/api/v0/blueprints/changes/failing"+id, ``, http.StatusOK, `{"blueprints":[],"errors":[{"id":"UnknownBlueprint","msg":"failing`+id+`"}],"limit":20,"offset":0}`, ignoreFields...)
test.TestRoute(t, api, true, "GET", "/api/v0/blueprints/changes/"+id, ``, http.StatusOK, `{"blueprints":[{"changes":[{"commit":"","message":"Recipe `+id+`, version 0.0.0 saved.","revision":null,"timestamp":""}],"name":"`+id+`","total":1}],"errors":[],"limit":20,"offset":0}`, ignoreFields...)
test.SendHTTP(api, true, "DELETE", "/api/v0/blueprints/delete/"+id, ``)
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"`+id+`","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.0"}`)
test.TestRoute(t, api, true, "GET", "/api/v0/blueprints/changes/"+id, ``, http.StatusOK, `{"blueprints":[{"changes":[{"commit":"","message":"Recipe `+id+`, version 0.0.0 saved.","revision":null,"timestamp":""},{"commit":"","message":"Recipe `+id+`, version 0.0.0 saved.","revision":null,"timestamp":""}],"name":"`+id+`","total":2}],"errors":[],"limit":20,"offset":0}`, ignoreFields...)
test.SendHTTP(api, true, "DELETE", "/api/v0/blueprints/delete/"+id, ``)
// Test with an empty Version
/* #nosec G404 */
id = strconv.Itoa(rand.Int())
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"`+id+`","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":""}`)
test.TestRoute(t, api, true, "GET", "/api/v0/blueprints/changes/"+id, ``, http.StatusOK, `{"blueprints":[{"changes":[{"commit":"","message":"Recipe `+id+`, version 0.0.0 saved.","revision":null,"timestamp":""}],"name":"`+id+`","total":1}],"errors":[],"limit":20,"offset":0}`, ignoreFields...)
test.SendHTTP(api, true, "DELETE", "/api/v0/blueprints/delete/"+id, ``)
}
// TestBlueprintChange tests getting a single blueprint commit
func TestBlueprintChange(t *testing.T) {
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
rand.Seed(time.Now().UnixNano())
// math/rand is good enough in this case
/* #nosec G404 */
id := strconv.Itoa(rand.Int())
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"`+id+`","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.1"}`)
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"`+id+`","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.2"}`)
resp := test.SendHTTP(api, true, "GET", "/api/v0/blueprints/changes/"+id, ``)
body, err := io.ReadAll(resp.Body)
require.Nil(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
var changes BlueprintsChangesV0
err = json.Unmarshal(body, &changes)
require.Nil(t, err)
require.Equal(t, 1, len(changes.BlueprintsChanges))
require.Equal(t, 2, len(changes.BlueprintsChanges[0].Changes))
commit := changes.BlueprintsChanges[0].Changes[1].Commit
// Get the blueprint's oldest commit
route := fmt.Sprintf("/api/v1/blueprints/change/%s/%s", id, commit)
resp = test.SendHTTP(api, true, "GET", route, ``)
body, err = io.ReadAll(resp.Body)
require.Nil(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
var bp blueprint.Blueprint
err = json.Unmarshal(body, &bp)
require.Nil(t, err)
require.Equal(t, "0.0.1", bp.Version)
}
func TestBlueprintsDepsolve(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, http.StatusOK, depsolveTestResponse},
{rpmmd_mock.NonExistingPackage, http.StatusOK, depsolvePackageNotExistError},
{rpmmd_mock.BadDepsolve, http.StatusOK, depsolveBadError},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.SendHTTP(api, false, "POST", "/api/v0/blueprints/new", `{"name":"test","description":"Test","packages":[{"name":"dep-package1","version":"*"}],"modules":[{"name":"dep-package3","version":"*"}],"version":"0.0.0"}`)
test.TestRoute(t, api, false, "GET", "/api/v0/blueprints/depsolve/test", ``, c.ExpectedStatus, c.ExpectedJSON)
test.SendHTTP(api, false, "DELETE", "/api/v0/blueprints/delete/test", ``)
}
}
// TestOldBlueprintsUndo run tests with blueprint changes after a service restart
// Old blueprints are not saved, after a restart the changes are listed, but cannot be recalled
func TestOldBlueprintsUndo(t *testing.T) {
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.OldChangesFixture)
rand.Seed(time.Now().UnixNano())
// math/rand is good enough in this case
/* #nosec G404 */
ignoreFields := []string{"commit", "timestamp"}
test.TestRoute(t, api, true, "GET", "/api/v0/blueprints/changes/test-old-changes", ``, http.StatusOK, oldBlueprintsUndoResponse, ignoreFields...)
resp := test.SendHTTP(api, true, "GET", "/api/v0/blueprints/changes/test-old-changes", ``)
body, err := io.ReadAll(resp.Body)
require.Nil(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
var changes BlueprintsChangesV0
err = json.Unmarshal(body, &changes)
require.Nil(t, err)
require.Equal(t, 1, len(changes.BlueprintsChanges))
require.Equal(t, 3, len(changes.BlueprintsChanges[0].Changes))
commit := changes.BlueprintsChanges[0].Changes[2].Commit
// Undo a known commit, that is old
test.TestRoute(t, api, true, "POST", "/api/v0/blueprints/undo/test-old-changes/"+commit, ``, http.StatusBadRequest, `{"errors":[{"id":"BlueprintsError", "msg":"no blueprint found for commit `+commit+`"}], "status":false}`)
// Check to make sure the undo is not present (can't undo something not there)
test.TestRoute(t, api, true, "GET", "/api/v0/blueprints/changes/test-old-changes", ``, http.StatusOK, oldBlueprintsUndoResponse, ignoreFields...)
// Check to make sure it didn't create an empty blueprint
test.TestRoute(t, api, true, "GET", "/api/v0/blueprints/list", ``, http.StatusOK, `{"total":1,"offset":0,"limit":1,"blueprints":["test-old-changes"]}`)
test.SendHTTP(api, true, "DELETE", "/api/v0/blueprints/delete/test-old-changes", ``)
}
// TestNewBlueprintsUndo run tests with blueprint changes without a service restart
func TestNewBlueprintsUndo(t *testing.T) {
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
rand.Seed(time.Now().UnixNano())
// math/rand is good enough in this case
/* #nosec G404 */
id := strconv.Itoa(rand.Int())
ignoreFields := []string{"commit", "timestamp"}
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"`+id+`","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}],"version":"0.0.1"}`)
test.SendHTTP(api, true, "POST", "/api/v0/blueprints/new", `{"name":"`+id+`","description":"Test","packages":[{"name":"httpd","version":"2.4.*"}, {"name": "tmux", "version":"*"}],"version":"0.1.0"}`)
test.TestRoute(t, api, true, "GET", "/api/v0/blueprints/changes/"+id, ``, http.StatusOK, `{"blueprints":[{"changes":[{"commit":"","message":"Recipe `+id+`, version 0.1.0 saved.","revision":null,"timestamp":""},{"commit":"","message":"Recipe `+id+`, version 0.0.1 saved.","revision":null,"timestamp":""}],"name":"`+id+`","total":2}],"errors":[],"limit":20,"offset":0}`, ignoreFields...)
resp := test.SendHTTP(api, true, "GET", "/api/v0/blueprints/changes/"+id, ``)
body, err := io.ReadAll(resp.Body)
require.Nil(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
var changes BlueprintsChangesV0
err = json.Unmarshal(body, &changes)
require.Nil(t, err)
require.Equal(t, 1, len(changes.BlueprintsChanges))
require.Equal(t, 2, len(changes.BlueprintsChanges[0].Changes))
commit := changes.BlueprintsChanges[0].Changes[1].Commit
// Undo an unknown commit
test.TestRoute(t, api, true, "POST", "/api/v0/blueprints/undo/"+id+"/d7e5fa641aad45300242a0f273827576e32bfc03", ``, http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownCommit","msg":"Unknown commit"}]}`)
// Undo a known commit
test.TestRoute(t, api, true, "POST", "/api/v0/blueprints/undo/"+id+"/"+commit, ``, http.StatusOK, `{"status":true}`)
// Check to make sure the undo is present
test.TestRoute(t, api, true, "GET", "/api/v0/blueprints/changes/"+id, ``, http.StatusOK, `{"blueprints":[{"changes":[{"commit":"","message":"`+id+`.toml reverted to commit `+commit+`","revision":null,"timestamp":""},{"commit":"","message":"Recipe `+id+`, version 0.1.0 saved.","revision":null,"timestamp":""},{"commit":"","message":"Recipe `+id+`, version 0.0.1 saved.","revision":null,"timestamp":""}],"name":"`+id+`","total":3}],"errors":[],"limit":20,"offset":0}`, ignoreFields...)
test.SendHTTP(api, true, "DELETE", "/api/v0/blueprints/delete/"+id, ``)
}
func TestCompose(t *testing.T) {
arch, err := test_distro.New().GetArch(test_distro.TestArchName)
require.NoError(t, err)
imgType, err := arch.GetImageType(test_distro.TestImageTypeName)
require.NoError(t, err)
manifest, _, err := imgType.Manifest(nil, distro.ImageOptions{}, nil, nil, nil, 0)
require.NoError(t, err)
ostreeImgType, err := arch.GetImageType(test_distro.TestImageTypeOSTree)
require.NoError(t, err)
ostreeManifest, _, err := ostreeImgType.Manifest(nil, distro.ImageOptions{}, nil, nil, nil, 0)
require.NoError(t, err)
expectedComposeLocal := &store.Compose{
Blueprint: &blueprint.Blueprint{
Name: "test",
Version: "0.0.0",
Packages: []blueprint.Package{},
Modules: []blueprint.Package{},
Groups: []blueprint.Group{},
Customizations: nil,
},
ImageBuild: store.ImageBuild{
QueueStatus: common.IBWaiting,
ImageType: imgType,
Manifest: manifest,
Targets: []*target.Target{
{
ImageName: imgType.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType.Filename(),
ExportName: imgType.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
},
},
},
Packages: dnfjson_mock.BaseDeps(),
}
expectedComposeLocalAndAws := &store.Compose{
Blueprint: &blueprint.Blueprint{
Name: "test",
Version: "0.0.0",
Packages: []blueprint.Package{},
Modules: []blueprint.Package{},
Groups: []blueprint.Group{},
Customizations: nil,
},
ImageBuild: store.ImageBuild{
QueueStatus: common.IBWaiting,
ImageType: imgType,
Manifest: manifest,
Targets: []*target.Target{
{
ImageName: imgType.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType.Filename(),
ExportName: imgType.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
},
{
Name: target.TargetNameAWS,
Status: common.IBWaiting,
ImageName: "test_upload",
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType.Filename(),
ExportName: imgType.Exports()[0],
},
Options: &target.AWSTargetOptions{
Region: "frankfurt",
AccessKeyID: "accesskey",
SecretAccessKey: "secretkey",
Bucket: "clay",
Key: "imagekey",
},
},
},
},
Packages: dnfjson_mock.BaseDeps(),
}
expectedComposeOSTree := &store.Compose{
Blueprint: &blueprint.Blueprint{
Name: "test",
Version: "0.0.0",
Packages: []blueprint.Package{},
Modules: []blueprint.Package{},
Groups: []blueprint.Group{},
Customizations: nil,
},
ImageBuild: store.ImageBuild{
QueueStatus: common.IBWaiting,
ImageType: ostreeImgType,
Manifest: ostreeManifest,
Targets: []*target.Target{
{
ImageName: ostreeImgType.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: ostreeImgType.Filename(),
ExportName: ostreeImgType.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
},
},
},
Packages: dnfjson_mock.BaseDeps(),
}
// For 2nd distribution
arch2, err := test_distro.New2().GetArch(test_distro.TestArchName)
require.NoError(t, err)
imgType2, err := arch2.GetImageType(test_distro.TestImageTypeName)
require.NoError(t, err)
manifest2, _, err := imgType.Manifest(nil, distro.ImageOptions{}, nil, nil, nil, 0)
require.NoError(t, err)
expectedComposeGoodDistro := &store.Compose{
Blueprint: &blueprint.Blueprint{
Name: "test-distro-2",
Version: "0.0.0",
Packages: []blueprint.Package{},
Modules: []blueprint.Package{},
Groups: []blueprint.Group{},
Customizations: nil,
Distro: "test-distro-2",
},
ImageBuild: store.ImageBuild{
QueueStatus: common.IBWaiting,
ImageType: imgType2,
Manifest: manifest2,
Targets: []*target.Target{
{
ImageName: imgType2.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType2.Filename(),
ExportName: imgType2.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
},
},
},
Packages: dnfjson_mock.BaseDeps(),
}
// create two ostree repos, one to serve the default test_distro ref (for fallback tests) and one to serve a custom ref
ostreeRepoDefault := mock_ostree_repo.Setup(test_distro.New().OSTreeRef())
defer ostreeRepoDefault.TearDown()
ostreeRepoOther := mock_ostree_repo.Setup("some/other/ref")
defer ostreeRepoOther.TearDown()
var cases = []struct {
External bool
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
ExpectedCompose *store.Compose
IgnoreFields []string
}{
{
true,
"POST",
"/api/v0/compose",
fmt.Sprintf(`{"blueprint_name": "http-server","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
http.StatusBadRequest,
`{"status":false,"errors":[{"id":"UnknownBlueprint","msg":"Unknown blueprint name: http-server"}]}`,
nil,
[]string{"build_id", "warnings"},
},
{
false,
"POST",
"/api/v0/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
http.StatusOK,
`{"status": true}`,
expectedComposeLocal,
[]string{"build_id", "warnings"},
},
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type":"%s","branch":"master","upload":{"image_name":"test_upload","provider":"aws","settings":{"region":"frankfurt","accessKeyID":"accesskey","secretAccessKey":"secretkey","bucket":"clay","key":"imagekey"}}}`, test_distro.TestImageTypeName),
http.StatusOK,
`{"status": true}`,
expectedComposeLocalAndAws,
[]string{"build_id", "warnings"},
},
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test-distro-2","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
http.StatusOK,
`{"status": true}`,
expectedComposeGoodDistro,
[]string{"build_id", "warnings"},
},
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test-fedora-1","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
http.StatusBadRequest,
`{"status": false,"errors":[{"id":"DistroError", "msg":"Unknown distribution: fedora-1"}]}`,
nil,
[]string{"build_id", "warnings"},
},
{
false,
"POST",
"/api/v1/compose",
`{"blueprint_name": "test-distro-2","compose_type": "imaginary_type","branch": "master"}`,
http.StatusBadRequest,
`{"status": false,"errors":[{"id":"ComposeError", "msg":"Failed to get compose type \"imaginary_type\": invalid image type: imaginary_type"}]}`,
nil,
[]string{"build_id", "warnings"},
},
// === OSTree params ===
// Ref + Parent = error (parent without URL)
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type":"%s","branch":"master","ostree":{"ref":"refid","parent":"parentid","url":""}}`, test_distro.TestImageTypeOSTree),
http.StatusBadRequest,
`{"status": false, "errors":[{"id":"OSTreeOptionsError","msg":"ostree parent ref specified, but no URL to retrieve it"}]}`,
expectedComposeOSTree,
[]string{"build_id", "warnings"},
},
// Valid Ref + URL = OK
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type":"%s","branch":"master","ostree":{"ref":"%s","parent":"","url":"%s"}}`, test_distro.TestImageTypeOSTree, ostreeRepoOther.OSTreeRef, ostreeRepoOther.Server.URL),
http.StatusOK,
`{"status": true}`,
expectedComposeOSTree,
[]string{"build_id", "warnings"},
},
// Ref + invalid URL = error
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type":"%s","branch":"master","ostree":{"ref":"whatever","parent":"","url":"invalid-url"}}`, test_distro.TestImageTypeOSTree),
http.StatusBadRequest,
`{"status":false,"errors":[{"id":"OSTreeOptionsError","msg":"error sending request to ostree repository \"invalid-url/refs/heads/whatever\": Get \"invalid-url/refs/heads/whatever\": unsupported protocol scheme \"\""}]}`,
nil,
[]string{"build_id", "warnings"},
},
// Bad Ref + URL = error
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type":"%s","branch":"master","ostree":{"ref":"/bad/ref","parent":"","url":"http://ostree/"}}`, test_distro.TestImageTypeOSTree),
http.StatusBadRequest,
`{"status":false,"errors":[{"id":"OSTreeOptionsError","msg":"Invalid ostree ref \"/bad/ref\""}]}`,
expectedComposeOSTree,
[]string{"build_id", "warnings"},
},
// Incorrect Ref + URL = the parameters are okay, but the ostree repo returns 404
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type":"%s","branch":"master","ostree":{"ref":"%s","parent":"","url":"%s"}}`, test_distro.TestImageTypeOSTree, "the/wrong/ref", ostreeRepoDefault.Server.URL),
http.StatusBadRequest,
fmt.Sprintf(`{"status":false,"errors":[{"id":"OSTreeOptionsError","msg":"ostree repository \"%s/refs/heads/the/wrong/ref\" returned status: 404 Not Found"}]}`, ostreeRepoDefault.Server.URL),
expectedComposeOSTree,
[]string{"build_id", "warnings"},
},
// Ref + Parent + URL = OK
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type":"%s","branch":"master","ostree":{"ref":"%s","parent":"%s","url":"%s"}}`, test_distro.TestImageTypeOSTree, "the/new/ref", ostreeRepoOther.OSTreeRef, ostreeRepoOther.Server.URL),
http.StatusOK,
`{"status":true}`,
expectedComposeOSTree,
[]string{"build_id", "warnings"},
},
// Parent + URL = OK
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type":"%s","branch":"master","ostree":{"ref":"","parent":"%s","url":"%s"}}`, test_distro.TestImageTypeOSTree, ostreeRepoDefault.OSTreeRef, ostreeRepoDefault.Server.URL),
http.StatusOK,
`{"status":true}`,
expectedComposeOSTree,
[]string{"build_id", "warnings"},
},
// URL only = OK (uses default ref, so we need to specify URL for ostree repo with default ref)
{
false,
"POST",
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type":"%s","branch":"master","ostree":{"ref":"","parent":"","url":"%s"}}`, test_distro.TestImageTypeOSTree, ostreeRepoDefault.Server.URL),
http.StatusOK,
`{"status":true}`,
expectedComposeOSTree,
[]string{"build_id", "warnings"},
},
}
tempdir := t.TempDir()
for _, c := range cases {
api, s := createWeldrAPI(tempdir, rpmmd_mock.NoComposesFixture)
test.TestRoute(t, api, c.External, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON, c.IgnoreFields...)
if c.ExpectedStatus != http.StatusOK {
continue
}
composes := s.GetAllComposes()
require.Equalf(t, 1, len(composes), "%s: bad compose count in store", c.Path)
// I have no idea how to get the compose in better way
var composeStruct store.Compose
for _, c := range composes {
composeStruct = c
break
}
require.NotNilf(t, composeStruct.ImageBuild.Manifest, "%s: the compose in the store did not contain a blueprint", c.Path)
if diff := cmp.Diff(composeStruct, *c.ExpectedCompose, test.IgnoreDates(), test.IgnoreUuids(), test.Ignore("Targets.Options.Location"), test.CompareImageTypes()); diff != "" {
t.Errorf("%s: compose in store isn't the same as expected, diff:\n%s", c.Path, diff)
}
}
}
func TestComposeDelete(t *testing.T) {
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
t.Skip("This test is for internal testing only")
}
var cases = []struct {
Path string
ExpectedJSON string
ExpectedIDsInStore []string
}{
{"/api/v0/compose/delete/30000000-0000-0000-0000-000000000002", `{"uuids":[{"uuid":"30000000-0000-0000-0000-000000000002","status":true}],"errors":[]}`, []string{"30000000-0000-0000-0000-000000000000", "30000000-0000-0000-0000-000000000001", "30000000-0000-0000-0000-000000000003", "30000000-0000-0000-0000-000000000004"}},
{"/api/v0/compose/delete/30000000-0000-0000-0000-000000000002,30000000-0000-0000-0000-000000000003", `{"uuids":[{"uuid":"30000000-0000-0000-0000-000000000002","status":true},{"uuid":"30000000-0000-0000-0000-000000000003","status":true}],"errors":[]}`, []string{"30000000-0000-0000-0000-000000000000", "30000000-0000-0000-0000-000000000001", "30000000-0000-0000-0000-000000000004"}},
{"/api/v0/compose/delete/30000000-0000-0000-0000-000000000003,30000000-0000-0000-0000-000000000000", `{"uuids":[{"uuid":"30000000-0000-0000-0000-000000000003","status":true}],"errors":[{"id":"BuildInWrongState","msg":"Compose 30000000-0000-0000-0000-000000000000 is not in FINISHED or FAILED."}]}`, []string{"30000000-0000-0000-0000-000000000000", "30000000-0000-0000-0000-000000000001", "30000000-0000-0000-0000-000000000002", "30000000-0000-0000-0000-000000000004"}},
{"/api/v0/compose/delete/30000000-0000-0000-0000-000000000003,30000000-0000-0000-0000", `{"uuids":[{"uuid":"30000000-0000-0000-0000-000000000003","status":true}],"errors":[{"id":"UnknownUUID","msg":"30000000-0000-0000-0000 is not a valid uuid"}]}`, []string{"30000000-0000-0000-0000-000000000000", "30000000-0000-0000-0000-000000000001", "30000000-0000-0000-0000-000000000002", "30000000-0000-0000-0000-000000000004"}},
{"/api/v0/compose/delete/30000000-0000-0000-0000-000000000003,42000000-0000-0000-0000-000000000000", `{"uuids":[{"uuid":"30000000-0000-0000-0000-000000000003","status":true}],"errors":[{"id":"UnknownUUID","msg":"compose 42000000-0000-0000-0000-000000000000 doesn't exist"}]}`, []string{"30000000-0000-0000-0000-000000000000", "30000000-0000-0000-0000-000000000001", "30000000-0000-0000-0000-000000000002", "30000000-0000-0000-0000-000000000004"}},
}
tempdir := t.TempDir()
for _, c := range cases {
api, s := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.TestRoute(t, api, false, "DELETE", c.Path, "", http.StatusOK, c.ExpectedJSON)
idsInStore := []string{}
for id := range s.GetAllComposes() {
idsInStore = append(idsInStore, id.String())
}
require.ElementsMatch(t, c.ExpectedIDsInStore, idsInStore, "%s: composes in store are different", c.Path)
}
}
func TestComposeStatus(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/status/30000000-0000-0000-0000-000000000000,30000000-0000-0000-0000-000000000002", ``, http.StatusOK, fmt.Sprintf(`{"uuids":[{"id":"30000000-0000-0000-0000-000000000000","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"WAITING","job_created":1574857140},{"id":"30000000-0000-0000-0000-000000000002","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/status/*", ``, http.StatusOK, fmt.Sprintf(`{"uuids":[{"id":"30000000-0000-0000-0000-000000000000","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"WAITING","job_created":1574857140},{"id":"30000000-0000-0000-0000-000000000001","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"RUNNING","job_created":1574857140,"job_started":1574857140},{"id":"30000000-0000-0000-0000-000000000002","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140},{"id":"30000000-0000-0000-0000-000000000003","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FAILED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140},{"id":"30000000-0000-0000-0000-000000000004","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/status/*?name=test", ``, http.StatusOK, fmt.Sprintf(`{"uuids":[{"id":"30000000-0000-0000-0000-000000000000","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"WAITING","job_created":1574857140},{"id":"30000000-0000-0000-0000-000000000001","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"RUNNING","job_created":1574857140,"job_started":1574857140},{"id":"30000000-0000-0000-0000-000000000002","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140},{"id":"30000000-0000-0000-0000-000000000003","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FAILED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140},{"id":"30000000-0000-0000-0000-000000000004","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/status/*?status=FINISHED", ``, http.StatusOK, fmt.Sprintf(`{"uuids":[{"id":"30000000-0000-0000-0000-000000000002","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140},{"id":"30000000-0000-0000-0000-000000000004","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.BaseFixture, "GET", fmt.Sprintf("/api/v0/compose/status/*?type=%s", test_distro.TestImageTypeName), ``, http.StatusOK, fmt.Sprintf(`{"uuids":[{"id":"30000000-0000-0000-0000-000000000000","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"WAITING","job_created":1574857140},{"id":"30000000-0000-0000-0000-000000000001","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"RUNNING","job_created":1574857140,"job_started":1574857140},{"id":"30000000-0000-0000-0000-000000000002","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140},{"id":"30000000-0000-0000-0000-000000000003","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FAILED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140},{"id":"30000000-0000-0000-0000-000000000004","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.BaseFixture, "GET", "/api/v1/compose/status/30000000-0000-0000-0000-000000000000", ``, http.StatusOK, fmt.Sprintf(`{"uuids":[{"id":"30000000-0000-0000-0000-000000000000","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"WAITING","job_created":1574857140,"uploads":[{"uuid":"10000000-0000-0000-0000-000000000000","status":"WAITING","provider_name":"aws","image_name":"awsimage","creation_time":1574857140,"settings":{"region":"frankfurt","bucket":"clay","key":"imagekey"}}]}]}`, test_distro.TestImageTypeName)},
}
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
t.Skip("This test is for internal testing only")
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.TestRoute(t, api, false, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON, "id", "job_created", "job_started")
}
}
func TestComposeInfo(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/info/30000000-0000-0000-0000-000000000000", ``, http.StatusOK, fmt.Sprintf(`{"id":"30000000-0000-0000-0000-000000000000","config":"","blueprint":{"name":"test","description":"","distro":"","version":"0.0.0","packages":[],"modules":[],"groups":[]},"commit":"","deps":{"packages":[]},"compose_type":"%s","queue_status":"WAITING","image_size":0}`, test_distro.TestImageTypeName)},
{rpmmd_mock.BaseFixture, "GET", "/api/v1/compose/info/30000000-0000-0000-0000-000000000000", ``, http.StatusOK, fmt.Sprintf(`{"id":"30000000-0000-0000-0000-000000000000","config":"","blueprint":{"name":"test","description":"","distro":"","version":"0.0.0","packages":[],"modules":[],"groups":[]},"commit":"","deps":{"packages":[]},"compose_type":"%s","queue_status":"WAITING","image_size":0,"uploads":[{"uuid":"10000000-0000-0000-0000-000000000000","status":"WAITING","provider_name":"aws","image_name":"awsimage","creation_time":1574857140,"settings":{"region":"frankfurt","bucket":"clay","key":"imagekey"}}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.BaseFixture, "GET", "/api/v1/compose/info/30000000-0000-0000-0000", ``, http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownUUID","msg":"30000000-0000-0000-0000 is not a valid build uuid"}]}`},
{rpmmd_mock.BaseFixture, "GET", "/api/v1/compose/info/42000000-0000-0000-0000-000000000000", ``, http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownUUID","msg":"42000000-0000-0000-0000-000000000000 is not a valid build uuid"}]}`},
}
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
t.Skip("This test is for internal testing only")
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.TestRoute(t, api, false, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
}
}
func TestComposeLogs(t *testing.T) {
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
t.Skip("This test is for internal testing only")
}
var successCases = []struct {
Path string
ExpectedContentDisposition string
ExpectedContentType string
ExpectedFileName string
ExpectedFileContent string
}{
{"/api/v0/compose/logs/30000000-0000-0000-0000-000000000002", "attachment; filename=30000000-0000-0000-0000-000000000002-logs.tar", "application/x-tar", "logs/osbuild.log", "The compose result is empty.\n"},
{"/api/v1/compose/logs/30000000-0000-0000-0000-000000000002", "attachment; filename=30000000-0000-0000-0000-000000000002-logs.tar", "application/x-tar", "logs/osbuild.log", "The compose result is empty.\n"},
{"/api/v0/compose/metadata/30000000-0000-0000-0000-000000000002", "attachment; filename=30000000-0000-0000-0000-000000000002-metadata.tar", "application/x-tar", "30000000-0000-0000-0000-000000000002.json", `{"version":"","pipelines":[],"sources":{}}`},
{"/api/v1/compose/metadata/30000000-0000-0000-0000-000000000002", "attachment; filename=30000000-0000-0000-0000-000000000002-metadata.tar", "application/x-tar", "30000000-0000-0000-0000-000000000002.json", `{"version":"","pipelines":[],"sources":{}}`},
{"/api/v0/compose/results/30000000-0000-0000-0000-000000000002", "attachment; filename=30000000-0000-0000-0000-000000000002.tar", "application/x-tar", "30000000-0000-0000-0000-000000000002.json", `{"version":"","pipelines":[],"sources":{}}`},
{"/api/v1/compose/results/30000000-0000-0000-0000-000000000002", "attachment; filename=30000000-0000-0000-0000-000000000002.tar", "application/x-tar", "30000000-0000-0000-0000-000000000002.json", `{"version":"","pipelines":[],"sources":{}}`},
}
tempdir := t.TempDir()
for _, c := range successCases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
response := test.SendHTTP(api, false, "GET", c.Path, "")
require.Equalf(t, http.StatusOK, response.StatusCode, "%s: unexpected status code", c.Path)
require.Equalf(t, c.ExpectedContentDisposition, response.Header.Get("content-disposition"), "%s: header mismatch", c.Path)
require.Equalf(t, c.ExpectedContentType, response.Header.Get("content-type"), "%s: header mismatch", c.Path)
tr := tar.NewReader(response.Body)
h, err := tr.Next()
require.NoErrorf(t, err, "untarring failed with error")
require.Falsef(t, h.ModTime.After(time.Now()), "ModTime cannot be in the future")
require.Equalf(t, c.ExpectedFileName, h.Name, "%s: unexpected file name", c.Path)
var buffer bytes.Buffer
// vulnerability already tested
/* #nosec G110 */
_, err = io.Copy(&buffer, tr)
require.NoErrorf(t, err, "cannot copy untar result")
require.Equalf(t, c.ExpectedFileContent, buffer.String(), "%s: unexpected log content", c.Path)
}
var failureCases = []struct {
Path string
ExpectedJSON string
}{
{"/api/v1/compose/logs/30000000-0000-0000-0000", `{"status":false,"errors":[{"id":"UnknownUUID","msg":"30000000-0000-0000-0000 is not a valid build uuid"}]}`},
{"/api/v1/compose/logs/42000000-0000-0000-0000-000000000000", `{"status":false,"errors":[{"id":"UnknownUUID","msg":"Compose 42000000-0000-0000-0000-000000000000 doesn't exist"}]}`},
{"/api/v1/compose/logs/30000000-0000-0000-0000-000000000000", `{"status":false,"errors":[{"id":"BuildInWrongState","msg":"Build 30000000-0000-0000-0000-000000000000 not in FINISHED or FAILED state."}]}`},
{"/api/v1/compose/metadata/30000000-0000-0000-0000-000000000000", `{"status":false,"errors":[{"id":"BuildInWrongState","msg":"Build 30000000-0000-0000-0000-000000000000 is in wrong state: WAITING"}]}`},
{"/api/v1/compose/results/30000000-0000-0000-0000-000000000000", `{"status":false,"errors":[{"id":"BuildInWrongState","msg":"Build 30000000-0000-0000-0000-000000000000 is in wrong state: WAITING"}]}`},
{"/api/v1/compose/metadata/30000000-0000-0000-0000-000000000001", `{"status":false,"errors":[{"id":"BuildInWrongState","msg":"Build 30000000-0000-0000-0000-000000000001 is in wrong state: RUNNING"}]}`},
{"/api/v1/compose/results/30000000-0000-0000-0000-000000000001", `{"status":false,"errors":[{"id":"BuildInWrongState","msg":"Build 30000000-0000-0000-0000-000000000001 is in wrong state: RUNNING"}]}`},
}
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
t.Skip("This test is for internal testing only")
}
for _, c := range failureCases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.TestRoute(t, api, false, "GET", c.Path, "", http.StatusBadRequest, c.ExpectedJSON)
}
}
func TestComposeLog(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Method string
Path string
ExpectedStatus int
ExpectedResponse string
}{
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/log/30000000-0000-0000-0000-000000000000", http.StatusOK, `{"status":false,"errors":[{"id":"BuildInWrongState","msg":"Build 30000000-0000-0000-0000-000000000000 has not started yet. No logs to view."}]}` + "\n"},
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/log/30000000-0000-0000-0000-000000000001", http.StatusOK, `Build 30000000-0000-0000-0000-000000000001 is still running.` + "\n"},
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/log/30000000-0000-0000-0000-000000000002", http.StatusOK, `The compose result is empty.` + "\n"},
{rpmmd_mock.BaseFixture, "GET", "/api/v1/compose/log/30000000-0000-0000-0000-000000000002", http.StatusOK, `The compose result is empty.` + "\n"},
{rpmmd_mock.BaseFixture, "GET", "/api/v1/compose/log/30000000-0000-0000-0000", http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownUUID","msg":"30000000-0000-0000-0000 is not a valid build uuid"}]}` + "\n"},
{rpmmd_mock.BaseFixture, "GET", "/api/v1/compose/log/42000000-0000-0000-0000-000000000000", http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownUUID","msg":"Compose 42000000-0000-0000-0000-000000000000 doesn't exist"}]}` + "\n"},
}
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
t.Skip("This test is for internal testing only")
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.TestNonJsonRoute(t, api, false, "GET", c.Path, "", c.ExpectedStatus, c.ExpectedResponse)
}
}
func TestComposeQueue(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/queue", ``, http.StatusOK, fmt.Sprintf(`{"new":[{"blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"WAITING"}],"run":[{"blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"RUNNING"}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.BaseFixture, "GET", "/api/v1/compose/queue", ``, http.StatusOK, fmt.Sprintf(`{"new":[{"blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"WAITING","uploads":[{"uuid":"10000000-0000-0000-0000-000000000000","status":"WAITING","provider_name":"aws","image_name":"awsimage","creation_time":1574857140,"settings":{"region":"frankfurt","bucket":"clay","key":"imagekey"}}]}],"run":[{"blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"RUNNING"}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.NoComposesFixture, "GET", "/api/v0/compose/queue", ``, http.StatusOK, `{"new":[],"run":[]}`},
}
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
t.Skip("This test is for internal testing only")
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.TestRoute(t, api, false, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON, "id", "job_created", "job_started")
}
}
func TestComposeFinished(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/finished", ``, http.StatusOK, fmt.Sprintf(`{"finished":[{"id":"30000000-0000-0000-0000-000000000002","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140},{"id":"30000000-0000-0000-0000-000000000004","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.BaseFixture, "GET", "/api/v1/compose/finished", ``, http.StatusOK, fmt.Sprintf(`{"finished":[{"id":"30000000-0000-0000-0000-000000000002","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140,"uploads":[{"uuid":"10000000-0000-0000-0000-000000000000","status":"FINISHED","provider_name":"aws","image_name":"awsimage","creation_time":1574857140,"settings":{"region":"frankfurt","bucket":"clay","key":"imagekey"}}]},{"id":"30000000-0000-0000-0000-000000000004","blueprint":"test","version":"0.0.0","compose_type":"%[1]s","image_size":0,"queue_status":"FINISHED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140,"uploads":[{"uuid":"10000000-0000-0000-0000-000000000000","status":"FINISHED","provider_name":"aws","image_name":"awsimage","creation_time":1574857140,"settings":{"region":"frankfurt","bucket":"clay","key":"imagekey"}}]}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.NoComposesFixture, "GET", "/api/v0/compose/finished", ``, http.StatusOK, `{"finished":[]}`},
}
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
t.Skip("This test is for internal testing only")
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.TestRoute(t, api, false, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON, "id", "job_created", "job_started")
}
}
func TestComposeFailed(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "GET", "/api/v0/compose/failed", ``, http.StatusOK, fmt.Sprintf(`{"failed":[{"id":"30000000-0000-0000-0000-000000000003","blueprint":"test","version":"0.0.0","compose_type":"%s","image_size":0,"queue_status":"FAILED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.BaseFixture, "GET", "/api/v1/compose/failed", ``, http.StatusOK, fmt.Sprintf(`{"failed":[{"id":"30000000-0000-0000-0000-000000000003","blueprint":"test","version":"0.0.0","compose_type":"%s","image_size":0,"queue_status":"FAILED","job_created":1574857140,"job_started":1574857140,"job_finished":1574857140,"uploads":[{"uuid":"10000000-0000-0000-0000-000000000000","status":"FAILED","provider_name":"aws","image_name":"awsimage","creation_time":1574857140,"settings":{"region":"frankfurt","bucket":"clay","key":"imagekey"}}]}]}`, test_distro.TestImageTypeName)},
{rpmmd_mock.NoComposesFixture, "GET", "/api/v0/compose/failed", ``, http.StatusOK, `{"failed":[]}`},
}
if len(os.Getenv("OSBUILD_COMPOSER_TEST_EXTERNAL")) > 0 {
t.Skip("This test is for internal testing only")
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.TestRoute(t, api, false, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON, "id", "job_created", "job_started")
}
}
func TestSourcesNew(t *testing.T) {
var cases = []struct {
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{"POST", "/api/v0/projects/source/new", ``, http.StatusBadRequest, `{"errors": [{"id": "ProjectsError","msg": "Missing source"}],"status":false}`},
// Bad JSON, missing quote after name
{"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}`, http.StatusBadRequest, `{"errors": [{"id": "ProjectsError","msg": "Problem parsing POST body: invalid character 'f' after object key"}],"status":false}`},
{"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}`, http.StatusOK, `{"status":true}`},
{"POST", "/api/v0/projects/source/new", `{"url": "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","type": "yum-baseurl","check_ssl": false,"check_gpg": false}`, http.StatusBadRequest, `{"errors": [{"id": "ProjectsError","msg": "Problem parsing POST body: 'name' field is missing from request"}],"status":false}`},
{"POST", "/api/v0/projects/source/new", `{"name": "fish", "type": "yum-baseurl","check_ssl": false,"check_gpg": false}`, http.StatusBadRequest, `{"errors": [{"id": "ProjectsError","msg": "Problem parsing POST body: 'url' field is missing from request"}],"status":false}`},
{"POST", "/api/v0/projects/source/new", `{"name": "fish", "url": "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","check_ssl": false,"check_gpg": false}`, http.StatusBadRequest, `{"errors": [{"id": "ProjectsError","msg": "Problem parsing POST body: 'type' field is missing from request"}],"status":false}`},
{"POST", "/api/v0/projects/source/new", `{"name": "test-id", "url": "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","type": "yum-baseurl","check_ssl": false,"check_gpg": false}`, http.StatusBadRequest, `{"errors": [{"id": "SystemSource","msg": "test-id is a system source, it cannot be changed."}],"status":false}`},
{"POST", "/api/v1/projects/source/new", `{"id": "test-id", "name": "test system repo", "url": "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","type": "yum-baseurl","check_ssl": false,"check_gpg": false}`, http.StatusBadRequest, `{"errors": [{"id": "SystemSource","msg": "test-id is a system source, it cannot be changed."}],"status":false}`},
{"POST", "/api/v1/projects/source/new", `{"id": "fish","name":"fish repo","url": "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","type": "yum-baseurl","check_ssl": false,"check_gpg": false,"distros":["test-distro", "test-distro-2"]}`, http.StatusOK, `{"status":true}`},
{"POST", "/api/v1/projects/source/new", `{"id": "fish","name":"fish repo","url": "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","type": "yum-baseurl","check_ssl": false,"check_gpg": false,"distros":["fedora-1"]}`, http.StatusBadRequest, `{"status":false, "errors":[{"id":"ProjectsError", "msg":"Invalid distributions: fedora-1"}]}`},
{"POST", "/api/v1/projects/source/new", `{"id": "fish","name":"fish repo","url": "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","type": "yum-baseurl","check_ssl": false,"check_gpg": true,"check_repogpg":true,"gpgkeys": ["https://repourl/path/to/key.pub"]}`, http.StatusOK, `{"status":true}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.TestRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
test.SendHTTP(api, true, "DELETE", "/api/v0/projects/source/delete/fish", ``)
}
}
func TestSourcesNewTomlV0(t *testing.T) {
tempdir := t.TempDir()
sources := []string{`
name = "fish"
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
check_ssl = false
check_gpg = false
`, `[fish]
name = "fish"
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
check_ssl = false
check_gpg = false
`}
for _, source := range sources {
req := httptest.NewRequest("POST", "/api/v0/projects/source/new", bytes.NewReader([]byte(source)))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusOK, r.StatusCode)
test.SendHTTP(api, true, "DELETE", "/api/v0/projects/source/delete/fish", ``)
}
}
// Empty TOML, and invalid TOML should return an error
func TestSourcesNewWrongTomlV0(t *testing.T) {
tempdir := t.TempDir()
sources := []string{``, `
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
check_ssl = false
check_gpg = false
`}
for _, source := range sources {
req := httptest.NewRequest("POST", "/api/v0/projects/source/new", bytes.NewReader([]byte(source)))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusBadRequest, r.StatusCode)
}
}
// TestSourcesNewTomlV1 tests the v1 sources API with id and name
func TestSourcesNewTomlV1(t *testing.T) {
tempdir := t.TempDir()
sources := []string{`
id = "fish"
name = "fish or cut bait"
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
check_ssl = false
check_gpg = false
`, `[fish]
name = "fish or cut bait"
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
check_ssl = false
check_gpg = false
`, `[fish]
id = "fish"
name = "fish or cut bait"
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
check_ssl = false
check_gpg = false
`, `id = "fish"
name = "fish or cut bait"
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
check_ssl = false
check_gpg = true
check_repogpg = true
gpgkeys = ['''-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.10 (GNU/Linux)
mQENBEt+xXMBCACkA1ZtcO4H7ZUG/0aL4RlZIozsorXzFrrTAsJEHvdy+rHCH3xR
cFz6IMbfCOdV+oKxlDP7PS0vWKfqxwkenOUut5o9b32uDdFMW4IbFXEQ94AuSQpS
jo8PlVMm/51pmmRxdJzyPnr0YD38mVK6qUEYLI/4zXSgFk493GT8Y4m3N18O/+ye
PnOOItj7qbrCMASoBx1TG8Zdg8ufehMnfb85x4xxAebXkqJQpEVTjt4lj4p6BhrW
R+pIW/nBUrz3OsV7WwPKjSLjJtTJFxYX+RFSCqOdfusuysoOxpIHOx1WxjGUOB5j
fnhmq41nWXf8ozb58zSpjDrJ7jGQ9pdUpAtRABEBAAG0HkJyaWFuIEMuIExhbmUg
PGJjbEByZWRoYXQuY29tPokBOAQTAQIAIgUCS37FcwIbAwYLCQgHAwIGFQgCCQoL
BBYCAwECHgECF4AACgkQEX6MFo7+On9dgAf9Hi2K1MKcmLkDeSUIXkXIAw0nAzl2
UDGLWEdDqAgFxP6UaCVtOIRCr7z4EDOQoxD7mkdekbH2W5GcTO4h8MQBHYD9EkY7
H/lTKchlFfsmafOoA3Y/tDLPKu+OIfH9Mqn2Mf7wMYGrnWSRNKYgvC5zkMgkhoPU
mSPPHyBabsdS/Kg5ZAf43ac/MXY9V8Mk6zqbBlj6QYqjJ0nBD6vwozrDQ5gJtDUL
mQho13zPn4lBJl9YJVjcgRB2WbzgSZOln0DfV22Seai66vnr5NyaOIw5B9QLSNhN
EaPFswEDLKCsns9dkDuGFX52/Mt/i7JySvwhMBqHElPzWmwCHeY45M8gBYhGBBAR
AgAGBQJLfsbpAAoJECH7Y/6XEsLNuasAn0Q0jB4Ea/95EREUkCFTm9L6nOpAAJ9t
QzwGXhrLFZzOdRWYiWcCQbX5/7kBDQRLfsVzAQgAvN5jr95pJthv2w9co9/7omhM
5rAnr9WJfbMLLiUfPPUvpL24RGO6SKy03aiVTUjlaHc+cGqOciwnNKMCSt+noyG2
kNnAESTDtCivpsjonaFP8jA3TqL0QK+yzBRKJnMnLEY1nWE1FtkMRccXvzi0Z/XQ
VhiWQyTvDFoKtepBFrH9UqWbNHyki22aighumUsW01pcPH2ogSj+HR01r7SfI/y2
EkE6loHQfCDycHmlqYV+X6GZEvf1qu2+EHEQChsHIAxWyshsxM/ZPmx/8e5S3Xmj
l7h/6E9wcsIpvnf504sLX5j4Km9I5HgJSRxHxgRPpqJ2/XiClAJanO5gCw0RdQAR
AQABiQEfBBgBAgAJBQJLfsVzAhsMAAoJEBF+jBaO/jp/SqEH/iArzrfVOhZQGuy1
KmG0+/FdJGqAEHP5HWpsaeYJok1VmhTPZd4IVFBz/bGJYyvsrPU0pJ6QLkdGxNnb
KulJocgkW5MKEL/CRc54ESKwYngigmbY4qLwhS+gB3BJg1TvoHD810MSj4wdxNNo
6JQmFmuoDsLRwaRYbKQDz95XXoGQtmV1o57T05WkLuC5OmHqnWv3rggVC8madpUJ
moUUvUWgU1qyXe3PrgMGFOibWIl7lPZ08nzKXBRvSK/xoTGxl+570AevfVHMu5Uk
Yu2U6D6/DYohtTYp0s1ekS5KQkCJM7lfqecDsQhfVfOfR0w4aF8k8u3HmWdOfUz+
9+2ZsBo=
=myjM
-----END PGP PUBLIC KEY BLOCK-----''']
`}
for _, source := range sources {
req := httptest.NewRequest("POST", "/api/v1/projects/source/new", bytes.NewReader([]byte(source)))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusOK, r.StatusCode)
test.SendHTTP(api, true, "DELETE", "/api/v1/projects/source/delete/fish", ``)
}
}
func TestSourcesInfoTomlV1(t *testing.T) {
source := `
id = "fish"
name = "fish"
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
rhsm = true
`
sourceStr := `{"check_gpg":false,"check_repogpg":false,"check_ssl":false,"id":"fish","name":"fish","rhsm":true,"system":false,"type":"yum-baseurl","url":"https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"}`
req := httptest.NewRequest("POST", "/api/v1/projects/source/new", bytes.NewReader([]byte(source)))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusOK, r.StatusCode)
test.TestRoute(t, api, true, "GET", "/api/v1/projects/source/info/fish", ``, 200, `{"sources":{"fish":`+sourceStr+`},"errors":[]}`)
test.TestRoute(t, api, true, "GET", "/api/v1/projects/source/info/fish?format=json", ``, 200, `{"sources":{"fish":`+sourceStr+`},"errors":[]}`)
}
func TestSourcesInfoGPGKeysV1(t *testing.T) {
sourceStr := `{"id":"fish","name":"fish repo","type":"yum-baseurl","url":"https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","check_gpg":true,"check_repogpg":true,"check_ssl":false,"gpgkeys":["https://repourl/path/to/key.pub"],"rhsm":false,"system":false}`
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
test.SendHTTP(api, true, "POST", "/api/v1/projects/source/new", sourceStr)
test.TestRoute(t, api, true, "GET", "/api/v1/projects/source/info/fish", ``, 200, `{"sources":{"fish":`+sourceStr+`},"errors":[]}`)
test.TestRoute(t, api, true, "GET", "/api/v1/projects/source/info/fish?format=json", ``, 200, `{"sources":{"fish":`+sourceStr+`},"errors":[]}`)
}
// TestSourcesNewWrongTomlV1 Tests that Empty TOML, and invalid TOML should return an error
func TestSourcesNewWrongTomlV1(t *testing.T) {
tempdir := t.TempDir()
sources := []string{``, `
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
check_ssl = false
check_gpg = false
`, `
[fish]
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
check_ssl = false
check_gpg = false
`, `
id = "fish"
url = "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/"
type = "yum-baseurl"
check_ssl = false
check_gpg = false
`}
for _, source := range sources {
req := httptest.NewRequest("POST", "/api/v1/projects/source/new", bytes.NewReader([]byte(source)))
req.Header.Set("Content-Type", "text/x-toml")
recorder := httptest.NewRecorder()
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
api.ServeHTTP(recorder, req)
r := recorder.Result()
require.Equal(t, http.StatusBadRequest, r.StatusCode)
}
}
func TestSourcesInfo(t *testing.T) {
sourceStr := `{"name":"fish","type":"yum-baseurl","url":"https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","check_gpg":false,"check_ssl":false,"system":false}`
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
test.SendHTTP(api, true, "POST", "/api/v0/projects/source/new", sourceStr)
test.TestRoute(t, api, true, "GET", "/api/v0/projects/source/info/fish", ``, 200, `{"sources":{"fish":`+sourceStr+`},"errors":[]}`)
test.TestRoute(t, api, true, "GET", "/api/v0/projects/source/info/fish?format=json", ``, 200, `{"sources":{"fish":`+sourceStr+`},"errors":[]}`)
test.TestRoute(t, api, true, "GET", "/api/v0/projects/source/info/fish?format=son", ``, 400, `{"status":false,"errors":[{"id":"InvalidChars","msg":"invalid format parameter: son"}]}`)
}
func TestSourcesInfoToml(t *testing.T) {
sourceStr := `{"name":"fish","type":"yum-baseurl","url":"https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/","check_gpg":false,"check_ssl":false,"system":false}`
api, _ := createWeldrAPI(t.TempDir(), rpmmd_mock.BaseFixture)
test.SendHTTP(api, true, "POST", "/api/v0/projects/source/new", sourceStr)
req := httptest.NewRequest("GET", "/api/v0/projects/source/info/fish?format=toml", nil)
recorder := httptest.NewRecorder()
api.ServeHTTP(recorder, req)
resp := recorder.Result()
var sources map[string]store.SourceConfig
_, err := toml.NewDecoder(resp.Body).Decode(&sources)
require.NoErrorf(t, err, "error decoding toml file")
expected := map[string]store.SourceConfig{
"fish": {
Name: "fish",
Type: "yum-baseurl",
URL: "https://download.opensuse.org/repositories/shells:/fish:/release:/3/Fedora_29/",
},
}
require.Equal(t, expected, sources)
}
func TestSourcesDelete(t *testing.T) {
var cases = []struct {
Method string
Path string
Body string
ExpectedStatus int
ExpectedJSON string
}{
{"DELETE", "/api/v0/projects/source/delete/", ``, http.StatusNotFound, `{"status":false,"errors":[{"code":404,"id":"HTTPError","msg":"Not Found"}]}`},
{"DELETE", "/api/v0/projects/source/delete/fish", ``, http.StatusOK, `{"status":true}`},
{"DELETE", "/api/v0/projects/source/delete/unknown", ``, http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownSource","msg":"unknown is not a valid source."}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, rpmmd_mock.BaseFixture)
test.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}`)
test.TestRoute(t, api, true, c.Method, c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON)
test.SendHTTP(api, true, "DELETE", "/api/v0/projects/source/delete/fish", ``)
}
}
func TestProjectsDepsolve(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Path string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.NonExistingPackage, "/api/v0/projects/depsolve/fash", http.StatusBadRequest, `{"status":false,"errors":[{"id":"ProjectsError","msg":"BadRequest: DNF error occurred: MarkingErrors: Error occurred when marking packages for installation: Problems in request:\nmissing packages: fash"}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/projects/depsolve/fish", http.StatusOK, `{"projects":[{"name":"dep-package3","epoch":7,"version":"3.0.3","release":"1.fc30","arch":"x86_64","check_gpg":true},{"name":"dep-package1","epoch":0,"version":"1.33","release":"2.fc30","arch":"x86_64","check_gpg":true},{"name":"dep-package2","epoch":0,"version":"2.9","release":"1.fc30","arch":"x86_64","check_gpg":true}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/projects/depsolve/fish?distro=test-distro-2", http.StatusOK, `{"projects":[{"name":"dep-package3","epoch":7,"version":"3.0.3","release":"1.fc30","arch":"x86_64","check_gpg":true},{"name":"dep-package1","epoch":0,"version":"1.33","release":"2.fc30","arch":"x86_64","check_gpg":true},{"name":"dep-package2","epoch":0,"version":"2.9","release":"1.fc30","arch":"x86_64","check_gpg":true}]}`},
{rpmmd_mock.BadDepsolve, "/api/v0/projects/depsolve/go2rpm", http.StatusBadRequest, `{"status":false,"errors":[{"id":"ProjectsError","msg":"BadRequest: DNF error occurred: DepsolveError: There was a problem depsolving ['go2rpm']: \n Problem: conflicting requests\n - nothing provides askalono-cli needed by go2rpm-1-4.fc31.noarch"}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/projects/depsolve/fish?distro=fedora-1", http.StatusBadRequest, `{"status":false,"errors":[{"id":"DistroError","msg":"Invalid distro: fedora-1"}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.TestRoute(t, api, true, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedJSON)
}
}
func TestProjectsInfo(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Path string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "/api/v0/projects/info", http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownProject","msg":"No packages specified."}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/projects/info/", http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownProject","msg":"No packages specified."}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/projects/info/nonexistingpkg", http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownProject","msg":"No packages have been found."}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/projects/info/*", http.StatusOK, projectsInfoResponse},
{rpmmd_mock.BaseFixture, "/api/v0/projects/info/package2*,package16", http.StatusOK, projectsInfoFilteredResponse},
{rpmmd_mock.BadFetch, "/api/v0/projects/info/badpackage1", http.StatusBadRequest, `{"status":false,"errors":[{"id":"ProjectsError","msg":"msg: DNF error occurred: FetchError: There was a problem when fetching packages."}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/projects/info/package16?distro=test-distro-2", http.StatusOK, projectsInfoPackage16Response},
{rpmmd_mock.BaseFixture, "/api/v0/projects/info/package16?distro=fedora-1", http.StatusBadRequest, `{"status":false,"errors":[{"id":"DistroError","msg":"Invalid distro: fedora-1"}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.TestRoute(t, api, true, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedJSON)
}
}
func TestModulesInfo(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Path string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "/api/v0/modules/info", http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownModule","msg":"No packages specified."}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/modules/info/", http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownModule","msg":"No packages specified."}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/modules/info/nonexistingpkg", http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownModule","msg":"No packages have been found."}]}`},
{rpmmd_mock.BadDepsolve, "/api/v0/modules/info/baddepsolve", http.StatusBadRequest, `{"status":false,"errors":[{"id":"ModulesError","msg":"Cannot depsolve package package1: DNF error occurred: DepsolveError: There was a problem depsolving ['go2rpm']: \n Problem: conflicting requests\n - nothing provides askalono-cli needed by go2rpm-1-4.fc31.noarch"}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/modules/info/package2*,package16", http.StatusOK, modulesInfoFilteredResponse},
{rpmmd_mock.BaseFixture, "/api/v0/modules/info/*", http.StatusOK, modulesInfoResponse},
{rpmmd_mock.BadFetch, "/api/v0/modules/info/badpackage1", http.StatusBadRequest, `{"status":false,"errors":[{"id":"ModulesError","msg":"msg: DNF error occurred: FetchError: There was a problem when fetching packages."}]}`},
{rpmmd_mock.BaseFixture, "/api/v1/modules/info/package2*,package16", http.StatusOK, modulesInfoFilteredResponse},
{rpmmd_mock.BaseFixture, "/api/v1/modules/info/package16?distro=test-distro-2", http.StatusOK, modulesInfoPackage16Response},
{rpmmd_mock.BaseFixture, "/api/v1/modules/info/package16?distro=fedora-1", http.StatusBadRequest, `{"status":false,"errors":[{"id":"DistroError","msg":"Invalid distro: fedora-1"}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.TestRoute(t, api, true, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedJSON)
}
}
func TestProjectsList(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Path string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "/api/v0/projects/list", http.StatusOK, projectsListResponse},
{rpmmd_mock.BaseFixture, "/api/v0/projects/list/", http.StatusOK, projectsListResponse},
{rpmmd_mock.BadFetch, "/api/v0/projects/list/", http.StatusBadRequest, `{"status":false,"errors":[{"id":"ProjectsError","msg":"msg: DNF error occurred: FetchError: There was a problem when fetching packages."}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/projects/list?offset=1&limit=1", http.StatusOK, projectsList1Response},
{rpmmd_mock.BaseFixture, "/api/v0/projects/list?distro=test-distro-2&offset=1&limit=1", http.StatusOK, projectsList1Response},
{rpmmd_mock.BaseFixture, "/api/v0/projects/list?distro=fedora-1&offset=1&limit=1", http.StatusBadRequest, `{"status":false,"errors":[{"id":"DistroError","msg":"Invalid distro: fedora-1"}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.TestRoute(t, api, true, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedJSON)
}
}
func TestModulesList(t *testing.T) {
var cases = []struct {
Fixture rpmmd_mock.FixtureGenerator
Path string
ExpectedStatus int
ExpectedJSON string
}{
{rpmmd_mock.BaseFixture, "/api/v0/modules/list", http.StatusOK, modulesListResponse},
{rpmmd_mock.BaseFixture, "/api/v0/modules/list/", http.StatusOK, modulesListResponse},
{rpmmd_mock.BaseFixture, "/api/v0/modules/list/nonexistingpkg", http.StatusBadRequest, `{"status":false,"errors":[{"id":"UnknownModule","msg":"No packages have been found."}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/modules/list/package2*,package16", http.StatusOK, modulesListFilteredResponse},
{rpmmd_mock.BadFetch, "/api/v0/modules/list/badpackage1", http.StatusBadRequest, `{"status":false,"errors":[{"id":"ModulesError","msg":"msg: DNF error occurred: FetchError: There was a problem when fetching packages."}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/modules/list/package2*,package16?offset=1&limit=1", http.StatusOK, `{"total":4,"offset":1,"limit":1,"modules":[{"name":"package2","group_type":"rpm"}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/modules/list/*", http.StatusOK, modulesListResponse},
{rpmmd_mock.BaseFixture, "/api/v0/modules/list/package2*,package16?distro=test-distro-2&offset=1&limit=1", http.StatusOK, `{"total":4,"offset":1,"limit":1,"modules":[{"name":"package2","group_type":"rpm"}]}`},
{rpmmd_mock.BaseFixture, "/api/v0/modules/list/package2*,package16?distro=fedora-1&offset=1&limit=1", http.StatusBadRequest, `{"status":false,"errors":[{"id":"DistroError","msg":"Invalid distro: fedora-1"}]}`},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI(tempdir, c.Fixture)
test.TestRoute(t, api, true, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedJSON)
}
}
func TestComposeTypes_ImageTypeDenylist(t *testing.T) {
var cases = []struct {
Path string
ImageTypeDenylist map[string][]string
ExpectedStatus int
ExpectedJSON string
}{
{
"/api/v1/compose/types",
map[string][]string{},
http.StatusOK,
fmt.Sprintf(`{"types": [{"enabled":true, "name":%q},{"enabled":true, "name":%q}]}`, test_distro.TestImageTypeName, test_distro.TestImageType2Name),
},
{
"/api/v1/compose/types?distro=test-distro-2",
map[string][]string{},
http.StatusOK,
fmt.Sprintf(`{"types": [{"enabled":true, "name":%q},{"enabled":true, "name":%q}]}`, test_distro.TestImageTypeName, test_distro.TestImageType2Name),
},
{
"/api/v1/compose/types",
map[string][]string{test_distro.TestDistro2Name: {test_distro.TestImageTypeName}},
http.StatusOK,
fmt.Sprintf(`{"types": [{"enabled":true, "name":%q}]}`, test_distro.TestImageType2Name),
},
{
"/api/v1/compose/types?distro=test-distro-2",
map[string][]string{test_distro.TestDistro2Name: {test_distro.TestImageTypeName}},
http.StatusOK,
fmt.Sprintf(`{"types": [{"enabled":true, "name":%q}]}`, test_distro.TestImageType2Name),
},
{
"/api/v1/compose/types",
map[string][]string{test_distro.TestDistro2Name: {test_distro.TestImageTypeName, test_distro.TestImageType2Name}},
http.StatusOK,
`{"types": null}`,
},
{
"/api/v1/compose/types?distro=test-distro-2",
map[string][]string{test_distro.TestDistro2Name: {test_distro.TestImageTypeName, test_distro.TestImageType2Name}},
http.StatusOK,
`{"types": null}`,
},
{
"/api/v1/compose/types",
map[string][]string{"*": {test_distro.TestImageTypeName}},
http.StatusOK,
fmt.Sprintf(`{"types": [{"enabled":true, "name":%q}]}`, test_distro.TestImageType2Name),
},
{
"/api/v1/compose/types",
map[string][]string{"*": {test_distro.TestImageTypeName, test_distro.TestImageType2Name}},
http.StatusOK,
`{"types": null}`,
},
{
"/api/v1/compose/types",
map[string][]string{test_distro.TestDistro2Name: {"*"}},
http.StatusOK,
`{"types": null}`,
},
{
"/api/v1/compose/types?distro=test-distro-2",
map[string][]string{test_distro.TestDistroName: {"*"}},
http.StatusOK,
fmt.Sprintf(`{"types": [{"enabled":true, "name":%q}, {"enabled":true, "name":%q}]}`,
test_distro.TestImageTypeName, test_distro.TestImageType2Name),
},
}
tempdir := t.TempDir()
for _, c := range cases {
api, _ := createWeldrAPI2(tempdir, rpmmd_mock.BaseFixture, c.ImageTypeDenylist)
test.TestRoute(t, api, true, "GET", c.Path, ``, c.ExpectedStatus, c.ExpectedJSON)
}
}
func TestComposePOST_ImageTypeDenylist(t *testing.T) {
arch, err := test_distro.New2().GetArch(test_distro.TestArch2Name)
require.NoError(t, err)
imgType, err := arch.GetImageType(test_distro.TestImageTypeName)
require.NoError(t, err)
imgType2, err := arch.GetImageType(test_distro.TestImageType2Name)
require.NoError(t, err)
manifest, _, err := imgType.Manifest(nil, distro.ImageOptions{}, nil, nil, nil, 0)
require.NoError(t, err)
expectedComposeLocal := &store.Compose{
Blueprint: &blueprint.Blueprint{
Name: "test",
Version: "0.0.0",
Packages: []blueprint.Package{},
Modules: []blueprint.Package{},
Groups: []blueprint.Group{},
Customizations: nil,
},
ImageBuild: store.ImageBuild{
QueueStatus: common.IBWaiting,
ImageType: imgType,
Manifest: manifest,
Targets: []*target.Target{
{
ImageName: imgType.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType.Filename(),
ExportName: imgType.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
},
},
},
Packages: dnfjson_mock.BaseDeps(),
}
expectedComposeLocal2 := &store.Compose{
Blueprint: &blueprint.Blueprint{
Name: "test",
Version: "0.0.0",
Packages: []blueprint.Package{},
Modules: []blueprint.Package{},
Groups: []blueprint.Group{},
Customizations: nil,
},
ImageBuild: store.ImageBuild{
QueueStatus: common.IBWaiting,
ImageType: imgType2,
Manifest: manifest,
Targets: []*target.Target{
{
ImageName: imgType2.Filename(),
OsbuildArtifact: target.OsbuildArtifact{
ExportFilename: imgType2.Filename(),
ExportName: imgType2.Exports()[0],
},
Name: target.TargetNameWorkerServer,
Options: &target.WorkerServerTargetOptions{},
},
},
},
Packages: dnfjson_mock.BaseDeps(),
}
var cases = []struct {
Path string
Body string
imageTypeDenylist map[string][]string
ExpectedStatus int
ExpectedJSON string
ExpectedCompose *store.Compose
IgnoreFields []string
}{
{
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
map[string][]string{},
http.StatusOK,
`{"status":true}`,
expectedComposeLocal,
[]string{"build_id", "warnings"},
},
{
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageType2Name),
map[string][]string{},
http.StatusOK,
`{"status": true}`,
expectedComposeLocal2,
[]string{"build_id", "warnings"},
},
{
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
map[string][]string{test_distro.TestDistro2Name: {test_distro.TestImageTypeName}},
http.StatusBadRequest,
fmt.Sprintf(`{"status":false,"errors":[{"id":"ComposeError","msg":"Failed to get compose type \"%[1]s\": image type \"%[1]s\" for distro \"%[2]s\" is denied by configuration"}]}`,
test_distro.TestImageTypeName, test_distro.TestDistro2Name),
expectedComposeLocal,
[]string{"build_id", "warnings"},
},
{
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageType2Name),
map[string][]string{test_distro.TestDistro2Name: {test_distro.TestImageTypeName}},
http.StatusOK,
`{"status": true}`,
expectedComposeLocal2,
[]string{"build_id", "warnings"},
},
{
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
map[string][]string{test_distro.TestDistro2Name: {test_distro.TestImageTypeName, test_distro.TestImageType2Name}},
http.StatusBadRequest,
fmt.Sprintf(`{"status":false,"errors":[{"id":"ComposeError","msg":"Failed to get compose type \"%[1]s\": image type \"%[1]s\" for distro \"%[2]s\" is denied by configuration"}]}`,
test_distro.TestImageTypeName, test_distro.TestDistro2Name),
expectedComposeLocal,
[]string{"build_id", "warnings"},
},
{
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageType2Name),
map[string][]string{test_distro.TestDistro2Name: {test_distro.TestImageTypeName, test_distro.TestImageType2Name}},
http.StatusBadRequest,
fmt.Sprintf(`{"status":false,"errors":[{"id":"ComposeError","msg":"Failed to get compose type \"%[1]s\": image type \"%[1]s\" for distro \"%[2]s\" is denied by configuration"}]}`,
test_distro.TestImageType2Name, test_distro.TestDistro2Name),
expectedComposeLocal2,
[]string{"build_id", "warnings"},
},
{
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
map[string][]string{"*": {test_distro.TestImageTypeName}},
http.StatusBadRequest,
fmt.Sprintf(`{"status":false,"errors":[{"id":"ComposeError","msg":"Failed to get compose type \"%[1]s\": image type \"%[1]s\" for distro \"%[2]s\" is denied by configuration"}]}`,
test_distro.TestImageTypeName, test_distro.TestDistro2Name),
expectedComposeLocal,
[]string{"build_id", "warnings"},
},
{
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
map[string][]string{test_distro.TestDistro2Name: {"*"}},
http.StatusBadRequest,
fmt.Sprintf(`{"status":false,"errors":[{"id":"ComposeError","msg":"Failed to get compose type \"%[1]s\": image type \"%[1]s\" for distro \"%[2]s\" is denied by configuration"}]}`,
test_distro.TestImageTypeName, test_distro.TestDistro2Name),
expectedComposeLocal,
[]string{"build_id", "warnings"},
},
{
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
map[string][]string{fmt.Sprintf("%s*", test_distro.TestDistroName): {fmt.Sprintf("%s*", test_distro.TestImageTypeName)}},
http.StatusBadRequest,
fmt.Sprintf(`{"status":false,"errors":[{"id":"ComposeError","msg":"Failed to get compose type \"%[1]s\": image type \"%[1]s\" for distro \"%[2]s\" is denied by configuration"}]}`,
test_distro.TestImageTypeName, test_distro.TestDistro2Name),
expectedComposeLocal,
[]string{"build_id", "warnings"},
},
{
"/api/v1/compose",
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageType2Name),
map[string][]string{fmt.Sprintf("%s*", test_distro.TestDistroName): {fmt.Sprintf("%s*", test_distro.TestImageTypeName)}},
http.StatusBadRequest,
fmt.Sprintf(`{"status":false,"errors":[{"id":"ComposeError","msg":"Failed to get compose type \"%[1]s\": image type \"%[1]s\" for distro \"%[2]s\" is denied by configuration"}]}`,
test_distro.TestImageType2Name, test_distro.TestDistro2Name),
expectedComposeLocal,
[]string{"build_id", "warnings"},
},
}
tempdir := t.TempDir()
for _, c := range cases {
api, s := createWeldrAPI2(tempdir, rpmmd_mock.NoComposesFixture, c.imageTypeDenylist)
test.TestRoute(t, api, true, "POST", c.Path, c.Body, c.ExpectedStatus, c.ExpectedJSON, c.IgnoreFields...)
if c.ExpectedStatus != http.StatusOK {
continue
}
composes := s.GetAllComposes()
require.Equalf(t, 1, len(composes), "%s: bad compose count in store", c.Path)
var composeStruct store.Compose
for _, c := range composes {
composeStruct = c
break
}
require.NotNilf(t, composeStruct.ImageBuild.Manifest, "%s: the compose in the store did not contain a blueprint", c.Path)
if diff := cmp.Diff(composeStruct, *c.ExpectedCompose, test.IgnoreDates(), test.IgnoreUuids(), test.Ignore("Targets.Options.Location"), test.CompareImageTypes()); diff != "" {
t.Errorf("%s: compose in store isn't the same as expected, diff:\n%s", c.Path, diff)
}
}
}
func TestMain(m *testing.M) {
setupDNFJSON()
defer os.RemoveAll(dnfjsonPath)
code := m.Run()
os.Exit(code)
}