func/cmd/config_labels_test.go

200 lines
3.8 KiB
Go

//go:build linux
// +build linux
package cmd
import (
"context"
"os"
"reflect"
"sync"
"testing"
"time"
"github.com/Netflix/go-expect"
"github.com/creack/pty"
"github.com/hinshun/vt10x"
"github.com/spf13/cobra"
fn "knative.dev/func/pkg/functions"
)
type mockFunctionLoaderSaver struct {
f fn.Function
}
func (m *mockFunctionLoaderSaver) Load(path string) (fn.Function, error) {
return m.f, nil
}
func (m *mockFunctionLoaderSaver) Save(f fn.Function) error {
m.f = f
return nil
}
func assertLabelEq(t *testing.T, actual []fn.Label, want []fn.Label) {
t.Helper()
if !reflect.DeepEqual(actual, want) {
t.Errorf("labels = %v, want %v", actual, want)
}
}
func createRunFunc(cmd *cobra.Command, t *testing.T) func(subcmd string, input ...string) {
return func(subcmd string, input ...string) {
ctx := context.Background()
ptm, pts, err := pty.Open()
if err != nil {
t.Fatal(err)
}
term := vt10x.New(vt10x.WithWriter(pts))
c, err := expect.NewConsole(expect.WithStdin(ptm), expect.WithStdout(term), expect.WithCloser(ptm, pts))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { c.Close() })
var wg sync.WaitGroup
wg.Add(1)
go func() {
//defer wg.Done()
_, _ = c.ExpectEOF()
}()
go func() {
defer wg.Done()
time.Sleep(time.Millisecond * 50)
for _, s := range input {
_, _ = c.Send(s)
time.Sleep(time.Millisecond * 50)
}
}()
a := []string{subcmd}
cmd.SetArgs(a)
func() {
defer withMockedStdio(t, c)()
err = cmd.ExecuteContext(ctx)
wg.Wait()
}()
if err != nil {
t.Fatal(err)
}
}
}
func withMockedStdio(t *testing.T, c *expect.Console) func() {
t.Helper()
oldIn := os.Stdin
oldOut := os.Stdout
oldErr := os.Stderr
os.Stdin = c.Tty()
os.Stdout = c.Tty()
os.Stderr = c.Tty()
return func() {
os.Stdin = oldIn
os.Stdout = oldOut
os.Stderr = oldErr
}
}
const (
arrowUp = "\033[A"
arrowDown = "\033[B"
enter = "\r"
)
func TestNewConfigLabelsCmd(t *testing.T) {
var loaderSaver mockFunctionLoaderSaver
labels := &loaderSaver.f.Deploy.Labels
cmd := NewConfigLabelsCmd(&loaderSaver)
cmd.SetArgs([]string{})
run := createRunFunc(cmd, t)
p := func(k, v string) fn.Label {
return fn.Label{Key: &k, Value: &v}
}
assertLabel := func(ps []fn.Label) {
t.Helper()
assertLabelEq(t, *labels, ps)
}
run("add", enter, "a", enter, "b", enter)
assertLabel([]fn.Label{p("a", "b")})
run("add", enter, enter, "c", enter, "d", enter)
assertLabel([]fn.Label{p("a", "b"), p("c", "d")})
run("add", arrowUp, arrowUp, enter, enter, "e", enter, "f", enter)
assertLabel([]fn.Label{p("e", "f"), p("a", "b"), p("c", "d")})
run("remove", arrowDown, enter)
assertLabel([]fn.Label{p("e", "f"), p("c", "d")})
}
func TestListLabels(t *testing.T) {
p := func(k, v string) fn.Label {
return fn.Label{Key: &k, Value: &v}
}
var loaderSaver mockFunctionLoaderSaver
labels := &loaderSaver.f.Deploy.Labels
*labels = append(*labels, p("a", "b"), p("c", "d"))
cmd := NewConfigLabelsCmd(&loaderSaver)
cmd.SetArgs([]string{})
ctx := context.Background()
c, err := expect.NewConsole()
if err != nil {
t.Fatal(err)
}
defer c.Close()
errChan := make(chan error, 1)
func() {
var err error
defer func() {
errChan <- err
}()
defer withMockedStdio(t, c)()
err = cmd.ExecuteContext(ctx)
}()
expected := []string{
`Configured labels:`,
`- Label with key "a" and value "b"`,
`- Label with key "c" and value "d"`,
}
// prevents the ExpectString() function from waiting indefinitely
// in case when expected string is not printed to stdout nor the stdout is closed
go func() {
time.Sleep(time.Second * 5)
c.Close()
}()
for _, s := range expected {
out, err := c.ExpectString(s)
if err != nil {
t.Errorf("unexpected output: %q, err: %v\n", out, err)
}
}
err = <-errChan
if err != nil {
t.Fatal(err)
}
}