moby/integration-cli/docker_api_logs_test.go

226 lines
6.4 KiB
Go
Raw Normal View History

package main
import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"testing"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/testutil/request"
"gotest.tools/v3/assert"
)
func (s *DockerAPISuite) TestLogsAPIWithStdout(c *testing.T) {
out, _ := dockerCmd(c, "run", "-d", "-t", "busybox", "/bin/sh", "-c", "while true; do echo hello; sleep 1; done")
id := strings.TrimSpace(out)
assert.NilError(c, waitRun(id))
type logOut struct {
out string
err error
}
chLog := make(chan logOut, 1)
res, body, err := request.Get(fmt.Sprintf("/containers/%s/logs?follow=1&stdout=1&timestamps=1", id))
assert.NilError(c, err)
assert.Equal(c, res.StatusCode, http.StatusOK)
go func() {
defer body.Close()
out, err := bufio.NewReader(body).ReadString('\n')
if err != nil {
chLog <- logOut{"", err}
return
}
chLog <- logOut{strings.TrimSpace(out), err}
}()
select {
case l := <-chLog:
assert.NilError(c, l.err)
if !strings.HasSuffix(l.out, "hello") {
c.Fatalf("expected log output to container 'hello', but it does not")
}
case <-time.After(30 * time.Second):
c.Fatal("timeout waiting for logs to exit")
}
}
func (s *DockerAPISuite) TestLogsAPINoStdoutNorStderr(c *testing.T) {
name := "logs_test"
dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "/bin/sh")
cli, err := client.NewClientWithOpts(client.FromEnv)
assert.NilError(c, err)
defer cli.Close()
_, err = cli.ContainerLogs(context.Background(), name, types.ContainerLogsOptions{})
assert.ErrorContains(c, err, "Bad parameters: you must choose at least one stream")
}
// Regression test for #12704
func (s *DockerAPISuite) TestLogsAPIFollowEmptyOutput(c *testing.T) {
name := "logs_test"
t0 := time.Now()
dockerCmd(c, "run", "-d", "-t", "--name", name, "busybox", "sleep", "10")
_, body, err := request.Get(fmt.Sprintf("/containers/%s/logs?follow=1&stdout=1&stderr=1&tail=all", name))
t1 := time.Now()
assert.NilError(c, err)
body.Close()
elapsed := t1.Sub(t0).Seconds()
if elapsed > 20.0 {
c.Fatalf("HTTP response was not immediate (elapsed %.1fs)", elapsed)
}
}
func (s *DockerAPISuite) TestLogsAPIContainerNotFound(c *testing.T) {
name := "nonExistentContainer"
resp, _, err := request.Get(fmt.Sprintf("/containers/%s/logs?follow=1&stdout=1&stderr=1&tail=all", name))
assert.NilError(c, err)
assert.Equal(c, resp.StatusCode, http.StatusNotFound)
}
func (s *DockerAPISuite) TestLogsAPIUntilFutureFollow(c *testing.T) {
testRequires(c, DaemonIsLinux)
name := "logsuntilfuturefollow"
dockerCmd(c, "run", "-d", "--name", name, "busybox", "/bin/sh", "-c", "while true; do date +%s; sleep 1; done")
assert.NilError(c, waitRun(name))
untilSecs := 5
untilDur, err := time.ParseDuration(fmt.Sprintf("%ds", untilSecs))
assert.NilError(c, err)
until := daemonTime(c).Add(untilDur)
client, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
c.Fatal(err)
}
cfg := types.ContainerLogsOptions{Until: until.Format(time.RFC3339Nano), Follow: true, ShowStdout: true, Timestamps: true}
reader, err := client.ContainerLogs(context.Background(), name, cfg)
assert.NilError(c, err)
type logOut struct {
out string
err error
}
chLog := make(chan logOut)
stop := make(chan struct{})
defer close(stop)
go func() {
bufReader := bufio.NewReader(reader)
defer reader.Close()
for i := 0; i < untilSecs; i++ {
out, _, err := bufReader.ReadLine()
if err != nil {
if err == io.EOF {
return
}
select {
case <-stop:
return
case chLog <- logOut{"", err}:
}
return
}
select {
case <-stop:
return
case chLog <- logOut{strings.TrimSpace(string(out)), err}:
}
}
}()
for i := 0; i < untilSecs; i++ {
select {
case l := <-chLog:
assert.NilError(c, l.err)
i, err := strconv.ParseInt(strings.Split(l.out, " ")[1], 10, 64)
assert.NilError(c, err)
assert.Assert(c, time.Unix(i, 0).UnixNano() <= until.UnixNano())
case <-time.After(20 * time.Second):
c.Fatal("timeout waiting for logs to exit")
}
}
}
func (s *DockerAPISuite) TestLogsAPIUntil(c *testing.T) {
testRequires(c, MinimumAPIVersion("1.34"))
name := "logsuntil"
dockerCmd(c, "run", "--name", name, "busybox", "/bin/sh", "-c", "for i in $(seq 1 3); do echo log$i; sleep 1; done")
client, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
c.Fatal(err)
}
rm-gocheck: check.C -> testing.T sed -E -i 's#\bcheck\.C\b#testing.T#g' \ -- "integration-cli/check_test.go" "integration-cli/daemon/daemon.go" "integration-cli/daemon/daemon_swarm.go" "integration-cli/daemon_swarm_hack_test.go" "integration-cli/docker_api_attach_test.go" "integration-cli/docker_api_build_test.go" "integration-cli/docker_api_build_windows_test.go" "integration-cli/docker_api_containers_test.go" "integration-cli/docker_api_containers_windows_test.go" "integration-cli/docker_api_exec_resize_test.go" "integration-cli/docker_api_exec_test.go" "integration-cli/docker_api_images_test.go" "integration-cli/docker_api_inspect_test.go" "integration-cli/docker_api_logs_test.go" "integration-cli/docker_api_network_test.go" "integration-cli/docker_api_stats_test.go" "integration-cli/docker_api_swarm_node_test.go" "integration-cli/docker_api_swarm_service_test.go" "integration-cli/docker_api_swarm_test.go" "integration-cli/docker_api_test.go" "integration-cli/docker_cli_attach_test.go" "integration-cli/docker_cli_attach_unix_test.go" "integration-cli/docker_cli_build_test.go" "integration-cli/docker_cli_build_unix_test.go" "integration-cli/docker_cli_by_digest_test.go" "integration-cli/docker_cli_commit_test.go" "integration-cli/docker_cli_cp_from_container_test.go" "integration-cli/docker_cli_cp_test.go" "integration-cli/docker_cli_cp_to_container_test.go" "integration-cli/docker_cli_cp_to_container_unix_test.go" "integration-cli/docker_cli_cp_utils_test.go" "integration-cli/docker_cli_create_test.go" "integration-cli/docker_cli_daemon_plugins_test.go" "integration-cli/docker_cli_daemon_test.go" "integration-cli/docker_cli_events_test.go" "integration-cli/docker_cli_events_unix_test.go" "integration-cli/docker_cli_exec_test.go" "integration-cli/docker_cli_exec_unix_test.go" "integration-cli/docker_cli_external_volume_driver_unix_test.go" "integration-cli/docker_cli_health_test.go" "integration-cli/docker_cli_history_test.go" "integration-cli/docker_cli_images_test.go" "integration-cli/docker_cli_import_test.go" "integration-cli/docker_cli_info_test.go" "integration-cli/docker_cli_info_unix_test.go" "integration-cli/docker_cli_inspect_test.go" "integration-cli/docker_cli_links_test.go" "integration-cli/docker_cli_login_test.go" "integration-cli/docker_cli_logout_test.go" "integration-cli/docker_cli_logs_test.go" "integration-cli/docker_cli_netmode_test.go" "integration-cli/docker_cli_network_unix_test.go" "integration-cli/docker_cli_plugins_logdriver_test.go" "integration-cli/docker_cli_plugins_test.go" "integration-cli/docker_cli_port_test.go" "integration-cli/docker_cli_proxy_test.go" "integration-cli/docker_cli_prune_unix_test.go" "integration-cli/docker_cli_ps_test.go" "integration-cli/docker_cli_pull_local_test.go" "integration-cli/docker_cli_pull_test.go" "integration-cli/docker_cli_push_test.go" "integration-cli/docker_cli_registry_user_agent_test.go" "integration-cli/docker_cli_restart_test.go" "integration-cli/docker_cli_rmi_test.go" "integration-cli/docker_cli_run_test.go" "integration-cli/docker_cli_run_unix_test.go" "integration-cli/docker_cli_save_load_test.go" "integration-cli/docker_cli_save_load_unix_test.go" "integration-cli/docker_cli_search_test.go" "integration-cli/docker_cli_service_create_test.go" "integration-cli/docker_cli_service_health_test.go" "integration-cli/docker_cli_service_logs_test.go" "integration-cli/docker_cli_service_scale_test.go" "integration-cli/docker_cli_sni_test.go" "integration-cli/docker_cli_start_test.go" "integration-cli/docker_cli_stats_test.go" "integration-cli/docker_cli_swarm_test.go" "integration-cli/docker_cli_swarm_unix_test.go" "integration-cli/docker_cli_top_test.go" "integration-cli/docker_cli_update_unix_test.go" "integration-cli/docker_cli_userns_test.go" "integration-cli/docker_cli_v2_only_test.go" "integration-cli/docker_cli_volume_test.go" "integration-cli/docker_deprecated_api_v124_test.go" "integration-cli/docker_deprecated_api_v124_unix_test.go" "integration-cli/docker_hub_pull_suite_test.go" "integration-cli/docker_utils_test.go" "integration-cli/events_utils_test.go" "integration-cli/fixtures_linux_daemon_test.go" "integration-cli/utils_test.go" "pkg/discovery/discovery_test.go" "pkg/discovery/file/file_test.go" "pkg/discovery/generator_test.go" "pkg/discovery/kv/kv_test.go" "pkg/discovery/memory/memory_test.go" "pkg/discovery/nodes/nodes_test.go" Signed-off-by: Tibor Vass <tibor@docker.com>
2019-09-09 21:05:55 +00:00
extractBody := func(c *testing.T, cfg types.ContainerLogsOptions) []string {
reader, err := client.ContainerLogs(context.Background(), name, cfg)
assert.NilError(c, err)
actualStdout := new(bytes.Buffer)
actualStderr := io.Discard
_, err = stdcopy.StdCopy(actualStdout, actualStderr, reader)
assert.NilError(c, err)
return strings.Split(actualStdout.String(), "\n")
}
// Get timestamp of second log line
allLogs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true})
assert.Assert(c, len(allLogs) >= 3)
t, err := time.Parse(time.RFC3339Nano, strings.Split(allLogs[1], " ")[0])
assert.NilError(c, err)
until := t.Format(time.RFC3339Nano)
// Get logs until the timestamp of second line, i.e. first two lines
logs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true, Until: until})
// Ensure log lines after cut-off are excluded
logsString := strings.Join(logs, "\n")
assert.Assert(c, !strings.Contains(logsString, "log3"), "unexpected log message returned, until=%v", until)
}
func (s *DockerAPISuite) TestLogsAPIUntilDefaultValue(c *testing.T) {
name := "logsuntildefaultval"
dockerCmd(c, "run", "--name", name, "busybox", "/bin/sh", "-c", "for i in $(seq 1 3); do echo log$i; done")
client, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
c.Fatal(err)
}
rm-gocheck: check.C -> testing.T sed -E -i 's#\bcheck\.C\b#testing.T#g' \ -- "integration-cli/check_test.go" "integration-cli/daemon/daemon.go" "integration-cli/daemon/daemon_swarm.go" "integration-cli/daemon_swarm_hack_test.go" "integration-cli/docker_api_attach_test.go" "integration-cli/docker_api_build_test.go" "integration-cli/docker_api_build_windows_test.go" "integration-cli/docker_api_containers_test.go" "integration-cli/docker_api_containers_windows_test.go" "integration-cli/docker_api_exec_resize_test.go" "integration-cli/docker_api_exec_test.go" "integration-cli/docker_api_images_test.go" "integration-cli/docker_api_inspect_test.go" "integration-cli/docker_api_logs_test.go" "integration-cli/docker_api_network_test.go" "integration-cli/docker_api_stats_test.go" "integration-cli/docker_api_swarm_node_test.go" "integration-cli/docker_api_swarm_service_test.go" "integration-cli/docker_api_swarm_test.go" "integration-cli/docker_api_test.go" "integration-cli/docker_cli_attach_test.go" "integration-cli/docker_cli_attach_unix_test.go" "integration-cli/docker_cli_build_test.go" "integration-cli/docker_cli_build_unix_test.go" "integration-cli/docker_cli_by_digest_test.go" "integration-cli/docker_cli_commit_test.go" "integration-cli/docker_cli_cp_from_container_test.go" "integration-cli/docker_cli_cp_test.go" "integration-cli/docker_cli_cp_to_container_test.go" "integration-cli/docker_cli_cp_to_container_unix_test.go" "integration-cli/docker_cli_cp_utils_test.go" "integration-cli/docker_cli_create_test.go" "integration-cli/docker_cli_daemon_plugins_test.go" "integration-cli/docker_cli_daemon_test.go" "integration-cli/docker_cli_events_test.go" "integration-cli/docker_cli_events_unix_test.go" "integration-cli/docker_cli_exec_test.go" "integration-cli/docker_cli_exec_unix_test.go" "integration-cli/docker_cli_external_volume_driver_unix_test.go" "integration-cli/docker_cli_health_test.go" "integration-cli/docker_cli_history_test.go" "integration-cli/docker_cli_images_test.go" "integration-cli/docker_cli_import_test.go" "integration-cli/docker_cli_info_test.go" "integration-cli/docker_cli_info_unix_test.go" "integration-cli/docker_cli_inspect_test.go" "integration-cli/docker_cli_links_test.go" "integration-cli/docker_cli_login_test.go" "integration-cli/docker_cli_logout_test.go" "integration-cli/docker_cli_logs_test.go" "integration-cli/docker_cli_netmode_test.go" "integration-cli/docker_cli_network_unix_test.go" "integration-cli/docker_cli_plugins_logdriver_test.go" "integration-cli/docker_cli_plugins_test.go" "integration-cli/docker_cli_port_test.go" "integration-cli/docker_cli_proxy_test.go" "integration-cli/docker_cli_prune_unix_test.go" "integration-cli/docker_cli_ps_test.go" "integration-cli/docker_cli_pull_local_test.go" "integration-cli/docker_cli_pull_test.go" "integration-cli/docker_cli_push_test.go" "integration-cli/docker_cli_registry_user_agent_test.go" "integration-cli/docker_cli_restart_test.go" "integration-cli/docker_cli_rmi_test.go" "integration-cli/docker_cli_run_test.go" "integration-cli/docker_cli_run_unix_test.go" "integration-cli/docker_cli_save_load_test.go" "integration-cli/docker_cli_save_load_unix_test.go" "integration-cli/docker_cli_search_test.go" "integration-cli/docker_cli_service_create_test.go" "integration-cli/docker_cli_service_health_test.go" "integration-cli/docker_cli_service_logs_test.go" "integration-cli/docker_cli_service_scale_test.go" "integration-cli/docker_cli_sni_test.go" "integration-cli/docker_cli_start_test.go" "integration-cli/docker_cli_stats_test.go" "integration-cli/docker_cli_swarm_test.go" "integration-cli/docker_cli_swarm_unix_test.go" "integration-cli/docker_cli_top_test.go" "integration-cli/docker_cli_update_unix_test.go" "integration-cli/docker_cli_userns_test.go" "integration-cli/docker_cli_v2_only_test.go" "integration-cli/docker_cli_volume_test.go" "integration-cli/docker_deprecated_api_v124_test.go" "integration-cli/docker_deprecated_api_v124_unix_test.go" "integration-cli/docker_hub_pull_suite_test.go" "integration-cli/docker_utils_test.go" "integration-cli/events_utils_test.go" "integration-cli/fixtures_linux_daemon_test.go" "integration-cli/utils_test.go" "pkg/discovery/discovery_test.go" "pkg/discovery/file/file_test.go" "pkg/discovery/generator_test.go" "pkg/discovery/kv/kv_test.go" "pkg/discovery/memory/memory_test.go" "pkg/discovery/nodes/nodes_test.go" Signed-off-by: Tibor Vass <tibor@docker.com>
2019-09-09 21:05:55 +00:00
extractBody := func(c *testing.T, cfg types.ContainerLogsOptions) []string {
reader, err := client.ContainerLogs(context.Background(), name, cfg)
assert.NilError(c, err)
actualStdout := new(bytes.Buffer)
actualStderr := io.Discard
_, err = stdcopy.StdCopy(actualStdout, actualStderr, reader)
assert.NilError(c, err)
return strings.Split(actualStdout.String(), "\n")
}
// Get timestamp of second log line
allLogs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true})
// Test with default value specified and parameter omitted
defaultLogs := extractBody(c, types.ContainerLogsOptions{Timestamps: true, ShowStdout: true, Until: "0"})
assert.DeepEqual(c, defaultLogs, allLogs)
}