mirror of
https://github.com/openshift/source-to-image.git
synced 2026-02-06 15:45:00 +01:00
354 lines
12 KiB
Go
354 lines
12 KiB
Go
package scripts
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/openshift/source-to-image/pkg/api"
|
|
"github.com/openshift/source-to-image/pkg/api/constants"
|
|
dockerpkg "github.com/openshift/source-to-image/pkg/docker"
|
|
"github.com/openshift/source-to-image/pkg/test"
|
|
testfs "github.com/openshift/source-to-image/pkg/test/fs"
|
|
"github.com/openshift/source-to-image/pkg/util/fs"
|
|
)
|
|
|
|
type fakeScriptManagerConfig struct {
|
|
download Downloader
|
|
docker dockerpkg.Docker
|
|
fs fs.FileSystem
|
|
url string
|
|
}
|
|
|
|
func newFakeConfig() *fakeScriptManagerConfig {
|
|
return &fakeScriptManagerConfig{
|
|
docker: &dockerpkg.FakeDocker{},
|
|
download: &test.FakeDownloader{},
|
|
fs: &testfs.FakeFileSystem{},
|
|
url: "http://the.scripts.url/s2i/bin",
|
|
}
|
|
}
|
|
|
|
func newFakeInstaller(config *fakeScriptManagerConfig) Installer {
|
|
m := DefaultScriptSourceManager{
|
|
Image: "test-image",
|
|
ScriptsURL: config.url,
|
|
docker: config.docker,
|
|
fs: config.fs,
|
|
download: config.download,
|
|
}
|
|
m.Add(&URLScriptHandler{URL: m.ScriptsURL, Download: m.download, FS: m.fs, Name: ScriptURLHandler})
|
|
m.Add(&SourceScriptHandler{fs: m.fs})
|
|
defaultURL, err := m.docker.GetScriptsURL(m.Image)
|
|
if err == nil && defaultURL != "" {
|
|
m.Add(&URLScriptHandler{URL: defaultURL, Download: m.download, FS: m.fs, Name: ImageURLHandler})
|
|
}
|
|
return &m
|
|
}
|
|
|
|
func isValidInstallResult(result api.InstallResult, t *testing.T) {
|
|
if len(result.Script) == 0 {
|
|
t.Errorf("expected the Script not be empty")
|
|
}
|
|
if result.Error != nil {
|
|
t.Errorf("unexpected the error %v for the %q script in install result", result.Error, result.Script)
|
|
}
|
|
if !result.Downloaded {
|
|
t.Errorf("expected the %q script install result to be downloaded", result.Script)
|
|
}
|
|
if !result.Installed {
|
|
t.Errorf("expected the %q script install result to be installed", result.Script)
|
|
}
|
|
if len(result.URL) == 0 {
|
|
t.Errorf("expected the %q script install result to have valid URL", result.Script)
|
|
}
|
|
}
|
|
|
|
func TestInstallOptionalFromURL(t *testing.T) {
|
|
config := newFakeConfig()
|
|
inst := newFakeInstaller(config)
|
|
scripts := []string{constants.Assemble, constants.Run}
|
|
results := inst.InstallOptional(scripts, "/output")
|
|
for _, r := range results {
|
|
isValidInstallResult(r, t)
|
|
}
|
|
for _, s := range scripts {
|
|
downloaded := false
|
|
targets := config.download.(*test.FakeDownloader).Target
|
|
for _, t := range targets {
|
|
if filepath.ToSlash(t) == "/output/upload/scripts/"+s {
|
|
downloaded = true
|
|
}
|
|
}
|
|
if !downloaded {
|
|
t.Errorf("the script %q was not downloaded properly (%#v)", s, targets)
|
|
}
|
|
validURL := false
|
|
urls := config.download.(*test.FakeDownloader).URL
|
|
for _, u := range urls {
|
|
if u.String() == config.url+"/"+s {
|
|
validURL = true
|
|
}
|
|
}
|
|
if !validURL {
|
|
t.Errorf("the script %q was downloaded from invalid URL (%+v)", s, urls)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInstallRequiredFromURL(t *testing.T) {
|
|
config := newFakeConfig()
|
|
config.download.(*test.FakeDownloader).Err = map[string]error{
|
|
config.url + "/" + constants.Assemble: fmt.Errorf("download error"),
|
|
}
|
|
inst := newFakeInstaller(config)
|
|
scripts := []string{constants.Assemble, constants.Run}
|
|
_, err := inst.InstallRequired(scripts, "/output")
|
|
if err == nil {
|
|
t.Errorf("expected assemble to fail install")
|
|
}
|
|
}
|
|
|
|
func TestInstallRequiredFromDocker(t *testing.T) {
|
|
config := newFakeConfig()
|
|
// We fail the download for assemble, which means the Docker image default URL
|
|
// should be used instead.
|
|
config.download.(*test.FakeDownloader).Err = map[string]error{
|
|
config.url + "/" + constants.Assemble: fmt.Errorf("not available"),
|
|
}
|
|
defaultDockerURL := "image:///usr/libexec/s2i/bin"
|
|
config.docker.(*dockerpkg.FakeDocker).DefaultURLResult = defaultDockerURL
|
|
inst := newFakeInstaller(config)
|
|
scripts := []string{constants.Assemble, constants.Run}
|
|
results, err := inst.InstallRequired(scripts, "/output")
|
|
if err != nil {
|
|
t.Errorf("unexpected error, assemble should be installed from docker image url")
|
|
}
|
|
for _, r := range results {
|
|
isValidInstallResult(r, t)
|
|
}
|
|
for _, s := range scripts {
|
|
validURL := false
|
|
urls := config.download.(*test.FakeDownloader).URL
|
|
for _, u := range urls {
|
|
url := config.url
|
|
// The assemble script should be downloaded from image default URL
|
|
if s == constants.Assemble {
|
|
url = defaultDockerURL
|
|
}
|
|
if u.String() == url+"/"+s {
|
|
validURL = true
|
|
}
|
|
}
|
|
if !validURL {
|
|
t.Errorf("the script %q was downloaded from invalid URL (%+v)", s, urls)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInstallRequiredFromSource(t *testing.T) {
|
|
config := newFakeConfig()
|
|
// There is no other script source than the source code
|
|
config.url = ""
|
|
deprecatedSourceScripts := strings.Replace(constants.SourceScripts, ".s2i", ".sti", -1)
|
|
config.fs.(*testfs.FakeFileSystem).ExistsResult = map[string]bool{
|
|
filepath.Join("/workdir", constants.SourceScripts, constants.Assemble): true,
|
|
filepath.Join("/workdir", deprecatedSourceScripts, constants.Run): true,
|
|
}
|
|
inst := newFakeInstaller(config)
|
|
scripts := []string{constants.Assemble, constants.Run}
|
|
result, err := inst.InstallRequired(scripts, "/workdir")
|
|
if err != nil {
|
|
t.Errorf("unexpected error, assemble should be installed from docker image url: %v", err)
|
|
}
|
|
for _, r := range result {
|
|
isValidInstallResult(r, t)
|
|
}
|
|
for _, s := range scripts {
|
|
validResultURL := false
|
|
for _, r := range result {
|
|
// The constants.Run use deprecated path, but it should still work.
|
|
if s == constants.Run && r.URL == filepath.FromSlash(sourcesRootAbbrev+"/.sti/bin/"+s) {
|
|
validResultURL = true
|
|
}
|
|
if r.URL == filepath.FromSlash(sourcesRootAbbrev+"/.s2i/bin/"+s) {
|
|
validResultURL = true
|
|
}
|
|
}
|
|
if !validResultURL {
|
|
t.Errorf("expected %q has result URL %s, got %#v", s, filepath.FromSlash(sourcesRootAbbrev+"/.s2i/bin/"+s), result)
|
|
}
|
|
chmodCalled := false
|
|
filesystem := config.fs.(*testfs.FakeFileSystem)
|
|
for _, f := range filesystem.ChmodFile {
|
|
if filepath.ToSlash(f) == "/workdir/upload/scripts/"+s {
|
|
chmodCalled = true
|
|
}
|
|
}
|
|
if !chmodCalled {
|
|
t.Errorf("expected chmod called on /workdir/upload/scripts/%s", s)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestInstallRequiredOrder tests the proper order for retrieving the source
|
|
// scripts.
|
|
// The scenario here is that the assemble script does not exists in provided
|
|
// scripts url, but it exists in source code directory. The save-artifacts does
|
|
// not exists at provided url nor in source code, so the docker image default
|
|
// URL should be used.
|
|
func TestInstallRequiredOrder(t *testing.T) {
|
|
config := newFakeConfig()
|
|
config.download.(*test.FakeDownloader).Err = map[string]error{
|
|
config.url + "/" + constants.Assemble: fmt.Errorf("not available"),
|
|
config.url + "/" + constants.SaveArtifacts: fmt.Errorf("not available"),
|
|
}
|
|
config.fs.(*testfs.FakeFileSystem).ExistsResult = map[string]bool{
|
|
filepath.Join("/workdir", constants.SourceScripts, constants.Assemble): true,
|
|
filepath.Join("/workdir", constants.SourceScripts, constants.Run): false,
|
|
filepath.Join("/workdir", constants.SourceScripts, constants.SaveArtifacts): false,
|
|
}
|
|
defaultDockerURL := "http://the.docker.url/s2i"
|
|
config.docker.(*dockerpkg.FakeDocker).DefaultURLResult = defaultDockerURL
|
|
scripts := []string{constants.Assemble, constants.Run, constants.SaveArtifacts}
|
|
inst := newFakeInstaller(config)
|
|
result, err := inst.InstallRequired(scripts, "/workdir")
|
|
if err != nil {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
for _, r := range result {
|
|
isValidInstallResult(r, t)
|
|
}
|
|
for _, s := range scripts {
|
|
found := false
|
|
for _, r := range result {
|
|
if r.Script == s && r.Script == constants.Assemble && r.URL == filepath.FromSlash(sourcesRootAbbrev+"/.s2i/bin/assemble") {
|
|
found = true
|
|
break
|
|
}
|
|
if r.Script == s && r.Script == constants.Run && r.URL == config.url+"/"+constants.Run {
|
|
found = true
|
|
break
|
|
}
|
|
if r.Script == s && r.Script == constants.SaveArtifacts && r.URL == defaultDockerURL+"/"+constants.SaveArtifacts {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("the %q script installed in wrong order: %+v", s, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInstallRequiredError(t *testing.T) {
|
|
config := newFakeConfig()
|
|
config.url = ""
|
|
scripts := []string{constants.Assemble, constants.Run}
|
|
inst := newFakeInstaller(config)
|
|
result, err := inst.InstallRequired(scripts, "/output")
|
|
if err == nil {
|
|
t.Errorf("expected error, got %+v", result)
|
|
}
|
|
}
|
|
|
|
func TestInstallRequiredFromInvalidURL(t *testing.T) {
|
|
config := newFakeConfig()
|
|
config.url = "../invalid-url"
|
|
scripts := []string{constants.Assemble}
|
|
inst := newFakeInstaller(config)
|
|
result, err := inst.InstallRequired(scripts, "/output")
|
|
if err == nil {
|
|
t.Errorf("expected error, got %+v", result)
|
|
}
|
|
}
|
|
|
|
func TestNewInstaller(t *testing.T) {
|
|
docker := &dockerpkg.FakeDocker{DefaultURLResult: "image://docker"}
|
|
inst := NewInstaller("test-image", "http://foo.bar", nil, docker, api.AuthConfig{}, &testfs.FakeFileSystem{}, nil)
|
|
sources := inst.(*DefaultScriptSourceManager).sources
|
|
firstHandler, ok := sources[0].(*URLScriptHandler)
|
|
if !ok {
|
|
t.Errorf("expected first handler to be script url handler, got %#v", inst.(*DefaultScriptSourceManager).sources)
|
|
}
|
|
if firstHandler.URL != "http://foo.bar" {
|
|
t.Errorf("expected first handler to handle the script url, got %+v", firstHandler)
|
|
}
|
|
lastHandler, ok := sources[len(sources)-1].(*URLScriptHandler)
|
|
if !ok {
|
|
t.Errorf("expected last handler to be docker url handler, got %#v", inst.(*DefaultScriptSourceManager).sources)
|
|
}
|
|
if lastHandler.URL != "image://docker" {
|
|
t.Errorf("expected last handler to handle the docker default url, got %+v", lastHandler)
|
|
}
|
|
}
|
|
|
|
func TestNewInstallerWithBuilderImageLabels(t *testing.T) {
|
|
config := &api.Config{
|
|
BuilderImageLabels: map[string]string{
|
|
constants.ScriptsURLLabel: "image:///usr/some/dir",
|
|
},
|
|
}
|
|
inst := NewInstaller("test-image", "http://foo.bar", nil, nil, api.AuthConfig{}, &testfs.FakeFileSystem{}, config)
|
|
sources := inst.(*DefaultScriptSourceManager).sources
|
|
firstHandler, ok := sources[0].(*URLScriptHandler)
|
|
if !ok {
|
|
t.Errorf("expected first handler to be script url handler, got %#v", inst.(*DefaultScriptSourceManager).sources)
|
|
}
|
|
if firstHandler.URL != "http://foo.bar" {
|
|
t.Errorf("expected first handler to handle the script url, got %+v", firstHandler)
|
|
}
|
|
lastHandler, ok := sources[len(sources)-1].(*URLScriptHandler)
|
|
if !ok {
|
|
t.Errorf("expected last handler to be docker url handler, got %#v", inst.(*DefaultScriptSourceManager).sources)
|
|
}
|
|
if lastHandler.URL != "image:///usr/some/dir" {
|
|
t.Errorf("expected last handler to handle the builder image label url, got %+v", lastHandler)
|
|
}
|
|
|
|
}
|
|
|
|
type fakeSource struct {
|
|
name string
|
|
failOn map[string]struct{}
|
|
}
|
|
|
|
func (f *fakeSource) Get(script string) *api.InstallResult {
|
|
return &api.InstallResult{Script: script}
|
|
}
|
|
|
|
func (f *fakeSource) Install(r *api.InstallResult) error {
|
|
if _, fail := f.failOn[r.Script]; fail {
|
|
return fmt.Errorf("error")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f *fakeSource) SetDestinationDir(string) {}
|
|
|
|
func (f *fakeSource) String() string {
|
|
return f.name
|
|
}
|
|
|
|
func TestInstallOptionalFailedSources(t *testing.T) {
|
|
|
|
m := DefaultScriptSourceManager{}
|
|
m.Add(&fakeSource{name: "failing1", failOn: map[string]struct{}{"one": {}, "two": {}, "three": {}}})
|
|
m.Add(&fakeSource{name: "failing2", failOn: map[string]struct{}{"one": {}, "two": {}, "three": {}}})
|
|
m.Add(&fakeSource{name: "almostpassing", failOn: map[string]struct{}{"three": {}}})
|
|
|
|
expect := map[string][]string{
|
|
"one": {"failing1", "failing2"},
|
|
"two": {"failing1", "failing2"},
|
|
"three": {"failing1", "failing2", "almostpassing"},
|
|
}
|
|
results := m.InstallOptional([]string{"one", "two", "three"}, "foo")
|
|
for _, result := range results {
|
|
if !reflect.DeepEqual(result.FailedSources, expect[result.Script]) {
|
|
t.Errorf("Did not get expected failed sources: %#v", result)
|
|
}
|
|
}
|
|
}
|