123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- package container
- import (
- "io"
- "strings"
- "testing"
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/integration/internal/container"
- "github.com/docker/docker/pkg/archive"
- "github.com/docker/docker/pkg/dmesg"
- "gotest.tools/v3/assert"
- "gotest.tools/v3/skip"
- )
- func TestNoOverlayfsWarningsAboutUndefinedBehaviors(t *testing.T) {
- skip.If(t, testEnv.DaemonInfo.OSType != "linux", "overlayfs is only available on linux")
- skip.If(t, testEnv.IsRemoteDaemon(), "local daemon is needed for kernel log access")
- skip.If(t, testEnv.IsRootless(), "root is needed for reading kernel log")
- ctx := setupTest(t)
- client := testEnv.APIClient()
- cID := container.Run(ctx, t, client, container.WithCmd("sh", "-c", `while true; do echo $RANDOM >>/file; sleep 0.1; done`))
- testCases := []struct {
- name string
- operation func(t *testing.T) error
- }{
- {name: "diff", operation: func(*testing.T) error {
- _, err := client.ContainerDiff(ctx, cID)
- return err
- }},
- {name: "export", operation: func(*testing.T) error {
- rc, err := client.ContainerExport(ctx, cID)
- if err == nil {
- defer rc.Close()
- _, err = io.Copy(io.Discard, rc)
- }
- return err
- }},
- {name: "cp to container", operation: func(t *testing.T) error {
- archive, err := archive.Generate("new-file", "hello-world")
- assert.NilError(t, err, "failed to create a temporary archive")
- return client.CopyToContainer(ctx, cID, "/", archive, types.CopyToContainerOptions{})
- }},
- {name: "cp from container", operation: func(*testing.T) error {
- rc, _, err := client.CopyFromContainer(ctx, cID, "/file")
- if err == nil {
- defer rc.Close()
- _, err = io.Copy(io.Discard, rc)
- }
- return err
- }},
- }
- for _, tc := range testCases {
- tc := tc
- t.Run(tc.name, func(t *testing.T) {
- prev := dmesgLines(256)
- err := tc.operation(t)
- assert.NilError(t, err)
- after := dmesgLines(2048)
- diff := diffDmesg(prev, after)
- for _, line := range diff {
- overlayfs := strings.Contains(line, "overlayfs: ")
- lowerDirInUse := strings.Contains(line, "lowerdir is in-use as ")
- upperDirInUse := strings.Contains(line, "upperdir is in-use as ")
- workDirInuse := strings.Contains(line, "workdir is in-use as ")
- undefinedBehavior := strings.Contains(line, "will result in undefined behavior")
- if overlayfs && (lowerDirInUse || upperDirInUse || workDirInuse) && undefinedBehavior {
- t.Errorf("%s caused overlayfs kernel warning: %s", tc.name, line)
- }
- }
- })
- }
- }
- func dmesgLines(bytes int) []string {
- data := dmesg.Dmesg(bytes)
- return strings.Split(strings.TrimSpace(string(data)), "\n")
- }
- func diffDmesg(prev, next []string) []string {
- // All lines have a timestamp, so just take the last one from the previous
- // log and find it in the new log.
- lastPrev := prev[len(prev)-1]
- for idx := len(next) - 1; idx >= 0; idx-- {
- line := next[idx]
- if line == lastPrev {
- nextIdx := idx + 1
- if nextIdx < len(next) {
- return next[nextIdx:]
- } else {
- // Found at the last position, log is the same.
- return nil
- }
- }
- }
- return next
- }
|