Skip to content

Commit

Permalink
Merge pull request #658 from kinvolk/alban/inceptiontap
Browse files Browse the repository at this point in the history
Fix TAP output with multiple RuntimeInsideValidate
  • Loading branch information
Zhou Hao authored Aug 21, 2018
2 parents 699dbce + 069db1a commit 2e13089
Show file tree
Hide file tree
Showing 20 changed files with 130 additions and 47 deletions.
49 changes: 46 additions & 3 deletions docs/devel_guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,52 @@ Each validation test has a `.go` file in the `validation/` directory and can be
### TAP output

Each validation test prints TAP output.
So far, we have two kinds of validation tests and they print the TAP output differently:
* tests using `util.RuntimeInsideValidate`: they start the process `runtimetest` inside the container and `runtimetest` prints the TAP output. The test process itself must not output anything to avoid mixing its output with the TAP output. Each test can only call `util.RuntimeInsideValidate` one time because several TAP outputs cannot be concatenated.
* tests using `util.RuntimeOutsideValidate`: they create a container but without executing `runtimetest`. The test program itself must print the TAP output.
So far, we have three kinds of validation tests and they print the TAP output differently:

#### Using `util.RuntimeOutsideValidate`

They create a container but without executing `runtimetest`. The test program itself must print the TAP output.

Example:
```go
err = util.RuntimeOutsideValidate(g, t, func(config *rspec.Spec, t *tap.T, state *rspec.State) error {
err := testFoo()
t.Ok((err == nil), "check foo")
if err != nil {
t.Diagnostic(err.Error())
return nil
}
return nil
})

```
#### Using `util.RuntimeInsideValidate` and passthrough

They start the process `runtimetest` inside the container and `runtimetest` prints the TAP output.
The test process itself must not output anything to avoid mixing its output with the TAP output.
Each test can only call `util.RuntimeInsideValidate` one time because several TAP outputs cannot be concatenated.

Example:
```go
err = util.RuntimeInsideValidate(g, nil, nil)
if err != nil {
util.Fatal(err)
}
```

#### Using `util.RuntimeInsideValidate` and encapsulation

Similar to the passthrough variant but the test consumes the output from `runtimetest` and re-emit a single TAP result for the container run.
For that, the TAP object must be passed as parameter to `util.RuntimeInsideValidate`.

Example:
```go
g.AddAnnotation("TestName", "check foo")
err = util.RuntimeInsideValidate(g, t, nil)
if err != nil {
util.Fatal(err)
}
```

### Exit status

Expand Down
2 changes: 1 addition & 1 deletion validation/default/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func main() {
if err != nil {
util.Fatal(err)
}
err = util.RuntimeInsideValidate(g, nil)
err = util.RuntimeInsideValidate(g, nil, nil)
if err != nil {
util.Fatal(err)
}
Expand Down
3 changes: 2 additions & 1 deletion validation/hostname/hostname.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ func testHostname(t *tap.T, hostname string) error {
}

g.SetHostname(hostname)
err = util.RuntimeInsideValidate(g, nil)
g.AddAnnotation("TestName", fmt.Sprintf("check hostname %q", hostname))
err = util.RuntimeInsideValidate(g, t, nil)
t.Ok(err == nil, "hostname is set correctly")
if err != nil {
t.Diagnosticf("expect: err == nil, actual: err != nil")
Expand Down
2 changes: 1 addition & 1 deletion validation/linux_devices/linux_devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func main() {
pdev.FileMode = &pmode
g.AddDevice(pdev)

err = util.RuntimeInsideValidate(g, nil)
err = util.RuntimeInsideValidate(g, nil, nil)
if err != nil {
util.Fatal(err)
}
Expand Down
33 changes: 21 additions & 12 deletions validation/linux_masked_paths/linux_masked_paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
"os"
"path/filepath"

"github.com/mndrix/tap-go"
"github.com/opencontainers/runtime-tools/validation/util"
"golang.org/x/sys/unix"
)

func checkMaskedPaths() error {
func checkMaskedPaths(t *tap.T) error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
Expand All @@ -32,7 +33,8 @@ func checkMaskedPaths() error {
g.AddLinuxMaskedPaths(maskedDirSub)
g.AddLinuxMaskedPaths(maskedFileSub)
g.AddLinuxMaskedPaths(maskedFileSubSub)
err = util.RuntimeInsideValidate(g, func(path string) error {
g.AddAnnotation("TestName", "check masked paths")
err = util.RuntimeInsideValidate(g, t, func(path string) error {
testDir := filepath.Join(path, maskedDirSub)
err = os.MkdirAll(testDir, 0777)
if err != nil {
Expand Down Expand Up @@ -63,7 +65,7 @@ func checkMaskedPaths() error {
return err
}

func checkMaskedRelPaths() error {
func checkMaskedRelPaths(t *tap.T) error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
Expand All @@ -73,7 +75,8 @@ func checkMaskedRelPaths() error {
maskedRelPath := "masked-relpath"

g.AddLinuxMaskedPaths(maskedRelPath)
err = util.RuntimeInsideValidate(g, func(path string) error {
g.AddAnnotation("TestName", "check masked relative paths")
err = util.RuntimeInsideValidate(g, t, func(path string) error {
testFile := filepath.Join(path, maskedRelPath)
if _, err := os.Stat(testFile); err != nil && os.IsNotExist(err) {
return err
Expand All @@ -87,7 +90,7 @@ func checkMaskedRelPaths() error {
return fmt.Errorf("expected: err != nil, actual: err == nil")
}

func checkMaskedSymlinks() error {
func checkMaskedSymlinks(t *tap.T) error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
Expand All @@ -98,7 +101,8 @@ func checkMaskedSymlinks() error {
maskedSymlink := "/masked-symlink"

g.AddLinuxMaskedPaths(maskedSymlink)
err = util.RuntimeInsideValidate(g, func(path string) error {
g.AddAnnotation("TestName", "check masked symlinks")
err = util.RuntimeInsideValidate(g, t, func(path string) error {
testFile := filepath.Join(path, maskedSymlink)
// ln -s .. /masked-symlink ; readlink -f /masked-symlink; ls -L /masked-symlink
if err := os.Symlink("../masked-symlink", testFile); err != nil {
Expand All @@ -121,7 +125,7 @@ func checkMaskedSymlinks() error {
return fmt.Errorf("expected: err != nil, actual: err == nil")
}

func checkMaskedDeviceNodes(mode uint32) error {
func checkMaskedDeviceNodes(t *tap.T, mode uint32) error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
Expand All @@ -130,7 +134,8 @@ func checkMaskedDeviceNodes(mode uint32) error {
maskedDevice := "/masked-device"

g.AddLinuxMaskedPaths(maskedDevice)
return util.RuntimeInsideValidate(g, func(path string) error {
g.AddAnnotation("TestName", "check masked device nodes")
return util.RuntimeInsideValidate(g, t, func(path string) error {
testFile := filepath.Join(path, maskedDevice)

if err := unix.Mknod(testFile, mode, 0); err != nil {
Expand All @@ -146,15 +151,19 @@ func checkMaskedDeviceNodes(mode uint32) error {
}

func main() {
if err := checkMaskedPaths(); err != nil {
t := tap.New()
t.Header(0)
defer t.AutoPlan()

if err := checkMaskedPaths(t); err != nil {
util.Fatal(err)
}

if err := checkMaskedRelPaths(); err != nil {
if err := checkMaskedRelPaths(t); err != nil {
util.Fatal(err)
}

if err := checkMaskedSymlinks(); err != nil {
if err := checkMaskedSymlinks(t); err != nil {
util.Fatal(err)
}

Expand All @@ -167,7 +176,7 @@ func main() {
}

for _, m := range modes {
if err := checkMaskedDeviceNodes(m); err != nil {
if err := checkMaskedDeviceNodes(t, m); err != nil {
util.Fatal(err)
}
}
Expand Down
33 changes: 21 additions & 12 deletions validation/linux_readonly_paths/linux_readonly_paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import (
"os"
"path/filepath"

"github.com/mndrix/tap-go"
"github.com/opencontainers/runtime-tools/validation/util"
"golang.org/x/sys/unix"
)

func checkReadonlyPaths() error {
func checkReadonlyPaths(t *tap.T) error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
Expand All @@ -32,7 +33,8 @@ func checkReadonlyPaths() error {
g.AddLinuxReadonlyPaths(readonlyDirSub)
g.AddLinuxReadonlyPaths(readonlyFileSub)
g.AddLinuxReadonlyPaths(readonlyFileSubSub)
err = util.RuntimeInsideValidate(g, func(path string) error {
g.AddAnnotation("TestName", "check read-only paths")
err = util.RuntimeInsideValidate(g, t, func(path string) error {
testDir := filepath.Join(path, readonlyDirSub)
err = os.MkdirAll(testDir, 0777)
if err != nil {
Expand Down Expand Up @@ -63,7 +65,7 @@ func checkReadonlyPaths() error {
return err
}

func checkReadonlyRelPaths() error {
func checkReadonlyRelPaths(t *tap.T) error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
Expand All @@ -73,7 +75,8 @@ func checkReadonlyRelPaths() error {
readonlyRelPath := "readonly-relpath"

g.AddLinuxReadonlyPaths(readonlyRelPath)
err = util.RuntimeInsideValidate(g, func(path string) error {
g.AddAnnotation("TestName", "check read-only relative paths")
err = util.RuntimeInsideValidate(g, t, func(path string) error {
testFile := filepath.Join(path, readonlyRelPath)
if _, err := os.Stat(testFile); err != nil && os.IsNotExist(err) {
return err
Expand All @@ -87,7 +90,7 @@ func checkReadonlyRelPaths() error {
return fmt.Errorf("expected: err != nil, actual: err == nil")
}

func checkReadonlySymlinks() error {
func checkReadonlySymlinks(t *tap.T) error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
Expand All @@ -98,7 +101,8 @@ func checkReadonlySymlinks() error {
readonlySymlink := "/readonly-symlink"

g.AddLinuxReadonlyPaths(readonlySymlink)
err = util.RuntimeInsideValidate(g, func(path string) error {
g.AddAnnotation("TestName", "check read-only symlinks")
err = util.RuntimeInsideValidate(g, t, func(path string) error {
testFile := filepath.Join(path, readonlySymlink)
// ln -s .. /readonly-symlink ; readlink -f /readonly-symlink; ls -L /readonly-symlink
if err := os.Symlink("../readonly-symlink", testFile); err != nil {
Expand All @@ -121,7 +125,7 @@ func checkReadonlySymlinks() error {
return fmt.Errorf("expected: err != nil, actual: err == nil")
}

func checkReadonlyDeviceNodes(mode uint32) error {
func checkReadonlyDeviceNodes(t *tap.T, mode uint32) error {
g, err := util.GetDefaultGenerator()
if err != nil {
return err
Expand All @@ -130,7 +134,8 @@ func checkReadonlyDeviceNodes(mode uint32) error {
readonlyDevice := "/readonly-device"

g.AddLinuxReadonlyPaths(readonlyDevice)
return util.RuntimeInsideValidate(g, func(path string) error {
g.AddAnnotation("TestName", "check read-only device nodes")
return util.RuntimeInsideValidate(g, t, func(path string) error {
testFile := filepath.Join(path, readonlyDevice)

if err := unix.Mknod(testFile, mode, 0); err != nil {
Expand All @@ -146,15 +151,19 @@ func checkReadonlyDeviceNodes(mode uint32) error {
}

func main() {
if err := checkReadonlyPaths(); err != nil {
t := tap.New()
t.Header(0)
defer t.AutoPlan()

if err := checkReadonlyPaths(t); err != nil {
util.Fatal(err)
}

if err := checkReadonlyRelPaths(); err != nil {
if err := checkReadonlyRelPaths(t); err != nil {
util.Fatal(err)
}

if err := checkReadonlySymlinks(); err != nil {
if err := checkReadonlySymlinks(t); err != nil {
util.Fatal(err)
}

Expand All @@ -167,7 +176,7 @@ func main() {
}

for _, m := range modes {
if err := checkReadonlyDeviceNodes(m); err != nil {
if err := checkReadonlyDeviceNodes(t, m); err != nil {
util.Fatal(err)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import (
"github.com/opencontainers/runtime-tools/validation/util"
)

func testLinuxRootPropagation(propMode string) error {
func testLinuxRootPropagation(t *tap.T, propMode string) error {
g, err := util.GetDefaultGenerator()
if err != nil {
util.Fatal(err)
}
g.SetupPrivileged(true)
g.SetLinuxRootPropagation(propMode)
return util.RuntimeInsideValidate(g, nil)
g.AddAnnotation("TestName", "check root propagation")
return util.RuntimeInsideValidate(g, t, nil)
}

func main() {
Expand All @@ -28,7 +29,7 @@ func main() {
}

for _, c := range cases {
if err := testLinuxRootPropagation(c); err != nil {
if err := testLinuxRootPropagation(t, c); err != nil {
t.Fail(err.Error())
}
}
Expand Down
2 changes: 1 addition & 1 deletion validation/linux_seccomp/linux_seccomp.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func main() {
}
g.SetDefaultSeccompAction("allow")
g.SetSyscallAction(syscallArgs)
err = util.RuntimeInsideValidate(g, nil)
err = util.RuntimeInsideValidate(g, nil, nil)
if err != nil {
util.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion validation/linux_sysctl/linux_sysctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func main() {
util.Fatal(err)
}
g.AddLinuxSysctl("net.ipv4.ip_forward", "1")
err = util.RuntimeInsideValidate(g, nil)
err = util.RuntimeInsideValidate(g, nil, nil)
if err != nil {
util.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion validation/linux_uid_mappings/linux_uid_mappings.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func main() {
g.AddOrReplaceLinuxNamespace("user", "")
g.AddLinuxUIDMapping(uint32(1000), uint32(0), uint32(2000))
g.AddLinuxGIDMapping(uint32(1000), uint32(0), uint32(3000))
err = util.RuntimeInsideValidate(g, nil)
err = util.RuntimeInsideValidate(g, nil, nil)
if err != nil {
util.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion validation/mounts/mounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func main() {
},
}
g.AddMount(mount)
err = util.RuntimeInsideValidate(g, nil)
err = util.RuntimeInsideValidate(g, nil, nil)
if err != nil {
util.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion validation/process/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func main() {
g.AddProcessEnv("testa", "valuea")
g.AddProcessEnv("testb", "123")

err = util.RuntimeInsideValidate(g, func(path string) error {
err = util.RuntimeInsideValidate(g, nil, func(path string) error {
pathName := filepath.Join(path, "test")
return os.MkdirAll(pathName, 0700)
})
Expand Down
2 changes: 1 addition & 1 deletion validation/process_capabilities/process_capabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func main() {
util.Fatal(err)
}
g.SetupPrivileged(true)
err = util.RuntimeInsideValidate(g, nil)
err = util.RuntimeInsideValidate(g, nil, nil)
if err != nil {
util.Fatal(err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func main() {
util.Fatal(err)
}
g.AddProcessCapabilityBounding("CAP_TEST")
err = util.RuntimeInsideValidate(g, nil)
err = util.RuntimeInsideValidate(g, nil, nil)
if err == nil {
util.Fatal(specerror.NewError(specerror.LinuxProcCapError, fmt.Errorf("Any value which cannot be mapped to a relevant kernel interface MUST cause an error"), rspecs.Version))
}
Expand Down
Loading

0 comments on commit 2e13089

Please sign in to comment.