Merge pull request #1825 from thaJeztah/bump_gotest_2.3.0

bump gotest.tools v2.3.0
This commit is contained in:
Silvin Lubecki 2019-04-15 11:56:37 +02:00 committed by GitHub
commit f02d94afbb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 193 additions and 35 deletions

View File

@ -89,7 +89,7 @@ google.golang.org/genproto 02b4e95473316948020af0b7a4f0
google.golang.org/grpc 41344da2231b913fa3d983840a57a6b1b7b631a1 # v1.12.0 google.golang.org/grpc 41344da2231b913fa3d983840a57a6b1b7b631a1 # v1.12.0
gopkg.in/inf.v0 d2d2541c53f18d2a059457998ce2876cc8e67cbf # v0.9.1 gopkg.in/inf.v0 d2d2541c53f18d2a059457998ce2876cc8e67cbf # v0.9.1
gopkg.in/yaml.v2 5420a8b6744d3b0345ab293f6fcba19c978f1183 # v2.2.1 gopkg.in/yaml.v2 5420a8b6744d3b0345ab293f6fcba19c978f1183 # v2.2.1
gotest.tools 7c797b5133e5460410dbb22ba779bf35e6975dea # v2.2.0 gotest.tools 1083505acf35a0bd8a696b26837e1fb3187a7a83 # v2.3.0
k8s.io/api 40a48860b5abbba9aa891b02b32da429b08d96a0 # kubernetes-1.14.0 k8s.io/api 40a48860b5abbba9aa891b02b32da429b08d96a0 # kubernetes-1.14.0
k8s.io/apimachinery d7deff9243b165ee192f5551710ea4285dcfd615 # kubernetes-1.14.0 k8s.io/apimachinery d7deff9243b165ee192f5551710ea4285dcfd615 # kubernetes-1.14.0
k8s.io/client-go 6ee68ca5fd8355d024d02f9db0b3b667e8357a0f # kubernetes-1.14.0 k8s.io/client-go 6ee68ca5fd8355d024d02f9db0b3b667e8357a0f # kubernetes-1.14.0

View File

@ -29,3 +29,7 @@ A collection of packages to augment `testing` and support common patterns.
* [gotest.tools/gotestsum](https://github.com/gotestyourself/gotestsum) - go test runner with custom output * [gotest.tools/gotestsum](https://github.com/gotestyourself/gotestsum) - go test runner with custom output
* [maxbrunsfeld/counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) - generate fakes for interfaces * [maxbrunsfeld/counterfeiter](https://github.com/maxbrunsfeld/counterfeiter) - generate fakes for interfaces
* [jonboulle/clockwork](https://github.com/jonboulle/clockwork) - a fake clock for testing code that uses `time` * [jonboulle/clockwork](https://github.com/jonboulle/clockwork) - a fake clock for testing code that uses `time`
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md).

View File

@ -9,31 +9,37 @@ import (
"gotest.tools/internal/source" "gotest.tools/internal/source"
) )
// Result of a Comparison. // A Result of a Comparison.
type Result interface { type Result interface {
Success() bool Success() bool
} }
type result struct { // StringResult is an implementation of Result that reports the error message
// string verbatim and does not provide any templating or formatting of the
// message.
type StringResult struct {
success bool success bool
message string message string
} }
func (r result) Success() bool { // Success returns true if the comparison was successful.
func (r StringResult) Success() bool {
return r.success return r.success
} }
func (r result) FailureMessage() string { // FailureMessage returns the message used to provide additional information
// about the failure.
func (r StringResult) FailureMessage() string {
return r.message return r.message
} }
// ResultSuccess is a constant which is returned by a ComparisonWithResult to // ResultSuccess is a constant which is returned by a ComparisonWithResult to
// indicate success. // indicate success.
var ResultSuccess = result{success: true} var ResultSuccess = StringResult{success: true}
// ResultFailure returns a failed Result with a failure message. // ResultFailure returns a failed Result with a failure message.
func ResultFailure(message string) Result { func ResultFailure(message string) StringResult {
return result{message: message} return StringResult{message: message}
} }
// ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure // ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure

View File

@ -46,10 +46,7 @@ func NewFile(t assert.TestingT, prefix string, ops ...PathOp) *File {
assert.NilError(t, err) assert.NilError(t, err)
file := &File{path: tempfile.Name()} file := &File{path: tempfile.Name()}
assert.NilError(t, tempfile.Close()) assert.NilError(t, tempfile.Close())
assert.NilError(t, applyPathOps(file, ops))
for _, op := range ops {
assert.NilError(t, op(file))
}
if tc, ok := t.(subtest.TestContext); ok { if tc, ok := t.(subtest.TestContext); ok {
tc.AddCleanup(file.Remove) tc.AddCleanup(file.Remove)
} }
@ -89,10 +86,7 @@ func NewDir(t assert.TestingT, prefix string, ops ...PathOp) *Dir {
path, err := ioutil.TempDir("", cleanPrefix(prefix)+"-") path, err := ioutil.TempDir("", cleanPrefix(prefix)+"-")
assert.NilError(t, err) assert.NilError(t, err)
dir := &Dir{path: path} dir := &Dir{path: path}
assert.NilError(t, applyPathOps(dir, ops))
for _, op := range ops {
assert.NilError(t, op(dir))
}
if tc, ok := t.(subtest.TestContext); ok { if tc, ok := t.(subtest.TestContext); ok {
tc.AddCleanup(dir.Remove) tc.AddCleanup(dir.Remove)
} }

View File

@ -26,6 +26,7 @@ type file struct {
resource resource
content io.ReadCloser content io.ReadCloser
ignoreCariageReturn bool ignoreCariageReturn bool
compareContentFunc func(b []byte) CompareResult
} }
func (f *file) Type() string { func (f *file) Type() string {
@ -44,6 +45,7 @@ func (f *symlink) Type() string {
type directory struct { type directory struct {
resource resource
items map[string]dirEntry items map[string]dirEntry
filepathGlobs map[string]*filePath
} }
func (f *directory) Type() string { func (f *directory) Type() string {
@ -97,6 +99,7 @@ func newDirectory(path string, info os.FileInfo) (*directory, error) {
return &directory{ return &directory{
resource: newResourceFromInfo(info), resource: newResourceFromInfo(info),
items: items, items: items,
filepathGlobs: make(map[string]*filePath),
}, nil }, nil
} }

View File

@ -10,6 +10,7 @@ import (
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
"gotest.tools/assert"
) )
const defaultFileMode = 0644 const defaultFileMode = 0644
@ -144,6 +145,14 @@ func WithDir(name string, ops ...PathOp) PathOp {
} }
} }
// Apply the PathOps to the File
func Apply(t assert.TestingT, path Path, ops ...PathOp) {
if ht, ok := t.(helperT); ok {
ht.Helper()
}
assert.NilError(t, applyPathOps(path, ops))
}
func applyPathOps(path Path, ops []PathOp) error { func applyPathOps(path Path, ops []PathOp) error {
for _, op := range ops { for _, op := range ops {
if err := op(path); err != nil { if err := op(path); err != nil {

View File

@ -64,6 +64,13 @@ func (p *directoryPath) AddFile(path string, ops ...PathOp) error {
return applyPathOps(exp, ops) return applyPathOps(exp, ops)
} }
func (p *directoryPath) AddGlobFiles(glob string, ops ...PathOp) error {
newFile := &file{resource: newResource(0)}
newFilePath := &filePath{file: newFile}
p.directory.filepathGlobs[glob] = newFilePath
return applyPathOps(newFilePath, ops)
}
func (p *directoryPath) AddDirectory(path string, ops ...PathOp) error { func (p *directoryPath) AddDirectory(path string, ops ...PathOp) error {
newDir := newDirectoryWithDefaults() newDir := newDirectoryWithDefaults()
p.directory.items[path] = newDir p.directory.items[path] = newDir
@ -89,6 +96,7 @@ func newDirectoryWithDefaults() *directory {
return &directory{ return &directory{
resource: newResource(defaultRootDirMode), resource: newResource(defaultRootDirMode),
items: make(map[string]dirEntry), items: make(map[string]dirEntry),
filepathGlobs: make(map[string]*filePath),
} }
} }
@ -147,6 +155,37 @@ func MatchExtraFiles(path Path) error {
return nil return nil
} }
// CompareResult is the result of comparison.
//
// See gotest.tools/assert/cmp.StringResult for a convenient implementation of
// this interface.
type CompareResult interface {
Success() bool
FailureMessage() string
}
// MatchFileContent is a PathOp that updates a Manifest to use the provided
// function to determine if a file's content matches the expectation.
func MatchFileContent(f func([]byte) CompareResult) PathOp {
return func(path Path) error {
if m, ok := path.(*filePath); ok {
m.file.compareContentFunc = f
}
return nil
}
}
// MatchFilesWithGlob is a PathOp that updates a Manifest to match files using
// glob pattern, and check them using the ops.
func MatchFilesWithGlob(glob string, ops ...PathOp) PathOp {
return func(path Path) error {
if m, ok := path.(*directoryPath); ok {
m.AddGlobFiles(glob, ops...)
}
return nil
}
}
// anyFileMode is represented by uint32_max // anyFileMode is represented by uint32_max
const anyFileMode os.FileMode = 4294967295 const anyFileMode os.FileMode = 4294967295

View File

@ -101,6 +101,15 @@ func eqFile(x, y *file) []problem {
if xErr != nil || yErr != nil { if xErr != nil || yErr != nil {
return p return p
} }
if x.compareContentFunc != nil {
r := x.compareContentFunc(yContent)
if !r.Success() {
p = append(p, existenceProblem("content", r.FailureMessage()))
}
return p
}
if x.ignoreCariageReturn || y.ignoreCariageReturn { if x.ignoreCariageReturn || y.ignoreCariageReturn {
xContent = removeCarriageReturn(xContent) xContent = removeCarriageReturn(xContent)
yContent = removeCarriageReturn(yContent) yContent = removeCarriageReturn(yContent)
@ -151,11 +160,13 @@ func eqSymlink(x, y *symlink) []problem {
func eqDirectory(path string, x, y *directory) []failure { func eqDirectory(path string, x, y *directory) []failure {
p := eqResource(x.resource, y.resource) p := eqResource(x.resource, y.resource)
var f []failure var f []failure
matchedFiles := make(map[string]bool)
for _, name := range sortedKeys(x.items) { for _, name := range sortedKeys(x.items) {
if name == anyFile { if name == anyFile {
continue continue
} }
matchedFiles[name] = true
xEntry := x.items[name] xEntry := x.items[name]
yEntry, ok := y.items[name] yEntry, ok := y.items[name]
if !ok { if !ok {
@ -171,19 +182,30 @@ func eqDirectory(path string, x, y *directory) []failure {
f = append(f, eqEntry(filepath.Join(path, name), xEntry, yEntry)...) f = append(f, eqEntry(filepath.Join(path, name), xEntry, yEntry)...)
} }
if _, ok := x.items[anyFile]; !ok { if len(x.filepathGlobs) != 0 {
for _, name := range sortedKeys(y.items) { for _, name := range sortedKeys(y.items) {
if _, ok := x.items[name]; !ok { m := matchGlob(name, y.items[name], x.filepathGlobs)
yEntry := y.items[name] matchedFiles[name] = m.match
p = append(p, existenceProblem(name, "unexpected %s", yEntry.Type())) f = append(f, m.failures...)
}
} }
} }
if len(p) > 0 { if _, ok := x.items[anyFile]; ok {
f = append(f, failure{path: path, problems: p}) return maybeAppendFailure(f, path, p)
} }
return f for _, name := range sortedKeys(y.items) {
if !matchedFiles[name] {
p = append(p, existenceProblem(name, "unexpected %s", y.items[name].Type()))
}
}
return maybeAppendFailure(f, path, p)
}
func maybeAppendFailure(failures []failure, path string, problems []problem) []failure {
if len(problems) > 0 {
return append(failures, failure{path: path, problems: problems})
}
return failures
} }
func sortedKeys(items map[string]dirEntry) []string { func sortedKeys(items map[string]dirEntry) []string {
@ -215,6 +237,30 @@ func eqEntry(path string, x, y dirEntry) []failure {
return nil return nil
} }
type globMatch struct {
match bool
failures []failure
}
func matchGlob(name string, yEntry dirEntry, globs map[string]*filePath) globMatch {
m := globMatch{}
for glob, expectedFile := range globs {
ok, err := filepath.Match(glob, name)
if err != nil {
p := errProblem("failed to match glob pattern", err)
f := failure{path: name, problems: []problem{p}}
m.failures = append(m.failures, f)
}
if ok {
m.match = true
m.failures = eqEntry(name, expectedFile.file, yEntry)
return m
}
}
return m
}
func formatFailures(failures []failure) string { func formatFailures(failures []failure) string {
sort.Slice(failures, func(i, j int) bool { sort.Slice(failures, func(i, j int) bool {
return failures[i].path < failures[j].path return failures[i].path < failures[j].path

39
vendor/gotest.tools/poll/check.go vendored Normal file
View File

@ -0,0 +1,39 @@
package poll
import (
"net"
"os"
)
// Check is a function which will be used as check for the WaitOn method.
type Check func(t LogT) Result
// FileExists looks on filesystem and check that path exists.
func FileExists(path string) Check {
return func(t LogT) Result {
_, err := os.Stat(path)
if os.IsNotExist(err) {
t.Logf("waiting on file %s to exist", path)
return Continue("file %s does not exist", path)
}
if err != nil {
return Error(err)
}
return Success()
}
}
// Connection try to open a connection to the address on the
// named network. See net.Dial for a description of the network and
// address parameters.
func Connection(network, address string) Check {
return func(t LogT) Result {
_, err := net.Dial(network, address)
if err != nil {
t.Logf("waiting on socket %s://%s to be available...", network, address)
return Continue("socket %s://%s not available", network, address)
}
return Success()
}
}

View File

@ -104,7 +104,7 @@ func Error(err error) Result {
// WaitOn a condition or until a timeout. Poll by calling check and exit when // WaitOn a condition or until a timeout. Poll by calling check and exit when
// check returns a done Result. To fail a test and exit polling with an error // check returns a done Result. To fail a test and exit polling with an error
// return a error result. // return a error result.
func WaitOn(t TestingT, check func(t LogT) Result, pollOps ...SettingOp) { func WaitOn(t TestingT, check Check, pollOps ...SettingOp) {
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
ht.Helper() ht.Helper()
} }

View File

@ -19,17 +19,29 @@ type skipT interface {
Log(args ...interface{}) Log(args ...interface{})
} }
// Result of skip function
type Result interface {
Skip() bool
Message() string
}
type helperT interface { type helperT interface {
Helper() Helper()
} }
// BoolOrCheckFunc can be a bool or func() bool, other types will panic // BoolOrCheckFunc can be a bool, func() bool, or func() Result. Other types will panic
type BoolOrCheckFunc interface{} type BoolOrCheckFunc interface{}
// If the condition expression evaluates to true, or the condition function returns // If the condition expression evaluates to true, skip the test.
// true, skip the test. //
// The condition argument may be one of three types: bool, func() bool, or
// func() SkipResult.
// When called with a bool, the test will be skip if the condition evaluates to true.
// When called with a func() bool, the test will be skip if the function returns true.
// When called with a func() Result, the test will be skip if the Skip method
// of the result returns true.
// The skip message will contain the source code of the expression. // The skip message will contain the source code of the expression.
// Extra message text can be passed as a format string with args // Extra message text can be passed as a format string with args.
func If(t skipT, condition BoolOrCheckFunc, msgAndArgs ...interface{}) { func If(t skipT, condition BoolOrCheckFunc, msgAndArgs ...interface{}) {
if ht, ok := t.(helperT); ok { if ht, ok := t.(helperT); ok {
ht.Helper() ht.Helper()
@ -41,12 +53,18 @@ func If(t skipT, condition BoolOrCheckFunc, msgAndArgs ...interface{}) {
if check() { if check() {
t.Skip(format.WithCustomMessage(getFunctionName(check), msgAndArgs...)) t.Skip(format.WithCustomMessage(getFunctionName(check), msgAndArgs...))
} }
case func() Result:
result := check()
if result.Skip() {
msg := getFunctionName(check) + ": " + result.Message()
t.Skip(format.WithCustomMessage(msg, msgAndArgs...))
}
default: default:
panic(fmt.Sprintf("invalid type for condition arg: %T", check)) panic(fmt.Sprintf("invalid type for condition arg: %T", check))
} }
} }
func getFunctionName(function func() bool) string { func getFunctionName(function interface{}) string {
funcPath := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name() funcPath := runtime.FuncForPC(reflect.ValueOf(function).Pointer()).Name()
return strings.SplitN(path.Base(funcPath), ".", 2)[1] return strings.SplitN(path.Base(funcPath), ".", 2)[1]
} }