summaryrefslogtreecommitdiff
path: root/integration/internal
diff options
context:
space:
mode:
authorPaweł Gronowski <pawel.gronowski@docker.com>2022-06-10 09:26:17 +0200
committerPaweł Gronowski <pawel.gronowski@docker.com>2022-06-10 09:26:17 +0200
commit2ec3e14c0ff7f8552c1f9b09ffde743632fa1f8c (patch)
treedd401831c34607a11c81eec526de2f190519b948 /integration/internal
parent20d6b5c1bdedffe74f9dd774e3e22ad59360a51c (diff)
downloaddocker-2ec3e14c0ff7f8552c1f9b09ffde743632fa1f8c.tar.gz
test: Add tests for logging
1. Add integration tests for the ContainerLogs API call Each test handle a distinct case of ContainerLogs output. - Muxed stream, when container is started without tty - Single stream, when container is started with tty 2. Add unit test for LogReader suite that tests concurrent logging It checks that there are no race conditions when logging concurrently from multiple goroutines. Co-authored-by: Cory Snider <csnider@mirantis.com> Signed-off-by: Cory Snider <csnider@mirantis.com> Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Diffstat (limited to 'integration/internal')
-rw-r--r--integration/internal/termtest/stripansi.go108
-rw-r--r--integration/internal/termtest/stripansi_test.go26
2 files changed, 134 insertions, 0 deletions
diff --git a/integration/internal/termtest/stripansi.go b/integration/internal/termtest/stripansi.go
new file mode 100644
index 0000000000..9c7bec9a04
--- /dev/null
+++ b/integration/internal/termtest/stripansi.go
@@ -0,0 +1,108 @@
+package termtest // import "github.com/docker/docker/integration/internal/termtest"
+
+import (
+ "errors"
+ "regexp"
+
+ "github.com/Azure/go-ansiterm"
+)
+
+var stripOSC = regexp.MustCompile(`\x1b\][^\x1b\a]*(\x1b\\|\a)`)
+
+// StripANSICommands attempts to strip ANSI console escape and control sequences
+// from s, returning a string containing only the final printed characters which
+// would be visible onscreen if the string was to be processed by a terminal
+// emulator. Basic cursor positioning and screen erase control sequences are
+// parsed and processed such that the output of simple CLI commands passed
+// through a Windows Pseudoterminal and then this function yields the same
+// string as if the output of those commands was redirected to a file.
+//
+// The only correct way to represent the result of processing ANSI console
+// output would be a two-dimensional array of an emulated terminal's display
+// buffer. That would be awkward to test against, so this function instead
+// attempts to render to a one-dimensional string without extra padding. This is
+// an inherently lossy process, and any attempts to render a string containing
+// many cursor positioning commands are unlikely to yield satisfactory results.
+// Handlers for several ANSI control sequences are also unimplemented; attempts
+// to parse a string containing one will panic.
+func StripANSICommands(s string, opts ...ansiterm.Option) (string, error) {
+ // Work around https://github.com/Azure/go-ansiterm/issues/34
+ s = stripOSC.ReplaceAllLiteralString(s, "")
+
+ var h stringHandler
+ p := ansiterm.CreateParser("Ground", &h, opts...)
+ _, err := p.Parse([]byte(s))
+ return h.String(), err
+}
+
+type stringHandler struct {
+ ansiterm.AnsiEventHandler
+ cursor int
+ b []byte
+}
+
+func (h *stringHandler) Print(b byte) error {
+ if h.cursor == len(h.b) {
+ h.b = append(h.b, b)
+ } else {
+ h.b[h.cursor] = b
+ }
+ h.cursor++
+ return nil
+}
+
+func (h *stringHandler) Execute(b byte) error {
+ switch b {
+ case '\b':
+ if h.cursor > 0 {
+ if h.cursor == len(h.b) && h.b[h.cursor-1] == ' ' {
+ h.b = h.b[:len(h.b)-1]
+ }
+ h.cursor--
+ }
+ case '\r', '\n':
+ h.Print(b)
+ }
+ return nil
+}
+
+// Erase Display
+func (h *stringHandler) ED(v int) error {
+ switch v {
+ case 1: // Erase from start to cursor.
+ for i := 0; i < h.cursor; i++ {
+ h.b[i] = ' '
+ }
+ case 2, 3: // Erase whole display.
+ h.b = make([]byte, h.cursor)
+ for i := range h.b {
+ h.b[i] = ' '
+ }
+ default: // Erase from cursor to end of display.
+ h.b = h.b[:h.cursor+1]
+ }
+ return nil
+}
+
+// CUrsor Position
+func (h *stringHandler) CUP(x, y int) error {
+ if x > 1 {
+ return errors.New("termtest: cursor position not supported for X > 1")
+ }
+ if y > len(h.b) {
+ for n := len(h.b) - y; n > 0; n-- {
+ h.b = append(h.b, ' ')
+ }
+ }
+ h.cursor = y - 1
+ return nil
+}
+
+func (h stringHandler) DECTCEM(bool) error { return nil } // Text Cursor Enable
+func (h stringHandler) SGR(v []int) error { return nil } // Set Graphics Rendition
+func (h stringHandler) DA(attrs []string) error { return nil }
+func (h stringHandler) Flush() error { return nil }
+
+func (h *stringHandler) String() string {
+ return string(h.b)
+}
diff --git a/integration/internal/termtest/stripansi_test.go b/integration/internal/termtest/stripansi_test.go
new file mode 100644
index 0000000000..ebf983340d
--- /dev/null
+++ b/integration/internal/termtest/stripansi_test.go
@@ -0,0 +1,26 @@
+package termtest // import "github.com/docker/docker/integration/internal/termtest"
+
+import (
+ "testing"
+
+ "gotest.tools/v3/assert"
+)
+
+func TestStripANSICommands(t *testing.T) {
+ for _, tt := range []struct{ input, want string }{
+ {
+ input: "\x1b[2J\x1b[?25l\x1b[m\x1b[Hthis is fine\b\x1b]0;C:\\bin\\sh.exe\x00\a\x1b[?25h\x1b[Ht\x1b[1;13H\x1b[?25laccidents happen \b\x1b[?25h\x1b[Ht\x1b[1;29H",
+ want: "this is fineaccidents happen",
+ },
+ {
+ input: "\x1b[2J\x1b[m\x1b[Hthis is fine\x1b]0;C:\\bin\\sh.exe\a\x1b[?25haccidents happen",
+ want: "this is fineaccidents happen",
+ },
+ } {
+ t.Run("", func(t *testing.T) {
+ got, err := StripANSICommands(tt.input)
+ assert.NilError(t, err)
+ assert.DeepEqual(t, tt.want, got)
+ })
+ }
+}