diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 190ea7df4..6a514c4bf 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -24,6 +24,10 @@ "ImportPath": "github.com/hashicorp/go-multierror", "Rev": "ed905158d87462226a13fe39ddf685ea65f1c11f" }, + { + "ImportPath": "github.com/mndrix/tap-go", + "Rev": "67c9553625499b7e7ed4ac4f2d8bf1cb8f5ecf52" + }, { "ImportPath": "github.com/opencontainers/runtime-spec/specs-go", "Comment": "v1.0.0-rc1-31-gbb6925e", diff --git a/Godeps/_workspace/src/github.com/mndrix/tap-go/.gitignore b/Godeps/_workspace/src/github.com/mndrix/tap-go/.gitignore new file mode 100644 index 000000000..9e8d7ca04 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mndrix/tap-go/.gitignore @@ -0,0 +1,3 @@ +gopath/pkg +test/*/test +/TAGS diff --git a/Godeps/_workspace/src/github.com/mndrix/tap-go/LICENSE b/Godeps/_workspace/src/github.com/mndrix/tap-go/LICENSE new file mode 100644 index 000000000..cf1ab25da --- /dev/null +++ b/Godeps/_workspace/src/github.com/mndrix/tap-go/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/Godeps/_workspace/src/github.com/mndrix/tap-go/Makefile b/Godeps/_workspace/src/github.com/mndrix/tap-go/Makefile new file mode 100644 index 000000000..dda78b2b2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mndrix/tap-go/Makefile @@ -0,0 +1,16 @@ +TESTS = auto check diagnostic known failing writer +GOPATH = $(CURDIR)/gopath + +.PHONY: $(TESTS) + +all: $(foreach t,$(TESTS),test/$(t)/test) + prove -v -e '' test/*/test + +clean: + rm -f test/*/test + +test/%/test: test/%/main.go tap.go + go build -o $@ $< + +$(TESTS): %: test/%/test + prove -v -e '' test/$@/test diff --git a/Godeps/_workspace/src/github.com/mndrix/tap-go/README.md b/Godeps/_workspace/src/github.com/mndrix/tap-go/README.md new file mode 100644 index 000000000..f795022df --- /dev/null +++ b/Godeps/_workspace/src/github.com/mndrix/tap-go/README.md @@ -0,0 +1,7 @@ +# Test Anything Protocol for Go + +The [Test Anything Protocol](http://testanything.org/) ("TAP") is a text-based +interface between tests and a test harness. This package helps Go to generate +TAP output. + +Read the [full package documentation](https://godoc.org/github.com/mndrix/tap-go) diff --git a/Godeps/_workspace/src/github.com/mndrix/tap-go/tap.go b/Godeps/_workspace/src/github.com/mndrix/tap-go/tap.go new file mode 100644 index 000000000..240542636 --- /dev/null +++ b/Godeps/_workspace/src/github.com/mndrix/tap-go/tap.go @@ -0,0 +1,130 @@ +// Package tap provides support for automated Test Anything Protocol ("TAP") +// tests in Go. For example: +// +// package main +// +// import "github.com/mndrix/tap-go" +// +// func main() { +// t := tap.New() +// t.Header(2) +// t.Ok(true, "first test") +// t.Ok(true, "second test") +// } +// +// generates the following output +// +// TAP version 13 +// 1..2 +// ok 1 - first test +// ok 2 - second test +package tap + +import ( + "fmt" + "io" + "os" + "strings" +) +import "testing/quick" + +// T is a type to encapsulate test state. Methods on this type generate TAP +// output. +type T struct { + nextTestNumber int + + // Writer indicates where TAP output should be sent. The default is os.Stdout. + Writer io.Writer +} + +// New creates a new Tap value +func New() *T { + return &T{ + nextTestNumber: 1, + } +} + +func (t *T) w() io.Writer { + if t.Writer == nil { + return os.Stdout + } + return t.Writer +} + +func (t *T) printf(format string, a ...interface{}) { + fmt.Fprintf(t.w(), format, a...) +} + +// Header displays a TAP header including version number and expected +// number of tests to run. For an unknown number of tests, set +// testCount to zero (in which case the plan is not written); this is +// useful with AutoPlan. +func (t *T) Header(testCount int) { + t.printf("TAP version 13\n") + if testCount > 0 { + t.printf("1..%d\n", testCount) + } +} + +// Ok generates TAP output indicating whether a test passed or failed. +func (t *T) Ok(test bool, description string) { + // did the test pass or not? + ok := "ok" + if !test { + ok = "not ok" + } + + t.printf("%s %d - %s\n", ok, t.nextTestNumber, description) + t.nextTestNumber++ +} + +// Fail indicates that a test has failed. This is typically only used when the +// logic is too complex to fit naturally into an Ok() call. +func (t *T) Fail(description string) { + t.Ok(false, description) +} + +// Pass indicates that a test has passed. This is typically only used when the +// logic is too complex to fit naturally into an Ok() call. +func (t *T) Pass(description string) { + t.Ok(true, description) +} + +// Check runs randomized tests against a function just as "testing/quick.Check" +// does. Success or failure generate appropriate TAP output. +func (t *T) Check(function interface{}, description string) { + err := quick.Check(function, nil) + if err == nil { + t.Ok(true, description) + return + } + + t.Diagnostic(err.Error()) + t.Ok(false, description) +} + +// Count returns the number of tests completed so far. +func (t *T) Count() int { + return t.nextTestNumber - 1 +} + +// AutoPlan generates a test plan based on the number of tests that were run. +func (t *T) AutoPlan() { + t.printf("1..%d\n", t.Count()) +} + +func escapeNewlines(s string) string { + return strings.Replace(strings.TrimRight(s, "\n"), "\n", "\n# ", -1) +} + +// Diagnostic generates a diagnostic from the message, +// which may span multiple lines. +func (t *T) Diagnostic(message string) { + t.printf("# %s\n", escapeNewlines(message)) +} + +// Diagnosticf generates a diagnostic from the format string and arguments, +// which may span multiple lines. +func (t *T) Diagnosticf(format string, a ...interface{}) { + t.printf("# "+escapeNewlines(format)+"\n", a...) +} diff --git a/cmd/runtimetest/main.go b/cmd/runtimetest/main.go index 7fd7ab0f6..371052c3b 100644 --- a/cmd/runtimetest/main.go +++ b/cmd/runtimetest/main.go @@ -15,6 +15,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/hashicorp/go-multierror" + "github.com/mndrix/tap-go" rspec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/cmd/runtimetest/mount" "github.com/syndtr/gocapability/capability" @@ -53,7 +54,10 @@ var ( } ) -type validation func(*rspec.Spec) error +type validation struct { + test func(*rspec.Spec) error + description string +} func loadSpecConfig() (spec *rspec.Spec, err error) { cf, err := os.Open(specConfig) @@ -588,41 +592,97 @@ func validate(context *cli.Context) error { } defaultValidations := []validation{ - validateRootFS, - validateHostname, - validateMountsExist, + { + test: validateRootFS, + description: "root filesystem", + }, + { + test: validateHostname, + description: "hostname", + }, + { + test: validateMountsExist, + description: "mounts", + }, } linuxValidations := []validation{ - validateCapabilities, - validateDefaultSymlinks, - validateDefaultFS, - validateDefaultDevices, - validateLinuxDevices, - validateLinuxProcess, - validateMaskedPaths, - validateOOMScoreAdj, - validateROPaths, - validateRlimits, - validateSysctls, - validateUIDMappings, - validateGIDMappings, + { + test: validateCapabilities, + description: "capabilities", + }, + { + test: validateDefaultSymlinks, + description: "default symlinks", + }, + { + test: validateDefaultFS, + description: "default file system", + }, + { + test: validateDefaultDevices, + description: "default devices", + }, + { + test: validateLinuxDevices, + description: "linux devices", + }, + { + test: validateLinuxProcess, + description: "linux process", + }, + { + test: validateMaskedPaths, + description: "masked paths", + }, + { + test: validateOOMScoreAdj, + description: "oom score adj", + }, + { + test: validateROPaths, + description: "read only paths", + }, + { + test: validateRlimits, + description: "rlimits", + }, + { + test: validateSysctls, + description: "sysctls", + }, + { + test: validateUIDMappings, + description: "uid mappings", + }, + { + test: validateGIDMappings, + description: "gid mappings", + }, } + t := tap.New() + t.Header(0) + var validationErrors error for _, v := range defaultValidations { - if err := v(spec); err != nil { + err := v.test(spec) + t.Ok(err == nil, v.description) + if err != nil { validationErrors = multierror.Append(validationErrors, err) } } if spec.Platform.OS == "linux" { for _, v := range linuxValidations { - if err := v(spec); err != nil { + err := v.test(spec) + t.Ok(err == nil, v.description) + if err != nil { validationErrors = multierror.Append(validationErrors, err) } } } + t.AutoPlan() return validationErrors }