Commit 312d87c6d5fab7ffd085a303e27b8db41111c86e adds validation of the checksums to the ImageType.Manifest call, so it requires a valid looking checksum, otherwise it will fail with a 'ManifestCreationFailed' error when running the unit tests.
2388 lines
109 KiB
Go
2388 lines
109 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/aws/aws-sdk-go/service/ec2"
|
|
"github.com/osbuild/images/pkg/distro"
|
|
"github.com/osbuild/images/pkg/distro/test_distro"
|
|
"github.com/osbuild/images/pkg/distroregistry"
|
|
"github.com/osbuild/images/pkg/ostree"
|
|
"github.com/osbuild/images/pkg/ostree/mock_ostree_repo"
|
|
"github.com/osbuild/images/pkg/rpmmd"
|
|
"github.com/osbuild/osbuild-composer/internal/blueprint"
|
|
"github.com/osbuild/osbuild-composer/internal/common"
|
|
"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/reporegistry"
|
|
"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/assert"
|
|
"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: common.ToPtr(true)},
|
|
},
|
|
},
|
|
test_distro.TestDistro2Name: {
|
|
test_distro.TestArchName: {
|
|
{Name: "test-id-2", BaseURLs: []string{"http://example.com/test-2/os/x86_64"}, CheckGPG: common.ToPtr(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: common.ToPtr(true)},
|
|
},
|
|
},
|
|
test_distro.TestDistro2Name: {
|
|
test_distro.TestArch2Name: {
|
|
{Name: "test-id-2", BaseURLs: []string{"http://example.com/test-2/os/x86_64"}, CheckGPG: common.ToPtr(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 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) {
|
|
// 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()
|
|
otherRef := "some/other/ref"
|
|
ostreeRepoOther := mock_ostree_repo.Setup(otherRef)
|
|
defer ostreeRepoOther.TearDown()
|
|
|
|
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, 0)
|
|
require.NoError(t, err)
|
|
|
|
rPkgs, rContainers, rCommits := test_distro.ResolveContent(manifest.GetPackageSetChains(), manifest.GetContainerSourceSpecs(), manifest.GetOSTreeSourceSpecs())
|
|
|
|
mf, err := manifest.Serialize(rPkgs, rContainers, rCommits)
|
|
require.NoError(t, err)
|
|
|
|
ostreeImgType, err := arch.GetImageType(test_distro.TestImageTypeOSTree)
|
|
require.NoError(t, err)
|
|
ostreeOptions := ostree.ImageOptions{URL: ostreeRepoDefault.Server.URL}
|
|
ostreeManifest, _, err := ostreeImgType.Manifest(nil, distro.ImageOptions{OSTree: &ostreeOptions}, nil, 0)
|
|
require.NoError(t, err)
|
|
|
|
rPkgs, rContainers, rCommits = test_distro.ResolveContent(ostreeManifest.GetPackageSetChains(), ostreeManifest.GetContainerSourceSpecs(), ostreeManifest.GetOSTreeSourceSpecs())
|
|
|
|
omf, err := ostreeManifest.Serialize(rPkgs, rContainers, rCommits)
|
|
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,
|
|
Size: imgType.Size(0),
|
|
Manifest: mf,
|
|
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,
|
|
Size: imgType.Size(0),
|
|
Manifest: mf,
|
|
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",
|
|
BootMode: common.ToPtr(ec2.BootModeValuesUefiPreferred),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
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,
|
|
Size: ostreeImgType.Size(0),
|
|
Manifest: omf,
|
|
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(),
|
|
}
|
|
|
|
ostreeOptionsOther := ostree.ImageOptions{ImageRef: otherRef, URL: ostreeRepoOther.Server.URL}
|
|
ostreeManifestOther, _, err := ostreeImgType.Manifest(nil, distro.ImageOptions{OSTree: &ostreeOptionsOther}, nil, 0)
|
|
require.NoError(t, err)
|
|
|
|
rPkgs, rContainers, rCommits = test_distro.ResolveContent(ostreeManifestOther.GetPackageSetChains(), ostreeManifestOther.GetContainerSourceSpecs(), ostreeManifestOther.GetOSTreeSourceSpecs())
|
|
|
|
omfo, err := ostreeManifest.Serialize(rPkgs, rContainers, rCommits)
|
|
require.NoError(t, err)
|
|
expectedComposeOSTreeOther := &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,
|
|
Size: ostreeImgType.Size(0),
|
|
Manifest: omfo,
|
|
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, 0)
|
|
require.NoError(t, err)
|
|
|
|
rPkgs, rContainers, rCommits = test_distro.ResolveContent(manifest2.GetPackageSetChains(), manifest2.GetContainerSourceSpecs(), manifest2.GetOSTreeSourceSpecs())
|
|
mf2, err := manifest2.Serialize(rPkgs, rContainers, rCommits)
|
|
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,
|
|
Size: imgType2.Size(0),
|
|
Manifest: mf2,
|
|
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 = map[string]struct {
|
|
External bool
|
|
Method string
|
|
Path string
|
|
Body string
|
|
ExpectedStatus int
|
|
ExpectedJSON string
|
|
ExpectedCompose *store.Compose
|
|
IgnoreFields []string
|
|
}{
|
|
"bad-request": {
|
|
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"},
|
|
},
|
|
"local": {
|
|
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"},
|
|
},
|
|
"aws": {
|
|
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"},
|
|
},
|
|
"good-distro": {
|
|
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"},
|
|
},
|
|
"unknown-distro": {
|
|
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"},
|
|
},
|
|
"imaginary": {
|
|
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)
|
|
"ostree-no-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":"ManifestCreationFailed","msg":"failed to initialize osbuild manifest: ostree parent ref specified, but no URL to retrieve it"}]}`,
|
|
expectedComposeOSTree,
|
|
[]string{"build_id", "warnings"},
|
|
},
|
|
// Valid Ref + URL = OK
|
|
"ostree-valid": {
|
|
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}`,
|
|
expectedComposeOSTreeOther,
|
|
[]string{"build_id", "warnings"},
|
|
},
|
|
// Ref + invalid URL = error
|
|
"ostree-invalid-url": {
|
|
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
|
|
"ostree-bad-ref": {
|
|
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 or commit \"/bad/ref\""}]}`,
|
|
expectedComposeOSTree,
|
|
[]string{"build_id", "warnings"},
|
|
},
|
|
// Incorrect Ref + URL = the parameters are okay, but the ostree repo returns 404
|
|
"ostree-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
|
|
"ostree-all-params": {
|
|
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}`,
|
|
expectedComposeOSTreeOther,
|
|
[]string{"build_id", "warnings"},
|
|
},
|
|
// Parent + URL = OK
|
|
"ostree-parent-url": {
|
|
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)
|
|
"ostree-url-only": {
|
|
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 name, 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: %s: bad compose count in store", name, 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: %s: the compose in the store did not contain a blueprint", name, c.Path)
|
|
|
|
if diff := cmp.Diff(composeStruct, *c.ExpectedCompose, test.IgnoreDates(), test.IgnoreUuids(), test.Ignore("Targets.Options.Location"), test.CompareImageTypes()); diff != "" {
|
|
t.Errorf("%s: %s: compose in store isn't the same as expected, diff:\n%s", name, 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")
|
|
}
|
|
|
|
emptyManifest := `{"version":"2","pipelines":[{"name":"build"},{"name":"os"}],"sources":{}}`
|
|
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", emptyManifest},
|
|
{"/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", emptyManifest},
|
|
{"/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", emptyManifest},
|
|
{"/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", emptyManifest},
|
|
}
|
|
|
|
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, "checksum":"sha256:62278d360aa5045eb202af39fe85743a4b5615f0c9c7439a04d75d785db4c720"},{"name":"dep-package1","epoch":0,"version":"1.33","release":"2.fc30","arch":"x86_64","check_gpg":true, "checksum":"sha256:fe3951d112c3b1c84dc8eac57afe0830df72df1ca0096b842f4db5d781189893"},{"name":"dep-package2","epoch":0,"version":"2.9","release":"1.fc30","arch":"x86_64","check_gpg":true, "checksum":"sha256:5797c0b0489681596b5b3cd7165d49870b85b69d65e08770946380a3dcd49ea2"}]}`},
|
|
{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, "checksum":"sha256:62278d360aa5045eb202af39fe85743a4b5615f0c9c7439a04d75d785db4c720"},{"name":"dep-package1","epoch":0,"version":"1.33","release":"2.fc30","arch":"x86_64","check_gpg":true, "checksum":"sha256:fe3951d112c3b1c84dc8eac57afe0830df72df1ca0096b842f4db5d781189893"},{"name":"dep-package2","epoch":0,"version":"2.9","release":"1.fc30","arch":"x86_64","check_gpg":true, "checksum":"sha256:5797c0b0489681596b5b3cd7165d49870b85b69d65e08770946380a3dcd49ea2"}]}`},
|
|
{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)
|
|
t.Logf("Path = %s", c.Path)
|
|
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, 0)
|
|
require.NoError(t, err)
|
|
|
|
rPkgs, rContainers, rCommits := test_distro.ResolveContent(manifest.GetPackageSetChains(), manifest.GetContainerSourceSpecs(), manifest.GetOSTreeSourceSpecs())
|
|
mf, err := manifest.Serialize(rPkgs, rContainers, rCommits)
|
|
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,
|
|
Size: imgType.Size(0),
|
|
Manifest: mf,
|
|
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,
|
|
Size: imgType2.Size(0),
|
|
Manifest: mf,
|
|
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 TestExpandBlueprintNoGlob(t *testing.T) {
|
|
packages := []blueprint.Package{
|
|
{Name: "tmux", Version: "3.3a"},
|
|
{Name: "openssh-server", Version: "*"},
|
|
{Name: "grub2", Version: "*"},
|
|
}
|
|
// Sorted list of dependencies
|
|
dependencies := []rpmmd.PackageSpec{
|
|
{
|
|
Name: "grub2",
|
|
Epoch: 1,
|
|
Version: "2.06",
|
|
Release: "94.fc38",
|
|
Arch: "noarch",
|
|
},
|
|
{
|
|
Name: "openssh-server",
|
|
Epoch: 0,
|
|
Version: "9.0p1",
|
|
Release: "15.fc38",
|
|
Arch: "x86_64",
|
|
},
|
|
{
|
|
Name: "tmux",
|
|
Epoch: 0,
|
|
Version: "3.3a",
|
|
Release: "3.fc38",
|
|
Arch: "x86_64",
|
|
},
|
|
}
|
|
|
|
newPackages, err := expandBlueprintGlobs(dependencies, packages)
|
|
require.NoError(t, err, "Error expanding globs")
|
|
expected := []blueprint.Package{
|
|
{Name: "grub2", Version: "1:2.06-94.fc38.noarch"},
|
|
{Name: "openssh-server", Version: "9.0p1-15.fc38.x86_64"},
|
|
{Name: "tmux", Version: "3.3a-3.fc38.x86_64"},
|
|
}
|
|
assert.Equal(t, expected, newPackages)
|
|
}
|
|
|
|
func TestExpandBlueprintError(t *testing.T) {
|
|
// Test that a missing package in deps returns an error
|
|
packages := []blueprint.Package{
|
|
{Name: "tmux", Version: "*"},
|
|
{Name: "dep-package0", Version: "*"},
|
|
}
|
|
// Sorted list of dependencies
|
|
dependencies := []rpmmd.PackageSpec{
|
|
{
|
|
Name: "openssh-server",
|
|
Epoch: 0,
|
|
Version: "9.0p1",
|
|
Release: "15.fc38",
|
|
Arch: "x86_64",
|
|
},
|
|
{
|
|
Name: "tmux",
|
|
Epoch: 0,
|
|
Version: "3.3a",
|
|
Release: "3.fc38",
|
|
Arch: "x86_64",
|
|
},
|
|
}
|
|
_, err := expandBlueprintGlobs(dependencies, packages)
|
|
require.EqualError(t, err, "dep-package0 missing from depsolve results")
|
|
}
|
|
|
|
func TestExpandBlueprintGlobs(t *testing.T) {
|
|
packages := []blueprint.Package{
|
|
{Name: "tmux", Version: "*"},
|
|
{Name: "openssh-*", Version: "*"},
|
|
{Name: "test-?-*", Version: "*"},
|
|
{Name: "test-three-*", Version: "11.1"},
|
|
{Name: "test-*", Version: "*"},
|
|
}
|
|
// Sorted list of dependencies
|
|
dependencies := []rpmmd.PackageSpec{
|
|
{
|
|
Name: "openssh-clients",
|
|
Epoch: 0,
|
|
Version: "9.0p1",
|
|
Release: "15.fc38",
|
|
Arch: "x86_64",
|
|
},
|
|
{
|
|
Name: "openssh-server",
|
|
Epoch: 0,
|
|
Version: "9.0p1",
|
|
Release: "15.fc38",
|
|
Arch: "x86_64",
|
|
},
|
|
{
|
|
Name: "test-1-one",
|
|
Epoch: 0,
|
|
Version: "1.0.0",
|
|
Release: "1.fc38",
|
|
Arch: "x86_64",
|
|
},
|
|
{
|
|
Name: "test-2-two",
|
|
Epoch: 2,
|
|
Version: "1.0.0",
|
|
Release: "1.fc38",
|
|
Arch: "x86_64",
|
|
},
|
|
{
|
|
Name: "test-three-3",
|
|
Epoch: 0,
|
|
Version: "11.1",
|
|
Release: "1.fc38",
|
|
Arch: "x86_64",
|
|
},
|
|
{
|
|
Name: "tmux",
|
|
Epoch: 0,
|
|
Version: "3.3a",
|
|
Release: "3.fc38",
|
|
Arch: "x86_64",
|
|
},
|
|
}
|
|
|
|
newPackages, err := expandBlueprintGlobs(dependencies, packages)
|
|
require.NoError(t, err, "Error expanding globs")
|
|
expected := []blueprint.Package{
|
|
{Name: "openssh-clients", Version: "9.0p1-15.fc38.x86_64"},
|
|
{Name: "openssh-server", Version: "9.0p1-15.fc38.x86_64"},
|
|
{Name: "test-1-one", Version: "1.0.0-1.fc38.x86_64"},
|
|
{Name: "test-2-two", Version: "2:1.0.0-1.fc38.x86_64"},
|
|
{Name: "test-three-3", Version: "11.1-1.fc38.x86_64"},
|
|
{Name: "tmux", Version: "3.3a-3.fc38.x86_64"},
|
|
}
|
|
assert.Equal(t, expected, newPackages)
|
|
}
|
|
|
|
func TestMain(m *testing.M) {
|
|
setupDNFJSON()
|
|
defer os.RemoveAll(dnfjsonPath)
|
|
code := m.Run()
|
|
os.Exit(code)
|
|
}
|