spiegel_podman/test/e2e/logs_test.go
Paul Holzinger ab29ff2f66
test/e2e: dedup Before/AfterEach nodes
There is no reason to define the same code every time in each file, just
use global nodes. This diff should speak for itself.

CleanupSecrets()/Volume() no longer call Cleanup() directly, as the
global AfterEach node will always call Cleanup() this is no longer
necessary. If one AfterEach() node fails it will still run the others.

Also always unset the CONTAINERS_CONF env vars. This prevents people
from forgetting to unset it. And fix the special CONTAINERS_CONF logic
in the system connection tests, we do not want to preserve
CONTAINERS_CONF anyway so just remove this logic.

Ginkgo orders the BeforeEach and AfterEach nodes. They will be executed
from the outer-most defined to inner-most. This means our global
BeforeEach is always first. Only then the inner one (in the Describe()
function in each file). For AfterEach it is inverted, from the inner to
the outer.
Also see https://onsi.github.io/ginkgo/#organizing-specs-with-container-nodes

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
2023-05-15 16:56:18 +02:00

588 lines
21 KiB
Go

package integration
import (
"fmt"
"os/exec"
"time"
. "github.com/containers/podman/v4/test/utils"
"github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
)
func isEventBackendJournald(podmanTest *PodmanTestIntegration) bool {
if !podmanTest.RemoteTest {
// If not remote test, '--events-backend' is set to 'file' or 'none'
return false
}
info := podmanTest.Podman([]string{"info", "--format", "{{.Host.EventLogger}}"})
info.WaitWithDefaultTimeout()
return info.OutputToString() == "journald"
}
var _ = Describe("Podman logs", func() {
It("podman logs on not existent container", func() {
results := podmanTest.Podman([]string{"logs", "notexist"})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(125))
Expect(results.ErrorToString()).To(Equal(`Error: no container with name or ID "notexist" found: no such container`))
})
for _, log := range []string{"k8s-file", "journald", "json-file"} {
// This is important to move the 'log' var to the correct scope under Ginkgo flow.
log := log
skipIfJournaldInContainer := func() {
if log == "journald" {
SkipIfJournaldUnavailable()
}
}
It("all lines: "+log, func() {
skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
results := podmanTest.Podman([]string{"wait", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
results = podmanTest.Podman([]string{"logs", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(3))
Expect(results.OutputToString()).To(Equal("podman podman podman"))
})
It("tail two lines: "+log, func() {
skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "--tail", "2", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(2))
})
It("tail zero lines: "+log, func() {
skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "--tail", "0", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(BeEmpty())
})
It("tail 99 lines: "+log, func() {
skipIfJournaldInContainer()
name := "test1"
logc := podmanTest.Podman([]string{"run", "--name", name, "--log-driver", log, ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
wait := podmanTest.Podman([]string{"wait", name})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "--tail", "99", name})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(3))
})
It("tail 800 lines: "+log, func() {
skipIfJournaldInContainer()
// this uses -d so that we do not have 1000 unnecessary lines printed in every test log
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
// make sure we wait for the container to finish writing its output
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "--tail", "800", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(800))
})
It("tail 2 lines with timestamps: "+log, func() {
skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "--tail", "2", "-t", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(2))
})
It("since time 2017-08-07: "+log, func() {
skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "--since", "2017-08-07T10:10:09.056611202-04:00", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(3))
})
It("since duration 10m: "+log, func() {
skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "--since", "10m", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(3))
})
It("until duration 10m: "+log, func() {
skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "--until", "10m", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(3))
})
It("until time NOW: "+log, func() {
skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
now := time.Now()
now = now.Add(time.Minute * 1)
nowS := now.Format(time.RFC3339)
results := podmanTest.Podman([]string{"logs", "--until", nowS, cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(3))
})
It("latest and container name should fail: "+log, func() {
skipIfJournaldInContainer()
results := podmanTest.Podman([]string{"logs", "-l", "foobar"})
results.WaitWithDefaultTimeout()
Expect(results).To(ExitWithError())
})
It("two containers showing short container IDs: "+log, func() {
skipIfJournaldInContainer()
SkipIfRemote("podman-remote logs does not support showing two containers at the same time")
log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
log1.WaitWithDefaultTimeout()
Expect(log1).Should(Exit(0))
cid1 := log1.OutputToString()
log2 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
log2.WaitWithDefaultTimeout()
Expect(log2).Should(Exit(0))
cid2 := log2.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid1, cid2})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", cid1, cid2})
results.WaitWithDefaultTimeout()
Expect(results).Should(Exit(0))
output := results.OutputToStringArray()
Expect(output).To(HaveLen(6))
Expect(output[0]).To(Or(ContainSubstring(cid1[:12]), ContainSubstring(cid2[:12])))
})
It("podman logs on a created container should result in 0 exit code: "+log, func() {
skipIfJournaldInContainer()
session := podmanTest.Podman([]string{"create", "--log-driver", log, "--name", "log", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "log"})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
})
It("streaming output: "+log, func() {
skipIfJournaldInContainer()
containerName := "logs-f"
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-dt", ALPINE, "sh", "-c", "echo podman-1; sleep 1; echo podman-2"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "-f", containerName})
results.WaitWithDefaultTimeout()
if log == "journald" && !isEventBackendJournald(podmanTest) {
// --follow + journald log-driver is only supported with journald events-backend(PR #10431)
Expect(results).To(Exit(125))
Expect(results.ErrorToString()).To(ContainSubstring("using --follow with the journald --log-driver but without the journald --events-backend"))
return
}
Expect(results).To(Exit(0))
Expect(results.OutputToString()).To(ContainSubstring("podman-1"))
Expect(results.OutputToString()).To(ContainSubstring("podman-2"))
// Container should now be terminatING or terminatED, but we
// have no guarantee of which: 'logs -f' does not necessarily
// wait for cleanup. Run 'inspect' and accept either state.
inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Status}}", containerName})
inspect.WaitWithDefaultTimeout()
if inspect.ExitCode() == 0 {
Expect(inspect.OutputToString()).To(Equal("exited"))
// TODO: add 2-second wait loop to confirm cleanup
} else {
Expect(inspect.ErrorToString()).To(ContainSubstring("no such container"))
}
results = podmanTest.Podman([]string{"rm", "--time", "0", "-f", containerName})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
})
It("follow output stopped container: "+log, func() {
skipIfJournaldInContainer()
containerName := "logs-f"
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-d", ALPINE, "true"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "-f", containerName})
results.WaitWithDefaultTimeout()
if log == "journald" && !isEventBackendJournald(podmanTest) {
// --follow + journald log-driver is only supported with journald events-backend(PR #10431)
Expect(results).To(Exit(125))
return
}
Expect(results).To(Exit(0))
})
It("using container with container log-size: "+log, func() {
skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--log-opt=max-size=10k", "-d", ALPINE, "sh", "-c", "echo podman podman podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.HostConfig.LogConfig.Size}}", cid})
inspect.WaitWithDefaultTimeout()
Expect(inspect).To(Exit(0))
Expect(inspect.OutputToString()).To(Equal("10kB"))
results := podmanTest.Podman([]string{"logs", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToString()).To(Equal("podman podman podman"))
})
It("Make sure logs match expected length: "+log, func() {
skipIfJournaldInContainer()
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", "test", ALPINE, "sh", "-c", "echo 1; echo 2"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
wait := podmanTest.Podman([]string{"wait", "test"})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", "test"})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
outlines := results.OutputToStringArray()
Expect(outlines).To(HaveLen(2))
Expect(outlines[0]).To(Equal("1"))
Expect(outlines[1]).To(Equal("2"))
})
It("podman logs test stdout and stderr: "+log, func() {
skipIfJournaldInContainer()
cname := "log-test"
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "sh", "-c", "echo stdout; echo stderr >&2"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
wait := podmanTest.Podman([]string{"wait", cname})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
results := podmanTest.Podman([]string{"logs", cname})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToString()).To(Equal("stdout"))
Expect(results.ErrorToString()).To(Equal("stderr"))
})
It("podman logs partial log lines: "+log, func() {
skipIfJournaldInContainer()
cname := "log-test"
content := stringid.GenerateRandomID()
// use printf to print no extra newline
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "printf", content})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
// Important: do not use OutputToString(), this will remove the trailing newline from the output.
// However this test must make sure that there is no such extra newline.
Expect(string(logc.Out.Contents())).To(Equal(content))
logs := podmanTest.Podman([]string{"logs", cname})
logs.WaitWithDefaultTimeout()
Expect(logs).To(Exit(0))
// see comment above
Expect(string(logs.Out.Contents())).To(Equal(content))
})
It("podman pod logs -l with newer container created: "+log, func() {
skipIfJournaldInContainer()
podName := "testPod"
containerName1 := "container1"
containerName2 := "container2"
containerName3 := "container3"
testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)})
testPod.WaitWithDefaultTimeout()
Expect(testPod).To(Exit(0))
log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName1, "-d", "--pod", podName, BB, "/bin/sh", "-c", "echo log1"})
log1.WaitWithDefaultTimeout()
Expect(log1).To(Exit(0))
log2 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName2, "-d", "--pod", podName, BB, "/bin/sh", "-c", "echo log2"})
log2.WaitWithDefaultTimeout()
Expect(log2).To(Exit(0))
ctr := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName3, "-d", BB, "date"})
ctr.WaitWithDefaultTimeout()
Expect(ctr).To(Exit(0))
results := podmanTest.Podman([]string{"pod", "logs", "-l"})
results.WaitWithDefaultTimeout()
if IsRemote() {
Expect(results).To(Exit(125))
} else {
Expect(results).To(Exit(0))
podOutput := results.OutputToString()
results = podmanTest.Podman([]string{"logs", "-l"})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
ctrOutput := results.OutputToString()
Expect(podOutput).ToNot(Equal(ctrOutput))
}
})
It("podman pod logs -l: "+log, func() {
skipIfJournaldInContainer()
podName := "testPod"
containerName1 := "container1"
containerName2 := "container2"
testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)})
testPod.WaitWithDefaultTimeout()
Expect(testPod).To(Exit(0))
log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName1, "-d", "--pod", podName, BB, "/bin/sh", "-c", "echo log1"})
log1.WaitWithDefaultTimeout()
Expect(log1).To(Exit(0))
log2 := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName2, "-d", "--pod", podName, BB, "/bin/sh", "-c", "echo log2"})
log2.WaitWithDefaultTimeout()
Expect(log2).To(Exit(0))
results := podmanTest.Podman([]string{"pod", "logs", "-l"})
results.WaitWithDefaultTimeout()
if IsRemote() {
Expect(results).To(Exit(125))
} else {
Expect(results).To(Exit(0))
output := results.OutputToString()
Expect(output).To(ContainSubstring("log1"))
Expect(output).To(ContainSubstring("log2"))
}
})
}
It("using journald for container with container tag", func() {
SkipIfJournaldUnavailable()
logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "--log-opt=tag={{.ImageName}}", "-d", ALPINE, "sh", "-c", "echo podman; sleep 0.1; echo podman; sleep 0.1; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_TAG", fmt.Sprintf("CONTAINER_ID_FULL=%s", cid))
out, err := cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred())
Expect(string(out)).To(ContainSubstring("alpine"))
})
It("using journald container name", func() {
SkipIfJournaldUnavailable()
containerName := "inside-journal"
logc := podmanTest.Podman([]string{"run", "--log-driver", "journald", "-d", "--name", containerName, ALPINE, "sh", "-c", "echo podman; sleep 0.1; echo podman; sleep 0.1; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
wait := podmanTest.Podman([]string{"wait", cid})
wait.WaitWithDefaultTimeout()
Expect(wait).To(Exit(0))
cmd := exec.Command("journalctl", "--no-pager", "-o", "json", "--output-fields=CONTAINER_NAME", fmt.Sprintf("CONTAINER_ID_FULL=%s", cid))
out, err := cmd.CombinedOutput()
Expect(err).ToNot(HaveOccurred())
Expect(string(out)).To(ContainSubstring(containerName))
})
It("podman logs with log-driver=none errors", func() {
ctrName := "logsctr"
logc := podmanTest.Podman([]string{"run", "--name", ctrName, "-d", "--log-driver", "none", ALPINE, "top"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
logs := podmanTest.Podman([]string{"logs", "-f", ctrName})
logs.WaitWithDefaultTimeout()
Expect(logs).To(Not(Exit(0)))
})
It("podman pod logs with container names", func() {
SkipIfRemote("Remote can only process one container at a time")
podName := "testPod"
containerName1 := "container1"
containerName2 := "container2"
testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)})
testPod.WaitWithDefaultTimeout()
Expect(testPod).To(Exit(0))
log1 := podmanTest.Podman([]string{"run", "--name", containerName1, "--pod", podName, BB, "/bin/sh", "-c", "echo log1"})
log1.WaitWithDefaultTimeout()
Expect(log1).To(Exit(0))
log2 := podmanTest.Podman([]string{"run", "--name", containerName2, "--pod", podName, BB, "/bin/sh", "-c", "echo log2"})
log2.WaitWithDefaultTimeout()
Expect(log2).To(Exit(0))
results := podmanTest.Podman([]string{"pod", "logs", "--names", podName})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
output := results.OutputToStringArray()
Expect(output).To(HaveLen(2))
Expect(output).To(ContainElement(ContainSubstring(containerName1)))
Expect(output).To(ContainElement(ContainSubstring(containerName2)))
})
It("podman pod logs with different colors", func() {
SkipIfRemote("Remote can only process one container at a time")
podName := "testPod"
containerName1 := "container1"
containerName2 := "container2"
testPod := podmanTest.Podman([]string{"pod", "create", fmt.Sprintf("--name=%s", podName)})
testPod.WaitWithDefaultTimeout()
Expect(testPod).To(Exit(0))
log1 := podmanTest.Podman([]string{"run", "--name", containerName1, "--pod", podName, BB, "/bin/sh", "-c", "echo log1"})
log1.WaitWithDefaultTimeout()
Expect(log1).To(Exit(0))
log2 := podmanTest.Podman([]string{"run", "--name", containerName2, "--pod", podName, BB, "/bin/sh", "-c", "echo log2"})
log2.WaitWithDefaultTimeout()
Expect(log2).To(Exit(0))
results := podmanTest.Podman([]string{"pod", "logs", "--color", podName})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
output := results.OutputToStringArray()
Expect(output).To(HaveLen(2))
Expect(output[0]).To(MatchRegexp(`\x1b\[3[0-9a-z ]+\x1b\[0m`))
Expect(output[1]).To(MatchRegexp(`\x1b\[3[0-9a-z ]+\x1b\[0m`))
})
})