bump gotest.tools v2.3.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2019-04-13 01:47:37 +02:00
parent 58ec72afca
commit c8d685457b
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
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
gopkg.in/inf.v0 d2d2541c53f18d2a059457998ce2876cc8e67cbf # v0.9.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/apimachinery d7deff9243b165ee192f5551710ea4285dcfd615 # 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
* [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`
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md).

View File

@ -9,31 +9,37 @@ import (
"gotest.tools/internal/source"
)
// Result of a Comparison.
// A Result of a Comparison.
type Result interface {
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
message string
}
func (r result) Success() bool {
// Success returns true if the comparison was successful.
func (r StringResult) Success() bool {
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
}
// ResultSuccess is a constant which is returned by a ComparisonWithResult to
// indicate success.
var ResultSuccess = result{success: true}
var ResultSuccess = StringResult{success: true}
// ResultFailure returns a failed Result with a failure message.
func ResultFailure(message string) Result {
return result{message: message}
func ResultFailure(message string) StringResult {
return StringResult{message: message}
}
// 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)
file := &File{path: tempfile.Name()}
assert.NilError(t, tempfile.Close())
for _, op := range ops {
assert.NilError(t, op(file))
}
assert.NilError(t, applyPathOps(file, ops))
if tc, ok := t.(subtest.TestContext); ok {
tc.AddCleanup(file.Remove)
}
@ -89,10 +86,7 @@ func NewDir(t assert.TestingT, prefix string, ops ...PathOp) *Dir {
path, err := ioutil.TempDir("", cleanPrefix(prefix)+"-")
assert.NilError(t, err)
dir := &Dir{path: path}
for _, op := range ops {
assert.NilError(t, op(dir))
}
assert.NilError(t, applyPathOps(dir, ops))
if tc, ok := t.(subtest.TestContext); ok {
tc.AddCleanup(dir.Remove)
}

View File

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

View File

@ -10,6 +10,7 @@ import (
"time"
"github.com/pkg/errors"
"gotest.tools/assert"
)
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 {
for _, op := range ops {
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)
}
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 {
newDir := newDirectoryWithDefaults()
p.directory.items[path] = newDir
@ -87,8 +94,9 @@ func Expected(t assert.TestingT, ops ...PathOp) Manifest {
func newDirectoryWithDefaults() *directory {
return &directory{
resource: newResource(defaultRootDirMode),
items: make(map[string]dirEntry),
resource: newResource(defaultRootDirMode),
items: make(map[string]dirEntry),
filepathGlobs: make(map[string]*filePath),
}
}
@ -147,6 +155,37 @@ func MatchExtraFiles(path Path) error {
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
const anyFileMode os.FileMode = 4294967295

View File

@ -101,6 +101,15 @@ func eqFile(x, y *file) []problem {
if xErr != nil || yErr != nil {
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 {
xContent = removeCarriageReturn(xContent)
yContent = removeCarriageReturn(yContent)
@ -151,11 +160,13 @@ func eqSymlink(x, y *symlink) []problem {
func eqDirectory(path string, x, y *directory) []failure {
p := eqResource(x.resource, y.resource)
var f []failure
matchedFiles := make(map[string]bool)
for _, name := range sortedKeys(x.items) {
if name == anyFile {
continue
}
matchedFiles[name] = true
xEntry := x.items[name]
yEntry, ok := y.items[name]
if !ok {
@ -171,19 +182,30 @@ func eqDirectory(path string, x, y *directory) []failure {
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) {
if _, ok := x.items[name]; !ok {
yEntry := y.items[name]
p = append(p, existenceProblem(name, "unexpected %s", yEntry.Type()))
}
m := matchGlob(name, y.items[name], x.filepathGlobs)
matchedFiles[name] = m.match
f = append(f, m.failures...)
}
}
if len(p) > 0 {
f = append(f, failure{path: path, problems: p})
if _, ok := x.items[anyFile]; ok {
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 {
@ -215,6 +237,30 @@ func eqEntry(path string, x, y dirEntry) []failure {
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 {
sort.Slice(failures, func(i, j int) bool {
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
// check returns a done Result. To fail a test and exit polling with an error
// 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 {
ht.Helper()
}

View File

@ -19,17 +19,29 @@ type skipT interface {
Log(args ...interface{})
}
// Result of skip function
type Result interface {
Skip() bool
Message() string
}
type helperT interface {
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{}
// If the condition expression evaluates to true, or the condition function returns
// true, skip the test.
// If the condition expression evaluates to 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.
// 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{}) {
if ht, ok := t.(helperT); ok {
ht.Helper()
@ -41,12 +53,18 @@ func If(t skipT, condition BoolOrCheckFunc, msgAndArgs ...interface{}) {
if check() {
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:
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()
return strings.SplitN(path.Base(funcPath), ".", 2)[1]
}