commit
aaf64c455a
@ -32,9 +32,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containerd/fifo"
|
"github.com/containerd/fifo"
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/stretchr/testify/assert"
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func assertHasPrefix(t *testing.T, s, prefix string) {
|
func assertHasPrefix(t *testing.T, s, prefix string) {
|
||||||
@ -52,7 +50,7 @@ func TestNewFIFOSetInDir(t *testing.T) {
|
|||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
|
|
||||||
fifos, err := NewFIFOSetInDir(root, "theid", true)
|
fifos, err := NewFIFOSetInDir(root, "theid", true)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
dir := filepath.Dir(fifos.Stdin)
|
dir := filepath.Dir(fifos.Stdin)
|
||||||
assertHasPrefix(t, dir, root)
|
assertHasPrefix(t, dir, root)
|
||||||
@ -64,20 +62,19 @@ func TestNewFIFOSetInDir(t *testing.T) {
|
|||||||
Terminal: true,
|
Terminal: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assert.Assert(t, is.DeepEqual(fifos, expected, cmpFIFOSet))
|
|
||||||
|
assert.Equal(t, fifos.Config, expected.Config)
|
||||||
|
|
||||||
files, err := os.ReadDir(root)
|
files, err := os.ReadDir(root)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Check(t, is.Len(files, 1))
|
assert.Len(t, files, 1)
|
||||||
|
|
||||||
assert.NilError(t, fifos.Close())
|
assert.Nil(t, fifos.Close())
|
||||||
files, err = os.ReadDir(root)
|
files, err = os.ReadDir(root)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Check(t, is.Len(files, 0))
|
assert.Len(t, files, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmpFIFOSet = cmpopts.IgnoreUnexported(FIFOSet{})
|
|
||||||
|
|
||||||
func TestNewAttach(t *testing.T) {
|
func TestNewAttach(t *testing.T) {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
t.Skip("setupFIFOProducers not yet implemented on windows")
|
t.Skip("setupFIFOProducers not yet implemented on windows")
|
||||||
@ -97,25 +94,25 @@ func TestNewAttach(t *testing.T) {
|
|||||||
attacher := NewAttach(withBytesBuffers)
|
attacher := NewAttach(withBytesBuffers)
|
||||||
|
|
||||||
fifos, err := NewFIFOSetInDir("", "theid", false)
|
fifos, err := NewFIFOSetInDir("", "theid", false)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
attachedFifos, err := attacher(fifos)
|
attachedFifos, err := attacher(fifos)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
defer attachedFifos.Close()
|
defer attachedFifos.Close()
|
||||||
|
|
||||||
producers := setupFIFOProducers(t, attachedFifos.Config())
|
producers := setupFIFOProducers(t, attachedFifos.Config())
|
||||||
initProducers(t, producers, expectedStdout, expectedStderr)
|
initProducers(t, producers, expectedStdout, expectedStderr)
|
||||||
|
|
||||||
actualStdin, err := io.ReadAll(producers.Stdin)
|
actualStdin, err := io.ReadAll(producers.Stdin)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
attachedFifos.Wait()
|
attachedFifos.Wait()
|
||||||
attachedFifos.Cancel()
|
attachedFifos.Cancel()
|
||||||
assert.NilError(t, attachedFifos.Close())
|
assert.Nil(t, attachedFifos.Close())
|
||||||
|
|
||||||
assert.Check(t, is.Equal(expectedStdout, stdout.String()))
|
assert.Equal(t, expectedStdout, stdout.String())
|
||||||
assert.Check(t, is.Equal(expectedStderr, stderr.String()))
|
assert.Equal(t, expectedStderr, stderr.String())
|
||||||
assert.Check(t, is.Equal(expectedStdin, string(actualStdin)))
|
assert.Equal(t, expectedStdin, string(actualStdin))
|
||||||
}
|
}
|
||||||
|
|
||||||
type producers struct {
|
type producers struct {
|
||||||
@ -132,41 +129,41 @@ func setupFIFOProducers(t *testing.T, fifos Config) producers {
|
|||||||
)
|
)
|
||||||
|
|
||||||
pipes.Stdin, err = fifo.OpenFifo(ctx, fifos.Stdin, syscall.O_RDONLY, 0)
|
pipes.Stdin, err = fifo.OpenFifo(ctx, fifos.Stdin, syscall.O_RDONLY, 0)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
pipes.Stdout, err = fifo.OpenFifo(ctx, fifos.Stdout, syscall.O_WRONLY, 0)
|
pipes.Stdout, err = fifo.OpenFifo(ctx, fifos.Stdout, syscall.O_WRONLY, 0)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
pipes.Stderr, err = fifo.OpenFifo(ctx, fifos.Stderr, syscall.O_WRONLY, 0)
|
pipes.Stderr, err = fifo.OpenFifo(ctx, fifos.Stderr, syscall.O_WRONLY, 0)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
return pipes
|
return pipes
|
||||||
}
|
}
|
||||||
|
|
||||||
func initProducers(t *testing.T, producers producers, stdout, stderr string) {
|
func initProducers(t *testing.T, producers producers, stdout, stderr string) {
|
||||||
_, err := producers.Stdout.Write([]byte(stdout))
|
_, err := producers.Stdout.Write([]byte(stdout))
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NilError(t, producers.Stdout.Close())
|
assert.Nil(t, producers.Stdout.Close())
|
||||||
|
|
||||||
_, err = producers.Stderr.Write([]byte(stderr))
|
_, err = producers.Stderr.Write([]byte(stderr))
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NilError(t, producers.Stderr.Close())
|
assert.Nil(t, producers.Stderr.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBinaryIOArgs(t *testing.T) {
|
func TestBinaryIOArgs(t *testing.T) {
|
||||||
res, err := BinaryIO("/file.bin", map[string]string{"id": "1"})("")
|
res, err := BinaryIO("/file.bin", map[string]string{"id": "1"})("")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "binary:///file.bin?id=1", res.Config().Stdout)
|
assert.Equal(t, "binary:///file.bin?id=1", res.Config().Stdout)
|
||||||
assert.Equal(t, "binary:///file.bin?id=1", res.Config().Stderr)
|
assert.Equal(t, "binary:///file.bin?id=1", res.Config().Stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBinaryIOAbsolutePath(t *testing.T) {
|
func TestBinaryIOAbsolutePath(t *testing.T) {
|
||||||
res, err := BinaryIO("/full/path/bin", nil)("!")
|
res, err := BinaryIO("/full/path/bin", nil)("!")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Test parse back
|
// Test parse back
|
||||||
parsed, err := url.Parse(res.Config().Stdout)
|
parsed, err := url.Parse(res.Config().Stdout)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "binary", parsed.Scheme)
|
assert.Equal(t, "binary", parsed.Scheme)
|
||||||
assert.Equal(t, "/full/path/bin", parsed.Path)
|
assert.Equal(t, "/full/path/bin", parsed.Path)
|
||||||
}
|
}
|
||||||
@ -178,13 +175,13 @@ func TestBinaryIOFailOnRelativePath(t *testing.T) {
|
|||||||
|
|
||||||
func TestLogFileAbsolutePath(t *testing.T) {
|
func TestLogFileAbsolutePath(t *testing.T) {
|
||||||
res, err := LogFile("/full/path/file.txt")("!")
|
res, err := LogFile("/full/path/file.txt")("!")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "file:///full/path/file.txt", res.Config().Stdout)
|
assert.Equal(t, "file:///full/path/file.txt", res.Config().Stdout)
|
||||||
assert.Equal(t, "file:///full/path/file.txt", res.Config().Stderr)
|
assert.Equal(t, "file:///full/path/file.txt", res.Config().Stderr)
|
||||||
|
|
||||||
// Test parse back
|
// Test parse back
|
||||||
parsed, err := url.Parse(res.Config().Stdout)
|
parsed, err := url.Parse(res.Config().Stdout)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "file", parsed.Scheme)
|
assert.Equal(t, "file", parsed.Scheme)
|
||||||
assert.Equal(t, "/full/path/file.txt", parsed.Path)
|
assert.Equal(t, "/full/path/file.txt", parsed.Path)
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOpenFifos(t *testing.T) {
|
func TestOpenFifos(t *testing.T) {
|
||||||
@ -53,7 +53,7 @@ func TestOpenFifos(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, scenario := range scenarios {
|
for _, scenario := range scenarios {
|
||||||
_, err := openFifos(context.Background(), scenario)
|
_, err := openFifos(context.Background(), scenario)
|
||||||
assert.Assert(t, err != nil, scenario)
|
assert.Error(t, err, scenario)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ package cio
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewFifoSetInDir_NoTerminal(t *testing.T) {
|
func TestNewFifoSetInDir_NoTerminal(t *testing.T) {
|
||||||
@ -28,10 +28,10 @@ func TestNewFifoSetInDir_NoTerminal(t *testing.T) {
|
|||||||
t.Fatalf("NewFifoSetInDir failed with: %v", err)
|
t.Fatalf("NewFifoSetInDir failed with: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Assert(t, !set.Terminal, "FIFOSet.Terminal should be false")
|
assert.True(t, !set.Terminal, "FIFOSet.Terminal should be false")
|
||||||
assert.Assert(t, set.Stdin != "", "FIFOSet.Stdin should be set")
|
assert.NotEmpty(t, set.Stdin, "FIFOSet.Stdin should be set")
|
||||||
assert.Assert(t, set.Stdout != "", "FIFOSet.Stdout should be set")
|
assert.NotEmpty(t, set.Stdout, "FIFOSet.Stdout should be set")
|
||||||
assert.Assert(t, set.Stderr != "", "FIFOSet.Stderr should be set")
|
assert.NotEmpty(t, set.Stderr, "FIFOSet.Stderr should be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewFifoSetInDir_Terminal(t *testing.T) {
|
func TestNewFifoSetInDir_Terminal(t *testing.T) {
|
||||||
@ -40,8 +40,8 @@ func TestNewFifoSetInDir_Terminal(t *testing.T) {
|
|||||||
t.Fatalf("NewFifoSetInDir failed with: %v", err)
|
t.Fatalf("NewFifoSetInDir failed with: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Assert(t, set.Terminal, "FIFOSet.Terminal should be false")
|
assert.True(t, set.Terminal, "FIFOSet.Terminal should be true")
|
||||||
assert.Assert(t, set.Stdin != "", "FIFOSet.Stdin should be set")
|
assert.NotEmpty(t, set.Stdin, "FIFOSet.Stdin should be set")
|
||||||
assert.Assert(t, set.Stdout != "", "FIFOSet.Stdout should be set")
|
assert.NotEmpty(t, set.Stdout, "FIFOSet.Stdout should be set")
|
||||||
assert.Assert(t, set.Stderr == "", "FIFOSet.Stderr should not be set")
|
assert.Empty(t, set.Stderr, "FIFOSet.Stderr should not be set")
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type copySource struct {
|
type copySource struct {
|
||||||
@ -81,9 +80,9 @@ func TestCopy(t *testing.T) {
|
|||||||
testcase.source.size,
|
testcase.source.size,
|
||||||
testcase.source.digest)
|
testcase.source.digest)
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Check(t, is.Equal(testcase.source.digest, testcase.writer.committedDigest))
|
assert.Equal(t, testcase.source.digest, testcase.writer.committedDigest)
|
||||||
assert.Check(t, is.Equal(testcase.expected, testcase.writer.String()))
|
assert.Equal(t, testcase.expected, testcase.writer.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,14 +19,16 @@ package local
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTryLock(t *testing.T) {
|
func TestTryLock(t *testing.T) {
|
||||||
err := tryLock("testref")
|
err := tryLock("testref")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
defer unlock("testref")
|
defer unlock("testref")
|
||||||
|
|
||||||
err = tryLock("testref")
|
err = tryLock("testref")
|
||||||
assert.ErrorContains(t, err, "ref testref locked for ")
|
require.NotNil(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "ref testref locked for ")
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ import (
|
|||||||
|
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type memoryLabelStore struct {
|
type memoryLabelStore struct {
|
||||||
@ -351,7 +351,7 @@ func checkWrite(ctx context.Context, t checker, cs content.Store, dgst digest.Di
|
|||||||
|
|
||||||
func TestWriterTruncateRecoversFromIncompleteWrite(t *testing.T) {
|
func TestWriterTruncateRecoversFromIncompleteWrite(t *testing.T) {
|
||||||
cs, err := NewStore(t.TempDir())
|
cs, err := NewStore(t.TempDir())
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -362,26 +362,26 @@ func TestWriterTruncateRecoversFromIncompleteWrite(t *testing.T) {
|
|||||||
setupIncompleteWrite(ctx, t, cs, ref, total)
|
setupIncompleteWrite(ctx, t, cs, ref, total)
|
||||||
|
|
||||||
writer, err := cs.Writer(ctx, content.WithRef(ref), content.WithDescriptor(ocispec.Descriptor{Size: total}))
|
writer, err := cs.Writer(ctx, content.WithRef(ref), content.WithDescriptor(ocispec.Descriptor{Size: total}))
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.NilError(t, writer.Truncate(0))
|
assert.Nil(t, writer.Truncate(0))
|
||||||
|
|
||||||
_, err = writer.Write(contentB)
|
_, err = writer.Write(contentB)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
dgst := digest.FromBytes(contentB)
|
dgst := digest.FromBytes(contentB)
|
||||||
err = writer.Commit(ctx, total, dgst)
|
err = writer.Commit(ctx, total, dgst)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupIncompleteWrite(ctx context.Context, t *testing.T, cs content.Store, ref string, total int64) {
|
func setupIncompleteWrite(ctx context.Context, t *testing.T, cs content.Store, ref string, total int64) {
|
||||||
writer, err := cs.Writer(ctx, content.WithRef(ref), content.WithDescriptor(ocispec.Descriptor{Size: total}))
|
writer, err := cs.Writer(ctx, content.WithRef(ref), content.WithDescriptor(ocispec.Descriptor{Size: total}))
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
_, err = writer.Write([]byte("bad data"))
|
_, err = writer.Write([]byte("bad data"))
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.NilError(t, writer.Close())
|
assert.Nil(t, writer.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteReadEmptyFileTimestamp(t *testing.T) {
|
func TestWriteReadEmptyFileTimestamp(t *testing.T) {
|
||||||
|
@ -32,9 +32,9 @@ import (
|
|||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/log/logtest"
|
"github.com/containerd/containerd/log/logtest"
|
||||||
"github.com/containerd/containerd/pkg/testutil"
|
"github.com/containerd/containerd/pkg/testutil"
|
||||||
digest "github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -271,7 +271,7 @@ func checkResumeWriter(ctx context.Context, t *testing.T, cs content.Store) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkStatus(t, w1, expected, dgstFirst, preStart, postStart, preUpdate, postUpdate)
|
checkStatus(t, w1, expected, dgstFirst, preStart, postStart, preUpdate, postUpdate)
|
||||||
assert.NilError(t, w1.Close(), "close first writer")
|
assert.Nil(t, w1.Close(), "close first writer")
|
||||||
|
|
||||||
w2, err := cs.Writer(ctx, content.WithRef(ref), content.WithDescriptor(ocispec.Descriptor{Size: 256, Digest: dgst}))
|
w2, err := cs.Writer(ctx, content.WithRef(ref), content.WithDescriptor(ocispec.Descriptor{Size: 256, Digest: dgst}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -295,7 +295,7 @@ func checkResumeWriter(ctx context.Context, t *testing.T, cs content.Store) {
|
|||||||
}
|
}
|
||||||
postCommit := time.Now()
|
postCommit := time.Now()
|
||||||
|
|
||||||
assert.NilError(t, w2.Close(), "close second writer")
|
assert.Nil(t, w2.Close(), "close second writer")
|
||||||
info := content.Info{
|
info := content.Info{
|
||||||
Digest: dgst,
|
Digest: dgst,
|
||||||
Size: 256,
|
Size: 256,
|
||||||
|
@ -6,7 +6,7 @@ package apparmor
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCleanProfileName(t *testing.T) {
|
func TestCleanProfileName(t *testing.T) {
|
||||||
|
@ -23,7 +23,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd/gc"
|
"github.com/containerd/containerd/gc"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPauseThreshold(t *testing.T) {
|
func TestPauseThreshold(t *testing.T) {
|
||||||
|
2
go.mod
2
go.mod
@ -68,7 +68,6 @@ require (
|
|||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
||||||
google.golang.org/grpc v1.43.0
|
google.golang.org/grpc v1.43.0
|
||||||
google.golang.org/protobuf v1.27.1
|
google.golang.org/protobuf v1.27.1
|
||||||
gotest.tools/v3 v3.0.3
|
|
||||||
k8s.io/api v0.22.5
|
k8s.io/api v0.22.5
|
||||||
k8s.io/apimachinery v0.22.5
|
k8s.io/apimachinery v0.22.5
|
||||||
k8s.io/apiserver v0.22.5
|
k8s.io/apiserver v0.22.5
|
||||||
@ -122,7 +121,6 @@ require (
|
|||||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
18
go.sum
18
go.sum
@ -78,7 +78,6 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
|
|||||||
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
|
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
|
||||||
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
|
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
|
||||||
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
|
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
|
||||||
github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
|
||||||
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
||||||
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
|
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
|
||||||
github.com/Microsoft/hcsshim v0.9.2 h1:wB06W5aYFfUB3IvootYAY2WnOmIdgPGfqSI6tufQNnY=
|
github.com/Microsoft/hcsshim v0.9.2 h1:wB06W5aYFfUB3IvootYAY2WnOmIdgPGfqSI6tufQNnY=
|
||||||
@ -99,7 +98,6 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
|||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||||
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
|
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
|
||||||
github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk=
|
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
@ -123,7 +121,6 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb
|
|||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
||||||
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
|
||||||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||||
@ -280,7 +277,6 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
|
|||||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||||
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||||
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
|
||||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
@ -401,7 +397,6 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
|
|||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
|
||||||
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||||
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
|
||||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||||
@ -611,7 +606,6 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
|
|||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||||
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
@ -662,11 +656,9 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
|||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||||
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||||
github.com/networkplumbing/go-nft v0.2.0/go.mod h1:HnnM+tYvlGAsMU7yoYwXEVLLiDW9gdMmb5HoGcwpuQs=
|
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||||
github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
@ -681,7 +673,6 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108
|
|||||||
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
|
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
|
||||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
|
||||||
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
@ -691,7 +682,6 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT
|
|||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||||
github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
|
github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
|
||||||
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
|
||||||
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||||
@ -781,13 +771,11 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
|
|||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
|
|
||||||
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
||||||
github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
|
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||||
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
|
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
|
||||||
@ -1045,7 +1033,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
|
||||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
@ -1150,7 +1137,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -1167,7 +1153,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -1255,12 +1240,10 @@ golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4X
|
|||||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@ -1381,7 +1364,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
|
||||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
"github.com/containerd/containerd/pkg/ttrpcutil"
|
"github.com/containerd/containerd/pkg/ttrpcutil"
|
||||||
"github.com/containerd/ttrpc"
|
"github.com/containerd/ttrpc"
|
||||||
"github.com/gogo/protobuf/types"
|
"github.com/gogo/protobuf/types"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestClientTTRPC_New(t *testing.T) {
|
func TestClientTTRPC_New(t *testing.T) {
|
||||||
@ -34,10 +34,10 @@ func TestClientTTRPC_New(t *testing.T) {
|
|||||||
t.Skip()
|
t.Skip()
|
||||||
}
|
}
|
||||||
client, err := ttrpcutil.NewClient(address + ".ttrpc")
|
client, err := ttrpcutil.NewClient(address + ".ttrpc")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = client.Close()
|
err = client.Close()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClientTTRPC_Reconnect(t *testing.T) {
|
func TestClientTTRPC_Reconnect(t *testing.T) {
|
||||||
@ -45,13 +45,13 @@ func TestClientTTRPC_Reconnect(t *testing.T) {
|
|||||||
t.Skip()
|
t.Skip()
|
||||||
}
|
}
|
||||||
client, err := ttrpcutil.NewClient(address + ".ttrpc")
|
client, err := ttrpcutil.NewClient(address + ".ttrpc")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = client.Reconnect()
|
err = client.Reconnect()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
service, err := client.EventsService()
|
service, err := client.EventsService()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Send test request to make sure its alive after reconnect
|
// Send test request to make sure its alive after reconnect
|
||||||
_, err = service.Forward(context.Background(), &v1.ForwardRequest{
|
_, err = service.Forward(context.Background(), &v1.ForwardRequest{
|
||||||
@ -62,10 +62,10 @@ func TestClientTTRPC_Reconnect(t *testing.T) {
|
|||||||
Event: &types.Any{},
|
Event: &types.Any{},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = client.Close()
|
err = client.Close()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClientTTRPC_Close(t *testing.T) {
|
func TestClientTTRPC_Close(t *testing.T) {
|
||||||
@ -73,17 +73,17 @@ func TestClientTTRPC_Close(t *testing.T) {
|
|||||||
t.Skip()
|
t.Skip()
|
||||||
}
|
}
|
||||||
client, err := ttrpcutil.NewClient(address + ".ttrpc")
|
client, err := ttrpcutil.NewClient(address + ".ttrpc")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
service, err := client.EventsService()
|
service, err := client.EventsService()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = client.Close()
|
err = client.Close()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
_, err = service.Forward(context.Background(), &v1.ForwardRequest{Envelope: &v1.Envelope{}})
|
_, err = service.Forward(context.Background(), &v1.ForwardRequest{Envelope: &v1.Envelope{}})
|
||||||
assert.Equal(t, err, ttrpc.ErrClosed)
|
assert.Equal(t, err, ttrpc.ErrClosed)
|
||||||
|
|
||||||
err = client.Close()
|
err = client.Close()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/containerd/containerd/images/converter/uncompress"
|
"github.com/containerd/containerd/images/converter/uncompress"
|
||||||
"github.com/containerd/containerd/platforms"
|
"github.com/containerd/containerd/platforms"
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestConvert creates an image from testImage, with the following conversion:
|
// TestConvert creates an image from testImage, with the following conversion:
|
||||||
@ -72,7 +72,7 @@ func TestConvert(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// Assert that the image does not have any extra arch.
|
// Assert that the image does not have any extra arch.
|
||||||
assert.Equal(t, 1, len(plats))
|
assert.Equal(t, 1, len(plats))
|
||||||
assert.Check(t, defPlat.Match(plats[0]))
|
assert.True(t, defPlat.Match(plats[0]))
|
||||||
|
|
||||||
// Assert that the media type is converted to OCI and also uncompressed
|
// Assert that the media type is converted to OCI and also uncompressed
|
||||||
mani, err := images.Manifest(ctx, cs, dstImg.Target, defPlat)
|
mani, err := images.Manifest(ctx, cs, dstImg.Target, defPlat)
|
||||||
|
@ -16,8 +16,8 @@ require (
|
|||||||
github.com/opencontainers/image-spec v1.0.3-0.20220303224323-02efb9a75ee1
|
github.com/opencontainers/image-spec v1.0.3-0.20220303224323-02efb9a75ee1
|
||||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
|
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
|
github.com/stretchr/testify v1.7.0
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
||||||
gotest.tools/v3 v3.0.3
|
|
||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
|
@ -1068,10 +1068,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
|
||||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoggerContext(t *testing.T) {
|
func TestLoggerContext(t *testing.T) {
|
||||||
@ -28,5 +28,5 @@ func TestLoggerContext(t *testing.T) {
|
|||||||
|
|
||||||
ctx = WithLogger(ctx, G(ctx).WithField("test", "one"))
|
ctx = WithLogger(ctx, G(ctx).WithField("test", "one"))
|
||||||
assert.Equal(t, GetLogger(ctx).Data["test"], "one")
|
assert.Equal(t, GetLogger(ctx).Data["test"], "one")
|
||||||
assert.Equal(t, G(ctx), GetLogger(ctx)) // these should be the same.
|
assert.Same(t, G(ctx), GetLogger(ctx)) // these should be the same.
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,9 @@ import (
|
|||||||
"github.com/containerd/typeurl"
|
"github.com/containerd/typeurl"
|
||||||
"github.com/gogo/protobuf/types"
|
"github.com/gogo/protobuf/types"
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
bolt "go.etcd.io/bbolt"
|
bolt "go.etcd.io/bbolt"
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -724,7 +724,8 @@ func checkContainersEqual(t *testing.T, a, b *containers.Container, format strin
|
|||||||
return true
|
return true
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
assert.DeepEqual(t, a, b, opt)
|
|
||||||
|
assert.True(t, cmp.Equal(a, b, opt))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEnv(t *testing.T) (context.Context, *bolt.DB, func()) {
|
func testEnv(t *testing.T) (context.Context, *bolt.DB, func()) {
|
||||||
|
@ -27,14 +27,14 @@ import (
|
|||||||
// so we use continuity/testutil instead.
|
// so we use continuity/testutil instead.
|
||||||
"github.com/containerd/continuity/testutil"
|
"github.com/containerd/continuity/testutil"
|
||||||
"github.com/containerd/continuity/testutil/loopback"
|
"github.com/containerd/continuity/testutil/loopback"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
exec "golang.org/x/sys/execabs"
|
exec "golang.org/x/sys/execabs"
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkLookup(t *testing.T, fsType, mntPoint, dir string) {
|
func checkLookup(t *testing.T, fsType, mntPoint, dir string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
info, err := Lookup(dir)
|
info, err := Lookup(dir)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, fsType, info.FSType)
|
assert.Equal(t, fsType, info.FSType)
|
||||||
assert.Equal(t, mntPoint, info.Mountpoint)
|
assert.Equal(t, mntPoint, info.Mountpoint)
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ func testLookup(t *testing.T, fsType string) {
|
|||||||
testutil.Unmount(t, mnt)
|
testutil.Unmount(t, mnt)
|
||||||
loop.Close()
|
loop.Close()
|
||||||
}()
|
}()
|
||||||
assert.Check(t, strings.HasPrefix(loop.Device, "/dev/loop"))
|
assert.True(t, strings.HasPrefix(loop.Device, "/dev/loop"))
|
||||||
checkLookup(t, fsType, mnt, mnt)
|
checkLookup(t, fsType, mnt, mnt)
|
||||||
|
|
||||||
newMnt := t.TempDir()
|
newMnt := t.TempDir()
|
||||||
@ -105,11 +105,11 @@ func TestLookupWithOverlay(t *testing.T) {
|
|||||||
|
|
||||||
testdir := filepath.Join(overlay, "testdir")
|
testdir := filepath.Join(overlay, "testdir")
|
||||||
err := os.Mkdir(testdir, 0777)
|
err := os.Mkdir(testdir, 0777)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
testfile := filepath.Join(overlay, "testfile")
|
testfile := filepath.Join(overlay, "testfile")
|
||||||
_, err = os.Create(testfile)
|
_, err = os.Create(testfile)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
checkLookup(t, "overlay", overlay, testdir)
|
checkLookup(t, "overlay", overlay, testdir)
|
||||||
checkLookup(t, "overlay", overlay, testfile)
|
checkLookup(t, "overlay", overlay, testfile)
|
||||||
|
@ -25,14 +25,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Unmount unmounts a given mountPoint and sets t.Error if it fails
|
// Unmount unmounts a given mountPoint and sets t.Error if it fails
|
||||||
func Unmount(t testing.TB, mountPoint string) {
|
func Unmount(t testing.TB, mountPoint string) {
|
||||||
t.Log("unmount", mountPoint)
|
t.Log("unmount", mountPoint)
|
||||||
err := mount.UnmountAll(mountPoint, umountflags)
|
err := mount.UnmountAll(mountPoint, umountflags)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequiresRoot skips tests that require root, unless the test.root flag has
|
// RequiresRoot skips tests that require root, unless the test.root flag has
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFetcherOpen(t *testing.T) {
|
func TestFetcherOpen(t *testing.T) {
|
||||||
|
@ -21,8 +21,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containerd/containerd/reference"
|
"github.com/containerd/containerd/reference"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRepositoryScope(t *testing.T) {
|
func TestRepositoryScope(t *testing.T) {
|
||||||
@ -51,7 +50,7 @@ func TestRepositoryScope(t *testing.T) {
|
|||||||
for _, x := range testCases {
|
for _, x := range testCases {
|
||||||
t.Run(x.refspec.String(), func(t *testing.T) {
|
t.Run(x.refspec.String(), func(t *testing.T) {
|
||||||
actual, err := RepositoryScope(x.refspec, x.push)
|
actual, err := RepositoryScope(x.refspec, x.push)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, x.expected, actual)
|
assert.Equal(t, x.expected, actual)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -97,7 +96,7 @@ func TestGetTokenScopes(t *testing.T) {
|
|||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
ctx := context.WithValue(context.TODO(), tokenScopesKey{}, tc.scopesInCtx)
|
ctx := context.WithValue(context.TODO(), tokenScopesKey{}, tc.scopesInCtx)
|
||||||
actual := GetTokenScopes(ctx, tc.commonScopes)
|
actual := GetTokenScopes(ctx, tc.commonScopes)
|
||||||
assert.DeepEqual(t, tc.expected, actual)
|
assert.Equal(t, tc.expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +106,5 @@ func TestCustomScope(t *testing.T) {
|
|||||||
ctx = ContextWithAppendPullRepositoryScope(ctx, "foo/bar")
|
ctx = ContextWithAppendPullRepositoryScope(ctx, "foo/bar")
|
||||||
|
|
||||||
scopes := GetTokenScopes(ctx, []string{})
|
scopes := GetTokenScopes(ctx, []string{})
|
||||||
assert.Assert(t, cmp.Len(scopes, 2))
|
assert.Equal(t, []string{"repository:foo/bar:pull", scope}, scopes)
|
||||||
assert.Check(t, cmp.Equal(scopes[0], "repository:foo/bar:pull"))
|
|
||||||
assert.Check(t, cmp.Equal(scopes[1], scope))
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/containerd/containerd/plugin"
|
"github.com/containerd/containerd/plugin"
|
||||||
)
|
)
|
||||||
@ -48,16 +48,16 @@ func TestMergeConfigs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := mergeConfig(a, b)
|
err := mergeConfig(a, b)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, a.Version, 2)
|
assert.Equal(t, 2, a.Version)
|
||||||
assert.Equal(t, a.Root, "new_root")
|
assert.Equal(t, "new_root", a.Root)
|
||||||
assert.Equal(t, a.State, "old_state")
|
assert.Equal(t, "old_state", a.State)
|
||||||
assert.Equal(t, a.OOMScore, 2)
|
assert.Equal(t, 2, a.OOMScore)
|
||||||
assert.DeepEqual(t, a.RequiredPlugins, []string{"old_plugin", "new_plugin1", "new_plugin2"})
|
assert.Equal(t, []string{"old_plugin", "new_plugin1", "new_plugin2"}, a.RequiredPlugins)
|
||||||
assert.DeepEqual(t, a.DisabledPlugins, []string{"old_plugin"})
|
assert.Equal(t, []string{"old_plugin"}, a.DisabledPlugins)
|
||||||
assert.DeepEqual(t, a.Timeouts, map[string]string{"a": "1", "b": "2"})
|
assert.Equal(t, map[string]string{"a": "1", "b": "2"}, a.Timeouts)
|
||||||
assert.DeepEqual(t, a.StreamProcessors, map[string]StreamProcessor{"1": {Path: "3"}, "2": {Path: "5"}})
|
assert.Equal(t, map[string]StreamProcessor{"1": {Path: "3"}, "2": {Path: "5"}}, a.StreamProcessors)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveImports(t *testing.T) {
|
func TestResolveImports(t *testing.T) {
|
||||||
@ -65,7 +65,7 @@ func TestResolveImports(t *testing.T) {
|
|||||||
|
|
||||||
for _, filename := range []string{"config_1.toml", "config_2.toml", "test.toml"} {
|
for _, filename := range []string{"config_1.toml", "config_2.toml", "test.toml"} {
|
||||||
err := os.WriteFile(filepath.Join(tempDir, filename), []byte(""), 0600)
|
err := os.WriteFile(filepath.Join(tempDir, filename), []byte(""), 0600)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
imports, err := resolveImports(filepath.Join(tempDir, "root.toml"), []string{
|
imports, err := resolveImports(filepath.Join(tempDir, "root.toml"), []string{
|
||||||
@ -73,9 +73,9 @@ func TestResolveImports(t *testing.T) {
|
|||||||
filepath.Join(tempDir, "./test.toml"), // Path clean up
|
filepath.Join(tempDir, "./test.toml"), // Path clean up
|
||||||
"current.toml", // Resolve current working dir
|
"current.toml", // Resolve current working dir
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.DeepEqual(t, imports, []string{
|
assert.Equal(t, imports, []string{
|
||||||
filepath.Join(tempDir, "config_1.toml"),
|
filepath.Join(tempDir, "config_1.toml"),
|
||||||
filepath.Join(tempDir, "config_2.toml"),
|
filepath.Join(tempDir, "config_2.toml"),
|
||||||
filepath.Join(tempDir, "test.toml"),
|
filepath.Join(tempDir, "test.toml"),
|
||||||
@ -97,14 +97,14 @@ root = "/var/lib/containerd"
|
|||||||
|
|
||||||
path := filepath.Join(tempDir, "config.toml")
|
path := filepath.Join(tempDir, "config.toml")
|
||||||
err := os.WriteFile(path, []byte(data), 0600)
|
err := os.WriteFile(path, []byte(data), 0600)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
var out Config
|
var out Config
|
||||||
err = LoadConfig(path, &out)
|
err = LoadConfig(path, &out)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 2, out.Version)
|
assert.Equal(t, 2, out.Version)
|
||||||
assert.Equal(t, "/var/lib/containerd", out.Root)
|
assert.Equal(t, "/var/lib/containerd", out.Root)
|
||||||
assert.DeepEqual(t, map[string]StreamProcessor{
|
assert.Equal(t, map[string]StreamProcessor{
|
||||||
"io.containerd.processor.v1.pigz": {
|
"io.containerd.processor.v1.pigz": {
|
||||||
Accepts: []string{"application/vnd.docker.image.rootfs.diff.tar.gzip"},
|
Accepts: []string{"application/vnd.docker.image.rootfs.diff.tar.gzip"},
|
||||||
Path: "unpigz",
|
Path: "unpigz",
|
||||||
@ -126,18 +126,18 @@ disabled_plugins = ["io.containerd.v1.xyz"]
|
|||||||
tempDir := t.TempDir()
|
tempDir := t.TempDir()
|
||||||
|
|
||||||
err := os.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0600)
|
err := os.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0600)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = os.WriteFile(filepath.Join(tempDir, "data2.toml"), []byte(data2), 0600)
|
err = os.WriteFile(filepath.Join(tempDir, "data2.toml"), []byte(data2), 0600)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
var out Config
|
var out Config
|
||||||
err = LoadConfig(filepath.Join(tempDir, "data1.toml"), &out)
|
err = LoadConfig(filepath.Join(tempDir, "data1.toml"), &out)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 2, out.Version)
|
assert.Equal(t, 2, out.Version)
|
||||||
assert.Equal(t, "/var/lib/containerd", out.Root)
|
assert.Equal(t, "/var/lib/containerd", out.Root)
|
||||||
assert.DeepEqual(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins)
|
assert.Equal(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadConfigWithCircularImports(t *testing.T) {
|
func TestLoadConfigWithCircularImports(t *testing.T) {
|
||||||
@ -154,21 +154,21 @@ imports = ["data1.toml", "data2.toml"]
|
|||||||
tempDir := t.TempDir()
|
tempDir := t.TempDir()
|
||||||
|
|
||||||
err := os.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0600)
|
err := os.WriteFile(filepath.Join(tempDir, "data1.toml"), []byte(data1), 0600)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = os.WriteFile(filepath.Join(tempDir, "data2.toml"), []byte(data2), 0600)
|
err = os.WriteFile(filepath.Join(tempDir, "data2.toml"), []byte(data2), 0600)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
var out Config
|
var out Config
|
||||||
err = LoadConfig(filepath.Join(tempDir, "data1.toml"), &out)
|
err = LoadConfig(filepath.Join(tempDir, "data1.toml"), &out)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 2, out.Version)
|
assert.Equal(t, 2, out.Version)
|
||||||
assert.Equal(t, "/var/lib/containerd", out.Root)
|
assert.Equal(t, "/var/lib/containerd", out.Root)
|
||||||
assert.DeepEqual(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins)
|
assert.Equal(t, []string{"io.containerd.v1.xyz"}, out.DisabledPlugins)
|
||||||
|
|
||||||
sort.Strings(out.Imports)
|
sort.Strings(out.Imports)
|
||||||
assert.DeepEqual(t, []string{
|
assert.Equal(t, []string{
|
||||||
filepath.Join(tempDir, "data1.toml"),
|
filepath.Join(tempDir, "data1.toml"),
|
||||||
filepath.Join(tempDir, "data2.toml"),
|
filepath.Join(tempDir, "data2.toml"),
|
||||||
}, out.Imports)
|
}, out.Imports)
|
||||||
@ -185,15 +185,15 @@ version = 2
|
|||||||
|
|
||||||
path := filepath.Join(tempDir, "config.toml")
|
path := filepath.Join(tempDir, "config.toml")
|
||||||
err := os.WriteFile(path, []byte(data), 0600)
|
err := os.WriteFile(path, []byte(data), 0600)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
var out Config
|
var out Config
|
||||||
err = LoadConfig(path, &out)
|
err = LoadConfig(path, &out)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
pluginConfig := map[string]interface{}{}
|
pluginConfig := map[string]interface{}{}
|
||||||
_, err = out.Decode(&plugin.Registration{Type: "io.containerd.runtime.v1", ID: "linux", Config: &pluginConfig})
|
_, err = out.Decode(&plugin.Registration{Type: "io.containerd.runtime.v1", ID: "linux", Config: &pluginConfig})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, true, pluginConfig["shim_debug"])
|
assert.Equal(t, true, pluginConfig["shim_debug"])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,14 +207,14 @@ func TestDecodePluginInV1Config(t *testing.T) {
|
|||||||
|
|
||||||
path := filepath.Join(t.TempDir(), "config.toml")
|
path := filepath.Join(t.TempDir(), "config.toml")
|
||||||
err := os.WriteFile(path, []byte(data), 0600)
|
err := os.WriteFile(path, []byte(data), 0600)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
var out Config
|
var out Config
|
||||||
err = LoadConfig(path, &out)
|
err = LoadConfig(path, &out)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
pluginConfig := map[string]interface{}{}
|
pluginConfig := map[string]interface{}{}
|
||||||
_, err = out.Decode(&plugin.Registration{ID: "linux", Config: &pluginConfig})
|
_, err = out.Decode(&plugin.Registration{ID: "linux", Config: &pluginConfig})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, true, pluginConfig["shim_debug"])
|
assert.Equal(t, true, pluginConfig["shim_debug"])
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
srvconfig "github.com/containerd/containerd/services/server/config"
|
srvconfig "github.com/containerd/containerd/services/server/config"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateTopLevelDirectoriesErrorsWithSamePathForRootAndState(t *testing.T) {
|
func TestCreateTopLevelDirectoriesErrorsWithSamePathForRootAndState(t *testing.T) {
|
||||||
@ -30,7 +29,7 @@ func TestCreateTopLevelDirectoriesErrorsWithSamePathForRootAndState(t *testing.T
|
|||||||
Root: path,
|
Root: path,
|
||||||
State: path,
|
State: path,
|
||||||
})
|
})
|
||||||
assert.Check(t, is.Error(err, "root and state must be different paths"))
|
assert.EqualError(t, err, "root and state must be different paths")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateTopLevelDirectoriesWithEmptyStatePath(t *testing.T) {
|
func TestCreateTopLevelDirectoriesWithEmptyStatePath(t *testing.T) {
|
||||||
@ -40,7 +39,7 @@ func TestCreateTopLevelDirectoriesWithEmptyStatePath(t *testing.T) {
|
|||||||
Root: rootPath,
|
Root: rootPath,
|
||||||
State: statePath,
|
State: statePath,
|
||||||
})
|
})
|
||||||
assert.Check(t, is.Error(err, "state must be specified"))
|
assert.EqualError(t, err, "state must be specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateTopLevelDirectoriesWithEmptyRootPath(t *testing.T) {
|
func TestCreateTopLevelDirectoriesWithEmptyRootPath(t *testing.T) {
|
||||||
@ -50,5 +49,5 @@ func TestCreateTopLevelDirectoriesWithEmptyRootPath(t *testing.T) {
|
|||||||
Root: rootPath,
|
Root: rootPath,
|
||||||
State: statePath,
|
State: statePath,
|
||||||
})
|
})
|
||||||
assert.Check(t, is.Error(err, "root must be specified"))
|
assert.EqualError(t, err, "root must be specified")
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containerd/continuity/fs/fstest"
|
"github.com/containerd/continuity/fs/fstest"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
"github.com/containerd/containerd/snapshots"
|
"github.com/containerd/containerd/snapshots"
|
||||||
@ -64,14 +64,14 @@ func BenchmarkNative(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
snapshotter, err := native.NewSnapshotter(nativeRootPath)
|
snapshotter, err := native.NewSnapshotter(nativeRootPath)
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err = snapshotter.Close()
|
err = snapshotter.Close()
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
|
|
||||||
err = os.RemoveAll(nativeRootPath)
|
err = os.RemoveAll(nativeRootPath)
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
benchmarkSnapshotter(b, snapshotter)
|
benchmarkSnapshotter(b, snapshotter)
|
||||||
@ -83,14 +83,14 @@ func BenchmarkOverlay(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
snapshotter, err := overlay.NewSnapshotter(overlayRootPath)
|
snapshotter, err := overlay.NewSnapshotter(overlayRootPath)
|
||||||
assert.NilError(b, err, "failed to create overlay snapshotter")
|
assert.Nil(b, err, "failed to create overlay snapshotter")
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err = snapshotter.Close()
|
err = snapshotter.Close()
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
|
|
||||||
err = os.RemoveAll(overlayRootPath)
|
err = os.RemoveAll(overlayRootPath)
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
benchmarkSnapshotter(b, snapshotter)
|
benchmarkSnapshotter(b, snapshotter)
|
||||||
@ -114,17 +114,17 @@ func BenchmarkDeviceMapper(b *testing.B) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
snapshotter, err := devmapper.NewSnapshotter(ctx, config)
|
snapshotter, err := devmapper.NewSnapshotter(ctx, config)
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := snapshotter.ResetPool(ctx)
|
err := snapshotter.ResetPool(ctx)
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
|
|
||||||
err = snapshotter.Close()
|
err = snapshotter.Close()
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
|
|
||||||
err = os.RemoveAll(dmRootPath)
|
err = os.RemoveAll(dmRootPath)
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
benchmarkSnapshotter(b, snapshotter)
|
benchmarkSnapshotter(b, snapshotter)
|
||||||
@ -184,19 +184,19 @@ func benchmarkSnapshotter(b *testing.B, snapshotter snapshots.Snapshotter) {
|
|||||||
|
|
||||||
timer = time.Now()
|
timer = time.Now()
|
||||||
mounts, err := snapshotter.Prepare(ctx, current, parent)
|
mounts, err := snapshotter.Prepare(ctx, current, parent)
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
prepareDuration += time.Since(timer)
|
prepareDuration += time.Since(timer)
|
||||||
|
|
||||||
timer = time.Now()
|
timer = time.Now()
|
||||||
err = mount.WithTempMount(ctx, mounts, layers[l].Apply)
|
err = mount.WithTempMount(ctx, mounts, layers[l].Apply)
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
writeDuration += time.Since(timer)
|
writeDuration += time.Since(timer)
|
||||||
|
|
||||||
parent = fmt.Sprintf("committed-%d", atomic.AddInt64(&layerIndex, 1))
|
parent = fmt.Sprintf("committed-%d", atomic.AddInt64(&layerIndex, 1))
|
||||||
|
|
||||||
timer = time.Now()
|
timer = time.Now()
|
||||||
err = snapshotter.Commit(ctx, parent, current)
|
err = snapshotter.Commit(ctx, parent, current)
|
||||||
assert.NilError(b, err)
|
assert.Nil(b, err)
|
||||||
commitDuration += time.Since(timer)
|
commitDuration += time.Since(timer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,7 @@ import (
|
|||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/pelletier/go-toml"
|
"github.com/pelletier/go-toml"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoadConfig(t *testing.T) {
|
func TestLoadConfig(t *testing.T) {
|
||||||
@ -37,28 +36,27 @@ func TestLoadConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.CreateTemp("", "devmapper-config-")
|
file, err := os.CreateTemp("", "devmapper-config-")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
encoder := toml.NewEncoder(file)
|
encoder := toml.NewEncoder(file)
|
||||||
err = encoder.Encode(&expected)
|
err = encoder.Encode(&expected)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := file.Close()
|
err := file.Close()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = os.Remove(file.Name())
|
err = os.Remove(file.Name())
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
loaded, err := LoadConfig(file.Name())
|
loaded, err := LoadConfig(file.Name())
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, loaded.RootPath, expected.RootPath)
|
assert.Equal(t, loaded.RootPath, expected.RootPath)
|
||||||
assert.Equal(t, loaded.PoolName, expected.PoolName)
|
assert.Equal(t, loaded.PoolName, expected.PoolName)
|
||||||
assert.Equal(t, loaded.BaseImageSize, expected.BaseImageSize)
|
assert.Equal(t, loaded.BaseImageSize, expected.BaseImageSize)
|
||||||
|
assert.True(t, loaded.BaseImageSizeBytes == 128*1024*1024)
|
||||||
assert.Assert(t, loaded.BaseImageSizeBytes == 128*1024*1024)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadConfigInvalidPath(t *testing.T) {
|
func TestLoadConfigInvalidPath(t *testing.T) {
|
||||||
@ -66,7 +64,7 @@ func TestLoadConfigInvalidPath(t *testing.T) {
|
|||||||
assert.Equal(t, os.ErrNotExist, err)
|
assert.Equal(t, os.ErrNotExist, err)
|
||||||
|
|
||||||
_, err = LoadConfig("/dev/null")
|
_, err = LoadConfig("/dev/null")
|
||||||
assert.Assert(t, err != nil)
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseInvalidData(t *testing.T) {
|
func TestParseInvalidData(t *testing.T) {
|
||||||
@ -81,15 +79,15 @@ func TestParseInvalidData(t *testing.T) {
|
|||||||
func TestFieldValidation(t *testing.T) {
|
func TestFieldValidation(t *testing.T) {
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
err := config.Validate()
|
err := config.Validate()
|
||||||
assert.Assert(t, err != nil)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
multErr := (err).(*multierror.Error)
|
multErr := (err).(*multierror.Error)
|
||||||
assert.Assert(t, is.Len(multErr.Errors, 4))
|
assert.Len(t, multErr.Errors, 4)
|
||||||
|
|
||||||
assert.Assert(t, multErr.Errors[0] != nil, "pool_name is empty")
|
assert.NotNil(t, multErr.Errors[0], "pool_name is empty")
|
||||||
assert.Assert(t, multErr.Errors[1] != nil, "root_path is empty")
|
assert.NotNil(t, multErr.Errors[1], "root_path is empty")
|
||||||
assert.Assert(t, multErr.Errors[2] != nil, "base_image_size is empty")
|
assert.NotNil(t, multErr.Errors[2], "base_image_size is empty")
|
||||||
assert.Assert(t, multErr.Errors[3] != nil, "filesystem type cannot be empty")
|
assert.NotNil(t, multErr.Errors[3], "filesystem type cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExistingPoolFieldValidation(t *testing.T) {
|
func TestExistingPoolFieldValidation(t *testing.T) {
|
||||||
@ -101,5 +99,5 @@ func TestExistingPoolFieldValidation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := config.Validate()
|
err := config.Validate()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/go-units"
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
|
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
"github.com/containerd/containerd/pkg/testutil"
|
"github.com/containerd/containerd/pkg/testutil"
|
||||||
|
"github.com/docker/go-units"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -50,23 +48,23 @@ func TestDMSetup(t *testing.T) {
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := mount.DetachLoopDevice(loopDataDevice, loopMetaDevice)
|
err := mount.DetachLoopDevice(loopDataDevice, loopMetaDevice)
|
||||||
assert.NilError(t, err, "failed to detach loop devices for data image: %s and meta image: %s", dataImage, metaImage)
|
assert.Nil(t, err, "failed to detach loop devices for data image: %s and meta image: %s", dataImage, metaImage)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
t.Run("CreatePool", func(t *testing.T) {
|
t.Run("CreatePool", func(t *testing.T) {
|
||||||
err := CreatePool(testPoolName, loopDataDevice, loopMetaDevice, 128)
|
err := CreatePool(testPoolName, loopDataDevice, loopMetaDevice, 128)
|
||||||
assert.NilError(t, err, "failed to create thin-pool with %s %s", loopDataDevice, loopMetaDevice)
|
assert.Nil(t, err, "failed to create thin-pool with %s %s", loopDataDevice, loopMetaDevice)
|
||||||
|
|
||||||
table, err := Table(testPoolName)
|
table, err := Table(testPoolName)
|
||||||
t.Logf("table: %s", table)
|
t.Logf("table: %s", table)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Assert(t, strings.HasPrefix(table, "0 32768 thin-pool"))
|
assert.True(t, strings.HasPrefix(table, "0 32768 thin-pool"))
|
||||||
assert.Assert(t, strings.HasSuffix(table, "128 32768 1 skip_block_zeroing"))
|
assert.True(t, strings.HasSuffix(table, "128 32768 1 skip_block_zeroing"))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ReloadPool", func(t *testing.T) {
|
t.Run("ReloadPool", func(t *testing.T) {
|
||||||
err := ReloadPool(testPoolName, loopDataDevice, loopMetaDevice, 256)
|
err := ReloadPool(testPoolName, loopDataDevice, loopMetaDevice, 256)
|
||||||
assert.NilError(t, err, "failed to reload thin-pool")
|
assert.Nil(t, err, "failed to reload thin-pool")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("CreateDevice", testCreateDevice)
|
t.Run("CreateDevice", testCreateDevice)
|
||||||
@ -82,7 +80,7 @@ func TestDMSetup(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("RemovePool", func(t *testing.T) {
|
t.Run("RemovePool", func(t *testing.T) {
|
||||||
err := RemoveDevice(testPoolName, RemoveWithForce, RemoveWithRetries)
|
err := RemoveDevice(testPoolName, RemoveWithForce, RemoveWithRetries)
|
||||||
assert.NilError(t, err, "failed to remove thin-pool")
|
assert.Nil(t, err, "failed to remove thin-pool")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Version", testVersion)
|
t.Run("Version", testVersion)
|
||||||
@ -90,116 +88,116 @@ func TestDMSetup(t *testing.T) {
|
|||||||
|
|
||||||
func testCreateDevice(t *testing.T) {
|
func testCreateDevice(t *testing.T) {
|
||||||
err := CreateDevice(testPoolName, deviceID)
|
err := CreateDevice(testPoolName, deviceID)
|
||||||
assert.NilError(t, err, "failed to create test device")
|
assert.Nil(t, err, "failed to create test device")
|
||||||
|
|
||||||
err = CreateDevice(testPoolName, deviceID)
|
err = CreateDevice(testPoolName, deviceID)
|
||||||
assert.Assert(t, err == unix.EEXIST)
|
assert.True(t, err == unix.EEXIST)
|
||||||
|
|
||||||
infos, err := Info(testPoolName)
|
infos, err := Info(testPoolName)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Assert(t, is.Len(infos, 1), "got unexpected number of device infos")
|
assert.Len(t, infos, 1, "got unexpected number of device infos")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreateSnapshot(t *testing.T) {
|
func testCreateSnapshot(t *testing.T) {
|
||||||
err := CreateSnapshot(testPoolName, snapshotID, deviceID)
|
err := CreateSnapshot(testPoolName, snapshotID, deviceID)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeleteSnapshot(t *testing.T) {
|
func testDeleteSnapshot(t *testing.T) {
|
||||||
err := DeleteDevice(testPoolName, snapshotID)
|
err := DeleteDevice(testPoolName, snapshotID)
|
||||||
assert.NilError(t, err, "failed to send delete message")
|
assert.Nil(t, err, "failed to send delete message")
|
||||||
|
|
||||||
err = DeleteDevice(testPoolName, snapshotID)
|
err = DeleteDevice(testPoolName, snapshotID)
|
||||||
assert.Assert(t, err == unix.ENODATA)
|
assert.Equal(t, err, unix.ENODATA)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testActivateDevice(t *testing.T) {
|
func testActivateDevice(t *testing.T) {
|
||||||
err := ActivateDevice(testPoolName, testDeviceName, 1, 1024, "")
|
err := ActivateDevice(testPoolName, testDeviceName, 1, 1024, "")
|
||||||
assert.NilError(t, err, "failed to activate device")
|
assert.Nil(t, err, "failed to activate device")
|
||||||
|
|
||||||
err = ActivateDevice(testPoolName, testDeviceName, 1, 1024, "")
|
err = ActivateDevice(testPoolName, testDeviceName, 1, 1024, "")
|
||||||
assert.Equal(t, err, unix.EBUSY)
|
assert.Equal(t, err, unix.EBUSY)
|
||||||
|
|
||||||
if _, err := os.Stat("/dev/mapper/" + testDeviceName); err != nil && !os.IsExist(err) {
|
if _, err := os.Stat("/dev/mapper/" + testDeviceName); err != nil && !os.IsExist(err) {
|
||||||
assert.NilError(t, err, "failed to stat device")
|
assert.Nil(t, err, "failed to stat device")
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := Info(testPoolName)
|
list, err := Info(testPoolName)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Assert(t, is.Len(list, 1))
|
assert.Len(t, list, 1)
|
||||||
|
|
||||||
info := list[0]
|
info := list[0]
|
||||||
assert.Equal(t, testPoolName, info.Name)
|
assert.Equal(t, testPoolName, info.Name)
|
||||||
assert.Assert(t, info.TableLive)
|
assert.True(t, info.TableLive)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeviceStatus(t *testing.T) {
|
func testDeviceStatus(t *testing.T) {
|
||||||
status, err := Status(testDeviceName)
|
status, err := Status(testDeviceName)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, int64(0), status.Offset)
|
assert.Equal(t, int64(0), status.Offset)
|
||||||
assert.Equal(t, int64(2), status.Length)
|
assert.Equal(t, int64(2), status.Length)
|
||||||
assert.Equal(t, "thin", status.Target)
|
assert.Equal(t, "thin", status.Target)
|
||||||
assert.DeepEqual(t, status.Params, []string{"0", "-"})
|
assert.Equal(t, status.Params, []string{"0", "-"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSuspendResumeDevice(t *testing.T) {
|
func testSuspendResumeDevice(t *testing.T) {
|
||||||
err := SuspendDevice(testDeviceName)
|
err := SuspendDevice(testDeviceName)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = SuspendDevice(testDeviceName)
|
err = SuspendDevice(testDeviceName)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
list, err := Info(testDeviceName)
|
list, err := Info(testDeviceName)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Assert(t, is.Len(list, 1))
|
assert.Len(t, list, 1)
|
||||||
|
|
||||||
info := list[0]
|
info := list[0]
|
||||||
assert.Assert(t, info.Suspended)
|
assert.True(t, info.Suspended)
|
||||||
|
|
||||||
err = ResumeDevice(testDeviceName)
|
err = ResumeDevice(testDeviceName)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = ResumeDevice(testDeviceName)
|
err = ResumeDevice(testDeviceName)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDiscardBlocks(t *testing.T) {
|
func testDiscardBlocks(t *testing.T) {
|
||||||
err := DiscardBlocks(testDeviceName)
|
err := DiscardBlocks(testDeviceName)
|
||||||
assert.NilError(t, err, "failed to discard blocks")
|
assert.Nil(t, err, "failed to discard blocks")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRemoveDevice(t *testing.T) {
|
func testRemoveDevice(t *testing.T) {
|
||||||
err := RemoveDevice(testPoolName)
|
err := RemoveDevice(testPoolName)
|
||||||
assert.Assert(t, err == unix.EBUSY, "removing thin-pool with dependencies shouldn't be allowed")
|
assert.Equal(t, err, unix.EBUSY, "removing thin-pool with dependencies shouldn't be allowed")
|
||||||
|
|
||||||
err = RemoveDevice(testDeviceName, RemoveWithRetries)
|
err = RemoveDevice(testDeviceName, RemoveWithRetries)
|
||||||
assert.NilError(t, err, "failed to remove thin-device")
|
assert.Nil(t, err, "failed to remove thin-device")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testVersion(t *testing.T) {
|
func testVersion(t *testing.T) {
|
||||||
version, err := Version()
|
version, err := Version()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Assert(t, version != "")
|
assert.NotEmpty(t, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createLoopbackDevice(t *testing.T, dir string) (string, string) {
|
func createLoopbackDevice(t *testing.T, dir string) (string, string) {
|
||||||
file, err := os.CreateTemp(dir, "dmsetup-tests-")
|
file, err := os.CreateTemp(dir, "dmsetup-tests-")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
size, err := units.RAMInBytes("16Mb")
|
size, err := units.RAMInBytes("16Mb")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = file.Truncate(size)
|
err = file.Truncate(size)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = file.Close()
|
err = file.Close()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
imagePath := file.Name()
|
imagePath := file.Name()
|
||||||
|
|
||||||
loopDevice, err := mount.AttachLoopDevice(imagePath)
|
loopDevice, err := mount.AttachLoopDevice(imagePath)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
return imagePath, loopDevice
|
return imagePath, loopDevice
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"go.etcd.io/bbolt"
|
"go.etcd.io/bbolt"
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -47,16 +46,16 @@ func TestPoolMetadata_AddDevice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := store.AddDevice(testCtx, expected)
|
err := store.AddDevice(testCtx, expected)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
result, err := store.GetDevice(testCtx, "test2")
|
result, err := store.GetDevice(testCtx, "test2")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, expected.Name, result.Name)
|
assert.Equal(t, expected.Name, result.Name)
|
||||||
assert.Equal(t, expected.ParentName, result.ParentName)
|
assert.Equal(t, expected.ParentName, result.ParentName)
|
||||||
assert.Equal(t, expected.Size, result.Size)
|
assert.Equal(t, expected.Size, result.Size)
|
||||||
assert.Equal(t, expected.State, result.State)
|
assert.Equal(t, expected.State, result.State)
|
||||||
assert.Assert(t, result.DeviceID != 0)
|
assert.NotZero(t, result.DeviceID, 0)
|
||||||
assert.Equal(t, expected.DeviceID, result.DeviceID)
|
assert.Equal(t, expected.DeviceID, result.DeviceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +64,7 @@ func TestPoolMetadata_AddDeviceRollback(t *testing.T) {
|
|||||||
defer cleanupStore(t, store)
|
defer cleanupStore(t, store)
|
||||||
|
|
||||||
err := store.AddDevice(testCtx, &DeviceInfo{Name: ""})
|
err := store.AddDevice(testCtx, &DeviceInfo{Name: ""})
|
||||||
assert.Assert(t, err != nil)
|
assert.True(t, err != nil)
|
||||||
|
|
||||||
_, err = store.GetDevice(testCtx, "")
|
_, err = store.GetDevice(testCtx, "")
|
||||||
assert.Equal(t, ErrNotFound, err)
|
assert.Equal(t, ErrNotFound, err)
|
||||||
@ -76,10 +75,10 @@ func TestPoolMetadata_AddDeviceDuplicate(t *testing.T) {
|
|||||||
defer cleanupStore(t, store)
|
defer cleanupStore(t, store)
|
||||||
|
|
||||||
err := store.AddDevice(testCtx, &DeviceInfo{Name: "test"})
|
err := store.AddDevice(testCtx, &DeviceInfo{Name: "test"})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = store.AddDevice(testCtx, &DeviceInfo{Name: "test"})
|
err = store.AddDevice(testCtx, &DeviceInfo{Name: "test"})
|
||||||
assert.Assert(t, errors.Is(err, ErrAlreadyExists))
|
assert.True(t, errors.Is(err, ErrAlreadyExists))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPoolMetadata_ReuseDeviceID(t *testing.T) {
|
func TestPoolMetadata_ReuseDeviceID(t *testing.T) {
|
||||||
@ -88,21 +87,21 @@ func TestPoolMetadata_ReuseDeviceID(t *testing.T) {
|
|||||||
|
|
||||||
info1 := &DeviceInfo{Name: "test1"}
|
info1 := &DeviceInfo{Name: "test1"}
|
||||||
err := store.AddDevice(testCtx, info1)
|
err := store.AddDevice(testCtx, info1)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
info2 := &DeviceInfo{Name: "test2"}
|
info2 := &DeviceInfo{Name: "test2"}
|
||||||
err = store.AddDevice(testCtx, info2)
|
err = store.AddDevice(testCtx, info2)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Assert(t, info1.DeviceID != info2.DeviceID)
|
assert.NotEqual(t, info1.DeviceID, info2.DeviceID)
|
||||||
assert.Assert(t, info1.DeviceID != 0)
|
assert.NotZero(t, info1.DeviceID)
|
||||||
|
|
||||||
err = store.RemoveDevice(testCtx, info2.Name)
|
err = store.RemoveDevice(testCtx, info2.Name)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
info3 := &DeviceInfo{Name: "test3"}
|
info3 := &DeviceInfo{Name: "test3"}
|
||||||
err = store.AddDevice(testCtx, info3)
|
err = store.AddDevice(testCtx, info3)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, info2.DeviceID, info3.DeviceID)
|
assert.Equal(t, info2.DeviceID, info3.DeviceID)
|
||||||
}
|
}
|
||||||
@ -112,10 +111,10 @@ func TestPoolMetadata_RemoveDevice(t *testing.T) {
|
|||||||
defer cleanupStore(t, store)
|
defer cleanupStore(t, store)
|
||||||
|
|
||||||
err := store.AddDevice(testCtx, &DeviceInfo{Name: "test"})
|
err := store.AddDevice(testCtx, &DeviceInfo{Name: "test"})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = store.RemoveDevice(testCtx, "test")
|
err = store.RemoveDevice(testCtx, "test")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
_, err = store.GetDevice(testCtx, "test")
|
_, err = store.GetDevice(testCtx, "test")
|
||||||
assert.Equal(t, ErrNotFound, err)
|
assert.Equal(t, ErrNotFound, err)
|
||||||
@ -133,7 +132,7 @@ func TestPoolMetadata_UpdateDevice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := store.AddDevice(testCtx, oldInfo)
|
err := store.AddDevice(testCtx, oldInfo)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = store.UpdateDevice(testCtx, oldInfo.Name, func(info *DeviceInfo) error {
|
err = store.UpdateDevice(testCtx, oldInfo.Name, func(info *DeviceInfo) error {
|
||||||
info.ParentName = "test5"
|
info.ParentName = "test5"
|
||||||
@ -142,14 +141,14 @@ func TestPoolMetadata_UpdateDevice(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
newInfo, err := store.GetDevice(testCtx, "test1")
|
newInfo, err := store.GetDevice(testCtx, "test1")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, "test1", newInfo.Name)
|
assert.Equal(t, "test1", newInfo.Name)
|
||||||
assert.Equal(t, "test5", newInfo.ParentName)
|
assert.Equal(t, "test5", newInfo.ParentName)
|
||||||
assert.Assert(t, newInfo.Size == 6)
|
assert.EqualValues(t, newInfo.Size, 6)
|
||||||
assert.Equal(t, Created, newInfo.State)
|
assert.Equal(t, Created, newInfo.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,15 +158,15 @@ func TestPoolMetadata_MarkFaulty(t *testing.T) {
|
|||||||
|
|
||||||
info := &DeviceInfo{Name: "test"}
|
info := &DeviceInfo{Name: "test"}
|
||||||
err := store.AddDevice(testCtx, info)
|
err := store.AddDevice(testCtx, info)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = store.MarkFaulty(testCtx, "test")
|
err = store.MarkFaulty(testCtx, "test")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
saved, err := store.GetDevice(testCtx, info.Name)
|
saved, err := store.GetDevice(testCtx, info.Name)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, saved.State, Faulty)
|
assert.Equal(t, saved.State, Faulty)
|
||||||
assert.Assert(t, saved.DeviceID > 0)
|
assert.True(t, saved.DeviceID > 0)
|
||||||
|
|
||||||
// Make sure a device ID marked as faulty as well
|
// Make sure a device ID marked as faulty as well
|
||||||
err = store.db.View(func(tx *bbolt.Tx) error {
|
err = store.db.View(func(tx *bbolt.Tx) error {
|
||||||
@ -177,7 +176,7 @@ func TestPoolMetadata_MarkFaulty(t *testing.T) {
|
|||||||
assert.Equal(t, value[0], byte(deviceFaulty))
|
assert.Equal(t, value[0], byte(deviceFaulty))
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPoolMetadata_WalkDevices(t *testing.T) {
|
func TestPoolMetadata_WalkDevices(t *testing.T) {
|
||||||
@ -185,10 +184,10 @@ func TestPoolMetadata_WalkDevices(t *testing.T) {
|
|||||||
defer cleanupStore(t, store)
|
defer cleanupStore(t, store)
|
||||||
|
|
||||||
err := store.AddDevice(testCtx, &DeviceInfo{Name: "device1", DeviceID: 1, State: Created})
|
err := store.AddDevice(testCtx, &DeviceInfo{Name: "device1", DeviceID: 1, State: Created})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = store.AddDevice(testCtx, &DeviceInfo{Name: "device2", DeviceID: 2, State: Faulty})
|
err = store.AddDevice(testCtx, &DeviceInfo{Name: "device2", DeviceID: 2, State: Faulty})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
called := 0
|
called := 0
|
||||||
err = store.WalkDevices(testCtx, func(info *DeviceInfo) error {
|
err = store.WalkDevices(testCtx, func(info *DeviceInfo) error {
|
||||||
@ -208,7 +207,7 @@ func TestPoolMetadata_WalkDevices(t *testing.T) {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, called, 2)
|
assert.Equal(t, called, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,14 +216,14 @@ func TestPoolMetadata_GetDeviceNames(t *testing.T) {
|
|||||||
defer cleanupStore(t, store)
|
defer cleanupStore(t, store)
|
||||||
|
|
||||||
err := store.AddDevice(testCtx, &DeviceInfo{Name: "test1"})
|
err := store.AddDevice(testCtx, &DeviceInfo{Name: "test1"})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = store.AddDevice(testCtx, &DeviceInfo{Name: "test2"})
|
err = store.AddDevice(testCtx, &DeviceInfo{Name: "test2"})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
names, err := store.GetDeviceNames(testCtx)
|
names, err := store.GetDeviceNames(testCtx)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Assert(t, is.Len(names, 2))
|
assert.Len(t, names, 2)
|
||||||
|
|
||||||
assert.Equal(t, "test1", names[0])
|
assert.Equal(t, "test1", names[0])
|
||||||
assert.Equal(t, "test2", names[1])
|
assert.Equal(t, "test2", names[1])
|
||||||
@ -233,12 +232,12 @@ func TestPoolMetadata_GetDeviceNames(t *testing.T) {
|
|||||||
func createStore(t *testing.T) (store *PoolMetadata) {
|
func createStore(t *testing.T) (store *PoolMetadata) {
|
||||||
path := filepath.Join(t.TempDir(), "test.db")
|
path := filepath.Join(t.TempDir(), "test.db")
|
||||||
metadata, err := NewPoolMetadata(path)
|
metadata, err := NewPoolMetadata(path)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupStore(t *testing.T, store *PoolMetadata) {
|
func cleanupStore(t *testing.T, store *PoolMetadata) {
|
||||||
err := store.Close()
|
err := store.Close()
|
||||||
assert.NilError(t, err, "failed to close metadata store")
|
assert.Nil(t, err, "failed to close metadata store")
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,8 @@ import (
|
|||||||
"github.com/containerd/containerd/snapshots/devmapper/dmsetup"
|
"github.com/containerd/containerd/snapshots/devmapper/dmsetup"
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
exec "golang.org/x/sys/execabs"
|
exec "golang.org/x/sys/execabs"
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -68,12 +68,12 @@ func TestPoolDevice(t *testing.T) {
|
|||||||
|
|
||||||
poolName := fmt.Sprintf("test-pool-device-%d", time.Now().Nanosecond())
|
poolName := fmt.Sprintf("test-pool-device-%d", time.Now().Nanosecond())
|
||||||
err := dmsetup.CreatePool(poolName, loopDataDevice, loopMetaDevice, 64*1024/dmsetup.SectorSize)
|
err := dmsetup.CreatePool(poolName, loopDataDevice, loopMetaDevice, 64*1024/dmsetup.SectorSize)
|
||||||
assert.NilError(t, err, "failed to create pool %q", poolName)
|
assert.Nil(t, err, "failed to create pool %q", poolName)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// Detach loop devices and remove images
|
// Detach loop devices and remove images
|
||||||
err := mount.DetachLoopDevice(loopDataDevice, loopMetaDevice)
|
err := mount.DetachLoopDevice(loopDataDevice, loopMetaDevice)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
config := &Config{
|
config := &Config{
|
||||||
@ -85,12 +85,12 @@ func TestPoolDevice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pool, err := NewPoolDevice(ctx, config)
|
pool, err := NewPoolDevice(ctx, config)
|
||||||
assert.NilError(t, err, "can't create device pool")
|
assert.Nil(t, err, "can't create device pool")
|
||||||
assert.Assert(t, pool != nil)
|
assert.True(t, pool != nil)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := pool.RemovePool(ctx)
|
err := pool.RemovePool(ctx)
|
||||||
assert.NilError(t, err, "can't close device pool")
|
assert.Nil(t, err, "can't close device pool")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create thin devices
|
// Create thin devices
|
||||||
@ -108,7 +108,7 @@ func TestPoolDevice(t *testing.T) {
|
|||||||
// Write v1 test file on 'thin-1' device
|
// Write v1 test file on 'thin-1' device
|
||||||
thin1TestFilePath := filepath.Join(thin1MountPath, "TEST")
|
thin1TestFilePath := filepath.Join(thin1MountPath, "TEST")
|
||||||
err := os.WriteFile(thin1TestFilePath, []byte("test file (v1)"), 0700)
|
err := os.WriteFile(thin1TestFilePath, []byte("test file (v1)"), 0700)
|
||||||
assert.NilError(t, err, "failed to write test file v1 on '%s' volume", thinDevice1)
|
assert.Nil(t, err, "failed to write test file v1 on '%s' volume", thinDevice1)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -122,24 +122,24 @@ func TestPoolDevice(t *testing.T) {
|
|||||||
err = mount.WithTempMount(ctx, getMounts(thinDevice1), func(thin1MountPath string) error {
|
err = mount.WithTempMount(ctx, getMounts(thinDevice1), func(thin1MountPath string) error {
|
||||||
thin1TestFilePath := filepath.Join(thin1MountPath, "TEST")
|
thin1TestFilePath := filepath.Join(thin1MountPath, "TEST")
|
||||||
err = os.WriteFile(thin1TestFilePath, []byte("test file (v2)"), 0700)
|
err = os.WriteFile(thin1TestFilePath, []byte("test file (v2)"), 0700)
|
||||||
assert.NilError(t, err, "failed to write test file v2 on 'thin-1' volume after taking snapshot")
|
assert.Nil(t, err, "failed to write test file v2 on 'thin-1' volume after taking snapshot")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Mount 'snap-1' and make sure TEST file is v1
|
// Mount 'snap-1' and make sure TEST file is v1
|
||||||
err = mount.WithTempMount(ctx, getMounts(snapDevice1), func(snap1MountPath string) error {
|
err = mount.WithTempMount(ctx, getMounts(snapDevice1), func(snap1MountPath string) error {
|
||||||
// Read test file from snapshot device and make sure it's v1
|
// Read test file from snapshot device and make sure it's v1
|
||||||
fileData, err := os.ReadFile(filepath.Join(snap1MountPath, "TEST"))
|
fileData, err := os.ReadFile(filepath.Join(snap1MountPath, "TEST"))
|
||||||
assert.NilError(t, err, "couldn't read test file from '%s' device", snapDevice1)
|
assert.Nil(t, err, "couldn't read test file from '%s' device", snapDevice1)
|
||||||
assert.Equal(t, "test file (v1)", string(fileData), "test file content is invalid on snapshot")
|
assert.Equal(t, "test file (v1)", string(fileData), "test file content is invalid on snapshot")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
t.Run("DeactivateDevice", func(t *testing.T) {
|
t.Run("DeactivateDevice", func(t *testing.T) {
|
||||||
testDeactivateThinDevice(t, pool)
|
testDeactivateThinDevice(t, pool)
|
||||||
@ -157,17 +157,17 @@ func TestPoolDevice(t *testing.T) {
|
|||||||
snapDevice := "snap2"
|
snapDevice := "snap2"
|
||||||
|
|
||||||
err := pool.CreateSnapshotDevice(ctx, thinDevice1, snapDevice, device1Size)
|
err := pool.CreateSnapshotDevice(ctx, thinDevice1, snapDevice, device1Size)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
info, err := pool.metadata.GetDevice(ctx, snapDevice)
|
info, err := pool.metadata.GetDevice(ctx, snapDevice)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Simulate a case that the device cannot be activated.
|
// Simulate a case that the device cannot be activated.
|
||||||
err = pool.DeactivateDevice(ctx, info.Name, false, false)
|
err = pool.DeactivateDevice(ctx, info.Name, false, false)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = pool.rollbackActivate(ctx, info, err)
|
err = pool.rollbackActivate(ctx, info, err)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,16 +176,16 @@ func TestPoolDeviceMarkFaulty(t *testing.T) {
|
|||||||
defer cleanupStore(t, store)
|
defer cleanupStore(t, store)
|
||||||
|
|
||||||
err := store.AddDevice(testCtx, &DeviceInfo{Name: "1", State: Unknown})
|
err := store.AddDevice(testCtx, &DeviceInfo{Name: "1", State: Unknown})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Note: do not use 'Activated' here because pool.ensureDeviceStates() will
|
// Note: do not use 'Activated' here because pool.ensureDeviceStates() will
|
||||||
// try to activate the real dm device, which will fail on a faked device.
|
// try to activate the real dm device, which will fail on a faked device.
|
||||||
err = store.AddDevice(testCtx, &DeviceInfo{Name: "2", State: Deactivated})
|
err = store.AddDevice(testCtx, &DeviceInfo{Name: "2", State: Deactivated})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
pool := &PoolDevice{metadata: store}
|
pool := &PoolDevice{metadata: store}
|
||||||
err = pool.ensureDeviceStates(testCtx)
|
err = pool.ensureDeviceStates(testCtx)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
called := 0
|
called := 0
|
||||||
err = pool.metadata.WalkDevices(testCtx, func(info *DeviceInfo) error {
|
err = pool.metadata.WalkDevices(testCtx, func(info *DeviceInfo) error {
|
||||||
@ -204,7 +204,7 @@ func TestPoolDeviceMarkFaulty(t *testing.T) {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, 2, called)
|
assert.Equal(t, 2, called)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,24 +212,24 @@ func testCreateThinDevice(t *testing.T, pool *PoolDevice) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
err := pool.CreateThinDevice(ctx, thinDevice1, device1Size)
|
err := pool.CreateThinDevice(ctx, thinDevice1, device1Size)
|
||||||
assert.NilError(t, err, "can't create first thin device")
|
assert.Nil(t, err, "can't create first thin device")
|
||||||
|
|
||||||
err = pool.CreateThinDevice(ctx, thinDevice1, device1Size)
|
err = pool.CreateThinDevice(ctx, thinDevice1, device1Size)
|
||||||
assert.Assert(t, err != nil, "device pool allows duplicated device names")
|
assert.True(t, err != nil, "device pool allows duplicated device names")
|
||||||
|
|
||||||
err = pool.CreateThinDevice(ctx, thinDevice2, device2Size)
|
err = pool.CreateThinDevice(ctx, thinDevice2, device2Size)
|
||||||
assert.NilError(t, err, "can't create second thin device")
|
assert.Nil(t, err, "can't create second thin device")
|
||||||
|
|
||||||
deviceInfo1, err := pool.metadata.GetDevice(ctx, thinDevice1)
|
deviceInfo1, err := pool.metadata.GetDevice(ctx, thinDevice1)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
deviceInfo2, err := pool.metadata.GetDevice(ctx, thinDevice2)
|
deviceInfo2, err := pool.metadata.GetDevice(ctx, thinDevice2)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.Assert(t, deviceInfo1.DeviceID != deviceInfo2.DeviceID, "assigned device ids should be different")
|
assert.True(t, deviceInfo1.DeviceID != deviceInfo2.DeviceID, "assigned device ids should be different")
|
||||||
|
|
||||||
usage, err := pool.GetUsage(thinDevice1)
|
usage, err := pool.GetUsage(thinDevice1)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, usage, int64(0))
|
assert.Equal(t, usage, int64(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,16 +242,16 @@ func testMakeFileSystem(t *testing.T, pool *PoolDevice) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
output, err := exec.Command("mkfs.ext4", args...).CombinedOutput()
|
output, err := exec.Command("mkfs.ext4", args...).CombinedOutput()
|
||||||
assert.NilError(t, err, "failed to make filesystem on '%s': %s", thinDevice1, string(output))
|
assert.Nil(t, err, "failed to make filesystem on '%s': %s", thinDevice1, string(output))
|
||||||
|
|
||||||
usage, err := pool.GetUsage(thinDevice1)
|
usage, err := pool.GetUsage(thinDevice1)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Assert(t, usage > 0)
|
assert.True(t, usage > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCreateSnapshot(t *testing.T, pool *PoolDevice) {
|
func testCreateSnapshot(t *testing.T, pool *PoolDevice) {
|
||||||
err := pool.CreateSnapshotDevice(context.Background(), thinDevice1, snapDevice1, device1Size)
|
err := pool.CreateSnapshotDevice(context.Background(), thinDevice1, snapDevice1, device1Size)
|
||||||
assert.NilError(t, err, "failed to create snapshot from '%s' volume", thinDevice1)
|
assert.Nil(t, err, "failed to create snapshot from '%s' volume", thinDevice1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeactivateThinDevice(t *testing.T, pool *PoolDevice) {
|
func testDeactivateThinDevice(t *testing.T, pool *PoolDevice) {
|
||||||
@ -261,21 +261,21 @@ func testDeactivateThinDevice(t *testing.T, pool *PoolDevice) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, deviceName := range deviceList {
|
for _, deviceName := range deviceList {
|
||||||
assert.Assert(t, pool.IsActivated(deviceName))
|
assert.True(t, pool.IsActivated(deviceName))
|
||||||
|
|
||||||
err := pool.DeactivateDevice(context.Background(), deviceName, false, true)
|
err := pool.DeactivateDevice(context.Background(), deviceName, false, true)
|
||||||
assert.NilError(t, err, "failed to remove '%s'", deviceName)
|
assert.Nil(t, err, "failed to remove '%s'", deviceName)
|
||||||
|
|
||||||
assert.Assert(t, !pool.IsActivated(deviceName))
|
assert.False(t, pool.IsActivated(deviceName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRemoveThinDevice(t *testing.T, pool *PoolDevice) {
|
func testRemoveThinDevice(t *testing.T, pool *PoolDevice) {
|
||||||
err := pool.RemoveDevice(testCtx, thinDevice1)
|
err := pool.RemoveDevice(testCtx, thinDevice1)
|
||||||
assert.NilError(t, err, "should delete thin device from pool")
|
assert.Nil(t, err, "should delete thin device from pool")
|
||||||
|
|
||||||
err = pool.RemoveDevice(testCtx, thinDevice2)
|
err = pool.RemoveDevice(testCtx, thinDevice2)
|
||||||
assert.NilError(t, err, "should delete thin device from pool")
|
assert.Nil(t, err, "should delete thin device from pool")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMounts(thinDeviceName string) []mount.Mount {
|
func getMounts(thinDeviceName string) []mount.Mount {
|
||||||
@ -289,21 +289,21 @@ func getMounts(thinDeviceName string) []mount.Mount {
|
|||||||
|
|
||||||
func createLoopbackDevice(t *testing.T, dir string) (string, string) {
|
func createLoopbackDevice(t *testing.T, dir string) (string, string) {
|
||||||
file, err := os.CreateTemp(dir, testsPrefix)
|
file, err := os.CreateTemp(dir, testsPrefix)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
size, err := units.RAMInBytes("128Mb")
|
size, err := units.RAMInBytes("128Mb")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = file.Truncate(size)
|
err = file.Truncate(size)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = file.Close()
|
err = file.Close()
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
imagePath := file.Name()
|
imagePath := file.Name()
|
||||||
|
|
||||||
loopDevice, err := mount.AttachLoopDevice(imagePath)
|
loopDevice, err := mount.AttachLoopDevice(imagePath)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
return imagePath, loopDevice
|
return imagePath, loopDevice
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ import (
|
|||||||
"github.com/containerd/continuity/fs/fstest"
|
"github.com/containerd/continuity/fs/fstest"
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
@ -61,7 +61,7 @@ func TestSnapshotterSuite(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("DevMapperUsage", func(t *testing.T) {
|
t.Run("DevMapperUsage", func(t *testing.T) {
|
||||||
snapshotter, closer, err := snapshotterFn(ctx, t.TempDir())
|
snapshotter, closer, err := snapshotterFn(ctx, t.TempDir())
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
testUsage(t, snapshotter)
|
testUsage(t, snapshotter)
|
||||||
@ -75,16 +75,16 @@ func testUsage(t *testing.T, snapshotter snapshots.Snapshotter) {
|
|||||||
|
|
||||||
// Create empty base layer
|
// Create empty base layer
|
||||||
_, err := snapshotter.Prepare(ctx, "prepare-1", "")
|
_, err := snapshotter.Prepare(ctx, "prepare-1", "")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
emptyLayerUsage, err := snapshotter.Usage(ctx, "prepare-1")
|
emptyLayerUsage, err := snapshotter.Usage(ctx, "prepare-1")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Should be > 0 as just written file system also consumes blocks
|
// Should be > 0 as just written file system also consumes blocks
|
||||||
assert.Assert(t, emptyLayerUsage.Size > 0)
|
assert.Greater(t, emptyLayerUsage.Size, int64(0))
|
||||||
|
|
||||||
err = snapshotter.Commit(ctx, "layer-1", "prepare-1")
|
err = snapshotter.Commit(ctx, "layer-1", "prepare-1")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Create child layer with 1MB file
|
// Create child layer with 1MB file
|
||||||
|
|
||||||
@ -94,19 +94,19 @@ func testUsage(t *testing.T, snapshotter snapshots.Snapshotter) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
mounts, err := snapshotter.Prepare(ctx, "prepare-2", "layer-1")
|
mounts, err := snapshotter.Prepare(ctx, "prepare-2", "layer-1")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = mount.WithTempMount(ctx, mounts, baseApplier.Apply)
|
err = mount.WithTempMount(ctx, mounts, baseApplier.Apply)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
err = snapshotter.Commit(ctx, "layer-2", "prepare-2")
|
err = snapshotter.Commit(ctx, "layer-2", "prepare-2")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
layer2Usage, err := snapshotter.Usage(ctx, "layer-2")
|
layer2Usage, err := snapshotter.Usage(ctx, "layer-2")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Should be at least 1 MB + fs metadata
|
// Should be at least 1 MB + fs metadata
|
||||||
assert.Check(t, layer2Usage.Size >= sizeBytes,
|
assert.GreaterOrEqual(t, layer2Usage.Size, sizeBytes,
|
||||||
"%d > %d", layer2Usage.Size, sizeBytes)
|
"%d > %d", layer2Usage.Size, sizeBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,26 +114,26 @@ func TestMkfsExt4(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
// We test the default setting which is lazy init is disabled
|
// We test the default setting which is lazy init is disabled
|
||||||
err := mkfs(ctx, "ext4", "nodiscard,lazy_itable_init=0,lazy_journal_init=0", "")
|
err := mkfs(ctx, "ext4", "nodiscard,lazy_itable_init=0,lazy_journal_init=0", "")
|
||||||
assert.ErrorContains(t, err, `mkfs.ext4 couldn't initialize ""`)
|
assert.Contains(t, err.Error(), `mkfs.ext4 couldn't initialize ""`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMkfsExt4NonDefault(t *testing.T) {
|
func TestMkfsExt4NonDefault(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
// We test a non default setting where we enable lazy init for ext4
|
// We test a non default setting where we enable lazy init for ext4
|
||||||
err := mkfs(ctx, "ext4", "nodiscard", "")
|
err := mkfs(ctx, "ext4", "nodiscard", "")
|
||||||
assert.ErrorContains(t, err, `mkfs.ext4 couldn't initialize ""`)
|
assert.Contains(t, err.Error(), `mkfs.ext4 couldn't initialize ""`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMkfsXfs(t *testing.T) {
|
func TestMkfsXfs(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := mkfs(ctx, "xfs", "", "")
|
err := mkfs(ctx, "xfs", "", "")
|
||||||
assert.ErrorContains(t, err, `mkfs.xfs couldn't initialize ""`)
|
assert.Contains(t, err.Error(), `mkfs.xfs couldn't initialize ""`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMkfsXfsNonDefault(t *testing.T) {
|
func TestMkfsXfsNonDefault(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := mkfs(ctx, "xfs", "noquota", "")
|
err := mkfs(ctx, "xfs", "noquota", "")
|
||||||
assert.ErrorContains(t, err, `mkfs.xfs couldn't initialize ""`)
|
assert.Contains(t, err.Error(), `mkfs.xfs couldn't initialize ""`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultipleXfsMounts(t *testing.T) {
|
func TestMultipleXfsMounts(t *testing.T) {
|
||||||
@ -152,7 +152,7 @@ func TestMultipleXfsMounts(t *testing.T) {
|
|||||||
FileSystemType: "xfs",
|
FileSystemType: "xfs",
|
||||||
}
|
}
|
||||||
snapshotter, closer, err := createSnapshotter(ctx, t, config)
|
snapshotter, closer, err := createSnapshotter(ctx, t, config)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
defer closer()
|
defer closer()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -162,27 +162,27 @@ func TestMultipleXfsMounts(t *testing.T) {
|
|||||||
|
|
||||||
// Create base layer
|
// Create base layer
|
||||||
mounts, err := snapshotter.Prepare(ctx, "prepare-1", "")
|
mounts, err := snapshotter.Prepare(ctx, "prepare-1", "")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
root1 := t.TempDir()
|
root1 := t.TempDir()
|
||||||
defer func() {
|
defer func() {
|
||||||
mount.UnmountAll(root1, 0)
|
mount.UnmountAll(root1, 0)
|
||||||
}()
|
}()
|
||||||
err = mount.All(mounts, root1)
|
err = mount.All(mounts, root1)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
baseApplier.Apply(root1)
|
baseApplier.Apply(root1)
|
||||||
snapshotter.Commit(ctx, "layer-1", "prepare-1")
|
snapshotter.Commit(ctx, "layer-1", "prepare-1")
|
||||||
|
|
||||||
// Create one child layer
|
// Create one child layer
|
||||||
mounts, err = snapshotter.Prepare(ctx, "prepare-2", "layer-1")
|
mounts, err = snapshotter.Prepare(ctx, "prepare-2", "layer-1")
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
root2 := t.TempDir()
|
root2 := t.TempDir()
|
||||||
defer func() {
|
defer func() {
|
||||||
mount.UnmountAll(root2, 0)
|
mount.UnmountAll(root2, 0)
|
||||||
}()
|
}()
|
||||||
err = mount.All(mounts, root2)
|
err = mount.All(mounts, root2)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSnapshotter(ctx context.Context, t *testing.T, config *Config) (snapshots.Snapshotter, func() error, error) {
|
func createSnapshotter(ctx context.Context, t *testing.T, config *Config) (snapshots.Snapshotter, func() error, error) {
|
||||||
@ -191,7 +191,7 @@ func createSnapshotter(ctx context.Context, t *testing.T, config *Config) (snaps
|
|||||||
_, loopMetaDevice := createLoopbackDevice(t, config.RootPath)
|
_, loopMetaDevice := createLoopbackDevice(t, config.RootPath)
|
||||||
|
|
||||||
err := dmsetup.CreatePool(config.PoolName, loopDataDevice, loopMetaDevice, 64*1024/dmsetup.SectorSize)
|
err := dmsetup.CreatePool(config.PoolName, loopDataDevice, loopMetaDevice, 64*1024/dmsetup.SectorSize)
|
||||||
assert.NilError(t, err, "failed to create pool %q", config.PoolName)
|
assert.Nil(t, err, "failed to create pool %q", config.PoolName)
|
||||||
|
|
||||||
snap, err := NewSnapshotter(ctx, config)
|
snap, err := NewSnapshotter(ctx, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -26,8 +26,7 @@ import (
|
|||||||
"github.com/containerd/containerd/errdefs"
|
"github.com/containerd/containerd/errdefs"
|
||||||
"github.com/containerd/containerd/snapshots"
|
"github.com/containerd/containerd/snapshots"
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type testFunc func(context.Context, *testing.T, *MetaStore)
|
type testFunc func(context.Context, *testing.T, *MetaStore)
|
||||||
@ -214,29 +213,29 @@ var baseInfo = map[string]snapshots.Info{
|
|||||||
|
|
||||||
func assertNotExist(t *testing.T, err error) {
|
func assertNotExist(t *testing.T, err error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
assert.Assert(t, errdefs.IsNotFound(err), "got %+v", err)
|
assert.True(t, errdefs.IsNotFound(err), "got %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertNotActive(t *testing.T, err error) {
|
func assertNotActive(t *testing.T, err error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
assert.Assert(t, errdefs.IsFailedPrecondition(err), "got %+v", err)
|
assert.True(t, errdefs.IsFailedPrecondition(err), "got %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertNotCommitted(t *testing.T, err error) {
|
func assertNotCommitted(t *testing.T, err error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
assert.Assert(t, errdefs.IsInvalidArgument(err), "got %+v", err)
|
assert.True(t, errdefs.IsInvalidArgument(err), "got %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertExist(t *testing.T, err error) {
|
func assertExist(t *testing.T, err error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
assert.Assert(t, errdefs.IsAlreadyExists(err), "got %+v", err)
|
assert.True(t, errdefs.IsAlreadyExists(err), "got %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetInfo(ctx context.Context, t *testing.T, _ *MetaStore) {
|
func testGetInfo(ctx context.Context, t *testing.T, _ *MetaStore) {
|
||||||
for key, expected := range baseInfo {
|
for key, expected := range baseInfo {
|
||||||
_, info, _, err := GetInfo(ctx, key)
|
_, info, _, err := GetInfo(ctx, key)
|
||||||
assert.NilError(t, err, "on key %v", key)
|
assert.Nil(t, err, "on key %v", key)
|
||||||
assert.Check(t, is.DeepEqual(expected, info, cmpSnapshotInfo), "on key %v", key)
|
assert.Truef(t, cmp.Equal(expected, info, cmpSnapshotInfo), "on key %v", key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,8 +275,8 @@ func testWalk(ctx context.Context, t *testing.T, _ *MetaStore) {
|
|||||||
found[info.Name] = info
|
found[info.Name] = info
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Assert(t, is.DeepEqual(baseInfo, found, cmpSnapshotInfo))
|
assert.True(t, cmp.Equal(baseInfo, found, cmpSnapshotInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetSnapshot(ctx context.Context, t *testing.T, ms *MetaStore) {
|
func testGetSnapshot(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
@ -326,8 +325,8 @@ func testGetSnapshot(ctx context.Context, t *testing.T, ms *MetaStore) {
|
|||||||
test := func(ctx context.Context, t *testing.T, ms *MetaStore) {
|
test := func(ctx context.Context, t *testing.T, ms *MetaStore) {
|
||||||
for key, expected := range snapshotMap {
|
for key, expected := range snapshotMap {
|
||||||
s, err := GetSnapshot(ctx, key)
|
s, err := GetSnapshot(ctx, key)
|
||||||
assert.NilError(t, err, "failed to get snapshot %s", key)
|
assert.Nil(t, err, "failed to get snapshot %s", key)
|
||||||
assert.Check(t, is.DeepEqual(expected, s), "on key %s", key)
|
assert.Equalf(t, expected, s, "on key %s", key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +35,7 @@ import (
|
|||||||
"github.com/containerd/containerd/pkg/testutil"
|
"github.com/containerd/containerd/pkg/testutil"
|
||||||
"github.com/containerd/containerd/snapshots"
|
"github.com/containerd/containerd/snapshots"
|
||||||
"github.com/containerd/continuity/fs/fstest"
|
"github.com/containerd/continuity/fs/fstest"
|
||||||
"gotest.tools/v3/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SnapshotterFunc is used in SnapshotterSuite
|
// SnapshotterFunc is used in SnapshotterSuite
|
||||||
@ -173,8 +172,8 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
|
|||||||
t.Fatalf("failure reason: %+v", err)
|
t.Fatalf("failure reason: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Check(t, is.Equal("", si.Parent))
|
assert.Empty(t, si.Parent)
|
||||||
assert.Check(t, is.Equal(snapshots.KindCommitted, si.Kind))
|
assert.Equal(t, snapshots.KindCommitted, si.Kind)
|
||||||
|
|
||||||
_, err = snapshotter.Stat(ctx, preparing)
|
_, err = snapshotter.Stat(ctx, preparing)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -209,8 +208,8 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Check(t, is.Equal(committed, ni.Parent))
|
assert.Equal(t, committed, ni.Parent)
|
||||||
assert.Check(t, is.Equal(snapshots.KindActive, ni.Kind))
|
assert.Equal(t, snapshots.KindActive, ni.Kind)
|
||||||
|
|
||||||
nextCommitted := filepath.Join(work, "committed-next")
|
nextCommitted := filepath.Join(work, "committed-next")
|
||||||
if err := snapshotter.Commit(ctx, nextCommitted, next, opt); err != nil {
|
if err := snapshotter.Commit(ctx, nextCommitted, next, opt); err != nil {
|
||||||
@ -222,8 +221,8 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
|
|||||||
t.Fatalf("failure reason: %+v", err)
|
t.Fatalf("failure reason: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Check(t, is.Equal(committed, si2.Parent))
|
assert.Equal(t, committed, si2.Parent)
|
||||||
assert.Check(t, is.Equal(snapshots.KindCommitted, si2.Kind))
|
assert.Equal(t, snapshots.KindCommitted, si2.Kind)
|
||||||
|
|
||||||
_, err = snapshotter.Stat(ctx, next)
|
_, err = snapshotter.Stat(ctx, next)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -235,7 +234,7 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
|
|||||||
si2.Name: si2,
|
si2.Name: si2,
|
||||||
}
|
}
|
||||||
walked := map[string]snapshots.Info{} // walk is not ordered
|
walked := map[string]snapshots.Info{} // walk is not ordered
|
||||||
assert.NilError(t, snapshotter.Walk(ctx, func(ctx context.Context, si snapshots.Info) error {
|
assert.Nil(t, snapshotter.Walk(ctx, func(ctx context.Context, si snapshots.Info) error {
|
||||||
walked[si.Name] = si
|
walked[si.Name] = si
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
@ -246,7 +245,7 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
|
|||||||
t.Errorf("Missing stat for %v", ek)
|
t.Errorf("Missing stat for %v", ek)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
assert.Check(t, is.DeepEqual(ev, av))
|
assert.Equal(t, ev, av)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextnext := filepath.Join(work, "nextnextlayer")
|
nextnext := filepath.Join(work, "nextnextlayer")
|
||||||
@ -269,10 +268,16 @@ func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapsh
|
|||||||
}
|
}
|
||||||
|
|
||||||
testutil.Unmount(t, nextnext)
|
testutil.Unmount(t, nextnext)
|
||||||
assert.NilError(t, snapshotter.Remove(ctx, nextnext))
|
assert.Nil(t, snapshotter.Remove(ctx, nextnext))
|
||||||
assert.Assert(t, is.ErrorContains(snapshotter.Remove(ctx, committed), "remove"))
|
|
||||||
assert.NilError(t, snapshotter.Remove(ctx, nextCommitted))
|
err = snapshotter.Remove(ctx, committed)
|
||||||
assert.NilError(t, snapshotter.Remove(ctx, committed))
|
assert.NotNil(t, err)
|
||||||
|
if err != nil {
|
||||||
|
assert.Contains(t, err.Error(), "remove")
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Nil(t, snapshotter.Remove(ctx, nextCommitted))
|
||||||
|
assert.Nil(t, snapshotter.Remove(ctx, committed))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a New Layer on top of base layer with Prepare, Stat on new layer, should return Active layer.
|
// Create a New Layer on top of base layer with Prepare, Stat on new layer, should return Active layer.
|
||||||
@ -304,9 +309,9 @@ func checkSnapshotterStatActive(ctx context.Context, t *testing.T, snapshotter s
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
assert.Check(t, is.Equal(si.Name, preparing))
|
assert.Equal(t, si.Name, preparing)
|
||||||
assert.Check(t, is.Equal(snapshots.KindActive, si.Kind))
|
assert.Equal(t, snapshots.KindActive, si.Kind)
|
||||||
assert.Check(t, is.Equal("", si.Parent))
|
assert.Equal(t, "", si.Parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit a New Layer on top of base layer with Prepare & Commit , Stat on new layer, should return Committed layer.
|
// Commit a New Layer on top of base layer with Prepare & Commit , Stat on new layer, should return Committed layer.
|
||||||
@ -343,9 +348,9 @@ func checkSnapshotterStatCommitted(ctx context.Context, t *testing.T, snapshotte
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
assert.Check(t, is.Equal(si.Name, committed))
|
assert.Equal(t, si.Name, committed)
|
||||||
assert.Check(t, is.Equal(snapshots.KindCommitted, si.Kind))
|
assert.Equal(t, snapshots.KindCommitted, si.Kind)
|
||||||
assert.Check(t, is.Equal("", si.Parent))
|
assert.Equal(t, "", si.Parent)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -418,9 +423,9 @@ func checkSnapshotterTransitivity(ctx context.Context, t *testing.T, snapshotter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test the transivity
|
// Test the transivity
|
||||||
assert.Check(t, is.Equal("", siA.Parent))
|
assert.Equal(t, "", siA.Parent)
|
||||||
assert.Check(t, is.Equal(snapA, siB.Parent))
|
assert.Equal(t, snapA, siB.Parent)
|
||||||
assert.Check(t, is.Equal("", siParentB.Parent))
|
assert.Equal(t, "", siParentB.Parent)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,7 +455,7 @@ func checkSnapshotterPrepareView(ctx context.Context, t *testing.T, snapshotter
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = snapshotter.View(ctx, newLayer, snapA, opt)
|
_, err = snapshotter.View(ctx, newLayer, snapA, opt)
|
||||||
assert.Check(t, err != nil)
|
assert.True(t, err != nil)
|
||||||
|
|
||||||
// Two Prepare with same key
|
// Two Prepare with same key
|
||||||
prepLayer := filepath.Join(work, "prepLayer")
|
prepLayer := filepath.Join(work, "prepLayer")
|
||||||
@ -464,7 +469,7 @@ func checkSnapshotterPrepareView(ctx context.Context, t *testing.T, snapshotter
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = snapshotter.Prepare(ctx, prepLayer, snapA, opt)
|
_, err = snapshotter.Prepare(ctx, prepLayer, snapA, opt)
|
||||||
assert.Check(t, err != nil)
|
assert.True(t, err != nil)
|
||||||
|
|
||||||
// Two View with same key
|
// Two View with same key
|
||||||
viewLayer := filepath.Join(work, "viewLayer")
|
viewLayer := filepath.Join(work, "viewLayer")
|
||||||
@ -478,7 +483,7 @@ func checkSnapshotterPrepareView(ctx context.Context, t *testing.T, snapshotter
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = snapshotter.View(ctx, viewLayer, snapA, opt)
|
_, err = snapshotter.View(ctx, viewLayer, snapA, opt)
|
||||||
assert.Check(t, err != nil)
|
assert.True(t, err != nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,8 +814,8 @@ func checkSnapshotterViewReadonly(ctx context.Context, t *testing.T, snapshotter
|
|||||||
t.Fatalf("write to %q should fail (EROFS) but did not fail", testfile)
|
t.Fatalf("write to %q should fail (EROFS) but did not fail", testfile)
|
||||||
}
|
}
|
||||||
testutil.Unmount(t, viewMountPoint)
|
testutil.Unmount(t, viewMountPoint)
|
||||||
assert.NilError(t, snapshotter.Remove(ctx, view))
|
assert.Nil(t, snapshotter.Remove(ctx, view))
|
||||||
assert.NilError(t, snapshotter.Remove(ctx, committed))
|
assert.Nil(t, snapshotter.Remove(ctx, committed))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move files from base layer to new location in intermediate layer.
|
// Move files from base layer to new location in intermediate layer.
|
||||||
|
@ -24,16 +24,16 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd/pkg/userns"
|
"github.com/containerd/containerd/pkg/userns"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
exec "golang.org/x/sys/execabs"
|
exec "golang.org/x/sys/execabs"
|
||||||
"gotest.tools/v3/assert"
|
|
||||||
is "gotest.tools/v3/assert/cmp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSetPositiveOomScoreAdjustment(t *testing.T) {
|
func TestSetPositiveOomScoreAdjustment(t *testing.T) {
|
||||||
// Setting a *positive* OOM score adjust does not require privileged
|
// Setting a *positive* OOM score adjust does not require privileged
|
||||||
_, adjustment, err := adjustOom(123)
|
_, adjustment, err := adjustOom(123)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Check(t, is.Equal(adjustment, 123))
|
assert.EqualValues(t, adjustment, 123)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetNegativeOomScoreAdjustmentWhenPrivileged(t *testing.T) {
|
func TestSetNegativeOomScoreAdjustmentWhenPrivileged(t *testing.T) {
|
||||||
@ -43,8 +43,8 @@ func TestSetNegativeOomScoreAdjustmentWhenPrivileged(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, adjustment, err := adjustOom(-123)
|
_, adjustment, err := adjustOom(-123)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Check(t, is.Equal(adjustment, -123))
|
assert.EqualValues(t, adjustment, -123)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetNegativeOomScoreAdjustmentWhenUnprivilegedHasNoEffect(t *testing.T) {
|
func TestSetNegativeOomScoreAdjustmentWhenUnprivilegedHasNoEffect(t *testing.T) {
|
||||||
@ -54,31 +54,33 @@ func TestSetNegativeOomScoreAdjustmentWhenUnprivilegedHasNoEffect(t *testing.T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
initial, adjustment, err := adjustOom(-123)
|
initial, adjustment, err := adjustOom(-123)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Check(t, is.Equal(adjustment, initial))
|
assert.EqualValues(t, adjustment, initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetOOMScoreBoundaries(t *testing.T) {
|
func TestSetOOMScoreBoundaries(t *testing.T) {
|
||||||
err := SetOOMScore(0, OOMScoreAdjMax+1)
|
err := SetOOMScore(0, OOMScoreAdjMax+1)
|
||||||
assert.ErrorContains(t, err, fmt.Sprintf("value out of range (%d): OOM score must be between", OOMScoreAdjMax+1))
|
require.NotNil(t, err)
|
||||||
|
assert.Contains(t, err.Error(), fmt.Sprintf("value out of range (%d): OOM score must be between", OOMScoreAdjMax+1))
|
||||||
|
|
||||||
err = SetOOMScore(0, OOMScoreAdjMin-1)
|
err = SetOOMScore(0, OOMScoreAdjMin-1)
|
||||||
assert.ErrorContains(t, err, fmt.Sprintf("value out of range (%d): OOM score must be between", OOMScoreAdjMin-1))
|
require.NotNil(t, err)
|
||||||
|
assert.Contains(t, err.Error(), fmt.Sprintf("value out of range (%d): OOM score must be between", OOMScoreAdjMin-1))
|
||||||
|
|
||||||
_, adjustment, err := adjustOom(OOMScoreAdjMax)
|
_, adjustment, err := adjustOom(OOMScoreAdjMax)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Check(t, is.Equal(adjustment, OOMScoreAdjMax))
|
assert.EqualValues(t, adjustment, OOMScoreAdjMax)
|
||||||
|
|
||||||
score, err := GetOOMScoreAdj(os.Getpid())
|
score, err := GetOOMScoreAdj(os.Getpid())
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
if score == OOMScoreAdjMin {
|
if score == OOMScoreAdjMin {
|
||||||
// We won't be able to set the score lower than the parent process. This
|
// We won't be able to set the score lower than the parent process. This
|
||||||
// could also be tested if the parent process does not have a oom-score-adj
|
// could also be tested if the parent process does not have a oom-score-adj
|
||||||
// set, but GetOOMScoreAdj does not distinguish between "not set" and
|
// set, but GetOOMScoreAdj does not distinguish between "not set" and
|
||||||
// "score is set, but zero".
|
// "score is set, but zero".
|
||||||
_, adjustment, err = adjustOom(OOMScoreAdjMin)
|
_, adjustment, err = adjustOom(OOMScoreAdjMin)
|
||||||
assert.NilError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Check(t, is.Equal(adjustment, OOMScoreAdjMin))
|
assert.EqualValues(t, adjustment, OOMScoreAdjMin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
148
vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go
generated
vendored
148
vendor/github.com/google/go-cmp/cmp/cmpopts/equate.go
generated
vendored
@ -1,148 +0,0 @@
|
|||||||
// Copyright 2017, The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package cmpopts provides common options for the cmp package.
|
|
||||||
package cmpopts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"reflect"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func equateAlways(_, _ interface{}) bool { return true }
|
|
||||||
|
|
||||||
// EquateEmpty returns a Comparer option that determines all maps and slices
|
|
||||||
// with a length of zero to be equal, regardless of whether they are nil.
|
|
||||||
//
|
|
||||||
// EquateEmpty can be used in conjunction with SortSlices and SortMaps.
|
|
||||||
func EquateEmpty() cmp.Option {
|
|
||||||
return cmp.FilterValues(isEmpty, cmp.Comparer(equateAlways))
|
|
||||||
}
|
|
||||||
|
|
||||||
func isEmpty(x, y interface{}) bool {
|
|
||||||
vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
|
|
||||||
return (x != nil && y != nil && vx.Type() == vy.Type()) &&
|
|
||||||
(vx.Kind() == reflect.Slice || vx.Kind() == reflect.Map) &&
|
|
||||||
(vx.Len() == 0 && vy.Len() == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EquateApprox returns a Comparer option that determines float32 or float64
|
|
||||||
// values to be equal if they are within a relative fraction or absolute margin.
|
|
||||||
// This option is not used when either x or y is NaN or infinite.
|
|
||||||
//
|
|
||||||
// The fraction determines that the difference of two values must be within the
|
|
||||||
// smaller fraction of the two values, while the margin determines that the two
|
|
||||||
// values must be within some absolute margin.
|
|
||||||
// To express only a fraction or only a margin, use 0 for the other parameter.
|
|
||||||
// The fraction and margin must be non-negative.
|
|
||||||
//
|
|
||||||
// The mathematical expression used is equivalent to:
|
|
||||||
// |x-y| ≤ max(fraction*min(|x|, |y|), margin)
|
|
||||||
//
|
|
||||||
// EquateApprox can be used in conjunction with EquateNaNs.
|
|
||||||
func EquateApprox(fraction, margin float64) cmp.Option {
|
|
||||||
if margin < 0 || fraction < 0 || math.IsNaN(margin) || math.IsNaN(fraction) {
|
|
||||||
panic("margin or fraction must be a non-negative number")
|
|
||||||
}
|
|
||||||
a := approximator{fraction, margin}
|
|
||||||
return cmp.Options{
|
|
||||||
cmp.FilterValues(areRealF64s, cmp.Comparer(a.compareF64)),
|
|
||||||
cmp.FilterValues(areRealF32s, cmp.Comparer(a.compareF32)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type approximator struct{ frac, marg float64 }
|
|
||||||
|
|
||||||
func areRealF64s(x, y float64) bool {
|
|
||||||
return !math.IsNaN(x) && !math.IsNaN(y) && !math.IsInf(x, 0) && !math.IsInf(y, 0)
|
|
||||||
}
|
|
||||||
func areRealF32s(x, y float32) bool {
|
|
||||||
return areRealF64s(float64(x), float64(y))
|
|
||||||
}
|
|
||||||
func (a approximator) compareF64(x, y float64) bool {
|
|
||||||
relMarg := a.frac * math.Min(math.Abs(x), math.Abs(y))
|
|
||||||
return math.Abs(x-y) <= math.Max(a.marg, relMarg)
|
|
||||||
}
|
|
||||||
func (a approximator) compareF32(x, y float32) bool {
|
|
||||||
return a.compareF64(float64(x), float64(y))
|
|
||||||
}
|
|
||||||
|
|
||||||
// EquateNaNs returns a Comparer option that determines float32 and float64
|
|
||||||
// NaN values to be equal.
|
|
||||||
//
|
|
||||||
// EquateNaNs can be used in conjunction with EquateApprox.
|
|
||||||
func EquateNaNs() cmp.Option {
|
|
||||||
return cmp.Options{
|
|
||||||
cmp.FilterValues(areNaNsF64s, cmp.Comparer(equateAlways)),
|
|
||||||
cmp.FilterValues(areNaNsF32s, cmp.Comparer(equateAlways)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func areNaNsF64s(x, y float64) bool {
|
|
||||||
return math.IsNaN(x) && math.IsNaN(y)
|
|
||||||
}
|
|
||||||
func areNaNsF32s(x, y float32) bool {
|
|
||||||
return areNaNsF64s(float64(x), float64(y))
|
|
||||||
}
|
|
||||||
|
|
||||||
// EquateApproxTime returns a Comparer option that determines two non-zero
|
|
||||||
// time.Time values to be equal if they are within some margin of one another.
|
|
||||||
// If both times have a monotonic clock reading, then the monotonic time
|
|
||||||
// difference will be used. The margin must be non-negative.
|
|
||||||
func EquateApproxTime(margin time.Duration) cmp.Option {
|
|
||||||
if margin < 0 {
|
|
||||||
panic("margin must be a non-negative number")
|
|
||||||
}
|
|
||||||
a := timeApproximator{margin}
|
|
||||||
return cmp.FilterValues(areNonZeroTimes, cmp.Comparer(a.compare))
|
|
||||||
}
|
|
||||||
|
|
||||||
func areNonZeroTimes(x, y time.Time) bool {
|
|
||||||
return !x.IsZero() && !y.IsZero()
|
|
||||||
}
|
|
||||||
|
|
||||||
type timeApproximator struct {
|
|
||||||
margin time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a timeApproximator) compare(x, y time.Time) bool {
|
|
||||||
// Avoid subtracting times to avoid overflow when the
|
|
||||||
// difference is larger than the largest representible duration.
|
|
||||||
if x.After(y) {
|
|
||||||
// Ensure x is always before y
|
|
||||||
x, y = y, x
|
|
||||||
}
|
|
||||||
// We're within the margin if x+margin >= y.
|
|
||||||
// Note: time.Time doesn't have AfterOrEqual method hence the negation.
|
|
||||||
return !x.Add(a.margin).Before(y)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnyError is an error that matches any non-nil error.
|
|
||||||
var AnyError anyError
|
|
||||||
|
|
||||||
type anyError struct{}
|
|
||||||
|
|
||||||
func (anyError) Error() string { return "any error" }
|
|
||||||
func (anyError) Is(err error) bool { return err != nil }
|
|
||||||
|
|
||||||
// EquateErrors returns a Comparer option that determines errors to be equal
|
|
||||||
// if errors.Is reports them to match. The AnyError error can be used to
|
|
||||||
// match any non-nil error.
|
|
||||||
func EquateErrors() cmp.Option {
|
|
||||||
return cmp.FilterValues(areConcreteErrors, cmp.Comparer(compareErrors))
|
|
||||||
}
|
|
||||||
|
|
||||||
// areConcreteErrors reports whether x and y are types that implement error.
|
|
||||||
// The input types are deliberately of the interface{} type rather than the
|
|
||||||
// error type so that we can handle situations where the current type is an
|
|
||||||
// interface{}, but the underlying concrete types both happen to implement
|
|
||||||
// the error interface.
|
|
||||||
func areConcreteErrors(x, y interface{}) bool {
|
|
||||||
_, ok1 := x.(error)
|
|
||||||
_, ok2 := y.(error)
|
|
||||||
return ok1 && ok2
|
|
||||||
}
|
|
15
vendor/github.com/google/go-cmp/cmp/cmpopts/errors_go113.go
generated
vendored
15
vendor/github.com/google/go-cmp/cmp/cmpopts/errors_go113.go
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
// Copyright 2021, The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build go1.13
|
|
||||||
|
|
||||||
package cmpopts
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func compareErrors(x, y interface{}) bool {
|
|
||||||
xe := x.(error)
|
|
||||||
ye := y.(error)
|
|
||||||
return errors.Is(xe, ye) || errors.Is(ye, xe)
|
|
||||||
}
|
|
18
vendor/github.com/google/go-cmp/cmp/cmpopts/errors_xerrors.go
generated
vendored
18
vendor/github.com/google/go-cmp/cmp/cmpopts/errors_xerrors.go
generated
vendored
@ -1,18 +0,0 @@
|
|||||||
// Copyright 2021, The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build !go1.13
|
|
||||||
|
|
||||||
// TODO(≥go1.13): For support on <go1.13, we use the xerrors package.
|
|
||||||
// Drop this file when we no longer support older Go versions.
|
|
||||||
|
|
||||||
package cmpopts
|
|
||||||
|
|
||||||
import "golang.org/x/xerrors"
|
|
||||||
|
|
||||||
func compareErrors(x, y interface{}) bool {
|
|
||||||
xe := x.(error)
|
|
||||||
ye := y.(error)
|
|
||||||
return xerrors.Is(xe, ye) || xerrors.Is(ye, xe)
|
|
||||||
}
|
|
206
vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go
generated
vendored
206
vendor/github.com/google/go-cmp/cmp/cmpopts/ignore.go
generated
vendored
@ -1,206 +0,0 @@
|
|||||||
// Copyright 2017, The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package cmpopts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"github.com/google/go-cmp/cmp/internal/function"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IgnoreFields returns an Option that ignores fields of the
|
|
||||||
// given names on a single struct type. It respects the names of exported fields
|
|
||||||
// that are forwarded due to struct embedding.
|
|
||||||
// The struct type is specified by passing in a value of that type.
|
|
||||||
//
|
|
||||||
// The name may be a dot-delimited string (e.g., "Foo.Bar") to ignore a
|
|
||||||
// specific sub-field that is embedded or nested within the parent struct.
|
|
||||||
func IgnoreFields(typ interface{}, names ...string) cmp.Option {
|
|
||||||
sf := newStructFilter(typ, names...)
|
|
||||||
return cmp.FilterPath(sf.filter, cmp.Ignore())
|
|
||||||
}
|
|
||||||
|
|
||||||
// IgnoreTypes returns an Option that ignores all values assignable to
|
|
||||||
// certain types, which are specified by passing in a value of each type.
|
|
||||||
func IgnoreTypes(typs ...interface{}) cmp.Option {
|
|
||||||
tf := newTypeFilter(typs...)
|
|
||||||
return cmp.FilterPath(tf.filter, cmp.Ignore())
|
|
||||||
}
|
|
||||||
|
|
||||||
type typeFilter []reflect.Type
|
|
||||||
|
|
||||||
func newTypeFilter(typs ...interface{}) (tf typeFilter) {
|
|
||||||
for _, typ := range typs {
|
|
||||||
t := reflect.TypeOf(typ)
|
|
||||||
if t == nil {
|
|
||||||
// This occurs if someone tries to pass in sync.Locker(nil)
|
|
||||||
panic("cannot determine type; consider using IgnoreInterfaces")
|
|
||||||
}
|
|
||||||
tf = append(tf, t)
|
|
||||||
}
|
|
||||||
return tf
|
|
||||||
}
|
|
||||||
func (tf typeFilter) filter(p cmp.Path) bool {
|
|
||||||
if len(p) < 1 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
t := p.Last().Type()
|
|
||||||
for _, ti := range tf {
|
|
||||||
if t.AssignableTo(ti) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// IgnoreInterfaces returns an Option that ignores all values or references of
|
|
||||||
// values assignable to certain interface types. These interfaces are specified
|
|
||||||
// by passing in an anonymous struct with the interface types embedded in it.
|
|
||||||
// For example, to ignore sync.Locker, pass in struct{sync.Locker}{}.
|
|
||||||
func IgnoreInterfaces(ifaces interface{}) cmp.Option {
|
|
||||||
tf := newIfaceFilter(ifaces)
|
|
||||||
return cmp.FilterPath(tf.filter, cmp.Ignore())
|
|
||||||
}
|
|
||||||
|
|
||||||
type ifaceFilter []reflect.Type
|
|
||||||
|
|
||||||
func newIfaceFilter(ifaces interface{}) (tf ifaceFilter) {
|
|
||||||
t := reflect.TypeOf(ifaces)
|
|
||||||
if ifaces == nil || t.Name() != "" || t.Kind() != reflect.Struct {
|
|
||||||
panic("input must be an anonymous struct")
|
|
||||||
}
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
|
||||||
fi := t.Field(i)
|
|
||||||
switch {
|
|
||||||
case !fi.Anonymous:
|
|
||||||
panic("struct cannot have named fields")
|
|
||||||
case fi.Type.Kind() != reflect.Interface:
|
|
||||||
panic("embedded field must be an interface type")
|
|
||||||
case fi.Type.NumMethod() == 0:
|
|
||||||
// This matches everything; why would you ever want this?
|
|
||||||
panic("cannot ignore empty interface")
|
|
||||||
default:
|
|
||||||
tf = append(tf, fi.Type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tf
|
|
||||||
}
|
|
||||||
func (tf ifaceFilter) filter(p cmp.Path) bool {
|
|
||||||
if len(p) < 1 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
t := p.Last().Type()
|
|
||||||
for _, ti := range tf {
|
|
||||||
if t.AssignableTo(ti) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if t.Kind() != reflect.Ptr && reflect.PtrTo(t).AssignableTo(ti) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// IgnoreUnexported returns an Option that only ignores the immediate unexported
|
|
||||||
// fields of a struct, including anonymous fields of unexported types.
|
|
||||||
// In particular, unexported fields within the struct's exported fields
|
|
||||||
// of struct types, including anonymous fields, will not be ignored unless the
|
|
||||||
// type of the field itself is also passed to IgnoreUnexported.
|
|
||||||
//
|
|
||||||
// Avoid ignoring unexported fields of a type which you do not control (i.e. a
|
|
||||||
// type from another repository), as changes to the implementation of such types
|
|
||||||
// may change how the comparison behaves. Prefer a custom Comparer instead.
|
|
||||||
func IgnoreUnexported(typs ...interface{}) cmp.Option {
|
|
||||||
ux := newUnexportedFilter(typs...)
|
|
||||||
return cmp.FilterPath(ux.filter, cmp.Ignore())
|
|
||||||
}
|
|
||||||
|
|
||||||
type unexportedFilter struct{ m map[reflect.Type]bool }
|
|
||||||
|
|
||||||
func newUnexportedFilter(typs ...interface{}) unexportedFilter {
|
|
||||||
ux := unexportedFilter{m: make(map[reflect.Type]bool)}
|
|
||||||
for _, typ := range typs {
|
|
||||||
t := reflect.TypeOf(typ)
|
|
||||||
if t == nil || t.Kind() != reflect.Struct {
|
|
||||||
panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
|
|
||||||
}
|
|
||||||
ux.m[t] = true
|
|
||||||
}
|
|
||||||
return ux
|
|
||||||
}
|
|
||||||
func (xf unexportedFilter) filter(p cmp.Path) bool {
|
|
||||||
sf, ok := p.Index(-1).(cmp.StructField)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return xf.m[p.Index(-2).Type()] && !isExported(sf.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
// isExported reports whether the identifier is exported.
|
|
||||||
func isExported(id string) bool {
|
|
||||||
r, _ := utf8.DecodeRuneInString(id)
|
|
||||||
return unicode.IsUpper(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IgnoreSliceElements returns an Option that ignores elements of []V.
|
|
||||||
// The discard function must be of the form "func(T) bool" which is used to
|
|
||||||
// ignore slice elements of type V, where V is assignable to T.
|
|
||||||
// Elements are ignored if the function reports true.
|
|
||||||
func IgnoreSliceElements(discardFunc interface{}) cmp.Option {
|
|
||||||
vf := reflect.ValueOf(discardFunc)
|
|
||||||
if !function.IsType(vf.Type(), function.ValuePredicate) || vf.IsNil() {
|
|
||||||
panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
|
|
||||||
}
|
|
||||||
return cmp.FilterPath(func(p cmp.Path) bool {
|
|
||||||
si, ok := p.Index(-1).(cmp.SliceIndex)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !si.Type().AssignableTo(vf.Type().In(0)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
vx, vy := si.Values()
|
|
||||||
if vx.IsValid() && vf.Call([]reflect.Value{vx})[0].Bool() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if vy.IsValid() && vf.Call([]reflect.Value{vy})[0].Bool() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}, cmp.Ignore())
|
|
||||||
}
|
|
||||||
|
|
||||||
// IgnoreMapEntries returns an Option that ignores entries of map[K]V.
|
|
||||||
// The discard function must be of the form "func(T, R) bool" which is used to
|
|
||||||
// ignore map entries of type K and V, where K and V are assignable to T and R.
|
|
||||||
// Entries are ignored if the function reports true.
|
|
||||||
func IgnoreMapEntries(discardFunc interface{}) cmp.Option {
|
|
||||||
vf := reflect.ValueOf(discardFunc)
|
|
||||||
if !function.IsType(vf.Type(), function.KeyValuePredicate) || vf.IsNil() {
|
|
||||||
panic(fmt.Sprintf("invalid discard function: %T", discardFunc))
|
|
||||||
}
|
|
||||||
return cmp.FilterPath(func(p cmp.Path) bool {
|
|
||||||
mi, ok := p.Index(-1).(cmp.MapIndex)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !mi.Key().Type().AssignableTo(vf.Type().In(0)) || !mi.Type().AssignableTo(vf.Type().In(1)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
k := mi.Key()
|
|
||||||
vx, vy := mi.Values()
|
|
||||||
if vx.IsValid() && vf.Call([]reflect.Value{k, vx})[0].Bool() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if vy.IsValid() && vf.Call([]reflect.Value{k, vy})[0].Bool() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}, cmp.Ignore())
|
|
||||||
}
|
|
147
vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go
generated
vendored
147
vendor/github.com/google/go-cmp/cmp/cmpopts/sort.go
generated
vendored
@ -1,147 +0,0 @@
|
|||||||
// Copyright 2017, The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package cmpopts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"github.com/google/go-cmp/cmp/internal/function"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SortSlices returns a Transformer option that sorts all []V.
|
|
||||||
// The less function must be of the form "func(T, T) bool" which is used to
|
|
||||||
// sort any slice with element type V that is assignable to T.
|
|
||||||
//
|
|
||||||
// The less function must be:
|
|
||||||
// • Deterministic: less(x, y) == less(x, y)
|
|
||||||
// • Irreflexive: !less(x, x)
|
|
||||||
// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
|
|
||||||
//
|
|
||||||
// The less function does not have to be "total". That is, if !less(x, y) and
|
|
||||||
// !less(y, x) for two elements x and y, their relative order is maintained.
|
|
||||||
//
|
|
||||||
// SortSlices can be used in conjunction with EquateEmpty.
|
|
||||||
func SortSlices(lessFunc interface{}) cmp.Option {
|
|
||||||
vf := reflect.ValueOf(lessFunc)
|
|
||||||
if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
|
|
||||||
panic(fmt.Sprintf("invalid less function: %T", lessFunc))
|
|
||||||
}
|
|
||||||
ss := sliceSorter{vf.Type().In(0), vf}
|
|
||||||
return cmp.FilterValues(ss.filter, cmp.Transformer("cmpopts.SortSlices", ss.sort))
|
|
||||||
}
|
|
||||||
|
|
||||||
type sliceSorter struct {
|
|
||||||
in reflect.Type // T
|
|
||||||
fnc reflect.Value // func(T, T) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss sliceSorter) filter(x, y interface{}) bool {
|
|
||||||
vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
|
|
||||||
if !(x != nil && y != nil && vx.Type() == vy.Type()) ||
|
|
||||||
!(vx.Kind() == reflect.Slice && vx.Type().Elem().AssignableTo(ss.in)) ||
|
|
||||||
(vx.Len() <= 1 && vy.Len() <= 1) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Check whether the slices are already sorted to avoid an infinite
|
|
||||||
// recursion cycle applying the same transform to itself.
|
|
||||||
ok1 := sort.SliceIsSorted(x, func(i, j int) bool { return ss.less(vx, i, j) })
|
|
||||||
ok2 := sort.SliceIsSorted(y, func(i, j int) bool { return ss.less(vy, i, j) })
|
|
||||||
return !ok1 || !ok2
|
|
||||||
}
|
|
||||||
func (ss sliceSorter) sort(x interface{}) interface{} {
|
|
||||||
src := reflect.ValueOf(x)
|
|
||||||
dst := reflect.MakeSlice(src.Type(), src.Len(), src.Len())
|
|
||||||
for i := 0; i < src.Len(); i++ {
|
|
||||||
dst.Index(i).Set(src.Index(i))
|
|
||||||
}
|
|
||||||
sort.SliceStable(dst.Interface(), func(i, j int) bool { return ss.less(dst, i, j) })
|
|
||||||
ss.checkSort(dst)
|
|
||||||
return dst.Interface()
|
|
||||||
}
|
|
||||||
func (ss sliceSorter) checkSort(v reflect.Value) {
|
|
||||||
start := -1 // Start of a sequence of equal elements.
|
|
||||||
for i := 1; i < v.Len(); i++ {
|
|
||||||
if ss.less(v, i-1, i) {
|
|
||||||
// Check that first and last elements in v[start:i] are equal.
|
|
||||||
if start >= 0 && (ss.less(v, start, i-1) || ss.less(v, i-1, start)) {
|
|
||||||
panic(fmt.Sprintf("incomparable values detected: want equal elements: %v", v.Slice(start, i)))
|
|
||||||
}
|
|
||||||
start = -1
|
|
||||||
} else if start == -1 {
|
|
||||||
start = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (ss sliceSorter) less(v reflect.Value, i, j int) bool {
|
|
||||||
vx, vy := v.Index(i), v.Index(j)
|
|
||||||
return ss.fnc.Call([]reflect.Value{vx, vy})[0].Bool()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SortMaps returns a Transformer option that flattens map[K]V types to be a
|
|
||||||
// sorted []struct{K, V}. The less function must be of the form
|
|
||||||
// "func(T, T) bool" which is used to sort any map with key K that is
|
|
||||||
// assignable to T.
|
|
||||||
//
|
|
||||||
// Flattening the map into a slice has the property that cmp.Equal is able to
|
|
||||||
// use Comparers on K or the K.Equal method if it exists.
|
|
||||||
//
|
|
||||||
// The less function must be:
|
|
||||||
// • Deterministic: less(x, y) == less(x, y)
|
|
||||||
// • Irreflexive: !less(x, x)
|
|
||||||
// • Transitive: if !less(x, y) and !less(y, z), then !less(x, z)
|
|
||||||
// • Total: if x != y, then either less(x, y) or less(y, x)
|
|
||||||
//
|
|
||||||
// SortMaps can be used in conjunction with EquateEmpty.
|
|
||||||
func SortMaps(lessFunc interface{}) cmp.Option {
|
|
||||||
vf := reflect.ValueOf(lessFunc)
|
|
||||||
if !function.IsType(vf.Type(), function.Less) || vf.IsNil() {
|
|
||||||
panic(fmt.Sprintf("invalid less function: %T", lessFunc))
|
|
||||||
}
|
|
||||||
ms := mapSorter{vf.Type().In(0), vf}
|
|
||||||
return cmp.FilterValues(ms.filter, cmp.Transformer("cmpopts.SortMaps", ms.sort))
|
|
||||||
}
|
|
||||||
|
|
||||||
type mapSorter struct {
|
|
||||||
in reflect.Type // T
|
|
||||||
fnc reflect.Value // func(T, T) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms mapSorter) filter(x, y interface{}) bool {
|
|
||||||
vx, vy := reflect.ValueOf(x), reflect.ValueOf(y)
|
|
||||||
return (x != nil && y != nil && vx.Type() == vy.Type()) &&
|
|
||||||
(vx.Kind() == reflect.Map && vx.Type().Key().AssignableTo(ms.in)) &&
|
|
||||||
(vx.Len() != 0 || vy.Len() != 0)
|
|
||||||
}
|
|
||||||
func (ms mapSorter) sort(x interface{}) interface{} {
|
|
||||||
src := reflect.ValueOf(x)
|
|
||||||
outType := reflect.StructOf([]reflect.StructField{
|
|
||||||
{Name: "K", Type: src.Type().Key()},
|
|
||||||
{Name: "V", Type: src.Type().Elem()},
|
|
||||||
})
|
|
||||||
dst := reflect.MakeSlice(reflect.SliceOf(outType), src.Len(), src.Len())
|
|
||||||
for i, k := range src.MapKeys() {
|
|
||||||
v := reflect.New(outType).Elem()
|
|
||||||
v.Field(0).Set(k)
|
|
||||||
v.Field(1).Set(src.MapIndex(k))
|
|
||||||
dst.Index(i).Set(v)
|
|
||||||
}
|
|
||||||
sort.Slice(dst.Interface(), func(i, j int) bool { return ms.less(dst, i, j) })
|
|
||||||
ms.checkSort(dst)
|
|
||||||
return dst.Interface()
|
|
||||||
}
|
|
||||||
func (ms mapSorter) checkSort(v reflect.Value) {
|
|
||||||
for i := 1; i < v.Len(); i++ {
|
|
||||||
if !ms.less(v, i-1, i) {
|
|
||||||
panic(fmt.Sprintf("partial order detected: want %v < %v", v.Index(i-1), v.Index(i)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (ms mapSorter) less(v reflect.Value, i, j int) bool {
|
|
||||||
vx, vy := v.Index(i).Field(0), v.Index(j).Field(0)
|
|
||||||
return ms.fnc.Call([]reflect.Value{vx, vy})[0].Bool()
|
|
||||||
}
|
|
187
vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go
generated
vendored
187
vendor/github.com/google/go-cmp/cmp/cmpopts/struct_filter.go
generated
vendored
@ -1,187 +0,0 @@
|
|||||||
// Copyright 2017, The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package cmpopts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// filterField returns a new Option where opt is only evaluated on paths that
|
|
||||||
// include a specific exported field on a single struct type.
|
|
||||||
// The struct type is specified by passing in a value of that type.
|
|
||||||
//
|
|
||||||
// The name may be a dot-delimited string (e.g., "Foo.Bar") to select a
|
|
||||||
// specific sub-field that is embedded or nested within the parent struct.
|
|
||||||
func filterField(typ interface{}, name string, opt cmp.Option) cmp.Option {
|
|
||||||
// TODO: This is currently unexported over concerns of how helper filters
|
|
||||||
// can be composed together easily.
|
|
||||||
// TODO: Add tests for FilterField.
|
|
||||||
|
|
||||||
sf := newStructFilter(typ, name)
|
|
||||||
return cmp.FilterPath(sf.filter, opt)
|
|
||||||
}
|
|
||||||
|
|
||||||
type structFilter struct {
|
|
||||||
t reflect.Type // The root struct type to match on
|
|
||||||
ft fieldTree // Tree of fields to match on
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStructFilter(typ interface{}, names ...string) structFilter {
|
|
||||||
// TODO: Perhaps allow * as a special identifier to allow ignoring any
|
|
||||||
// number of path steps until the next field match?
|
|
||||||
// This could be useful when a concrete struct gets transformed into
|
|
||||||
// an anonymous struct where it is not possible to specify that by type,
|
|
||||||
// but the transformer happens to provide guarantees about the names of
|
|
||||||
// the transformed fields.
|
|
||||||
|
|
||||||
t := reflect.TypeOf(typ)
|
|
||||||
if t == nil || t.Kind() != reflect.Struct {
|
|
||||||
panic(fmt.Sprintf("%T must be a non-pointer struct", typ))
|
|
||||||
}
|
|
||||||
var ft fieldTree
|
|
||||||
for _, name := range names {
|
|
||||||
cname, err := canonicalName(t, name)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("%s: %v", strings.Join(cname, "."), err))
|
|
||||||
}
|
|
||||||
ft.insert(cname)
|
|
||||||
}
|
|
||||||
return structFilter{t, ft}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sf structFilter) filter(p cmp.Path) bool {
|
|
||||||
for i, ps := range p {
|
|
||||||
if ps.Type().AssignableTo(sf.t) && sf.ft.matchPrefix(p[i+1:]) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// fieldTree represents a set of dot-separated identifiers.
|
|
||||||
//
|
|
||||||
// For example, inserting the following selectors:
|
|
||||||
// Foo
|
|
||||||
// Foo.Bar.Baz
|
|
||||||
// Foo.Buzz
|
|
||||||
// Nuka.Cola.Quantum
|
|
||||||
//
|
|
||||||
// Results in a tree of the form:
|
|
||||||
// {sub: {
|
|
||||||
// "Foo": {ok: true, sub: {
|
|
||||||
// "Bar": {sub: {
|
|
||||||
// "Baz": {ok: true},
|
|
||||||
// }},
|
|
||||||
// "Buzz": {ok: true},
|
|
||||||
// }},
|
|
||||||
// "Nuka": {sub: {
|
|
||||||
// "Cola": {sub: {
|
|
||||||
// "Quantum": {ok: true},
|
|
||||||
// }},
|
|
||||||
// }},
|
|
||||||
// }}
|
|
||||||
type fieldTree struct {
|
|
||||||
ok bool // Whether this is a specified node
|
|
||||||
sub map[string]fieldTree // The sub-tree of fields under this node
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert inserts a sequence of field accesses into the tree.
|
|
||||||
func (ft *fieldTree) insert(cname []string) {
|
|
||||||
if ft.sub == nil {
|
|
||||||
ft.sub = make(map[string]fieldTree)
|
|
||||||
}
|
|
||||||
if len(cname) == 0 {
|
|
||||||
ft.ok = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sub := ft.sub[cname[0]]
|
|
||||||
sub.insert(cname[1:])
|
|
||||||
ft.sub[cname[0]] = sub
|
|
||||||
}
|
|
||||||
|
|
||||||
// matchPrefix reports whether any selector in the fieldTree matches
|
|
||||||
// the start of path p.
|
|
||||||
func (ft fieldTree) matchPrefix(p cmp.Path) bool {
|
|
||||||
for _, ps := range p {
|
|
||||||
switch ps := ps.(type) {
|
|
||||||
case cmp.StructField:
|
|
||||||
ft = ft.sub[ps.Name()]
|
|
||||||
if ft.ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if len(ft.sub) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case cmp.Indirect:
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// canonicalName returns a list of identifiers where any struct field access
|
|
||||||
// through an embedded field is expanded to include the names of the embedded
|
|
||||||
// types themselves.
|
|
||||||
//
|
|
||||||
// For example, suppose field "Foo" is not directly in the parent struct,
|
|
||||||
// but actually from an embedded struct of type "Bar". Then, the canonical name
|
|
||||||
// of "Foo" is actually "Bar.Foo".
|
|
||||||
//
|
|
||||||
// Suppose field "Foo" is not directly in the parent struct, but actually
|
|
||||||
// a field in two different embedded structs of types "Bar" and "Baz".
|
|
||||||
// Then the selector "Foo" causes a panic since it is ambiguous which one it
|
|
||||||
// refers to. The user must specify either "Bar.Foo" or "Baz.Foo".
|
|
||||||
func canonicalName(t reflect.Type, sel string) ([]string, error) {
|
|
||||||
var name string
|
|
||||||
sel = strings.TrimPrefix(sel, ".")
|
|
||||||
if sel == "" {
|
|
||||||
return nil, fmt.Errorf("name must not be empty")
|
|
||||||
}
|
|
||||||
if i := strings.IndexByte(sel, '.'); i < 0 {
|
|
||||||
name, sel = sel, ""
|
|
||||||
} else {
|
|
||||||
name, sel = sel[:i], sel[i:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type must be a struct or pointer to struct.
|
|
||||||
if t.Kind() == reflect.Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
if t.Kind() != reflect.Struct {
|
|
||||||
return nil, fmt.Errorf("%v must be a struct", t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the canonical name for this current field name.
|
|
||||||
// If the field exists in an embedded struct, then it will be expanded.
|
|
||||||
sf, _ := t.FieldByName(name)
|
|
||||||
if !isExported(name) {
|
|
||||||
// Avoid using reflect.Type.FieldByName for unexported fields due to
|
|
||||||
// buggy behavior with regard to embeddeding and unexported fields.
|
|
||||||
// See https://golang.org/issue/4876 for details.
|
|
||||||
sf = reflect.StructField{}
|
|
||||||
for i := 0; i < t.NumField() && sf.Name == ""; i++ {
|
|
||||||
if t.Field(i).Name == name {
|
|
||||||
sf = t.Field(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if sf.Name == "" {
|
|
||||||
return []string{name}, fmt.Errorf("does not exist")
|
|
||||||
}
|
|
||||||
var ss []string
|
|
||||||
for i := range sf.Index {
|
|
||||||
ss = append(ss, t.FieldByIndex(sf.Index[:i+1]).Name)
|
|
||||||
}
|
|
||||||
if sel == "" {
|
|
||||||
return ss, nil
|
|
||||||
}
|
|
||||||
ssPost, err := canonicalName(sf.Type, sel)
|
|
||||||
return append(ss, ssPost...), err
|
|
||||||
}
|
|
35
vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go
generated
vendored
35
vendor/github.com/google/go-cmp/cmp/cmpopts/xform.go
generated
vendored
@ -1,35 +0,0 @@
|
|||||||
// Copyright 2018, The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package cmpopts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
type xformFilter struct{ xform cmp.Option }
|
|
||||||
|
|
||||||
func (xf xformFilter) filter(p cmp.Path) bool {
|
|
||||||
for _, ps := range p {
|
|
||||||
if t, ok := ps.(cmp.Transform); ok && t.Option() == xf.xform {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// AcyclicTransformer returns a Transformer with a filter applied that ensures
|
|
||||||
// that the transformer cannot be recursively applied upon its own output.
|
|
||||||
//
|
|
||||||
// An example use case is a transformer that splits a string by lines:
|
|
||||||
// AcyclicTransformer("SplitLines", func(s string) []string{
|
|
||||||
// return strings.Split(s, "\n")
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// Had this been an unfiltered Transformer instead, this would result in an
|
|
||||||
// infinite cycle converting a string to []string to [][]string and so on.
|
|
||||||
func AcyclicTransformer(name string, xformFunc interface{}) cmp.Option {
|
|
||||||
xf := xformFilter{cmp.Transformer(name, xformFunc)}
|
|
||||||
return cmp.FilterPath(xf.filter, xf.xform)
|
|
||||||
}
|
|
27
vendor/golang.org/x/xerrors/LICENSE
generated
vendored
27
vendor/golang.org/x/xerrors/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
Copyright (c) 2019 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
22
vendor/golang.org/x/xerrors/PATENTS
generated
vendored
22
vendor/golang.org/x/xerrors/PATENTS
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
2
vendor/golang.org/x/xerrors/README
generated
vendored
2
vendor/golang.org/x/xerrors/README
generated
vendored
@ -1,2 +0,0 @@
|
|||||||
This repository holds the transition packages for the new Go 1.13 error values.
|
|
||||||
See golang.org/design/29934-error-values.
|
|
193
vendor/golang.org/x/xerrors/adaptor.go
generated
vendored
193
vendor/golang.org/x/xerrors/adaptor.go
generated
vendored
@ -1,193 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FormatError calls the FormatError method of f with an errors.Printer
|
|
||||||
// configured according to s and verb, and writes the result to s.
|
|
||||||
func FormatError(f Formatter, s fmt.State, verb rune) {
|
|
||||||
// Assuming this function is only called from the Format method, and given
|
|
||||||
// that FormatError takes precedence over Format, it cannot be called from
|
|
||||||
// any package that supports errors.Formatter. It is therefore safe to
|
|
||||||
// disregard that State may be a specific printer implementation and use one
|
|
||||||
// of our choice instead.
|
|
||||||
|
|
||||||
// limitations: does not support printing error as Go struct.
|
|
||||||
|
|
||||||
var (
|
|
||||||
sep = " " // separator before next error
|
|
||||||
p = &state{State: s}
|
|
||||||
direct = true
|
|
||||||
)
|
|
||||||
|
|
||||||
var err error = f
|
|
||||||
|
|
||||||
switch verb {
|
|
||||||
// Note that this switch must match the preference order
|
|
||||||
// for ordinary string printing (%#v before %+v, and so on).
|
|
||||||
|
|
||||||
case 'v':
|
|
||||||
if s.Flag('#') {
|
|
||||||
if stringer, ok := err.(fmt.GoStringer); ok {
|
|
||||||
io.WriteString(&p.buf, stringer.GoString())
|
|
||||||
goto exit
|
|
||||||
}
|
|
||||||
// proceed as if it were %v
|
|
||||||
} else if s.Flag('+') {
|
|
||||||
p.printDetail = true
|
|
||||||
sep = "\n - "
|
|
||||||
}
|
|
||||||
case 's':
|
|
||||||
case 'q', 'x', 'X':
|
|
||||||
// Use an intermediate buffer in the rare cases that precision,
|
|
||||||
// truncation, or one of the alternative verbs (q, x, and X) are
|
|
||||||
// specified.
|
|
||||||
direct = false
|
|
||||||
|
|
||||||
default:
|
|
||||||
p.buf.WriteString("%!")
|
|
||||||
p.buf.WriteRune(verb)
|
|
||||||
p.buf.WriteByte('(')
|
|
||||||
switch {
|
|
||||||
case err != nil:
|
|
||||||
p.buf.WriteString(reflect.TypeOf(f).String())
|
|
||||||
default:
|
|
||||||
p.buf.WriteString("<nil>")
|
|
||||||
}
|
|
||||||
p.buf.WriteByte(')')
|
|
||||||
io.Copy(s, &p.buf)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
loop:
|
|
||||||
for {
|
|
||||||
switch v := err.(type) {
|
|
||||||
case Formatter:
|
|
||||||
err = v.FormatError((*printer)(p))
|
|
||||||
case fmt.Formatter:
|
|
||||||
v.Format(p, 'v')
|
|
||||||
break loop
|
|
||||||
default:
|
|
||||||
io.WriteString(&p.buf, v.Error())
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if p.needColon || !p.printDetail {
|
|
||||||
p.buf.WriteByte(':')
|
|
||||||
p.needColon = false
|
|
||||||
}
|
|
||||||
p.buf.WriteString(sep)
|
|
||||||
p.inDetail = false
|
|
||||||
p.needNewline = false
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
|
||||||
width, okW := s.Width()
|
|
||||||
prec, okP := s.Precision()
|
|
||||||
|
|
||||||
if !direct || (okW && width > 0) || okP {
|
|
||||||
// Construct format string from State s.
|
|
||||||
format := []byte{'%'}
|
|
||||||
if s.Flag('-') {
|
|
||||||
format = append(format, '-')
|
|
||||||
}
|
|
||||||
if s.Flag('+') {
|
|
||||||
format = append(format, '+')
|
|
||||||
}
|
|
||||||
if s.Flag(' ') {
|
|
||||||
format = append(format, ' ')
|
|
||||||
}
|
|
||||||
if okW {
|
|
||||||
format = strconv.AppendInt(format, int64(width), 10)
|
|
||||||
}
|
|
||||||
if okP {
|
|
||||||
format = append(format, '.')
|
|
||||||
format = strconv.AppendInt(format, int64(prec), 10)
|
|
||||||
}
|
|
||||||
format = append(format, string(verb)...)
|
|
||||||
fmt.Fprintf(s, string(format), p.buf.String())
|
|
||||||
} else {
|
|
||||||
io.Copy(s, &p.buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var detailSep = []byte("\n ")
|
|
||||||
|
|
||||||
// state tracks error printing state. It implements fmt.State.
|
|
||||||
type state struct {
|
|
||||||
fmt.State
|
|
||||||
buf bytes.Buffer
|
|
||||||
|
|
||||||
printDetail bool
|
|
||||||
inDetail bool
|
|
||||||
needColon bool
|
|
||||||
needNewline bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) Write(b []byte) (n int, err error) {
|
|
||||||
if s.printDetail {
|
|
||||||
if len(b) == 0 {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
if s.inDetail && s.needColon {
|
|
||||||
s.needNewline = true
|
|
||||||
if b[0] == '\n' {
|
|
||||||
b = b[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
k := 0
|
|
||||||
for i, c := range b {
|
|
||||||
if s.needNewline {
|
|
||||||
if s.inDetail && s.needColon {
|
|
||||||
s.buf.WriteByte(':')
|
|
||||||
s.needColon = false
|
|
||||||
}
|
|
||||||
s.buf.Write(detailSep)
|
|
||||||
s.needNewline = false
|
|
||||||
}
|
|
||||||
if c == '\n' {
|
|
||||||
s.buf.Write(b[k:i])
|
|
||||||
k = i + 1
|
|
||||||
s.needNewline = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.buf.Write(b[k:])
|
|
||||||
if !s.inDetail {
|
|
||||||
s.needColon = true
|
|
||||||
}
|
|
||||||
} else if !s.inDetail {
|
|
||||||
s.buf.Write(b)
|
|
||||||
}
|
|
||||||
return len(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// printer wraps a state to implement an xerrors.Printer.
|
|
||||||
type printer state
|
|
||||||
|
|
||||||
func (s *printer) Print(args ...interface{}) {
|
|
||||||
if !s.inDetail || s.printDetail {
|
|
||||||
fmt.Fprint((*state)(s), args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *printer) Printf(format string, args ...interface{}) {
|
|
||||||
if !s.inDetail || s.printDetail {
|
|
||||||
fmt.Fprintf((*state)(s), format, args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *printer) Detail() bool {
|
|
||||||
s.inDetail = true
|
|
||||||
return s.printDetail
|
|
||||||
}
|
|
1
vendor/golang.org/x/xerrors/codereview.cfg
generated
vendored
1
vendor/golang.org/x/xerrors/codereview.cfg
generated
vendored
@ -1 +0,0 @@
|
|||||||
issuerepo: golang/go
|
|
22
vendor/golang.org/x/xerrors/doc.go
generated
vendored
22
vendor/golang.org/x/xerrors/doc.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
// Copyright 2019 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package xerrors implements functions to manipulate errors.
|
|
||||||
//
|
|
||||||
// This package is based on the Go 2 proposal for error values:
|
|
||||||
// https://golang.org/design/29934-error-values
|
|
||||||
//
|
|
||||||
// These functions were incorporated into the standard library's errors package
|
|
||||||
// in Go 1.13:
|
|
||||||
// - Is
|
|
||||||
// - As
|
|
||||||
// - Unwrap
|
|
||||||
//
|
|
||||||
// Also, Errorf's %w verb was incorporated into fmt.Errorf.
|
|
||||||
//
|
|
||||||
// Use this package to get equivalent behavior in all supported Go versions.
|
|
||||||
//
|
|
||||||
// No other features of this package were included in Go 1.13, and at present
|
|
||||||
// there are no plans to include any of them.
|
|
||||||
package xerrors // import "golang.org/x/xerrors"
|
|
33
vendor/golang.org/x/xerrors/errors.go
generated
vendored
33
vendor/golang.org/x/xerrors/errors.go
generated
vendored
@ -1,33 +0,0 @@
|
|||||||
// Copyright 2011 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// errorString is a trivial implementation of error.
|
|
||||||
type errorString struct {
|
|
||||||
s string
|
|
||||||
frame Frame
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns an error that formats as the given text.
|
|
||||||
//
|
|
||||||
// The returned error contains a Frame set to the caller's location and
|
|
||||||
// implements Formatter to show this information when printed with details.
|
|
||||||
func New(text string) error {
|
|
||||||
return &errorString{text, Caller(1)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *errorString) Error() string {
|
|
||||||
return e.s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *errorString) Format(s fmt.State, v rune) { FormatError(e, s, v) }
|
|
||||||
|
|
||||||
func (e *errorString) FormatError(p Printer) (next error) {
|
|
||||||
p.Print(e.s)
|
|
||||||
e.frame.Format(p)
|
|
||||||
return nil
|
|
||||||
}
|
|
187
vendor/golang.org/x/xerrors/fmt.go
generated
vendored
187
vendor/golang.org/x/xerrors/fmt.go
generated
vendored
@ -1,187 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors/internal"
|
|
||||||
)
|
|
||||||
|
|
||||||
const percentBangString = "%!"
|
|
||||||
|
|
||||||
// Errorf formats according to a format specifier and returns the string as a
|
|
||||||
// value that satisfies error.
|
|
||||||
//
|
|
||||||
// The returned error includes the file and line number of the caller when
|
|
||||||
// formatted with additional detail enabled. If the last argument is an error
|
|
||||||
// the returned error's Format method will return it if the format string ends
|
|
||||||
// with ": %s", ": %v", or ": %w". If the last argument is an error and the
|
|
||||||
// format string ends with ": %w", the returned error implements an Unwrap
|
|
||||||
// method returning it.
|
|
||||||
//
|
|
||||||
// If the format specifier includes a %w verb with an error operand in a
|
|
||||||
// position other than at the end, the returned error will still implement an
|
|
||||||
// Unwrap method returning the operand, but the error's Format method will not
|
|
||||||
// return the wrapped error.
|
|
||||||
//
|
|
||||||
// It is invalid to include more than one %w verb or to supply it with an
|
|
||||||
// operand that does not implement the error interface. The %w verb is otherwise
|
|
||||||
// a synonym for %v.
|
|
||||||
func Errorf(format string, a ...interface{}) error {
|
|
||||||
format = formatPlusW(format)
|
|
||||||
// Support a ": %[wsv]" suffix, which works well with xerrors.Formatter.
|
|
||||||
wrap := strings.HasSuffix(format, ": %w")
|
|
||||||
idx, format2, ok := parsePercentW(format)
|
|
||||||
percentWElsewhere := !wrap && idx >= 0
|
|
||||||
if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) {
|
|
||||||
err := errorAt(a, len(a)-1)
|
|
||||||
if err == nil {
|
|
||||||
return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)}
|
|
||||||
}
|
|
||||||
// TODO: this is not entirely correct. The error value could be
|
|
||||||
// printed elsewhere in format if it mixes numbered with unnumbered
|
|
||||||
// substitutions. With relatively small changes to doPrintf we can
|
|
||||||
// have it optionally ignore extra arguments and pass the argument
|
|
||||||
// list in its entirety.
|
|
||||||
msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...)
|
|
||||||
frame := Frame{}
|
|
||||||
if internal.EnableTrace {
|
|
||||||
frame = Caller(1)
|
|
||||||
}
|
|
||||||
if wrap {
|
|
||||||
return &wrapError{msg, err, frame}
|
|
||||||
}
|
|
||||||
return &noWrapError{msg, err, frame}
|
|
||||||
}
|
|
||||||
// Support %w anywhere.
|
|
||||||
// TODO: don't repeat the wrapped error's message when %w occurs in the middle.
|
|
||||||
msg := fmt.Sprintf(format2, a...)
|
|
||||||
if idx < 0 {
|
|
||||||
return &noWrapError{msg, nil, Caller(1)}
|
|
||||||
}
|
|
||||||
err := errorAt(a, idx)
|
|
||||||
if !ok || err == nil {
|
|
||||||
// Too many %ws or argument of %w is not an error. Approximate the Go
|
|
||||||
// 1.13 fmt.Errorf message.
|
|
||||||
return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)}
|
|
||||||
}
|
|
||||||
frame := Frame{}
|
|
||||||
if internal.EnableTrace {
|
|
||||||
frame = Caller(1)
|
|
||||||
}
|
|
||||||
return &wrapError{msg, err, frame}
|
|
||||||
}
|
|
||||||
|
|
||||||
func errorAt(args []interface{}, i int) error {
|
|
||||||
if i < 0 || i >= len(args) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err, ok := args[i].(error)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatPlusW is used to avoid the vet check that will barf at %w.
|
|
||||||
func formatPlusW(s string) string {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the index of the only %w in format, or -1 if none.
|
|
||||||
// Also return a rewritten format string with %w replaced by %v, and
|
|
||||||
// false if there is more than one %w.
|
|
||||||
// TODO: handle "%[N]w".
|
|
||||||
func parsePercentW(format string) (idx int, newFormat string, ok bool) {
|
|
||||||
// Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go.
|
|
||||||
idx = -1
|
|
||||||
ok = true
|
|
||||||
n := 0
|
|
||||||
sz := 0
|
|
||||||
var isW bool
|
|
||||||
for i := 0; i < len(format); i += sz {
|
|
||||||
if format[i] != '%' {
|
|
||||||
sz = 1
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// "%%" is not a format directive.
|
|
||||||
if i+1 < len(format) && format[i+1] == '%' {
|
|
||||||
sz = 2
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sz, isW = parsePrintfVerb(format[i:])
|
|
||||||
if isW {
|
|
||||||
if idx >= 0 {
|
|
||||||
ok = false
|
|
||||||
} else {
|
|
||||||
idx = n
|
|
||||||
}
|
|
||||||
// "Replace" the last character, the 'w', with a 'v'.
|
|
||||||
p := i + sz - 1
|
|
||||||
format = format[:p] + "v" + format[p+1:]
|
|
||||||
}
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
return idx, format, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the printf verb starting with a % at s[0].
|
|
||||||
// Return how many bytes it occupies and whether the verb is 'w'.
|
|
||||||
func parsePrintfVerb(s string) (int, bool) {
|
|
||||||
// Assume only that the directive is a sequence of non-letters followed by a single letter.
|
|
||||||
sz := 0
|
|
||||||
var r rune
|
|
||||||
for i := 1; i < len(s); i += sz {
|
|
||||||
r, sz = utf8.DecodeRuneInString(s[i:])
|
|
||||||
if unicode.IsLetter(r) {
|
|
||||||
return i + sz, r == 'w'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(s), false
|
|
||||||
}
|
|
||||||
|
|
||||||
type noWrapError struct {
|
|
||||||
msg string
|
|
||||||
err error
|
|
||||||
frame Frame
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *noWrapError) Error() string {
|
|
||||||
return fmt.Sprint(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
|
|
||||||
|
|
||||||
func (e *noWrapError) FormatError(p Printer) (next error) {
|
|
||||||
p.Print(e.msg)
|
|
||||||
e.frame.Format(p)
|
|
||||||
return e.err
|
|
||||||
}
|
|
||||||
|
|
||||||
type wrapError struct {
|
|
||||||
msg string
|
|
||||||
err error
|
|
||||||
frame Frame
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *wrapError) Error() string {
|
|
||||||
return fmt.Sprint(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
|
|
||||||
|
|
||||||
func (e *wrapError) FormatError(p Printer) (next error) {
|
|
||||||
p.Print(e.msg)
|
|
||||||
e.frame.Format(p)
|
|
||||||
return e.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *wrapError) Unwrap() error {
|
|
||||||
return e.err
|
|
||||||
}
|
|
34
vendor/golang.org/x/xerrors/format.go
generated
vendored
34
vendor/golang.org/x/xerrors/format.go
generated
vendored
@ -1,34 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
// A Formatter formats error messages.
|
|
||||||
type Formatter interface {
|
|
||||||
error
|
|
||||||
|
|
||||||
// FormatError prints the receiver's first error and returns the next error in
|
|
||||||
// the error chain, if any.
|
|
||||||
FormatError(p Printer) (next error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Printer formats error messages.
|
|
||||||
//
|
|
||||||
// The most common implementation of Printer is the one provided by package fmt
|
|
||||||
// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message
|
|
||||||
// typically provide their own implementations.
|
|
||||||
type Printer interface {
|
|
||||||
// Print appends args to the message output.
|
|
||||||
Print(args ...interface{})
|
|
||||||
|
|
||||||
// Printf writes a formatted string.
|
|
||||||
Printf(format string, args ...interface{})
|
|
||||||
|
|
||||||
// Detail reports whether error detail is requested.
|
|
||||||
// After the first call to Detail, all text written to the Printer
|
|
||||||
// is formatted as additional detail, or ignored when
|
|
||||||
// detail has not been requested.
|
|
||||||
// If Detail returns false, the caller can avoid printing the detail at all.
|
|
||||||
Detail() bool
|
|
||||||
}
|
|
56
vendor/golang.org/x/xerrors/frame.go
generated
vendored
56
vendor/golang.org/x/xerrors/frame.go
generated
vendored
@ -1,56 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Frame contains part of a call stack.
|
|
||||||
type Frame struct {
|
|
||||||
// Make room for three PCs: the one we were asked for, what it called,
|
|
||||||
// and possibly a PC for skipPleaseUseCallersFrames. See:
|
|
||||||
// https://go.googlesource.com/go/+/032678e0fb/src/runtime/extern.go#169
|
|
||||||
frames [3]uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Caller returns a Frame that describes a frame on the caller's stack.
|
|
||||||
// The argument skip is the number of frames to skip over.
|
|
||||||
// Caller(0) returns the frame for the caller of Caller.
|
|
||||||
func Caller(skip int) Frame {
|
|
||||||
var s Frame
|
|
||||||
runtime.Callers(skip+1, s.frames[:])
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// location reports the file, line, and function of a frame.
|
|
||||||
//
|
|
||||||
// The returned function may be "" even if file and line are not.
|
|
||||||
func (f Frame) location() (function, file string, line int) {
|
|
||||||
frames := runtime.CallersFrames(f.frames[:])
|
|
||||||
if _, ok := frames.Next(); !ok {
|
|
||||||
return "", "", 0
|
|
||||||
}
|
|
||||||
fr, ok := frames.Next()
|
|
||||||
if !ok {
|
|
||||||
return "", "", 0
|
|
||||||
}
|
|
||||||
return fr.Function, fr.File, fr.Line
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format prints the stack as error detail.
|
|
||||||
// It should be called from an error's Format implementation
|
|
||||||
// after printing any other error detail.
|
|
||||||
func (f Frame) Format(p Printer) {
|
|
||||||
if p.Detail() {
|
|
||||||
function, file, line := f.location()
|
|
||||||
if function != "" {
|
|
||||||
p.Printf("%s\n ", function)
|
|
||||||
}
|
|
||||||
if file != "" {
|
|
||||||
p.Printf("%s:%d\n", file, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
8
vendor/golang.org/x/xerrors/internal/internal.go
generated
vendored
8
vendor/golang.org/x/xerrors/internal/internal.go
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package internal
|
|
||||||
|
|
||||||
// EnableTrace indicates whether stack information should be recorded in errors.
|
|
||||||
var EnableTrace = true
|
|
106
vendor/golang.org/x/xerrors/wrap.go
generated
vendored
106
vendor/golang.org/x/xerrors/wrap.go
generated
vendored
@ -1,106 +0,0 @@
|
|||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package xerrors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Wrapper provides context around another error.
|
|
||||||
type Wrapper interface {
|
|
||||||
// Unwrap returns the next error in the error chain.
|
|
||||||
// If there is no next error, Unwrap returns nil.
|
|
||||||
Unwrap() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opaque returns an error with the same error formatting as err
|
|
||||||
// but that does not match err and cannot be unwrapped.
|
|
||||||
func Opaque(err error) error {
|
|
||||||
return noWrapper{err}
|
|
||||||
}
|
|
||||||
|
|
||||||
type noWrapper struct {
|
|
||||||
error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e noWrapper) FormatError(p Printer) (next error) {
|
|
||||||
if f, ok := e.error.(Formatter); ok {
|
|
||||||
return f.FormatError(p)
|
|
||||||
}
|
|
||||||
p.Print(e.error)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap returns the result of calling the Unwrap method on err, if err implements
|
|
||||||
// Unwrap. Otherwise, Unwrap returns nil.
|
|
||||||
func Unwrap(err error) error {
|
|
||||||
u, ok := err.(Wrapper)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return u.Unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is reports whether any error in err's chain matches target.
|
|
||||||
//
|
|
||||||
// An error is considered to match a target if it is equal to that target or if
|
|
||||||
// it implements a method Is(error) bool such that Is(target) returns true.
|
|
||||||
func Is(err, target error) bool {
|
|
||||||
if target == nil {
|
|
||||||
return err == target
|
|
||||||
}
|
|
||||||
|
|
||||||
isComparable := reflect.TypeOf(target).Comparable()
|
|
||||||
for {
|
|
||||||
if isComparable && err == target {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// TODO: consider supporing target.Is(err). This would allow
|
|
||||||
// user-definable predicates, but also may allow for coping with sloppy
|
|
||||||
// APIs, thereby making it easier to get away with them.
|
|
||||||
if err = Unwrap(err); err == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// As finds the first error in err's chain that matches the type to which target
|
|
||||||
// points, and if so, sets the target to its value and returns true. An error
|
|
||||||
// matches a type if it is assignable to the target type, or if it has a method
|
|
||||||
// As(interface{}) bool such that As(target) returns true. As will panic if target
|
|
||||||
// is not a non-nil pointer to a type which implements error or is of interface type.
|
|
||||||
//
|
|
||||||
// The As method should set the target to its value and return true if err
|
|
||||||
// matches the type to which target points.
|
|
||||||
func As(err error, target interface{}) bool {
|
|
||||||
if target == nil {
|
|
||||||
panic("errors: target cannot be nil")
|
|
||||||
}
|
|
||||||
val := reflect.ValueOf(target)
|
|
||||||
typ := val.Type()
|
|
||||||
if typ.Kind() != reflect.Ptr || val.IsNil() {
|
|
||||||
panic("errors: target must be a non-nil pointer")
|
|
||||||
}
|
|
||||||
if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
|
|
||||||
panic("errors: *target must be interface or implement error")
|
|
||||||
}
|
|
||||||
targetType := typ.Elem()
|
|
||||||
for err != nil {
|
|
||||||
if reflect.TypeOf(err).AssignableTo(targetType) {
|
|
||||||
val.Elem().Set(reflect.ValueOf(err))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
err = Unwrap(err)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var errorType = reflect.TypeOf((*error)(nil)).Elem()
|
|
13
vendor/gotest.tools/v3/LICENSE
vendored
13
vendor/gotest.tools/v3/LICENSE
vendored
@ -1,13 +0,0 @@
|
|||||||
Copyright 2018 gotest.tools authors
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
219
vendor/gotest.tools/v3/assert/assert.go
vendored
219
vendor/gotest.tools/v3/assert/assert.go
vendored
@ -1,219 +0,0 @@
|
|||||||
/*Package assert provides assertions for comparing expected values to actual
|
|
||||||
values. When an assertion fails a helpful error message is printed.
|
|
||||||
|
|
||||||
Assert and Check
|
|
||||||
|
|
||||||
Assert() and Check() both accept a Comparison, and fail the test when the
|
|
||||||
comparison fails. The one difference is that Assert() will end the test execution
|
|
||||||
immediately (using t.FailNow()) whereas Check() will fail the test (using t.Fail()),
|
|
||||||
return the value of the comparison, then proceed with the rest of the test case.
|
|
||||||
|
|
||||||
Example usage
|
|
||||||
|
|
||||||
The example below shows assert used with some common types.
|
|
||||||
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"gotest.tools/assert"
|
|
||||||
is "gotest.tools/assert/cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEverything(t *testing.T) {
|
|
||||||
// booleans
|
|
||||||
assert.Assert(t, ok)
|
|
||||||
assert.Assert(t, !missing)
|
|
||||||
|
|
||||||
// primitives
|
|
||||||
assert.Equal(t, count, 1)
|
|
||||||
assert.Equal(t, msg, "the message")
|
|
||||||
assert.Assert(t, total != 10) // NotEqual
|
|
||||||
|
|
||||||
// errors
|
|
||||||
assert.NilError(t, closer.Close())
|
|
||||||
assert.Error(t, err, "the exact error message")
|
|
||||||
assert.ErrorContains(t, err, "includes this")
|
|
||||||
assert.ErrorType(t, err, os.IsNotExist)
|
|
||||||
|
|
||||||
// complex types
|
|
||||||
assert.DeepEqual(t, result, myStruct{Name: "title"})
|
|
||||||
assert.Assert(t, is.Len(items, 3))
|
|
||||||
assert.Assert(t, len(sequence) != 0) // NotEmpty
|
|
||||||
assert.Assert(t, is.Contains(mapping, "key"))
|
|
||||||
|
|
||||||
// pointers and interface
|
|
||||||
assert.Assert(t, is.Nil(ref))
|
|
||||||
assert.Assert(t, ref != nil) // NotNil
|
|
||||||
}
|
|
||||||
|
|
||||||
Comparisons
|
|
||||||
|
|
||||||
Package http://pkg.go.dev/gotest.tools/v3/assert/cmp provides
|
|
||||||
many common comparisons. Additional comparisons can be written to compare
|
|
||||||
values in other ways. See the example Assert (CustomComparison).
|
|
||||||
|
|
||||||
Automated migration from testify
|
|
||||||
|
|
||||||
gty-migrate-from-testify is a command which translates Go source code from
|
|
||||||
testify assertions to the assertions provided by this package.
|
|
||||||
|
|
||||||
See http://pkg.go.dev/gotest.tools/v3/assert/cmd/gty-migrate-from-testify.
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
package assert // import "gotest.tools/v3/assert"
|
|
||||||
|
|
||||||
import (
|
|
||||||
gocmp "github.com/google/go-cmp/cmp"
|
|
||||||
"gotest.tools/v3/assert/cmp"
|
|
||||||
"gotest.tools/v3/internal/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BoolOrComparison can be a bool, or cmp.Comparison. See Assert() for usage.
|
|
||||||
type BoolOrComparison interface{}
|
|
||||||
|
|
||||||
// TestingT is the subset of testing.T used by the assert package.
|
|
||||||
type TestingT interface {
|
|
||||||
FailNow()
|
|
||||||
Fail()
|
|
||||||
Log(args ...interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
type helperT interface {
|
|
||||||
Helper()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assert performs a comparison. If the comparison fails, the test is marked as
|
|
||||||
// failed, a failure message is logged, and execution is stopped immediately.
|
|
||||||
//
|
|
||||||
// The comparison argument may be one of three types:
|
|
||||||
// bool
|
|
||||||
// True is success. False is a failure.
|
|
||||||
// The failure message will contain the literal source code of the expression.
|
|
||||||
// cmp.Comparison
|
|
||||||
// Uses cmp.Result.Success() to check for success of failure.
|
|
||||||
// The comparison is responsible for producing a helpful failure message.
|
|
||||||
// http://pkg.go.dev/gotest.tools/v3/assert/cmp provides many common comparisons.
|
|
||||||
// error
|
|
||||||
// A nil value is considered success.
|
|
||||||
// A non-nil error is a failure, err.Error() is used as the failure message.
|
|
||||||
func Assert(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
if !assert.Eval(t, assert.ArgsFromComparisonCall, comparison, msgAndArgs...) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check performs a comparison. If the comparison fails the test is marked as
|
|
||||||
// failed, a failure message is logged, and Check returns false. Otherwise returns
|
|
||||||
// true.
|
|
||||||
//
|
|
||||||
// See Assert for details about the comparison arg and failure messages.
|
|
||||||
func Check(t TestingT, comparison BoolOrComparison, msgAndArgs ...interface{}) bool {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
if !assert.Eval(t, assert.ArgsFromComparisonCall, comparison, msgAndArgs...) {
|
|
||||||
t.Fail()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// NilError fails the test immediately if err is not nil.
|
|
||||||
// This is equivalent to Assert(t, err)
|
|
||||||
func NilError(t TestingT, err error, msgAndArgs ...interface{}) {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
if !assert.Eval(t, assert.ArgsAfterT, err, msgAndArgs...) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal uses the == operator to assert two values are equal and fails the test
|
|
||||||
// if they are not equal.
|
|
||||||
//
|
|
||||||
// If the comparison fails Equal will use the variable names for x and y as part
|
|
||||||
// of the failure message to identify the actual and expected values.
|
|
||||||
//
|
|
||||||
// If either x or y are a multi-line string the failure message will include a
|
|
||||||
// unified diff of the two values. If the values only differ by whitespace
|
|
||||||
// the unified diff will be augmented by replacing whitespace characters with
|
|
||||||
// visible characters to identify the whitespace difference.
|
|
||||||
//
|
|
||||||
// This is equivalent to Assert(t, cmp.Equal(x, y)).
|
|
||||||
func Equal(t TestingT, x, y interface{}, msgAndArgs ...interface{}) {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
if !assert.Eval(t, assert.ArgsAfterT, cmp.Equal(x, y), msgAndArgs...) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepEqual uses google/go-cmp (https://godoc.org/github.com/google/go-cmp/cmp)
|
|
||||||
// to assert two values are equal and fails the test if they are not equal.
|
|
||||||
//
|
|
||||||
// Package http://pkg.go.dev/gotest.tools/v3/assert/opt provides some additional
|
|
||||||
// commonly used Options.
|
|
||||||
//
|
|
||||||
// This is equivalent to Assert(t, cmp.DeepEqual(x, y)).
|
|
||||||
func DeepEqual(t TestingT, x, y interface{}, opts ...gocmp.Option) {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
if !assert.Eval(t, assert.ArgsAfterT, cmp.DeepEqual(x, y, opts...)) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error fails the test if err is nil, or the error message is not the expected
|
|
||||||
// message.
|
|
||||||
// Equivalent to Assert(t, cmp.Error(err, message)).
|
|
||||||
func Error(t TestingT, err error, message string, msgAndArgs ...interface{}) {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
if !assert.Eval(t, assert.ArgsAfterT, cmp.Error(err, message), msgAndArgs...) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorContains fails the test if err is nil, or the error message does not
|
|
||||||
// contain the expected substring.
|
|
||||||
// Equivalent to Assert(t, cmp.ErrorContains(err, substring)).
|
|
||||||
func ErrorContains(t TestingT, err error, substring string, msgAndArgs ...interface{}) {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
if !assert.Eval(t, assert.ArgsAfterT, cmp.ErrorContains(err, substring), msgAndArgs...) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorType fails the test if err is nil, or err is not the expected type.
|
|
||||||
// Equivalent to Assert(t, cmp.ErrorType(err, expected)).
|
|
||||||
//
|
|
||||||
// Expected can be one of:
|
|
||||||
// func(error) bool
|
|
||||||
// Function should return true if the error is the expected type.
|
|
||||||
// type struct{}, type &struct{}
|
|
||||||
// A struct or a pointer to a struct.
|
|
||||||
// Fails if the error is not of the same type as expected.
|
|
||||||
// type &interface{}
|
|
||||||
// A pointer to an interface type.
|
|
||||||
// Fails if err does not implement the interface.
|
|
||||||
// reflect.Type
|
|
||||||
// Fails if err does not implement the reflect.Type
|
|
||||||
func ErrorType(t TestingT, err error, expected interface{}, msgAndArgs ...interface{}) {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
if !assert.Eval(t, assert.ArgsAfterT, cmp.ErrorType(err, expected), msgAndArgs...) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
365
vendor/gotest.tools/v3/assert/cmp/compare.go
vendored
365
vendor/gotest.tools/v3/assert/cmp/compare.go
vendored
@ -1,365 +0,0 @@
|
|||||||
/*Package cmp provides Comparisons for Assert and Check*/
|
|
||||||
package cmp // import "gotest.tools/v3/assert/cmp"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
|
||||||
"gotest.tools/v3/internal/format"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Comparison is a function which compares values and returns ResultSuccess if
|
|
||||||
// the actual value matches the expected value. If the values do not match the
|
|
||||||
// Result will contain a message about why it failed.
|
|
||||||
type Comparison func() Result
|
|
||||||
|
|
||||||
// DeepEqual compares two values using google/go-cmp
|
|
||||||
// (https://godoc.org/github.com/google/go-cmp/cmp)
|
|
||||||
// and succeeds if the values are equal.
|
|
||||||
//
|
|
||||||
// The comparison can be customized using comparison Options.
|
|
||||||
// Package http://pkg.go.dev/gotest.tools/v3/assert/opt provides some additional
|
|
||||||
// commonly used Options.
|
|
||||||
func DeepEqual(x, y interface{}, opts ...cmp.Option) Comparison {
|
|
||||||
return func() (result Result) {
|
|
||||||
defer func() {
|
|
||||||
if panicmsg, handled := handleCmpPanic(recover()); handled {
|
|
||||||
result = ResultFailure(panicmsg)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
diff := cmp.Diff(x, y, opts...)
|
|
||||||
if diff == "" {
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
return multiLineDiffResult(diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleCmpPanic(r interface{}) (string, bool) {
|
|
||||||
if r == nil {
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
panicmsg, ok := r.(string)
|
|
||||||
if !ok {
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(panicmsg, "cannot handle unexported field"):
|
|
||||||
return panicmsg, true
|
|
||||||
}
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func toResult(success bool, msg string) Result {
|
|
||||||
if success {
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
return ResultFailure(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegexOrPattern may be either a *regexp.Regexp or a string that is a valid
|
|
||||||
// regexp pattern.
|
|
||||||
type RegexOrPattern interface{}
|
|
||||||
|
|
||||||
// Regexp succeeds if value v matches regular expression re.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// assert.Assert(t, cmp.Regexp("^[0-9a-f]{32}$", str))
|
|
||||||
// r := regexp.MustCompile("^[0-9a-f]{32}$")
|
|
||||||
// assert.Assert(t, cmp.Regexp(r, str))
|
|
||||||
func Regexp(re RegexOrPattern, v string) Comparison {
|
|
||||||
match := func(re *regexp.Regexp) Result {
|
|
||||||
return toResult(
|
|
||||||
re.MatchString(v),
|
|
||||||
fmt.Sprintf("value %q does not match regexp %q", v, re.String()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return func() Result {
|
|
||||||
switch regex := re.(type) {
|
|
||||||
case *regexp.Regexp:
|
|
||||||
return match(regex)
|
|
||||||
case string:
|
|
||||||
re, err := regexp.Compile(regex)
|
|
||||||
if err != nil {
|
|
||||||
return ResultFailure(err.Error())
|
|
||||||
}
|
|
||||||
return match(re)
|
|
||||||
default:
|
|
||||||
return ResultFailure(fmt.Sprintf("invalid type %T for regex pattern", regex))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal succeeds if x == y. See assert.Equal for full documentation.
|
|
||||||
func Equal(x, y interface{}) Comparison {
|
|
||||||
return func() Result {
|
|
||||||
switch {
|
|
||||||
case x == y:
|
|
||||||
return ResultSuccess
|
|
||||||
case isMultiLineStringCompare(x, y):
|
|
||||||
diff := format.UnifiedDiff(format.DiffConfig{A: x.(string), B: y.(string)})
|
|
||||||
return multiLineDiffResult(diff)
|
|
||||||
}
|
|
||||||
return ResultFailureTemplate(`
|
|
||||||
{{- printf "%v" .Data.x}} (
|
|
||||||
{{- with callArg 0 }}{{ formatNode . }} {{end -}}
|
|
||||||
{{- printf "%T" .Data.x -}}
|
|
||||||
) != {{ printf "%v" .Data.y}} (
|
|
||||||
{{- with callArg 1 }}{{ formatNode . }} {{end -}}
|
|
||||||
{{- printf "%T" .Data.y -}}
|
|
||||||
)`,
|
|
||||||
map[string]interface{}{"x": x, "y": y})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isMultiLineStringCompare(x, y interface{}) bool {
|
|
||||||
strX, ok := x.(string)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
strY, ok := y.(string)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return strings.Contains(strX, "\n") || strings.Contains(strY, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func multiLineDiffResult(diff string) Result {
|
|
||||||
return ResultFailureTemplate(`
|
|
||||||
--- {{ with callArg 0 }}{{ formatNode . }}{{else}}←{{end}}
|
|
||||||
+++ {{ with callArg 1 }}{{ formatNode . }}{{else}}→{{end}}
|
|
||||||
{{ .Data.diff }}`,
|
|
||||||
map[string]interface{}{"diff": diff})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len succeeds if the sequence has the expected length.
|
|
||||||
func Len(seq interface{}, expected int) Comparison {
|
|
||||||
return func() (result Result) {
|
|
||||||
defer func() {
|
|
||||||
if e := recover(); e != nil {
|
|
||||||
result = ResultFailure(fmt.Sprintf("type %T does not have a length", seq))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
value := reflect.ValueOf(seq)
|
|
||||||
length := value.Len()
|
|
||||||
if length == expected {
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
msg := fmt.Sprintf("expected %s (length %d) to have length %d", seq, length, expected)
|
|
||||||
return ResultFailure(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains succeeds if item is in collection. Collection may be a string, map,
|
|
||||||
// slice, or array.
|
|
||||||
//
|
|
||||||
// If collection is a string, item must also be a string, and is compared using
|
|
||||||
// strings.Contains().
|
|
||||||
// If collection is a Map, contains will succeed if item is a key in the map.
|
|
||||||
// If collection is a slice or array, item is compared to each item in the
|
|
||||||
// sequence using reflect.DeepEqual().
|
|
||||||
func Contains(collection interface{}, item interface{}) Comparison {
|
|
||||||
return func() Result {
|
|
||||||
colValue := reflect.ValueOf(collection)
|
|
||||||
if !colValue.IsValid() {
|
|
||||||
return ResultFailure(fmt.Sprintf("nil does not contain items"))
|
|
||||||
}
|
|
||||||
msg := fmt.Sprintf("%v does not contain %v", collection, item)
|
|
||||||
|
|
||||||
itemValue := reflect.ValueOf(item)
|
|
||||||
switch colValue.Type().Kind() {
|
|
||||||
case reflect.String:
|
|
||||||
if itemValue.Type().Kind() != reflect.String {
|
|
||||||
return ResultFailure("string may only contain strings")
|
|
||||||
}
|
|
||||||
return toResult(
|
|
||||||
strings.Contains(colValue.String(), itemValue.String()),
|
|
||||||
fmt.Sprintf("string %q does not contain %q", collection, item))
|
|
||||||
|
|
||||||
case reflect.Map:
|
|
||||||
if itemValue.Type() != colValue.Type().Key() {
|
|
||||||
return ResultFailure(fmt.Sprintf(
|
|
||||||
"%v can not contain a %v key", colValue.Type(), itemValue.Type()))
|
|
||||||
}
|
|
||||||
return toResult(colValue.MapIndex(itemValue).IsValid(), msg)
|
|
||||||
|
|
||||||
case reflect.Slice, reflect.Array:
|
|
||||||
for i := 0; i < colValue.Len(); i++ {
|
|
||||||
if reflect.DeepEqual(colValue.Index(i).Interface(), item) {
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ResultFailure(msg)
|
|
||||||
default:
|
|
||||||
return ResultFailure(fmt.Sprintf("type %T does not contain items", collection))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panics succeeds if f() panics.
|
|
||||||
func Panics(f func()) Comparison {
|
|
||||||
return func() (result Result) {
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
result = ResultSuccess
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
f()
|
|
||||||
return ResultFailure("did not panic")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error succeeds if err is a non-nil error, and the error message equals the
|
|
||||||
// expected message.
|
|
||||||
func Error(err error, message string) Comparison {
|
|
||||||
return func() Result {
|
|
||||||
switch {
|
|
||||||
case err == nil:
|
|
||||||
return ResultFailure("expected an error, got nil")
|
|
||||||
case err.Error() != message:
|
|
||||||
return ResultFailure(fmt.Sprintf(
|
|
||||||
"expected error %q, got %s", message, formatErrorMessage(err)))
|
|
||||||
}
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorContains succeeds if err is a non-nil error, and the error message contains
|
|
||||||
// the expected substring.
|
|
||||||
func ErrorContains(err error, substring string) Comparison {
|
|
||||||
return func() Result {
|
|
||||||
switch {
|
|
||||||
case err == nil:
|
|
||||||
return ResultFailure("expected an error, got nil")
|
|
||||||
case !strings.Contains(err.Error(), substring):
|
|
||||||
return ResultFailure(fmt.Sprintf(
|
|
||||||
"expected error to contain %q, got %s", substring, formatErrorMessage(err)))
|
|
||||||
}
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type causer interface {
|
|
||||||
Cause() error
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatErrorMessage(err error) string {
|
|
||||||
if _, ok := err.(causer); ok {
|
|
||||||
return fmt.Sprintf("%q\n%+v", err, err)
|
|
||||||
}
|
|
||||||
// This error was not wrapped with github.com/pkg/errors
|
|
||||||
return fmt.Sprintf("%q", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nil succeeds if obj is a nil interface, pointer, or function.
|
|
||||||
//
|
|
||||||
// Use NilError() for comparing errors. Use Len(obj, 0) for comparing slices,
|
|
||||||
// maps, and channels.
|
|
||||||
func Nil(obj interface{}) Comparison {
|
|
||||||
msgFunc := func(value reflect.Value) string {
|
|
||||||
return fmt.Sprintf("%v (type %s) is not nil", reflect.Indirect(value), value.Type())
|
|
||||||
}
|
|
||||||
return isNil(obj, msgFunc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNil(obj interface{}, msgFunc func(reflect.Value) string) Comparison {
|
|
||||||
return func() Result {
|
|
||||||
if obj == nil {
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
value := reflect.ValueOf(obj)
|
|
||||||
kind := value.Type().Kind()
|
|
||||||
if kind >= reflect.Chan && kind <= reflect.Slice {
|
|
||||||
if value.IsNil() {
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
return ResultFailure(msgFunc(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultFailure(fmt.Sprintf("%v (type %s) can not be nil", value, value.Type()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorType succeeds if err is not nil and is of the expected type.
|
|
||||||
//
|
|
||||||
// Expected can be one of:
|
|
||||||
// func(error) bool
|
|
||||||
// Function should return true if the error is the expected type.
|
|
||||||
// type struct{}, type &struct{}
|
|
||||||
// A struct or a pointer to a struct.
|
|
||||||
// Fails if the error is not of the same type as expected.
|
|
||||||
// type &interface{}
|
|
||||||
// A pointer to an interface type.
|
|
||||||
// Fails if err does not implement the interface.
|
|
||||||
// reflect.Type
|
|
||||||
// Fails if err does not implement the reflect.Type
|
|
||||||
func ErrorType(err error, expected interface{}) Comparison {
|
|
||||||
return func() Result {
|
|
||||||
switch expectedType := expected.(type) {
|
|
||||||
case func(error) bool:
|
|
||||||
return cmpErrorTypeFunc(err, expectedType)
|
|
||||||
case reflect.Type:
|
|
||||||
if expectedType.Kind() == reflect.Interface {
|
|
||||||
return cmpErrorTypeImplementsType(err, expectedType)
|
|
||||||
}
|
|
||||||
return cmpErrorTypeEqualType(err, expectedType)
|
|
||||||
case nil:
|
|
||||||
return ResultFailure(fmt.Sprintf("invalid type for expected: nil"))
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedType := reflect.TypeOf(expected)
|
|
||||||
switch {
|
|
||||||
case expectedType.Kind() == reflect.Struct, isPtrToStruct(expectedType):
|
|
||||||
return cmpErrorTypeEqualType(err, expectedType)
|
|
||||||
case isPtrToInterface(expectedType):
|
|
||||||
return cmpErrorTypeImplementsType(err, expectedType.Elem())
|
|
||||||
}
|
|
||||||
return ResultFailure(fmt.Sprintf("invalid type for expected: %T", expected))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmpErrorTypeFunc(err error, f func(error) bool) Result {
|
|
||||||
if f(err) {
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
actual := "nil"
|
|
||||||
if err != nil {
|
|
||||||
actual = fmt.Sprintf("%s (%T)", err, err)
|
|
||||||
}
|
|
||||||
return ResultFailureTemplate(`error is {{ .Data.actual }}
|
|
||||||
{{- with callArg 1 }}, not {{ formatNode . }}{{end -}}`,
|
|
||||||
map[string]interface{}{"actual": actual})
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmpErrorTypeEqualType(err error, expectedType reflect.Type) Result {
|
|
||||||
if err == nil {
|
|
||||||
return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
|
|
||||||
}
|
|
||||||
errValue := reflect.ValueOf(err)
|
|
||||||
if errValue.Type() == expectedType {
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmpErrorTypeImplementsType(err error, expectedType reflect.Type) Result {
|
|
||||||
if err == nil {
|
|
||||||
return ResultFailure(fmt.Sprintf("error is nil, not %s", expectedType))
|
|
||||||
}
|
|
||||||
errValue := reflect.ValueOf(err)
|
|
||||||
if errValue.Type().Implements(expectedType) {
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
return ResultFailure(fmt.Sprintf("error is %s (%T), not %s", err, err, expectedType))
|
|
||||||
}
|
|
||||||
|
|
||||||
func isPtrToInterface(typ reflect.Type) bool {
|
|
||||||
return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Interface
|
|
||||||
}
|
|
||||||
|
|
||||||
func isPtrToStruct(typ reflect.Type) bool {
|
|
||||||
return typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct
|
|
||||||
}
|
|
99
vendor/gotest.tools/v3/assert/cmp/result.go
vendored
99
vendor/gotest.tools/v3/assert/cmp/result.go
vendored
@ -1,99 +0,0 @@
|
|||||||
package cmp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"gotest.tools/v3/internal/source"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Result of a Comparison.
|
|
||||||
type Result interface {
|
|
||||||
Success() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success returns true if the comparison was successful.
|
|
||||||
func (r StringResult) Success() bool {
|
|
||||||
return r.success
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 = StringResult{success: true}
|
|
||||||
|
|
||||||
// ResultFailure returns a failed Result with a failure message.
|
|
||||||
func ResultFailure(message string) StringResult {
|
|
||||||
return StringResult{message: message}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResultFromError returns ResultSuccess if err is nil. Otherwise ResultFailure
|
|
||||||
// is returned with the error message as the failure message.
|
|
||||||
func ResultFromError(err error) Result {
|
|
||||||
if err == nil {
|
|
||||||
return ResultSuccess
|
|
||||||
}
|
|
||||||
return ResultFailure(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
type templatedResult struct {
|
|
||||||
template string
|
|
||||||
data map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r templatedResult) Success() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r templatedResult) FailureMessage(args []ast.Expr) string {
|
|
||||||
msg, err := renderMessage(r, args)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Sprintf("failed to render failure message: %s", err)
|
|
||||||
}
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResultFailureTemplate returns a Result with a template string and data which
|
|
||||||
// can be used to format a failure message. The template may access data from .Data,
|
|
||||||
// the comparison args with the callArg function, and the formatNode function may
|
|
||||||
// be used to format the call args.
|
|
||||||
func ResultFailureTemplate(template string, data map[string]interface{}) Result {
|
|
||||||
return templatedResult{template: template, data: data}
|
|
||||||
}
|
|
||||||
|
|
||||||
func renderMessage(result templatedResult, args []ast.Expr) (string, error) {
|
|
||||||
tmpl := template.New("failure").Funcs(template.FuncMap{
|
|
||||||
"formatNode": source.FormatNode,
|
|
||||||
"callArg": func(index int) ast.Expr {
|
|
||||||
if index >= len(args) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return args[index]
|
|
||||||
},
|
|
||||||
})
|
|
||||||
var err error
|
|
||||||
tmpl, err = tmpl.Parse(result.template)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
err = tmpl.Execute(buf, map[string]interface{}{
|
|
||||||
"Data": result.data,
|
|
||||||
})
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
143
vendor/gotest.tools/v3/internal/assert/assert.go
vendored
143
vendor/gotest.tools/v3/internal/assert/assert.go
vendored
@ -1,143 +0,0 @@
|
|||||||
package assert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
|
||||||
"go/token"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"gotest.tools/v3/assert/cmp"
|
|
||||||
"gotest.tools/v3/internal/format"
|
|
||||||
"gotest.tools/v3/internal/source"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LogT is the subset of testing.T used by the assert package.
|
|
||||||
type LogT interface {
|
|
||||||
Log(args ...interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
type helperT interface {
|
|
||||||
Helper()
|
|
||||||
}
|
|
||||||
|
|
||||||
const failureMessage = "assertion failed: "
|
|
||||||
|
|
||||||
// Eval the comparison and print a failure messages if the comparison has failed.
|
|
||||||
// nolint: gocyclo
|
|
||||||
func Eval(
|
|
||||||
t LogT,
|
|
||||||
argSelector argSelector,
|
|
||||||
comparison interface{},
|
|
||||||
msgAndArgs ...interface{},
|
|
||||||
) bool {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
var success bool
|
|
||||||
switch check := comparison.(type) {
|
|
||||||
case bool:
|
|
||||||
if check {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
logFailureFromBool(t, msgAndArgs...)
|
|
||||||
|
|
||||||
// Undocumented legacy comparison without Result type
|
|
||||||
case func() (success bool, message string):
|
|
||||||
success = runCompareFunc(t, check, msgAndArgs...)
|
|
||||||
|
|
||||||
case nil:
|
|
||||||
return true
|
|
||||||
|
|
||||||
case error:
|
|
||||||
msg := failureMsgFromError(check)
|
|
||||||
t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
|
|
||||||
|
|
||||||
case cmp.Comparison:
|
|
||||||
success = RunComparison(t, argSelector, check, msgAndArgs...)
|
|
||||||
|
|
||||||
case func() cmp.Result:
|
|
||||||
success = RunComparison(t, argSelector, check, msgAndArgs...)
|
|
||||||
|
|
||||||
default:
|
|
||||||
t.Log(fmt.Sprintf("invalid Comparison: %v (%T)", check, check))
|
|
||||||
}
|
|
||||||
return success
|
|
||||||
}
|
|
||||||
|
|
||||||
func runCompareFunc(
|
|
||||||
t LogT,
|
|
||||||
f func() (success bool, message string),
|
|
||||||
msgAndArgs ...interface{},
|
|
||||||
) bool {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
if success, message := f(); !success {
|
|
||||||
t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func logFailureFromBool(t LogT, msgAndArgs ...interface{}) {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
const stackIndex = 3 // Assert()/Check(), assert(), logFailureFromBool()
|
|
||||||
args, err := source.CallExprArgs(stackIndex)
|
|
||||||
if err != nil {
|
|
||||||
t.Log(err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const comparisonArgIndex = 1 // Assert(t, comparison)
|
|
||||||
if len(args) <= comparisonArgIndex {
|
|
||||||
t.Log(failureMessage + "but assert failed to find the expression to print")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
msg, err := boolFailureMessage(args[comparisonArgIndex])
|
|
||||||
if err != nil {
|
|
||||||
t.Log(err.Error())
|
|
||||||
msg = "expression is false"
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Log(format.WithCustomMessage(failureMessage+msg, msgAndArgs...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func failureMsgFromError(err error) string {
|
|
||||||
// Handle errors with non-nil types
|
|
||||||
v := reflect.ValueOf(err)
|
|
||||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
|
||||||
return fmt.Sprintf("error is not nil: error has type %T", err)
|
|
||||||
}
|
|
||||||
return "error is not nil: " + err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func boolFailureMessage(expr ast.Expr) (string, error) {
|
|
||||||
if binaryExpr, ok := expr.(*ast.BinaryExpr); ok && binaryExpr.Op == token.NEQ {
|
|
||||||
x, err := source.FormatNode(binaryExpr.X)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
y, err := source.FormatNode(binaryExpr.Y)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return x + " is " + y, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if unaryExpr, ok := expr.(*ast.UnaryExpr); ok && unaryExpr.Op == token.NOT {
|
|
||||||
x, err := source.FormatNode(unaryExpr.X)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return x + " is true", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
formatted, err := source.FormatNode(expr)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return "expression is false: " + formatted, nil
|
|
||||||
}
|
|
125
vendor/gotest.tools/v3/internal/assert/result.go
vendored
125
vendor/gotest.tools/v3/internal/assert/result.go
vendored
@ -1,125 +0,0 @@
|
|||||||
package assert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
|
||||||
|
|
||||||
"gotest.tools/v3/assert/cmp"
|
|
||||||
"gotest.tools/v3/internal/format"
|
|
||||||
"gotest.tools/v3/internal/source"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RunComparison and return Comparison.Success. If the comparison fails a messages
|
|
||||||
// will be printed using t.Log.
|
|
||||||
func RunComparison(
|
|
||||||
t LogT,
|
|
||||||
argSelector argSelector,
|
|
||||||
f cmp.Comparison,
|
|
||||||
msgAndArgs ...interface{},
|
|
||||||
) bool {
|
|
||||||
if ht, ok := t.(helperT); ok {
|
|
||||||
ht.Helper()
|
|
||||||
}
|
|
||||||
result := f()
|
|
||||||
if result.Success() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
var message string
|
|
||||||
switch typed := result.(type) {
|
|
||||||
case resultWithComparisonArgs:
|
|
||||||
const stackIndex = 3 // Assert/Check, assert, RunComparison
|
|
||||||
args, err := source.CallExprArgs(stackIndex)
|
|
||||||
if err != nil {
|
|
||||||
t.Log(err.Error())
|
|
||||||
}
|
|
||||||
message = typed.FailureMessage(filterPrintableExpr(argSelector(args)))
|
|
||||||
case resultBasic:
|
|
||||||
message = typed.FailureMessage()
|
|
||||||
default:
|
|
||||||
message = fmt.Sprintf("comparison returned invalid Result type: %T", result)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Log(format.WithCustomMessage(failureMessage+message, msgAndArgs...))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type resultWithComparisonArgs interface {
|
|
||||||
FailureMessage(args []ast.Expr) string
|
|
||||||
}
|
|
||||||
|
|
||||||
type resultBasic interface {
|
|
||||||
FailureMessage() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// filterPrintableExpr filters the ast.Expr slice to only include Expr that are
|
|
||||||
// easy to read when printed and contain relevant information to an assertion.
|
|
||||||
//
|
|
||||||
// Ident and SelectorExpr are included because they print nicely and the variable
|
|
||||||
// names may provide additional context to their values.
|
|
||||||
// BasicLit and CompositeLit are excluded because their source is equivalent to
|
|
||||||
// their value, which is already available.
|
|
||||||
// Other types are ignored for now, but could be added if they are relevant.
|
|
||||||
func filterPrintableExpr(args []ast.Expr) []ast.Expr {
|
|
||||||
result := make([]ast.Expr, len(args))
|
|
||||||
for i, arg := range args {
|
|
||||||
if isShortPrintableExpr(arg) {
|
|
||||||
result[i] = arg
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if starExpr, ok := arg.(*ast.StarExpr); ok {
|
|
||||||
result[i] = starExpr.X
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func isShortPrintableExpr(expr ast.Expr) bool {
|
|
||||||
switch expr.(type) {
|
|
||||||
case *ast.Ident, *ast.SelectorExpr, *ast.IndexExpr, *ast.SliceExpr:
|
|
||||||
return true
|
|
||||||
case *ast.BinaryExpr, *ast.UnaryExpr:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
// CallExpr, ParenExpr, TypeAssertExpr, KeyValueExpr, StarExpr
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type argSelector func([]ast.Expr) []ast.Expr
|
|
||||||
|
|
||||||
// ArgsAfterT selects args starting at position 1. Used when the caller has a
|
|
||||||
// testing.T as the first argument, and the args to select should follow it.
|
|
||||||
func ArgsAfterT(args []ast.Expr) []ast.Expr {
|
|
||||||
if len(args) < 1 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return args[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArgsFromComparisonCall selects args from the CallExpression at position 1.
|
|
||||||
// Used when the caller has a testing.T as the first argument, and the args to
|
|
||||||
// select are passed to the cmp.Comparison at position 1.
|
|
||||||
func ArgsFromComparisonCall(args []ast.Expr) []ast.Expr {
|
|
||||||
if len(args) <= 1 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if callExpr, ok := args[1].(*ast.CallExpr); ok {
|
|
||||||
return callExpr.Args
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArgsAtZeroIndex selects args from the CallExpression at position 1.
|
|
||||||
// Used when the caller accepts a single cmp.Comparison argument.
|
|
||||||
func ArgsAtZeroIndex(args []ast.Expr) []ast.Expr {
|
|
||||||
if len(args) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if callExpr, ok := args[0].(*ast.CallExpr); ok {
|
|
||||||
return callExpr.Args
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
27
vendor/gotest.tools/v3/internal/difflib/LICENSE
vendored
27
vendor/gotest.tools/v3/internal/difflib/LICENSE
vendored
@ -1,27 +0,0 @@
|
|||||||
Copyright (c) 2013, Patrick Mezard
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
The names of its contributors may not be used to endorse or promote
|
|
||||||
products derived from this software without specific prior written
|
|
||||||
permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
||||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
||||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
||||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
423
vendor/gotest.tools/v3/internal/difflib/difflib.go
vendored
423
vendor/gotest.tools/v3/internal/difflib/difflib.go
vendored
@ -1,423 +0,0 @@
|
|||||||
/*Package difflib is a partial port of Python difflib module.
|
|
||||||
|
|
||||||
Original source: https://github.com/pmezard/go-difflib
|
|
||||||
|
|
||||||
This file is trimmed to only the parts used by this repository.
|
|
||||||
*/
|
|
||||||
package difflib // import "gotest.tools/v3/internal/difflib"
|
|
||||||
|
|
||||||
func min(a, b int) int {
|
|
||||||
if a < b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func max(a, b int) int {
|
|
||||||
if a > b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match stores line numbers of size of match
|
|
||||||
type Match struct {
|
|
||||||
A int
|
|
||||||
B int
|
|
||||||
Size int
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpCode identifies the type of diff
|
|
||||||
type OpCode struct {
|
|
||||||
Tag byte
|
|
||||||
I1 int
|
|
||||||
I2 int
|
|
||||||
J1 int
|
|
||||||
J2 int
|
|
||||||
}
|
|
||||||
|
|
||||||
// SequenceMatcher compares sequence of strings. The basic
|
|
||||||
// algorithm predates, and is a little fancier than, an algorithm
|
|
||||||
// published in the late 1980's by Ratcliff and Obershelp under the
|
|
||||||
// hyperbolic name "gestalt pattern matching". The basic idea is to find
|
|
||||||
// the longest contiguous matching subsequence that contains no "junk"
|
|
||||||
// elements (R-O doesn't address junk). The same idea is then applied
|
|
||||||
// recursively to the pieces of the sequences to the left and to the right
|
|
||||||
// of the matching subsequence. This does not yield minimal edit
|
|
||||||
// sequences, but does tend to yield matches that "look right" to people.
|
|
||||||
//
|
|
||||||
// SequenceMatcher tries to compute a "human-friendly diff" between two
|
|
||||||
// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
|
|
||||||
// longest *contiguous* & junk-free matching subsequence. That's what
|
|
||||||
// catches peoples' eyes. The Windows(tm) windiff has another interesting
|
|
||||||
// notion, pairing up elements that appear uniquely in each sequence.
|
|
||||||
// That, and the method here, appear to yield more intuitive difference
|
|
||||||
// reports than does diff. This method appears to be the least vulnerable
|
|
||||||
// to synching up on blocks of "junk lines", though (like blank lines in
|
|
||||||
// ordinary text files, or maybe "<P>" lines in HTML files). That may be
|
|
||||||
// because this is the only method of the 3 that has a *concept* of
|
|
||||||
// "junk" <wink>.
|
|
||||||
//
|
|
||||||
// Timing: Basic R-O is cubic time worst case and quadratic time expected
|
|
||||||
// case. SequenceMatcher is quadratic time for the worst case and has
|
|
||||||
// expected-case behavior dependent in a complicated way on how many
|
|
||||||
// elements the sequences have in common; best case time is linear.
|
|
||||||
type SequenceMatcher struct {
|
|
||||||
a []string
|
|
||||||
b []string
|
|
||||||
b2j map[string][]int
|
|
||||||
IsJunk func(string) bool
|
|
||||||
autoJunk bool
|
|
||||||
bJunk map[string]struct{}
|
|
||||||
matchingBlocks []Match
|
|
||||||
fullBCount map[string]int
|
|
||||||
bPopular map[string]struct{}
|
|
||||||
opCodes []OpCode
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMatcher returns a new SequenceMatcher
|
|
||||||
func NewMatcher(a, b []string) *SequenceMatcher {
|
|
||||||
m := SequenceMatcher{autoJunk: true}
|
|
||||||
m.SetSeqs(a, b)
|
|
||||||
return &m
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSeqs sets two sequences to be compared.
|
|
||||||
func (m *SequenceMatcher) SetSeqs(a, b []string) {
|
|
||||||
m.SetSeq1(a)
|
|
||||||
m.SetSeq2(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSeq1 sets the first sequence to be compared. The second sequence to be compared is
|
|
||||||
// not changed.
|
|
||||||
//
|
|
||||||
// SequenceMatcher computes and caches detailed information about the second
|
|
||||||
// sequence, so if you want to compare one sequence S against many sequences,
|
|
||||||
// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
|
|
||||||
// sequences.
|
|
||||||
//
|
|
||||||
// See also SetSeqs() and SetSeq2().
|
|
||||||
func (m *SequenceMatcher) SetSeq1(a []string) {
|
|
||||||
if &a == &m.a {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.a = a
|
|
||||||
m.matchingBlocks = nil
|
|
||||||
m.opCodes = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSeq2 sets the second sequence to be compared. The first sequence to be compared is
|
|
||||||
// not changed.
|
|
||||||
func (m *SequenceMatcher) SetSeq2(b []string) {
|
|
||||||
if &b == &m.b {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.b = b
|
|
||||||
m.matchingBlocks = nil
|
|
||||||
m.opCodes = nil
|
|
||||||
m.fullBCount = nil
|
|
||||||
m.chainB()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SequenceMatcher) chainB() {
|
|
||||||
// Populate line -> index mapping
|
|
||||||
b2j := map[string][]int{}
|
|
||||||
for i, s := range m.b {
|
|
||||||
indices := b2j[s]
|
|
||||||
indices = append(indices, i)
|
|
||||||
b2j[s] = indices
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purge junk elements
|
|
||||||
m.bJunk = map[string]struct{}{}
|
|
||||||
if m.IsJunk != nil {
|
|
||||||
junk := m.bJunk
|
|
||||||
for s := range b2j {
|
|
||||||
if m.IsJunk(s) {
|
|
||||||
junk[s] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for s := range junk {
|
|
||||||
delete(b2j, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purge remaining popular elements
|
|
||||||
popular := map[string]struct{}{}
|
|
||||||
n := len(m.b)
|
|
||||||
if m.autoJunk && n >= 200 {
|
|
||||||
ntest := n/100 + 1
|
|
||||||
for s, indices := range b2j {
|
|
||||||
if len(indices) > ntest {
|
|
||||||
popular[s] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for s := range popular {
|
|
||||||
delete(b2j, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.bPopular = popular
|
|
||||||
m.b2j = b2j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SequenceMatcher) isBJunk(s string) bool {
|
|
||||||
_, ok := m.bJunk[s]
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find longest matching block in a[alo:ahi] and b[blo:bhi].
|
|
||||||
//
|
|
||||||
// If IsJunk is not defined:
|
|
||||||
//
|
|
||||||
// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
|
|
||||||
// alo <= i <= i+k <= ahi
|
|
||||||
// blo <= j <= j+k <= bhi
|
|
||||||
// and for all (i',j',k') meeting those conditions,
|
|
||||||
// k >= k'
|
|
||||||
// i <= i'
|
|
||||||
// and if i == i', j <= j'
|
|
||||||
//
|
|
||||||
// In other words, of all maximal matching blocks, return one that
|
|
||||||
// starts earliest in a, and of all those maximal matching blocks that
|
|
||||||
// start earliest in a, return the one that starts earliest in b.
|
|
||||||
//
|
|
||||||
// If IsJunk is defined, first the longest matching block is
|
|
||||||
// determined as above, but with the additional restriction that no
|
|
||||||
// junk element appears in the block. Then that block is extended as
|
|
||||||
// far as possible by matching (only) junk elements on both sides. So
|
|
||||||
// the resulting block never matches on junk except as identical junk
|
|
||||||
// happens to be adjacent to an "interesting" match.
|
|
||||||
//
|
|
||||||
// If no blocks match, return (alo, blo, 0).
|
|
||||||
func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
|
|
||||||
// CAUTION: stripping common prefix or suffix would be incorrect.
|
|
||||||
// E.g.,
|
|
||||||
// ab
|
|
||||||
// acab
|
|
||||||
// Longest matching block is "ab", but if common prefix is
|
|
||||||
// stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
|
|
||||||
// strip, so ends up claiming that ab is changed to acab by
|
|
||||||
// inserting "ca" in the middle. That's minimal but unintuitive:
|
|
||||||
// "it's obvious" that someone inserted "ac" at the front.
|
|
||||||
// Windiff ends up at the same place as diff, but by pairing up
|
|
||||||
// the unique 'b's and then matching the first two 'a's.
|
|
||||||
besti, bestj, bestsize := alo, blo, 0
|
|
||||||
|
|
||||||
// find longest junk-free match
|
|
||||||
// during an iteration of the loop, j2len[j] = length of longest
|
|
||||||
// junk-free match ending with a[i-1] and b[j]
|
|
||||||
j2len := map[int]int{}
|
|
||||||
for i := alo; i != ahi; i++ {
|
|
||||||
// look at all instances of a[i] in b; note that because
|
|
||||||
// b2j has no junk keys, the loop is skipped if a[i] is junk
|
|
||||||
newj2len := map[int]int{}
|
|
||||||
for _, j := range m.b2j[m.a[i]] {
|
|
||||||
// a[i] matches b[j]
|
|
||||||
if j < blo {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if j >= bhi {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
k := j2len[j-1] + 1
|
|
||||||
newj2len[j] = k
|
|
||||||
if k > bestsize {
|
|
||||||
besti, bestj, bestsize = i-k+1, j-k+1, k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
j2len = newj2len
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extend the best by non-junk elements on each end. In particular,
|
|
||||||
// "popular" non-junk elements aren't in b2j, which greatly speeds
|
|
||||||
// the inner loop above, but also means "the best" match so far
|
|
||||||
// doesn't contain any junk *or* popular non-junk elements.
|
|
||||||
for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
|
|
||||||
m.a[besti-1] == m.b[bestj-1] {
|
|
||||||
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
|
|
||||||
}
|
|
||||||
for besti+bestsize < ahi && bestj+bestsize < bhi &&
|
|
||||||
!m.isBJunk(m.b[bestj+bestsize]) &&
|
|
||||||
m.a[besti+bestsize] == m.b[bestj+bestsize] {
|
|
||||||
bestsize += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we have a wholly interesting match (albeit possibly
|
|
||||||
// empty!), we may as well suck up the matching junk on each
|
|
||||||
// side of it too. Can't think of a good reason not to, and it
|
|
||||||
// saves post-processing the (possibly considerable) expense of
|
|
||||||
// figuring out what to do with it. In the case of an empty
|
|
||||||
// interesting match, this is clearly the right thing to do,
|
|
||||||
// because no other kind of match is possible in the regions.
|
|
||||||
for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
|
|
||||||
m.a[besti-1] == m.b[bestj-1] {
|
|
||||||
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
|
|
||||||
}
|
|
||||||
for besti+bestsize < ahi && bestj+bestsize < bhi &&
|
|
||||||
m.isBJunk(m.b[bestj+bestsize]) &&
|
|
||||||
m.a[besti+bestsize] == m.b[bestj+bestsize] {
|
|
||||||
bestsize += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return Match{A: besti, B: bestj, Size: bestsize}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMatchingBlocks returns a list of triples describing matching subsequences.
|
|
||||||
//
|
|
||||||
// Each triple is of the form (i, j, n), and means that
|
|
||||||
// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
|
|
||||||
// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
|
|
||||||
// adjacent triples in the list, and the second is not the last triple in the
|
|
||||||
// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
|
|
||||||
// adjacent equal blocks.
|
|
||||||
//
|
|
||||||
// The last triple is a dummy, (len(a), len(b), 0), and is the only
|
|
||||||
// triple with n==0.
|
|
||||||
func (m *SequenceMatcher) GetMatchingBlocks() []Match {
|
|
||||||
if m.matchingBlocks != nil {
|
|
||||||
return m.matchingBlocks
|
|
||||||
}
|
|
||||||
|
|
||||||
var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
|
|
||||||
matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
|
|
||||||
match := m.findLongestMatch(alo, ahi, blo, bhi)
|
|
||||||
i, j, k := match.A, match.B, match.Size
|
|
||||||
if match.Size > 0 {
|
|
||||||
if alo < i && blo < j {
|
|
||||||
matched = matchBlocks(alo, i, blo, j, matched)
|
|
||||||
}
|
|
||||||
matched = append(matched, match)
|
|
||||||
if i+k < ahi && j+k < bhi {
|
|
||||||
matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matched
|
|
||||||
}
|
|
||||||
matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
|
|
||||||
|
|
||||||
// It's possible that we have adjacent equal blocks in the
|
|
||||||
// matching_blocks list now.
|
|
||||||
nonAdjacent := []Match{}
|
|
||||||
i1, j1, k1 := 0, 0, 0
|
|
||||||
for _, b := range matched {
|
|
||||||
// Is this block adjacent to i1, j1, k1?
|
|
||||||
i2, j2, k2 := b.A, b.B, b.Size
|
|
||||||
if i1+k1 == i2 && j1+k1 == j2 {
|
|
||||||
// Yes, so collapse them -- this just increases the length of
|
|
||||||
// the first block by the length of the second, and the first
|
|
||||||
// block so lengthened remains the block to compare against.
|
|
||||||
k1 += k2
|
|
||||||
} else {
|
|
||||||
// Not adjacent. Remember the first block (k1==0 means it's
|
|
||||||
// the dummy we started with), and make the second block the
|
|
||||||
// new block to compare against.
|
|
||||||
if k1 > 0 {
|
|
||||||
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
|
|
||||||
}
|
|
||||||
i1, j1, k1 = i2, j2, k2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if k1 > 0 {
|
|
||||||
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
|
|
||||||
}
|
|
||||||
|
|
||||||
nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
|
|
||||||
m.matchingBlocks = nonAdjacent
|
|
||||||
return m.matchingBlocks
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOpCodes returns a list of 5-tuples describing how to turn a into b.
|
|
||||||
//
|
|
||||||
// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
|
|
||||||
// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
|
|
||||||
// tuple preceding it, and likewise for j1 == the previous j2.
|
|
||||||
//
|
|
||||||
// The tags are characters, with these meanings:
|
|
||||||
//
|
|
||||||
// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2]
|
|
||||||
//
|
|
||||||
// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case.
|
|
||||||
//
|
|
||||||
// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
|
|
||||||
//
|
|
||||||
// 'e' (equal): a[i1:i2] == b[j1:j2]
|
|
||||||
func (m *SequenceMatcher) GetOpCodes() []OpCode {
|
|
||||||
if m.opCodes != nil {
|
|
||||||
return m.opCodes
|
|
||||||
}
|
|
||||||
i, j := 0, 0
|
|
||||||
matching := m.GetMatchingBlocks()
|
|
||||||
opCodes := make([]OpCode, 0, len(matching))
|
|
||||||
for _, m := range matching {
|
|
||||||
// invariant: we've pumped out correct diffs to change
|
|
||||||
// a[:i] into b[:j], and the next matching block is
|
|
||||||
// a[ai:ai+size] == b[bj:bj+size]. So we need to pump
|
|
||||||
// out a diff to change a[i:ai] into b[j:bj], pump out
|
|
||||||
// the matching block, and move (i,j) beyond the match
|
|
||||||
ai, bj, size := m.A, m.B, m.Size
|
|
||||||
tag := byte(0)
|
|
||||||
if i < ai && j < bj {
|
|
||||||
tag = 'r'
|
|
||||||
} else if i < ai {
|
|
||||||
tag = 'd'
|
|
||||||
} else if j < bj {
|
|
||||||
tag = 'i'
|
|
||||||
}
|
|
||||||
if tag > 0 {
|
|
||||||
opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
|
|
||||||
}
|
|
||||||
i, j = ai+size, bj+size
|
|
||||||
// the list of matching blocks is terminated by a
|
|
||||||
// sentinel with size 0
|
|
||||||
if size > 0 {
|
|
||||||
opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.opCodes = opCodes
|
|
||||||
return m.opCodes
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGroupedOpCodes isolates change clusters by eliminating ranges with no changes.
|
|
||||||
//
|
|
||||||
// Return a generator of groups with up to n lines of context.
|
|
||||||
// Each group is in the same format as returned by GetOpCodes().
|
|
||||||
func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
|
|
||||||
if n < 0 {
|
|
||||||
n = 3
|
|
||||||
}
|
|
||||||
codes := m.GetOpCodes()
|
|
||||||
if len(codes) == 0 {
|
|
||||||
codes = []OpCode{{'e', 0, 1, 0, 1}}
|
|
||||||
}
|
|
||||||
// Fixup leading and trailing groups if they show no changes.
|
|
||||||
if codes[0].Tag == 'e' {
|
|
||||||
c := codes[0]
|
|
||||||
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
|
||||||
codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
|
|
||||||
}
|
|
||||||
if codes[len(codes)-1].Tag == 'e' {
|
|
||||||
c := codes[len(codes)-1]
|
|
||||||
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
|
||||||
codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
|
|
||||||
}
|
|
||||||
nn := n + n
|
|
||||||
groups := [][]OpCode{}
|
|
||||||
group := []OpCode{}
|
|
||||||
for _, c := range codes {
|
|
||||||
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
|
||||||
// End the current group and start a new one whenever
|
|
||||||
// there is a large range with no changes.
|
|
||||||
if c.Tag == 'e' && i2-i1 > nn {
|
|
||||||
group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
|
|
||||||
j1, min(j2, j1+n)})
|
|
||||||
groups = append(groups, group)
|
|
||||||
group = []OpCode{}
|
|
||||||
i1, j1 = max(i1, i2-n), max(j1, j2-n)
|
|
||||||
}
|
|
||||||
group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
|
|
||||||
}
|
|
||||||
if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
|
|
||||||
groups = append(groups, group)
|
|
||||||
}
|
|
||||||
return groups
|
|
||||||
}
|
|
161
vendor/gotest.tools/v3/internal/format/diff.go
vendored
161
vendor/gotest.tools/v3/internal/format/diff.go
vendored
@ -1,161 +0,0 @@
|
|||||||
package format
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"gotest.tools/v3/internal/difflib"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
contextLines = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
// DiffConfig for a unified diff
|
|
||||||
type DiffConfig struct {
|
|
||||||
A string
|
|
||||||
B string
|
|
||||||
From string
|
|
||||||
To string
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnifiedDiff is a modified version of difflib.WriteUnifiedDiff with better
|
|
||||||
// support for showing the whitespace differences.
|
|
||||||
func UnifiedDiff(conf DiffConfig) string {
|
|
||||||
a := strings.SplitAfter(conf.A, "\n")
|
|
||||||
b := strings.SplitAfter(conf.B, "\n")
|
|
||||||
groups := difflib.NewMatcher(a, b).GetGroupedOpCodes(contextLines)
|
|
||||||
if len(groups) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
writeFormat := func(format string, args ...interface{}) {
|
|
||||||
buf.WriteString(fmt.Sprintf(format, args...))
|
|
||||||
}
|
|
||||||
writeLine := func(prefix string, s string) {
|
|
||||||
buf.WriteString(prefix + s)
|
|
||||||
}
|
|
||||||
if hasWhitespaceDiffLines(groups, a, b) {
|
|
||||||
writeLine = visibleWhitespaceLine(writeLine)
|
|
||||||
}
|
|
||||||
formatHeader(writeFormat, conf)
|
|
||||||
for _, group := range groups {
|
|
||||||
formatRangeLine(writeFormat, group)
|
|
||||||
for _, opCode := range group {
|
|
||||||
in, out := a[opCode.I1:opCode.I2], b[opCode.J1:opCode.J2]
|
|
||||||
switch opCode.Tag {
|
|
||||||
case 'e':
|
|
||||||
formatLines(writeLine, " ", in)
|
|
||||||
case 'r':
|
|
||||||
formatLines(writeLine, "-", in)
|
|
||||||
formatLines(writeLine, "+", out)
|
|
||||||
case 'd':
|
|
||||||
formatLines(writeLine, "-", in)
|
|
||||||
case 'i':
|
|
||||||
formatLines(writeLine, "+", out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasWhitespaceDiffLines returns true if any diff groups is only different
|
|
||||||
// because of whitespace characters.
|
|
||||||
func hasWhitespaceDiffLines(groups [][]difflib.OpCode, a, b []string) bool {
|
|
||||||
for _, group := range groups {
|
|
||||||
in, out := new(bytes.Buffer), new(bytes.Buffer)
|
|
||||||
for _, opCode := range group {
|
|
||||||
if opCode.Tag == 'e' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, line := range a[opCode.I1:opCode.I2] {
|
|
||||||
in.WriteString(line)
|
|
||||||
}
|
|
||||||
for _, line := range b[opCode.J1:opCode.J2] {
|
|
||||||
out.WriteString(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if removeWhitespace(in.String()) == removeWhitespace(out.String()) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeWhitespace(s string) string {
|
|
||||||
var result []rune
|
|
||||||
for _, r := range s {
|
|
||||||
if !unicode.IsSpace(r) {
|
|
||||||
result = append(result, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return string(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func visibleWhitespaceLine(ws func(string, string)) func(string, string) {
|
|
||||||
mapToVisibleSpace := func(r rune) rune {
|
|
||||||
switch r {
|
|
||||||
case '\n':
|
|
||||||
case ' ':
|
|
||||||
return '·'
|
|
||||||
case '\t':
|
|
||||||
return '▷'
|
|
||||||
case '\v':
|
|
||||||
return '▽'
|
|
||||||
case '\r':
|
|
||||||
return '↵'
|
|
||||||
case '\f':
|
|
||||||
return '↓'
|
|
||||||
default:
|
|
||||||
if unicode.IsSpace(r) {
|
|
||||||
return '<27>'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
return func(prefix, s string) {
|
|
||||||
ws(prefix, strings.Map(mapToVisibleSpace, s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatHeader(wf func(string, ...interface{}), conf DiffConfig) {
|
|
||||||
if conf.From != "" || conf.To != "" {
|
|
||||||
wf("--- %s\n", conf.From)
|
|
||||||
wf("+++ %s\n", conf.To)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatRangeLine(wf func(string, ...interface{}), group []difflib.OpCode) {
|
|
||||||
first, last := group[0], group[len(group)-1]
|
|
||||||
range1 := formatRangeUnified(first.I1, last.I2)
|
|
||||||
range2 := formatRangeUnified(first.J1, last.J2)
|
|
||||||
wf("@@ -%s +%s @@\n", range1, range2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert range to the "ed" format
|
|
||||||
func formatRangeUnified(start, stop int) string {
|
|
||||||
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
|
||||||
beginning := start + 1 // lines start numbering with one
|
|
||||||
length := stop - start
|
|
||||||
if length == 1 {
|
|
||||||
return fmt.Sprintf("%d", beginning)
|
|
||||||
}
|
|
||||||
if length == 0 {
|
|
||||||
beginning-- // empty ranges begin at line just before the range
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%d,%d", beginning, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatLines(writeLine func(string, string), prefix string, lines []string) {
|
|
||||||
for _, line := range lines {
|
|
||||||
writeLine(prefix, line)
|
|
||||||
}
|
|
||||||
// Add a newline if the last line is missing one so that the diff displays
|
|
||||||
// properly.
|
|
||||||
if !strings.HasSuffix(lines[len(lines)-1], "\n") {
|
|
||||||
writeLine("", "\n")
|
|
||||||
}
|
|
||||||
}
|
|
27
vendor/gotest.tools/v3/internal/format/format.go
vendored
27
vendor/gotest.tools/v3/internal/format/format.go
vendored
@ -1,27 +0,0 @@
|
|||||||
package format // import "gotest.tools/v3/internal/format"
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
// Message accepts a msgAndArgs varargs and formats it using fmt.Sprintf
|
|
||||||
func Message(msgAndArgs ...interface{}) string {
|
|
||||||
switch len(msgAndArgs) {
|
|
||||||
case 0:
|
|
||||||
return ""
|
|
||||||
case 1:
|
|
||||||
return fmt.Sprintf("%v", msgAndArgs[0])
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithCustomMessage accepts one or two messages and formats them appropriately
|
|
||||||
func WithCustomMessage(source string, msgAndArgs ...interface{}) string {
|
|
||||||
custom := Message(msgAndArgs...)
|
|
||||||
switch {
|
|
||||||
case custom == "":
|
|
||||||
return source
|
|
||||||
case source == "":
|
|
||||||
return custom
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s: %s", source, custom)
|
|
||||||
}
|
|
53
vendor/gotest.tools/v3/internal/source/defers.go
vendored
53
vendor/gotest.tools/v3/internal/source/defers.go
vendored
@ -1,53 +0,0 @@
|
|||||||
package source
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go/ast"
|
|
||||||
"go/token"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func scanToDeferLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
|
|
||||||
var matchedNode ast.Node
|
|
||||||
ast.Inspect(node, func(node ast.Node) bool {
|
|
||||||
switch {
|
|
||||||
case node == nil || matchedNode != nil:
|
|
||||||
return false
|
|
||||||
case fileset.Position(node.End()).Line == lineNum:
|
|
||||||
if funcLit, ok := node.(*ast.FuncLit); ok {
|
|
||||||
matchedNode = funcLit
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
debug("defer line node: %s", debugFormatNode{matchedNode})
|
|
||||||
return matchedNode
|
|
||||||
}
|
|
||||||
|
|
||||||
func guessDefer(node ast.Node) (ast.Node, error) {
|
|
||||||
defers := collectDefers(node)
|
|
||||||
switch len(defers) {
|
|
||||||
case 0:
|
|
||||||
return nil, errors.New("failed to expression in defer")
|
|
||||||
case 1:
|
|
||||||
return defers[0].Call, nil
|
|
||||||
default:
|
|
||||||
return nil, errors.Errorf(
|
|
||||||
"ambiguous call expression: multiple (%d) defers in call block",
|
|
||||||
len(defers))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectDefers(node ast.Node) []*ast.DeferStmt {
|
|
||||||
var defers []*ast.DeferStmt
|
|
||||||
ast.Inspect(node, func(node ast.Node) bool {
|
|
||||||
if d, ok := node.(*ast.DeferStmt); ok {
|
|
||||||
defers = append(defers, d)
|
|
||||||
debug("defer: %s", debugFormatNode{d})
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return defers
|
|
||||||
}
|
|
181
vendor/gotest.tools/v3/internal/source/source.go
vendored
181
vendor/gotest.tools/v3/internal/source/source.go
vendored
@ -1,181 +0,0 @@
|
|||||||
package source // import "gotest.tools/v3/internal/source"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
|
||||||
"go/format"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const baseStackIndex = 1
|
|
||||||
|
|
||||||
// FormattedCallExprArg returns the argument from an ast.CallExpr at the
|
|
||||||
// index in the call stack. The argument is formatted using FormatNode.
|
|
||||||
func FormattedCallExprArg(stackIndex int, argPos int) (string, error) {
|
|
||||||
args, err := CallExprArgs(stackIndex + 1)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if argPos >= len(args) {
|
|
||||||
return "", errors.New("failed to find expression")
|
|
||||||
}
|
|
||||||
return FormatNode(args[argPos])
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallExprArgs returns the ast.Expr slice for the args of an ast.CallExpr at
|
|
||||||
// the index in the call stack.
|
|
||||||
func CallExprArgs(stackIndex int) ([]ast.Expr, error) {
|
|
||||||
_, filename, lineNum, ok := runtime.Caller(baseStackIndex + stackIndex)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("failed to get call stack")
|
|
||||||
}
|
|
||||||
debug("call stack position: %s:%d", filename, lineNum)
|
|
||||||
|
|
||||||
node, err := getNodeAtLine(filename, lineNum)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
debug("found node: %s", debugFormatNode{node})
|
|
||||||
|
|
||||||
return getCallExprArgs(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNodeAtLine(filename string, lineNum int) (ast.Node, error) {
|
|
||||||
fileset := token.NewFileSet()
|
|
||||||
astFile, err := parser.ParseFile(fileset, filename, nil, parser.AllErrors)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "failed to parse source file: %s", filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
if node := scanToLine(fileset, astFile, lineNum); node != nil {
|
|
||||||
return node, nil
|
|
||||||
}
|
|
||||||
if node := scanToDeferLine(fileset, astFile, lineNum); node != nil {
|
|
||||||
node, err := guessDefer(node)
|
|
||||||
if err != nil || node != nil {
|
|
||||||
return node, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, errors.Errorf(
|
|
||||||
"failed to find an expression on line %d in %s", lineNum, filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func scanToLine(fileset *token.FileSet, node ast.Node, lineNum int) ast.Node {
|
|
||||||
var matchedNode ast.Node
|
|
||||||
ast.Inspect(node, func(node ast.Node) bool {
|
|
||||||
switch {
|
|
||||||
case node == nil || matchedNode != nil:
|
|
||||||
return false
|
|
||||||
case nodePosition(fileset, node).Line == lineNum:
|
|
||||||
matchedNode = node
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return matchedNode
|
|
||||||
}
|
|
||||||
|
|
||||||
// In golang 1.9 the line number changed from being the line where the statement
|
|
||||||
// ended to the line where the statement began.
|
|
||||||
func nodePosition(fileset *token.FileSet, node ast.Node) token.Position {
|
|
||||||
if goVersionBefore19 {
|
|
||||||
return fileset.Position(node.End())
|
|
||||||
}
|
|
||||||
return fileset.Position(node.Pos())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GoVersionLessThan returns true if runtime.Version() is semantically less than
|
|
||||||
// version major.minor. Returns false if a release version can not be parsed from
|
|
||||||
// runtime.Version().
|
|
||||||
func GoVersionLessThan(major, minor int64) bool {
|
|
||||||
version := runtime.Version()
|
|
||||||
// not a release version
|
|
||||||
if !strings.HasPrefix(version, "go") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
version = strings.TrimPrefix(version, "go")
|
|
||||||
parts := strings.Split(version, ".")
|
|
||||||
if len(parts) < 2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
rMajor, err := strconv.ParseInt(parts[0], 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if rMajor != major {
|
|
||||||
return rMajor < major
|
|
||||||
}
|
|
||||||
rMinor, err := strconv.ParseInt(parts[1], 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return rMinor < minor
|
|
||||||
}
|
|
||||||
|
|
||||||
var goVersionBefore19 = GoVersionLessThan(1, 9)
|
|
||||||
|
|
||||||
func getCallExprArgs(node ast.Node) ([]ast.Expr, error) {
|
|
||||||
visitor := &callExprVisitor{}
|
|
||||||
ast.Walk(visitor, node)
|
|
||||||
if visitor.expr == nil {
|
|
||||||
return nil, errors.New("failed to find call expression")
|
|
||||||
}
|
|
||||||
debug("callExpr: %s", debugFormatNode{visitor.expr})
|
|
||||||
return visitor.expr.Args, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type callExprVisitor struct {
|
|
||||||
expr *ast.CallExpr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *callExprVisitor) Visit(node ast.Node) ast.Visitor {
|
|
||||||
if v.expr != nil || node == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
debug("visit: %s", debugFormatNode{node})
|
|
||||||
|
|
||||||
switch typed := node.(type) {
|
|
||||||
case *ast.CallExpr:
|
|
||||||
v.expr = typed
|
|
||||||
return nil
|
|
||||||
case *ast.DeferStmt:
|
|
||||||
ast.Walk(v, typed.Call.Fun)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatNode using go/format.Node and return the result as a string
|
|
||||||
func FormatNode(node ast.Node) (string, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
err := format.Node(buf, token.NewFileSet(), node)
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
|
|
||||||
var debugEnabled = os.Getenv("GOTESTTOOLS_DEBUG") != ""
|
|
||||||
|
|
||||||
func debug(format string, args ...interface{}) {
|
|
||||||
if debugEnabled {
|
|
||||||
fmt.Fprintf(os.Stderr, "DEBUG: "+format+"\n", args...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type debugFormatNode struct {
|
|
||||||
ast.Node
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n debugFormatNode) String() string {
|
|
||||||
out, err := FormatNode(n.Node)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Sprintf("failed to format %s: %s", n.Node, err)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("(%T) %s", n.Node, out)
|
|
||||||
}
|
|
13
vendor/modules.txt
vendored
13
vendor/modules.txt
vendored
@ -243,7 +243,6 @@ github.com/golang/protobuf/ptypes/wrappers
|
|||||||
# github.com/google/go-cmp v0.5.6
|
# github.com/google/go-cmp v0.5.6
|
||||||
## explicit; go 1.8
|
## explicit; go 1.8
|
||||||
github.com/google/go-cmp/cmp
|
github.com/google/go-cmp/cmp
|
||||||
github.com/google/go-cmp/cmp/cmpopts
|
|
||||||
github.com/google/go-cmp/cmp/internal/diff
|
github.com/google/go-cmp/cmp/internal/diff
|
||||||
github.com/google/go-cmp/cmp/internal/flags
|
github.com/google/go-cmp/cmp/internal/flags
|
||||||
github.com/google/go-cmp/cmp/internal/function
|
github.com/google/go-cmp/cmp/internal/function
|
||||||
@ -513,10 +512,6 @@ golang.org/x/text/unicode/norm
|
|||||||
# golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
# golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
|
||||||
## explicit
|
## explicit
|
||||||
golang.org/x/time/rate
|
golang.org/x/time/rate
|
||||||
# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
|
||||||
## explicit; go 1.11
|
|
||||||
golang.org/x/xerrors
|
|
||||||
golang.org/x/xerrors/internal
|
|
||||||
# google.golang.org/appengine v1.6.7
|
# google.golang.org/appengine v1.6.7
|
||||||
## explicit; go 1.11
|
## explicit; go 1.11
|
||||||
google.golang.org/appengine/internal
|
google.golang.org/appengine/internal
|
||||||
@ -633,14 +628,6 @@ gopkg.in/yaml.v2
|
|||||||
# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
# gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||||
## explicit
|
## explicit
|
||||||
gopkg.in/yaml.v3
|
gopkg.in/yaml.v3
|
||||||
# gotest.tools/v3 v3.0.3
|
|
||||||
## explicit; go 1.11
|
|
||||||
gotest.tools/v3/assert
|
|
||||||
gotest.tools/v3/assert/cmp
|
|
||||||
gotest.tools/v3/internal/assert
|
|
||||||
gotest.tools/v3/internal/difflib
|
|
||||||
gotest.tools/v3/internal/format
|
|
||||||
gotest.tools/v3/internal/source
|
|
||||||
# k8s.io/api v0.22.5
|
# k8s.io/api v0.22.5
|
||||||
## explicit; go 1.16
|
## explicit; go 1.16
|
||||||
k8s.io/api/authentication/v1
|
k8s.io/api/authentication/v1
|
||||||
|
Loading…
Reference in New Issue
Block a user