From 1bfb549b2c0717c48ebd84b2a5ca79b2023d9af7 Mon Sep 17 00:00:00 2001 From: Anqi Pang Date: Wed, 23 Nov 2022 13:48:07 -0800 Subject: [PATCH] feat: add e2e tests for logging flags of run command Signed-off-by: Anqi Pang --- run/run_test.go | 15 +++++- tests/run.go | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/tests.go | 1 + 3 files changed, 138 insertions(+), 1 deletion(-) diff --git a/run/run_test.go b/run/run_test.go index 9634c20..b3a34e1 100644 --- a/run/run_test.go +++ b/run/run_test.go @@ -28,6 +28,19 @@ func TestRun(t *testing.T) { t.Fatalf("failed to initialize a testing option: %v", err) } + var journalctlOpt *option.Option + var jerr error + + if *subject == "finch" { + journalctlOpt, jerr = option.New( + []string{"/Applications/Finch/lima/bin/limactl", "shell", "finch", "sudo", "journalctl"}, + option.Env([]string{"LIMA_HOME=/Applications/Finch/lima/data"}), + ) + } + if jerr != nil { + t.Fatalf("failed to initialize the journactl option: %v", err) + } + ginkgo.SynchronizedBeforeSuite(func() []byte { tests.SetupLocalRegistry(o) return nil @@ -44,7 +57,7 @@ func TestRun(t *testing.T) { tests.Pull(o) tests.Rm(o) tests.Rmi(o) - tests.Run(&tests.RunOption{BaseOpt: o, CGMode: tests.Unified}) + tests.Run(&tests.RunOption{BaseOpt: o, CGMode: tests.Unified, JournalctlOpt: journalctlOpt}) tests.Start(o) tests.Stop(o) tests.Cp(o) diff --git a/tests/run.go b/tests/run.go index 1237d24..0373d65 100644 --- a/tests/run.go +++ b/tests/run.go @@ -27,6 +27,8 @@ type RunOption struct { BaseOpt *option.Option // CGMode is the cgroup mode that the host uses. CGMode CGMode + // JournalctlOpt instructs how to run the journalctl binary. If it's nil, test cases related to `--log-driver journald` will be skipped. + JournalctlOpt *option.Option } // Run tests running a container image. @@ -560,6 +562,127 @@ func Run(o *RunOption) { } }) } + ginkgo.When("running a container with logging flags", func() { + ginkgo.It("should set the logging driver as json-file with --log-driver json-file", func() { + ctrID := command.StdoutStr(o.BaseOpt, "run", "-d", "--log-driver", "json-file", "--name", testContainerName, defaultImage) + logPath := command.StdoutStr(o.BaseOpt, "inspect", testContainerName, "--format", "{{.LogPath}}") + gomega.Expect(logPath).Should(gomega.ContainSubstring(fmt.Sprintf("%s-json.log", ctrID))) + }) + + ginkgo.It("should set the logging path of the logging driver json-file with --log-opt log-path option", func() { + tmpDir := ffs.CreateTempDir("finch-test-logging") + ginkgo.DeferCleanup(os.RemoveAll, tmpDir) + customPath := filepath.Join(tmpDir, testContainerName, testContainerName+"-json.log") + command.Run(o.BaseOpt, "run", "-d", "--log-driver", "json-file", "--log-opt", fmt.Sprintf("log-path=%s", customPath), + "--name", testContainerName, defaultImage, "echo", "foo") + time.Sleep(3 * time.Second) + logData, err := os.ReadFile(filepath.Clean(customPath)) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(string(logData)).To(gomega.ContainSubstring("foo")) + }) + + ginkgo.It("should set the log max size of the logging driver json-file with --log-opt max-size option", func() { + tmpDir := ffs.CreateTempDir("finch-test-logging") + ginkgo.DeferCleanup(os.RemoveAll, tmpDir) + customPath := filepath.Join(tmpDir, testContainerName, testContainerName+"-json.log") + command.Run(o.BaseOpt, "run", "-d", "--log-driver", "json-file", "--log-opt", fmt.Sprintf("log-path=%s", customPath), + "--log-opt", "max-size=5k", "--name", testContainerName, defaultImage, "sh", "-c", + "cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 100 | head -n 1000") + time.Sleep(3 * time.Second) + logs, err := filepath.Glob(customPath + "*") + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + for _, l := range logs { + li, err := os.Stat(l) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + // The log file size is compared to 5200 bytes (instead 5k) to keep docker compatibility. + //nolint: lll // Ref. https://github.com/containerd/nerdctl/blob/b71443b2a3abc6288944c72229a2e21a1ae7ec6e/cmd/nerdctl/run_test.go#L242-L244 + gomega.Expect(li.Size()).Should(gomega.BeNumerically("<=", 5200)) + } + }) + + ginkgo.It("should set the max number of log files of the logging driver json-file with --log-opt max-file option", func() { + tmpDir := ffs.CreateTempDir("finch-test-logging") + ginkgo.DeferCleanup(os.RemoveAll, tmpDir) + customPath := filepath.Join(tmpDir, testContainerName, testContainerName+"-json.log") + command.Run(o.BaseOpt, "run", "-d", "--log-driver", "json-file", "--log-opt", fmt.Sprintf("log-path=%s", customPath), + "--log-opt", "max-file=2", "--log-opt", "max-size=2k", "--name", testContainerName, defaultImage, "sh", "-c", + "cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 100 | head -n 1000") + time.Sleep(3 * time.Second) + logs, err := filepath.Glob(filepath.Join(filepath.Dir(customPath), testContainerName+"*")) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Expect(len(logs)).To(gomega.Equal(2)) + }) + + ginkgo.It("should set the logging driver as journald with --log-driver journald", func() { + if o.JournalctlOpt == nil { + ginkgo.Skip("Skip the test spec because the journald option is nil.") + } + ctrID := command.StdoutStr(o.BaseOpt, "run", "-d", "--log-driver", "journald", "--name", + testContainerName, defaultImage, "sh", "-c", "echo test") + time.Sleep(3 * time.Second) + output := command.StdoutStr(o.JournalctlOpt, "--since", "1 minute ago", fmt.Sprintf("SYSLOG_IDENTIFIER=%s", ctrID[:12])) + gomega.Expect(output).Should(gomega.ContainSubstring("test")) + }) + + // TODO: figure out why custom logging tags doesn't work https://docs.docker.com/config/containers/logging/log_tags/ + ginkgo.It("should set the tag option of the logging driver journald with --log-driver=journald --log-opt=tag={{.FullID}}}", func() { + if o.JournalctlOpt == nil { + ginkgo.Skip("Skip the test spec because the journald option is nil.") + } + ctrID := command.StdoutStr(o.BaseOpt, "run", "-d", "--log-driver", "journald", "--name", testContainerName, + "--log-opt", "tag={{.FullID}}", defaultImage, "sh", "-c", "echo foo") + time.Sleep(3 * time.Second) + output := command.StdoutStr(o.JournalctlOpt, "--since", "3 minute ago", fmt.Sprintf("SYSLOG_IDENTIFIER=%s", ctrID)) + gomega.Expect(output).Should(gomega.ContainSubstring("foo")) + }) + + ginkgo.It("should set the logging driver as fluentd with --log-driver fluentd", func() { + testConfStr := ` + @type forward + + + + @type file + path /tmp/log + ` + testConfFilename := "test.conf" + testConfFile := ffs.CreateTempFile(testConfFilename, testConfStr) + ginkgo.DeferCleanup(os.RemoveAll, testConfFile) + fluentCtrID := command.StdoutStr(o.BaseOpt, "run", "-d", "-p", "24224:24224", "-v", + fmt.Sprintf("%s:/fluentd/etc/%s", testConfFile, testConfFilename), + "-u", "root", "-e", fmt.Sprintf("FLUENTD_CONF=%s", testConfFilename), fluentdImage) + time.Sleep(3 * time.Second) + ctrID := command.StdoutStr(o.BaseOpt, "run", "-d", "--log-driver", "fluentd", defaultImage, "sh", "-c", "echo foo") + output := command.StdoutStr(o.BaseOpt, "exec", fluentCtrID, "sh", "-c", "cat /tmp/log/*.log") + gomega.Expect(output).Should(gomega.ContainSubstring("foo")) + gomega.Expect(output).Should(gomega.ContainSubstring(ctrID)) + }) + + ginkgo.It("should set the fluentd address with --log-driver fluentd --fluentd-address=127.0.0.1:24225", func() { + testConfStr := ` + @type forward + + + + @type file + path /tmp/log + ` + testConfFilename := "test.conf" + testConfFile := ffs.CreateTempFile(testConfFilename, testConfStr) + ginkgo.DeferCleanup(os.RemoveAll, testConfFile) + fluentCtrID := command.StdoutStr(o.BaseOpt, "run", "-d", "-p", "24225:24224", "-v", + fmt.Sprintf("%s:/fluentd/etc/%s", testConfFile, testConfFilename), + "-u", "root", "-e", fmt.Sprintf("FLUENTD_CONF=%s", testConfFilename), fluentdImage) + time.Sleep(3 * time.Second) + ctrID := command.StdoutStr(o.BaseOpt, "run", "-d", "--log-driver", "fluentd", "--log-opt", + "fluentd-address=127.0.0.1:24225", defaultImage, "sh", "-c", "echo foo") + output := command.StdoutStr(o.BaseOpt, "exec", fluentCtrID, "sh", "-c", "cat /tmp/log/*.log") + gomega.Expect(output).Should(gomega.ContainSubstring("foo")) + gomega.Expect(output).Should(gomega.ContainSubstring(ctrID)) + }) + + // TODO: test syslog + }) }) } diff --git a/tests/tests.go b/tests/tests.go index c63ba9f..4159487 100644 --- a/tests/tests.go +++ b/tests/tests.go @@ -27,6 +27,7 @@ import ( const ( alpineImage = "public.ecr.aws/docker/library/alpine:latest" olderAlpineImage = "public.ecr.aws/docker/library/alpine:3.13" + fluentdImage = "public.ecr.aws/docker/library/fluentd:latest" testImageName = "test:tag" nonexistentImageName = "ne-repo:ne-tag" nonexistentContainerName = "ne-ctr"