Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hack/make/test-unit
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ bundle_test_unit() {
fi

go test -cover -ldflags "$LDFLAGS" "${BUILDFLAGS[@]}" $TESTFLAGS $pkg_list
go test -cover -ldflags "$LDFLAGS" "${BUILDFLAGS[@]}" $TESTFLAGS github.com/docker/docker/pkg/term -test.root
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

}

bundle_test_unit 2>&1 | tee -a "$DEST/test.log"
92 changes: 92 additions & 0 deletions pkg/term/proxy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package term

import (
"bytes"
"fmt"
"reflect"
"testing"

"github.com/stretchr/testify/require"
)

func TestEscapeProxyRead(t *testing.T) {
escapeKeys, _ := ToBytes("DEL")
keys, _ := ToBytes("a,b,c,+")
reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
buf := make([]byte, len(keys))
nr, err := reader.Read(buf)
require.NoError(t, err)
require.EqualValues(t, nr, len(keys), fmt.Sprintf("nr %d should be equal to the number of %d", nr, len(keys)))
require.Equal(t, keys, buf, "keys & the read buffer should be equal")

keys, _ = ToBytes("")
reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
buf = make([]byte, len(keys))
nr, err = reader.Read(buf)
require.Error(t, err, "Should throw error when no keys are to read")
require.EqualValues(t, nr, 0, "nr should be zero")
require.Condition(t, func() (success bool) { return len(keys) == 0 && len(buf) == 0 }, "keys & the read buffer size should be zero")

escapeKeys, _ = ToBytes("ctrl-x,ctrl-@")
keys, _ = ToBytes("DEL")
reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
buf = make([]byte, len(keys))
nr, err = reader.Read(buf)
require.NoError(t, err)
require.EqualValues(t, nr, 1, fmt.Sprintf("nr %d should be equal to the number of 1", nr))
require.Equal(t, keys, buf, "keys & the read buffer should be equal")

escapeKeys, _ = ToBytes("ctrl-c")
keys, _ = ToBytes("ctrl-c")
reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
buf = make([]byte, len(keys))
nr, err = reader.Read(buf)
require.Condition(t, func() (success bool) {
return reflect.TypeOf(err).Name() == "EscapeError"
}, err)
require.EqualValues(t, nr, 0, "nr should be equal to 0")
require.Equal(t, keys, buf, "keys & the read buffer should be equal")

escapeKeys, _ = ToBytes("ctrl-c,ctrl-z")
keys, _ = ToBytes("ctrl-c,ctrl-z")
reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
buf = make([]byte, 1)
nr, err = reader.Read(buf)
require.NoError(t, err)
require.EqualValues(t, nr, 0, "nr should be equal to 0")
require.Equal(t, keys[0:1], buf, "keys & the read buffer should be equal")
nr, err = reader.Read(buf)
require.Condition(t, func() (success bool) {
return reflect.TypeOf(err).Name() == "EscapeError"
}, err)
require.EqualValues(t, nr, 0, "nr should be equal to 0")
require.Equal(t, keys[1:], buf, "keys & the read buffer should be equal")

escapeKeys, _ = ToBytes("ctrl-c,ctrl-z")
keys, _ = ToBytes("ctrl-c,DEL,+")
reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
buf = make([]byte, 1)
nr, err = reader.Read(buf)
require.NoError(t, err)
require.EqualValues(t, nr, 0, "nr should be equal to 0")
require.Equal(t, keys[0:1], buf, "keys & the read buffer should be equal")
buf = make([]byte, len(keys))
nr, err = reader.Read(buf)
require.NoError(t, err)
require.EqualValues(t, nr, len(keys), fmt.Sprintf("nr should be equal to %d", len(keys)))
require.Equal(t, keys, buf, "keys & the read buffer should be equal")

escapeKeys, _ = ToBytes("ctrl-c,ctrl-z")
keys, _ = ToBytes("ctrl-c,DEL")
reader = NewEscapeProxy(bytes.NewReader(keys), escapeKeys)
buf = make([]byte, 1)
nr, err = reader.Read(buf)
require.NoError(t, err)
require.EqualValues(t, nr, 0, "nr should be equal to 0")
require.Equal(t, keys[0:1], buf, "keys & the read buffer should be equal")
buf = make([]byte, len(keys))
nr, err = reader.Read(buf)
require.NoError(t, err)
require.EqualValues(t, nr, len(keys), fmt.Sprintf("nr should be equal to %d", len(keys)))
require.Equal(t, keys, buf, "keys & the read buffer should be equal")
}
120 changes: 120 additions & 0 deletions pkg/term/term_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//+build linux

package term

import (
"flag"
"io/ioutil"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var rootEnabled bool

func init() {
flag.BoolVar(&rootEnabled, "test.root", false, "enable tests that require root")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this flag necessary? Why not just skip the tests if the uid isn't 0?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose that would work, but I think I prefer the flag, because it means the set of tests that runs won't be sensitive to the environment. It's nice to avoid scenarios where the tests pass for one person but fail for another person running the same comment.

containerd uses this flag to enable/disable tests that require root privileges.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm more concerned that tests don't run unless you happen to provide this flag. and there's really no way to discover this flag. I really don't think this is a good solution. Skipping if uid != 0 is the same behaviour without the need to discover a flag.

If we know a test is going to fail, why bother running it? This is what we do for all the integration tests, we skip them if the environment does not support the test. This is pretty standard for many tests suites I think.

If for some reason we really want to force these to run, unless someone sets something explicit then I think we should be using an environment variable. We can always run the tests, unless the environment variable PKG_TERM_SKIP_ROOT_ONLY_TESTS is set. Then we can inform users about this env var with an error message when uid != 0.

}

// RequiresRoot skips tests that require root, unless the test.root flag has
// been set
func RequiresRoot(t *testing.T) {
if !rootEnabled {
t.Skip("skipping test that requires root")
return
}
assert.Equal(t, 0, os.Getuid(), "This test must be run as root.")
}

func newTtyForTest(t *testing.T) (*os.File, error) {
RequiresRoot(t)
return os.OpenFile("/dev/tty", os.O_RDWR, os.ModeDevice)
}

func newTempFile() (*os.File, error) {
return ioutil.TempFile(os.TempDir(), "temp")
}

func TestGetWinsize(t *testing.T) {
tty, err := newTtyForTest(t)
defer tty.Close()
require.NoError(t, err)
winSize, err := GetWinsize(tty.Fd())
require.NoError(t, err)
require.NotNil(t, winSize)
require.NotNil(t, winSize.Height)
require.NotNil(t, winSize.Width)
newSize := Winsize{Width: 200, Height: 200, x: winSize.x, y: winSize.y}
err = SetWinsize(tty.Fd(), &newSize)
require.NoError(t, err)
winSize, err = GetWinsize(tty.Fd())
require.NoError(t, err)
require.Equal(t, *winSize, newSize)
}

func TestSetWinsize(t *testing.T) {
tty, err := newTtyForTest(t)
defer tty.Close()
require.NoError(t, err)
winSize, err := GetWinsize(tty.Fd())
require.NoError(t, err)
require.NotNil(t, winSize)
newSize := Winsize{Width: 200, Height: 200, x: winSize.x, y: winSize.y}
err = SetWinsize(tty.Fd(), &newSize)
require.NoError(t, err)
winSize, err = GetWinsize(tty.Fd())
require.NoError(t, err)
require.Equal(t, *winSize, newSize)
}

func TestGetFdInfo(t *testing.T) {
tty, err := newTtyForTest(t)
defer tty.Close()
require.NoError(t, err)
inFd, isTerminal := GetFdInfo(tty)
require.Equal(t, inFd, tty.Fd())
require.Equal(t, isTerminal, true)
tmpFile, err := newTempFile()
defer tmpFile.Close()
inFd, isTerminal = GetFdInfo(tmpFile)
require.Equal(t, inFd, tmpFile.Fd())
require.Equal(t, isTerminal, false)
}

func TestIsTerminal(t *testing.T) {
tty, err := newTtyForTest(t)
defer tty.Close()
require.NoError(t, err)
isTerminal := IsTerminal(tty.Fd())
require.Equal(t, isTerminal, true)
tmpFile, err := newTempFile()
defer tmpFile.Close()
isTerminal = IsTerminal(tmpFile.Fd())
require.Equal(t, isTerminal, false)
}

func TestSaveState(t *testing.T) {
tty, err := newTtyForTest(t)
defer tty.Close()
require.NoError(t, err)
state, err := SaveState(tty.Fd())
require.NoError(t, err)
require.NotNil(t, state)
tty, err = newTtyForTest(t)
defer tty.Close()
err = RestoreTerminal(tty.Fd(), state)
require.NoError(t, err)
}

func TestDisableEcho(t *testing.T) {
tty, err := newTtyForTest(t)
defer tty.Close()
require.NoError(t, err)
state, err := SetRawTerminal(tty.Fd())
require.NoError(t, err)
require.NotNil(t, state)
err = DisableEcho(tty.Fd(), state)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm running the unit tests on master and I'm seeing my shell is missing echo after running these tests. I think this tests needs to re-enable echo to clean up after itself.

I'm preparing a PR to fix this now.

require.NoError(t, err)
}