1package logging
2
3import (
4	"bufio"
5	"context"
6	"os"
7	"strings"
8	"testing"
9	"time"
10
11	"github.com/docker/docker/api/types"
12	"github.com/docker/docker/integration/internal/container"
13	"github.com/docker/docker/internal/test/daemon"
14	"gotest.tools/assert"
15	"gotest.tools/skip"
16)
17
18func TestContinueAfterPluginCrash(t *testing.T) {
19	skip.If(t, testEnv.IsRemoteDaemon(), "test requires daemon on the same host")
20	t.Parallel()
21
22	d := daemon.New(t)
23	d.StartWithBusybox(t, "--iptables=false", "--init")
24	defer d.Stop(t)
25
26	client := d.NewClientT(t)
27	createPlugin(t, client, "test", "close_on_start", asLogDriver)
28
29	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
30	assert.Assert(t, client.PluginEnable(ctx, "test", types.PluginEnableOptions{Timeout: 30}))
31	cancel()
32	defer client.PluginRemove(context.Background(), "test", types.PluginRemoveOptions{Force: true})
33
34	ctx, cancel = context.WithTimeout(context.Background(), 60*time.Second)
35
36	id := container.Run(t, ctx, client,
37		container.WithAutoRemove,
38		container.WithLogDriver("test"),
39		container.WithCmd(
40			"/bin/sh", "-c", "while true; do sleep 1; echo hello; done",
41		),
42	)
43	cancel()
44	defer client.ContainerRemove(context.Background(), id, types.ContainerRemoveOptions{Force: true})
45
46	// Attach to the container to make sure it's written a few times to stdout
47	attach, err := client.ContainerAttach(context.Background(), id, types.ContainerAttachOptions{Stream: true, Stdout: true})
48	assert.Assert(t, err)
49
50	chErr := make(chan error)
51	go func() {
52		defer close(chErr)
53		rdr := bufio.NewReader(attach.Reader)
54		for i := 0; i < 5; i++ {
55			_, _, err := rdr.ReadLine()
56			if err != nil {
57				chErr <- err
58				return
59			}
60		}
61	}()
62
63	select {
64	case err := <-chErr:
65		assert.Assert(t, err)
66	case <-time.After(60 * time.Second):
67		t.Fatal("timeout waiting for container i/o")
68	}
69
70	// check daemon logs for "broken pipe"
71	// TODO(@cpuguy83): This is horribly hacky but is the only way to really test this case right now.
72	// It would be nice if there was a way to know that a broken pipe has occurred without looking through the logs.
73	log, err := os.Open(d.LogFileName())
74	assert.Assert(t, err)
75	scanner := bufio.NewScanner(log)
76	for scanner.Scan() {
77		assert.Assert(t, !strings.Contains(scanner.Text(), "broken pipe"))
78	}
79}
80