1
0
mirror of https://github.com/openshift/source-to-image.git synced 2026-02-06 06:44:58 +01:00
Files
source-to-image/pkg/scripts/install_test.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)
}
}
}