Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example tests #2

Open
wants to merge 1 commit into
base: master-stest
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 189 additions & 0 deletions e2e/example/example.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// Copyright (c) 2019, Sylabs Inc. All rights reserved.
// This software is licensed under a 3-clause BSD license. Please consult the
// LICENSE.md file distributed with the sources of this project regarding your
// rights to use or distribute this software.

package example

import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"

"github.com/sylabs/singularity/e2e/internal/e2e"
"github.com/sylabs/singularity/internal/pkg/test"
)

type testingEnv struct {
// base env for running tests
CmdPath string `split_words:"true"`
TestDir string `split_words:"true"`
RunDisabled bool `default:"false"`
// base image for tests
ImagePath string `split_words:"true"`
}

var testenv testingEnv

// exec tests min fuctionality for singularity exec
func testSingularityGeneric(t *testing.T, name string, privileged bool, action string, options e2e.ExecOpts, image string) {
testFn := test.WithoutPrivilege
if privileged {
testFn = test.WithPrivilege
}

const (
testfile = "testSingularityExec.tmp"
testdir = "testSingularityExec.dir"
)

t.Run(name, testFn(func(t *testing.T) {
if options.Userns {
// check if user namespace is supported and skip test if not
}

workdir, err := e2e.MakeTmpDir(testenv.TestDir, "d-", 0755)
defer os.RemoveAll(workdir)

if err := os.MkdirAll(filepath.Join(workdir, "tmp", testdir), 0755); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(workdir, testfile), []byte{}, 0755); err != nil {
t.Fatal(err)
}

// running parallel test could have side effects while
// setting current working directory because it would affect
// other Go threads too, it's safer to set cmd.Dir instead
pwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
defer os.Chdir(pwd)

// required when running as root with user namespace enabled
// because generally current working directory is located in
// user home directory, so even if running as root and user
// namespace enabled, root will get a permission denied while
// mounting current working directory. Change this to temporary
// workdir
if err := os.Chdir(workdir); err != nil {
t.Fatal(err)
}

tests := []struct {
name string
argv []string
e2e.ExecOpts
exitCode int
searchOutput string
}{
{"true", []string{"true"}, e2e.ExecOpts{}, 0, ""},
{"trueAbsPAth", []string{"/bin/true"}, e2e.ExecOpts{}, 0, ""},
{"false", []string{"false"}, e2e.ExecOpts{}, 1, ""},
{"falseAbsPath", []string{"/bin/false"}, e2e.ExecOpts{}, 1, ""},
// Scif apps tests
{"ScifTestAppGood", []string{"testapp.sh"}, e2e.ExecOpts{App: "testapp"}, 0, ""},
{"ScifTestAppBad", []string{"testapp.sh"}, e2e.ExecOpts{App: "fakeapp"}, 1, ""},
{"ScifTestfolderOrg", []string{"test", "-d", "/scif"}, e2e.ExecOpts{}, 0, ""},
{"ScifTestfolderOrg", []string{"test", "-d", "/scif/apps"}, e2e.ExecOpts{}, 0, ""},
{"ScifTestfolderOrg", []string{"test", "-d", "/scif/data"}, e2e.ExecOpts{}, 0, ""},
{"ScifTestfolderOrg", []string{"test", "-d", "/scif/apps/foo"}, e2e.ExecOpts{}, 0, ""},
{"ScifTestfolderOrg", []string{"test", "-d", "/scif/apps/bar"}, e2e.ExecOpts{}, 0, ""},
// blocked by issue [scif-apps] Files created at install step fall into an unexpected path #2404
{"ScifTestfolderOrg", []string{"test", "-f", "/scif/apps/foo/filefoo.exec"}, e2e.ExecOpts{}, 0, ""},
{"ScifTestfolderOrg", []string{"test", "-f", "/scif/apps/bar/filebar.exec"}, e2e.ExecOpts{}, 0, ""},
{"ScifTestfolderOrg", []string{"test", "-d", "/scif/data/foo/output"}, e2e.ExecOpts{}, 0, ""},
{"ScifTestfolderOrg", []string{"test", "-d", "/scif/data/foo/input"}, e2e.ExecOpts{}, 0, ""},
{"WorkdirContain", []string{"test", "-d", "/tmp/" + testdir}, e2e.ExecOpts{Workdir: workdir, Contain: true}, 0, ""},
{"Workdir", []string{"test", "-d", "/tmp/" + testdir}, e2e.ExecOpts{Workdir: workdir}, 1, ""},
{"pwdGood", []string{"true"}, e2e.ExecOpts{Pwd: "/etc"}, 0, ""},
{"home", []string{"test", "-f", filepath.Join(workdir, testfile)}, e2e.ExecOpts{Home: workdir}, 0, ""},
{"noHome", []string{"test", "-f", "/home/" + testfile}, e2e.ExecOpts{Home: workdir + ":/home", NoHome: true}, 1, ""},
{"homePath", []string{"test", "-f", "/home/" + testfile}, e2e.ExecOpts{Home: workdir + ":/home"}, 0, ""},
{"homeTmp", []string{"true"}, e2e.ExecOpts{Home: "/tmp"}, 0, ""},
{"homeTmpExplicit", []string{"true"}, e2e.ExecOpts{Home: "/tmp:/home"}, 0, ""},
{"ScifTestAppGood", []string{"testapp.sh"}, e2e.ExecOpts{App: "testapp"}, 0, ""},
{"ScifTestAppBad", []string{"testapp.sh"}, e2e.ExecOpts{App: "fakeapp"}, 1, ""},
{"userBind", []string{"test", "-f", "/mnt/" + testfile}, e2e.ExecOpts{Binds: []string{workdir + ":/mnt"}}, 0, ""},
{"PwdGood", []string{"pwd"}, e2e.ExecOpts{Pwd: "/etc"}, 0, "/etc"},
}

for _, tt := range tests {
// note that we need to run tests with the same
// privileges wrapper function otherwise tests
// will be always executed as root
t.Run(tt.name, testFn(func(t *testing.T) {
if options.Userns {
tt.ExecOpts.Userns = true
}
stdout, stderr, exitCode, err := e2e.ImageExec(t, testenv.CmdPath, action, tt.ExecOpts, image, tt.argv)
if stdout != "" && !strings.Contains(stdout, tt.searchOutput) {
t.Log(stdout)
t.Fatalf("unexpected output returned running '%v': %v", strings.Join(tt.argv, " "), err)
} else if tt.exitCode >= 0 && exitCode == tt.exitCode {
// PASS
return
} else if tt.exitCode == 0 && exitCode != 0 {
// FAIL
t.Log(stderr)
t.Fatalf("unexpected failure running '%v': %v", strings.Join(tt.argv, " "), err)
} else if tt.exitCode != 0 && exitCode == 0 {
// FAIL
t.Log(stderr)
t.Fatalf("unexpected success running '%v'", strings.Join(tt.argv, " "))
} else if err != nil {
// FAIL
t.Log(stderr)
t.Fatalf("unexpected error running '%v': %s", strings.Join(tt.argv, " "), err)
}
}))
}
}))
}

// RunE2ETests is the main func to trigger the test suite
func RunE2ETests(t *testing.T) {
e2e.LoadEnv(t, &testenv)
e2e.EnsureImage(t)

// world writable to allow unprivileged build to write
// sandbox image
sandboxUnpriv, err := e2e.MakeTmpDir(testenv.TestDir, "d-", 0777)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(sandboxUnpriv)

// need to change how SINGULARITY_CACHEDIR is set for parallel tests
test.DropPrivilege(t)
if output, err := e2e.ImageBuild(testenv.CmdPath, e2e.BuildOpts{Force: true, Sandbox: true}, sandboxUnpriv, testenv.ImagePath); err != nil {
t.Fatalf("%s: %s", err, string(output))
}
test.ResetPrivilege(t)

sandboxPriv, err := e2e.MakeTmpDir(testenv.TestDir, "d-", 0755)
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(sandboxPriv)

if output, err := e2e.ImageBuild(testenv.CmdPath, e2e.BuildOpts{Force: true, Sandbox: true}, sandboxPriv, testenv.ImagePath); err != nil {
t.Fatalf("%s: %s", err, string(output))
}

testSingularityGeneric(t, "Exec", false, "exec", e2e.ExecOpts{}, testenv.ImagePath)
testSingularityGeneric(t, "ExecPriv", true, "exec", e2e.ExecOpts{}, testenv.ImagePath)
testSingularityGeneric(t, "Run", false, "run", e2e.ExecOpts{}, testenv.ImagePath)
testSingularityGeneric(t, "RunPriv", true, "run", e2e.ExecOpts{}, testenv.ImagePath)
testSingularityGeneric(t, "ExecUsernsWithSIF", false, "exec", e2e.ExecOpts{Userns: true}, testenv.ImagePath)
testSingularityGeneric(t, "ExecUsernsPrivWithSIF", true, "exec", e2e.ExecOpts{Userns: true}, testenv.ImagePath)
testSingularityGeneric(t, "RunUsernsWithSIF", false, "run", e2e.ExecOpts{Userns: true}, testenv.ImagePath)
testSingularityGeneric(t, "RunUsernsPrivWithSIF", true, "run", e2e.ExecOpts{Userns: true}, testenv.ImagePath)
testSingularityGeneric(t, "ExecUsernsWithSandbox", false, "exec", e2e.ExecOpts{Userns: true}, sandboxUnpriv)
testSingularityGeneric(t, "ExecUsernsPrivWithSandbox", true, "exec", e2e.ExecOpts{Userns: true}, sandboxPriv)
testSingularityGeneric(t, "RunUsernsWithSandbox", false, "run", e2e.ExecOpts{Userns: true}, sandboxUnpriv)
testSingularityGeneric(t, "RunUsernsPrivWithSandbox", true, "run", e2e.ExecOpts{Userns: true}, sandboxPriv)
}
102 changes: 102 additions & 0 deletions e2e/scripts/example/example.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@

source common.func

test-singularity-generic() {
local name="$1"
local privileged="$2"
local command="$3"
local options="$4"
local img="$5"
local oldcwd="$PWD"

case "${options}" in
*-u*|*--userns*)
if ! check-namespace "user"; then
test-skip "${name}" "user namespace not supported"
return
fi
;;
esac

# create test file/dir
local testfile="testSingularityExec.tmp"
local testdir="testSingularityExec.dir"

# workdir
if [ $privileged = "true" ]; then
local workdir=`mktmpdir 0755 root:root`
sudo mkdir -p ${workdir}/tmp/${testdir}
sudo touch ${workdir}/${testfile}

set sudo singularity ${command} ${options}
else
local workdir=`mktmpdir`
mkdir -p ${workdir}/tmp/${testdir}
touch ${workdir}/${testfile}

set singularity ${command} ${options}
fi

# go into workdir to not trigger error with user namespace execution
cd ${workdir}

expect-exit 1 "${name}/NoImage" $@
expect-exit 0 "${name}/True" $@ ${img} true
expect-exit 0 "${name}/TrueAbsPath" $@ ${img} /bin/true
expect-exit 1 "${name}/False" $@ ${img} false
expect-exit 1 "${name}/FalseAbsPath" $@ ${img} /bin/false

# Scif apps tests
expect-exit 0 "${name}/ScifTestAppGood" $@ --app testapp ${img} testapp.sh
expect-exit 1 "${name}/ScifTestAppBad" $@ --app fakeapp ${img} testapp.sh
expect-exit 0 "${name}/ScifTestfolderOrg" $@ ${img} test -d /scif
expect-exit 0 "${name}/ScifTestfolderOrg" $@ ${img} test -d /scif/apps
expect-exit 0 "${name}/ScifTestfolderOrg" $@ ${img} test -d /scif/data
expect-exit 0 "${name}/ScifTestfolderOrg" $@ ${img} test -d /scif/apps/foo
expect-exit 0 "${name}/ScifTestfolderOrg" $@ ${img} test -d /scif/apps/bar

# blocked by issue [scif-apps] Files created at install step fall into an unexpected path #2404
expect-exit 0 "${name}/ScifTestfolderOrg" $@ ${img} test -f /scif/apps/foo/filefoo.exec
expect-exit 0 "${name}/ScifTestfolderOrg" $@ ${img} test -f /scif/apps/bar/filebar.exec
expect-exit 0 "${name}/ScifTestfolderOrg" $@ ${img} test -d /scif/data/foo/output
expect-exit 0 "${name}/ScifTestfolderOrg" $@ ${img} test -d /scif/data/foo/input

# --workdir
expect-exit 0 "${name}/WorkdirContain" $@ --contain --workdir ${workdir} ${img} test -d /tmp/${testdir}
expect-exit 1 "${name}/Workdir" $@ --workdir ${workdir} ${img} test -d /tmp/${testdir}

# --home
expect-exit 0 "${name}/Home" $@ --home ${workdir} ${img} test -f ${workdir}/${testfile}
expect-exit 1 "${name}/NoHome" $@ --home ${workdir}:/home --no-home ${img} test -f /home/${testfile}
expect-exit 0 "${name}/HomePath" $@ --home ${workdir}:/home ${img} test -f /home/${testfile}
expect-exit 0 "${name}/HomeTmp" $@ --home /tmp ${img} true
expect-exit 0 "${name}/HomeTmpExplicit" $@ --home /tmp:/home ${img} true

expect-exit 0 "${name}/UserBind" $@ --bind ${workdir}:/mnt ${img} test -f /mnt/${testfile}

stdout-contains "${name}/PwdGood" "/etc" $@ --pwd /etc ${img} pwd

cd ${oldcwd}
}

image=`get-test-image`

sandbox_unpriv=`mktmpdir`
run-command singularity build -F -s ${sandbox_unpriv} ${image}

sandbox_priv=`mktmpdir 0700 root:root`
run-command sudo singularity build -F -s ${sandbox_priv} ${image}

######################## NAME RUN-PRIVILEGED COMMAND CUSTOM_OPTIONS IMAGE
test-singularity-generic "Exec" false exec "" ${image}
test-singularity-generic "ExecPriv" true exec "" ${image}
test-singularity-generic "Run" false run "" ${image}
test-singularity-generic "RunPriv" true run "" ${image}
test-singularity-generic "ExecUsernsWithSIF" false exec "-u" ${image}
test-singularity-generic "ExecUsernsPrivWithSIF" true exec "-u" ${image}
test-singularity-generic "RunUsernsWithSIF" false run "-u" ${image}
test-singularity-generic "RunUsernsPrivWithSIF" true run "-u" ${image}
test-singularity-generic "ExecUsernsWithSandbox" false exec "-u" ${sandbox_unpriv}
test-singularity-generic "ExecUsernsPrivWithSandbox" true exec "-u" ${sandbox_priv}
test-singularity-generic "RunUsernsWithSandbox" false run "-u" ${sandbox_unpriv}
test-singularity-generic "RunUsernsPrivWithSandbox" true run "-u" ${sandbox_priv}
8 changes: 5 additions & 3 deletions e2e/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import (
"github.com/sylabs/singularity/e2e/actions"
"github.com/sylabs/singularity/e2e/docker"
singularityenv "github.com/sylabs/singularity/e2e/env"
"github.com/sylabs/singularity/e2e/example"
"github.com/sylabs/singularity/e2e/help"
"github.com/sylabs/singularity/e2e/imgbuild"
"github.com/sylabs/singularity/e2e/instance"
singularitye2e "github.com/sylabs/singularity/e2e/internal/e2e"
"github.com/sylabs/singularity/e2e/pull"
"github.com/sylabs/singularity/e2e/remote"
version "github.com/sylabs/singularity/e2e/version"
Expand Down Expand Up @@ -91,8 +91,8 @@ func Run(t *testing.T) {
defer os.Remove(imagePath)

// Start registry for tests
singularitye2e.PrepRegistry(t)
defer singularitye2e.KillRegistry(t)
//singularitye2e.PrepRegistry(t)
//defer singularitye2e.KillRegistry(t)

// RunE2ETests by functionality

Expand All @@ -113,4 +113,6 @@ func Run(t *testing.T) {
t.Run("ENV", singularityenv.RunE2ETests)

t.Run("VERSION", version.RunE2ETests)

t.Run("EXAMPLE", example.RunE2ETests)
}