mirror of https://github.com/docker/compose.git
Add a CliSuite for cli unit tests
Makes writing unit tests for commands quite easier
This commit is contained in:
parent
fe36c49246
commit
8495500aa2
|
@ -1,5 +1,5 @@
|
||||||
# syntax = docker/dockerfile:experimental
|
# syntax = docker/dockerfile:experimental
|
||||||
ARG GO_VERSION=1.14.3-alpine3.11
|
ARG GO_VERSION=1.14.3-alpine
|
||||||
|
|
||||||
FROM golang:${GO_VERSION} AS base
|
FROM golang:${GO_VERSION} AS base
|
||||||
ARG TARGET_OS=unknown
|
ARG TARGET_OS=unknown
|
||||||
|
@ -7,7 +7,7 @@ ARG TARGET_ARCH=unknown
|
||||||
ARG PWD=/api
|
ARG PWD=/api
|
||||||
ENV GO111MODULE=on
|
ENV GO111MODULE=on
|
||||||
|
|
||||||
RUN apk update && apk add docker make
|
RUN apk update && apk add -U docker make
|
||||||
|
|
||||||
WORKDIR ${PWD}
|
WORKDIR ${PWD}
|
||||||
ADD go.* ${PWD}
|
ADD go.* ${PWD}
|
||||||
|
|
|
@ -1,76 +1,23 @@
|
||||||
package context
|
package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"gotest.tools/v3/golden"
|
"gotest.tools/v3/golden"
|
||||||
|
|
||||||
apicontext "github.com/docker/api/context"
|
"github.com/docker/api/tests/framework"
|
||||||
"github.com/docker/api/context/store"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ContextSuite struct {
|
type ContextSuite struct {
|
||||||
suite.Suite
|
framework.CliSuite
|
||||||
ctx context.Context
|
|
||||||
writer *os.File
|
|
||||||
reader *os.File
|
|
||||||
originalStdout *os.File
|
|
||||||
storeRoot string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sut *ContextSuite) BeforeTest(suiteName, testName string) {
|
|
||||||
ctx := context.Background()
|
|
||||||
ctx = apicontext.WithCurrentContext(ctx, "example")
|
|
||||||
dir, err := ioutil.TempDir("", "store")
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
s, err := store.New(
|
|
||||||
store.WithRoot(dir),
|
|
||||||
)
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
|
|
||||||
err = s.Create("example", store.TypedContext{
|
|
||||||
Type: "example",
|
|
||||||
})
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
|
|
||||||
sut.storeRoot = dir
|
|
||||||
|
|
||||||
ctx = store.WithContextStore(ctx, s)
|
|
||||||
sut.ctx = ctx
|
|
||||||
|
|
||||||
sut.originalStdout = os.Stdout
|
|
||||||
r, w, err := os.Pipe()
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
|
|
||||||
os.Stdout = w
|
|
||||||
sut.writer = w
|
|
||||||
sut.reader = r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sut *ContextSuite) getStdOut() string {
|
|
||||||
err := sut.writer.Close()
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
|
|
||||||
out, _ := ioutil.ReadAll(sut.reader)
|
|
||||||
|
|
||||||
return string(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sut *ContextSuite) AfterTest(suiteName, testName string) {
|
|
||||||
os.Stdout = sut.originalStdout
|
|
||||||
err := os.RemoveAll(sut.storeRoot)
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sut *ContextSuite) TestLs() {
|
func (sut *ContextSuite) TestLs() {
|
||||||
err := runList(sut.ctx)
|
err := runList(sut.Context())
|
||||||
require.Nil(sut.T(), err)
|
require.Nil(sut.T(), err)
|
||||||
golden.Assert(sut.T(), sut.getStdOut(), "ls-out.golden")
|
golden.Assert(sut.T(), sut.GetStdOut(), "ls-out.golden")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPs(t *testing.T) {
|
func TestPs(t *testing.T) {
|
||||||
|
|
|
@ -1,72 +1,18 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"gotest.tools/v3/golden"
|
"gotest.tools/v3/golden"
|
||||||
|
|
||||||
apicontext "github.com/docker/api/context"
|
|
||||||
"github.com/docker/api/context/store"
|
|
||||||
_ "github.com/docker/api/example"
|
_ "github.com/docker/api/example"
|
||||||
|
"github.com/docker/api/tests/framework"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PsSuite struct {
|
type PsSuite struct {
|
||||||
suite.Suite
|
framework.CliSuite
|
||||||
ctx context.Context
|
|
||||||
writer *os.File
|
|
||||||
reader *os.File
|
|
||||||
originalStdout *os.File
|
|
||||||
storeRoot string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sut *PsSuite) BeforeTest(suiteName, testName string) {
|
|
||||||
ctx := context.Background()
|
|
||||||
ctx = apicontext.WithCurrentContext(ctx, "example")
|
|
||||||
dir, err := ioutil.TempDir("", "store")
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
s, err := store.New(
|
|
||||||
store.WithRoot(dir),
|
|
||||||
)
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
|
|
||||||
err = s.Create("example", store.TypedContext{
|
|
||||||
Type: "example",
|
|
||||||
})
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
|
|
||||||
sut.storeRoot = dir
|
|
||||||
|
|
||||||
ctx = store.WithContextStore(ctx, s)
|
|
||||||
sut.ctx = ctx
|
|
||||||
|
|
||||||
sut.originalStdout = os.Stdout
|
|
||||||
r, w, err := os.Pipe()
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
|
|
||||||
os.Stdout = w
|
|
||||||
sut.writer = w
|
|
||||||
sut.reader = r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sut *PsSuite) getStdOut() string {
|
|
||||||
err := sut.writer.Close()
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
|
|
||||||
out, _ := ioutil.ReadAll(sut.reader)
|
|
||||||
|
|
||||||
return string(out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sut *PsSuite) AfterTest(suiteName, testName string) {
|
|
||||||
os.Stdout = sut.originalStdout
|
|
||||||
err := os.RemoveAll(sut.storeRoot)
|
|
||||||
require.Nil(sut.T(), err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sut *PsSuite) TestPs() {
|
func (sut *PsSuite) TestPs() {
|
||||||
|
@ -74,10 +20,10 @@ func (sut *PsSuite) TestPs() {
|
||||||
quiet: false,
|
quiet: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := runPs(sut.ctx, opts)
|
err := runPs(sut.Context(), opts)
|
||||||
assert.Nil(sut.T(), err)
|
require.Nil(sut.T(), err)
|
||||||
|
|
||||||
golden.Assert(sut.T(), sut.getStdOut(), "ps-out.golden")
|
golden.Assert(sut.T(), sut.GetStdOut(), "ps-out.golden")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sut *PsSuite) TestPsQuiet() {
|
func (sut *PsSuite) TestPsQuiet() {
|
||||||
|
@ -85,10 +31,10 @@ func (sut *PsSuite) TestPsQuiet() {
|
||||||
quiet: true,
|
quiet: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := runPs(sut.ctx, opts)
|
err := runPs(sut.Context(), opts)
|
||||||
assert.Nil(sut.T(), err)
|
require.Nil(sut.T(), err)
|
||||||
|
|
||||||
golden.Assert(sut.T(), sut.getStdOut(), "ps-out-quiet.golden")
|
golden.Assert(sut.T(), sut.GetStdOut(), "ps-out-quiet.golden")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPs(t *testing.T) {
|
func TestPs(t *testing.T) {
|
||||||
|
|
|
@ -146,12 +146,12 @@ func read(meta string, getter func() interface{}) (*Metadata, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var um untypedMetadata
|
var um untypedMetadata
|
||||||
if err := marshalTyped(bytes, &um); err != nil {
|
if err := json.Unmarshal(bytes, &um); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var uc untypedContext
|
var uc untypedContext
|
||||||
if err := marshalTyped(um.Metadata, &uc); err != nil {
|
if err := json.Unmarshal(um.Metadata, &uc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if uc.Type == "" {
|
if uc.Type == "" {
|
||||||
|
@ -178,10 +178,6 @@ func read(meta string, getter func() interface{}) (*Metadata, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalTyped(in []byte, val interface{}) error {
|
|
||||||
return json.Unmarshal(in, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(payload []byte, getter func() interface{}) (interface{}, error) {
|
func parse(payload []byte, getter func() interface{}) (interface{}, error) {
|
||||||
if getter == nil {
|
if getter == nil {
|
||||||
var res map[string]interface{}
|
var res map[string]interface{}
|
||||||
|
@ -266,7 +262,7 @@ func (s *store) List() ([]*Metadata, error) {
|
||||||
|
|
||||||
// The default context is not stored in the store, it is in-memory only
|
// The default context is not stored in the store, it is in-memory only
|
||||||
// so we need a special case for it.
|
// so we need a special case for it.
|
||||||
dockerDefault, err := dockerGefaultContext()
|
dockerDefault, err := dockerDefaultContext()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ type endpoint struct {
|
||||||
DefaultNamespace string
|
DefaultNamespace string
|
||||||
}
|
}
|
||||||
|
|
||||||
func dockerGefaultContext() (*Metadata, error) {
|
func dockerDefaultContext() (*Metadata, error) {
|
||||||
cmd := exec.Command("docker", "context", "inspect", "default")
|
cmd := exec.Command("docker", "context", "inspect", "default")
|
||||||
var stdout bytes.Buffer
|
var stdout bytes.Buffer
|
||||||
cmd.Stdout = &stdout
|
cmd.Stdout = &stdout
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDefaultContext(t *testing.T) {
|
func TestDefaultContext(t *testing.T) {
|
||||||
s, err := dockerGefaultContext()
|
s, err := dockerDefaultContext()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "default", s.Name)
|
assert.Equal(t, "default", s.Name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package framework
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
apicontext "github.com/docker/api/context"
|
||||||
|
"github.com/docker/api/context/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CliSuite is a helper struct that creates a configured context
|
||||||
|
// and captures the output of a command. it should be used in the
|
||||||
|
// same way as testify.suite.Suite
|
||||||
|
type CliSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
ctx context.Context
|
||||||
|
writer *os.File
|
||||||
|
reader *os.File
|
||||||
|
OriginalStdout *os.File
|
||||||
|
storeRoot string
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeTest is called by testify.suite
|
||||||
|
func (sut *CliSuite) BeforeTest(suiteName, testName string) {
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx = apicontext.WithCurrentContext(ctx, "example")
|
||||||
|
dir, err := ioutil.TempDir("", "store")
|
||||||
|
require.Nil(sut.T(), err)
|
||||||
|
s, err := store.New(
|
||||||
|
store.WithRoot(dir),
|
||||||
|
)
|
||||||
|
require.Nil(sut.T(), err)
|
||||||
|
|
||||||
|
err = s.Create("example", store.TypedContext{
|
||||||
|
Type: "example",
|
||||||
|
})
|
||||||
|
require.Nil(sut.T(), err)
|
||||||
|
|
||||||
|
sut.storeRoot = dir
|
||||||
|
|
||||||
|
ctx = store.WithContextStore(ctx, s)
|
||||||
|
sut.ctx = ctx
|
||||||
|
|
||||||
|
sut.OriginalStdout = os.Stdout
|
||||||
|
r, w, err := os.Pipe()
|
||||||
|
require.Nil(sut.T(), err)
|
||||||
|
|
||||||
|
os.Stdout = w
|
||||||
|
sut.writer = w
|
||||||
|
sut.reader = r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context returns a configured context
|
||||||
|
func (sut *CliSuite) Context() context.Context {
|
||||||
|
return sut.ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStdOut returns the output of the command
|
||||||
|
func (sut *CliSuite) GetStdOut() string {
|
||||||
|
err := sut.writer.Close()
|
||||||
|
require.Nil(sut.T(), err)
|
||||||
|
|
||||||
|
out, _ := ioutil.ReadAll(sut.reader)
|
||||||
|
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterTest is called by testify.suite
|
||||||
|
func (sut *CliSuite) AfterTest(suiteName, testName string) {
|
||||||
|
os.Stdout = sut.OriginalStdout
|
||||||
|
err := os.RemoveAll(sut.storeRoot)
|
||||||
|
require.Nil(sut.T(), err)
|
||||||
|
}
|
Loading…
Reference in New Issue