From d72536cb40d8b607a71a2ec8997397ac3d6759de Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Thu, 14 Dec 2023 10:59:48 +0100 Subject: [PATCH] new(cmd/driver): added more driver commands tests. Signed-off-by: Federico Di Pierro --- cmd/driver/cleanup/cleanup_suite_test.go | 69 ++++++++++ cmd/driver/cleanup/cleanup_test.go | 100 ++++++++++++++ cmd/driver/install/install_suite_test.go | 69 ++++++++++ cmd/driver/install/install_test.go | 130 ++++++++++++++++++ cmd/driver/printenv/printenv_suite_test.go | 69 ++++++++++ cmd/driver/printenv/printenv_test.go | 145 +++++++++++++++++++++ 6 files changed, 582 insertions(+) create mode 100644 cmd/driver/cleanup/cleanup_suite_test.go create mode 100644 cmd/driver/cleanup/cleanup_test.go create mode 100644 cmd/driver/install/install_suite_test.go create mode 100644 cmd/driver/install/install_test.go create mode 100644 cmd/driver/printenv/printenv_suite_test.go create mode 100644 cmd/driver/printenv/printenv_test.go diff --git a/cmd/driver/cleanup/cleanup_suite_test.go b/cmd/driver/cleanup/cleanup_suite_test.go new file mode 100644 index 00000000..6099ba49 --- /dev/null +++ b/cmd/driver/cleanup/cleanup_suite_test.go @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package drivercleanup_test + +import ( + "context" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + "github.com/spf13/cobra" + + "github.com/falcosecurity/falcoctl/cmd" + commonoptions "github.com/falcosecurity/falcoctl/pkg/options" + testutils "github.com/falcosecurity/falcoctl/pkg/test" +) + +var ( + ctx = context.Background() + output = gbytes.NewBuffer() + rootCmd *cobra.Command + opt *commonoptions.Common + configFile string + err error + args []string +) + +func TestCleanup(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Cleanup Suite") +} + +var _ = BeforeSuite(func() { + + // Create and configure the common options. + opt = commonoptions.NewOptions() + opt.Initialize(commonoptions.WithWriter(output)) + + // Create temporary directory used to save the configuration file. + configFile, err = testutils.CreateEmptyFile("falcoctl.yaml") + Expect(err).Should(Succeed()) +}) + +var _ = AfterSuite(func() { + configDir := filepath.Dir(configFile) + Expect(os.RemoveAll(configDir)).Should(Succeed()) +}) + +func executeRoot(args []string) error { + rootCmd.SetArgs(args) + rootCmd.SetOut(output) + return cmd.Execute(rootCmd, opt) +} diff --git a/cmd/driver/cleanup/cleanup_test.go b/cmd/driver/cleanup/cleanup_test.go new file mode 100644 index 00000000..d9159367 --- /dev/null +++ b/cmd/driver/cleanup/cleanup_test.go @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package drivercleanup_test + +import ( + "regexp" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + + "github.com/falcosecurity/falcoctl/cmd" +) + +var driverCleanupHelp = `[Preview] Cleans a driver up, eg for kmod, by removing it from dkms. +** This command is in preview and under development. ** + +Usage: + falcoctl driver cleanup [flags] + +Flags: + -h, --help help for cleanup + +Global Flags: + --config string config file to be used for falcoctl (default "/etc/falcoctl/falcoctl.yaml") + --host-root string Driver host root to be used. (default "/") + --log-format string Set formatting for logs (color, text, json) (default "color") + --log-level string Set level for logs (info, warn, debug, trace) (default "info") + --name string Driver name to be used. (default "falco") + --repo strings Driver repo to be used. (default [https://download.falco.org/driver]) + --type string Driver type to be used (auto, ebpf, kmod, modern_ebpf) (default "kmod") + --version string Driver version to be used. +` + +var addAssertFailedBehavior = func(specificError string) { + It("check that fails and the usage is not printed", func() { + Expect(err).To(HaveOccurred()) + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(specificError))) + }) +} + +var _ = Describe("cleanup", func() { + + var ( + driverCmd = "driver" + cleanupCmd = "cleanup" + ) + + // Each test gets its own root command and runs it. + // The err variable is asserted by each test. + JustBeforeEach(func() { + rootCmd = cmd.New(ctx, opt) + err = executeRoot(args) + }) + + JustAfterEach(func() { + Expect(output.Clear()).ShouldNot(HaveOccurred()) + }) + + Context("help message", func() { + BeforeEach(func() { + args = []string{driverCmd, cleanupCmd, "--help"} + }) + + It("should match the saved one", func() { + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(driverCleanupHelp))) + }) + }) + + // Here we are testing failure cases for cleaning a driver. + Context("failure", func() { + When("with non absolute host-root", func() { + BeforeEach(func() { + args = []string{driverCmd, cleanupCmd, "--config", configFile, "--host-root", "foo/"} + }) + addAssertFailedBehavior("ERROR host-root must be an absolute path (foo/)") + }) + + When("with invalid driver type", func() { + BeforeEach(func() { + args = []string{driverCmd, cleanupCmd, "--config", configFile, "--type", "foo"} + }) + addAssertFailedBehavior(`ERROR invalid argument "foo" for "--type" flag: invalid argument "foo",` + + ` please provide one of (auto, ebpf, kmod, modern_ebpf)`) + }) + }) +}) diff --git a/cmd/driver/install/install_suite_test.go b/cmd/driver/install/install_suite_test.go new file mode 100644 index 00000000..fb178e6a --- /dev/null +++ b/cmd/driver/install/install_suite_test.go @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverinstall_test + +import ( + "context" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + "github.com/spf13/cobra" + + "github.com/falcosecurity/falcoctl/cmd" + commonoptions "github.com/falcosecurity/falcoctl/pkg/options" + testutils "github.com/falcosecurity/falcoctl/pkg/test" +) + +var ( + ctx = context.Background() + output = gbytes.NewBuffer() + rootCmd *cobra.Command + opt *commonoptions.Common + configFile string + err error + args []string +) + +func TestInstall(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Install Suite") +} + +var _ = BeforeSuite(func() { + + // Create and configure the common options. + opt = commonoptions.NewOptions() + opt.Initialize(commonoptions.WithWriter(output)) + + // Create temporary directory used to save the configuration file. + configFile, err = testutils.CreateEmptyFile("falcoctl.yaml") + Expect(err).Should(Succeed()) +}) + +var _ = AfterSuite(func() { + configDir := filepath.Dir(configFile) + Expect(os.RemoveAll(configDir)).Should(Succeed()) +}) + +func executeRoot(args []string) error { + rootCmd.SetArgs(args) + rootCmd.SetOut(output) + return cmd.Execute(rootCmd, opt) +} diff --git a/cmd/driver/install/install_test.go b/cmd/driver/install/install_test.go new file mode 100644 index 00000000..a3591dc1 --- /dev/null +++ b/cmd/driver/install/install_test.go @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverinstall_test + +import ( + "regexp" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + + "github.com/falcosecurity/falcoctl/cmd" +) + +//nolint:lll // no need to check for line length. +var driverInstallHelp = `[Preview] Install previously configured driver, either downloading it or attempting a build. +** This command is in preview and under development. ** + +Usage: + falcoctl driver install [flags] + +Flags: + --compile Whether to enable local compilation of drivers (default true) + --download Whether to enable download of prebuilt drivers (default true) + -h, --help help for install + --http-insecure Whether you want to allow insecure downloads or not + --http-timeout duration Timeout for each http try (default 1m0s) + --kernelrelease string Specify the kernel release for which to download/build the driver in the same format used by 'uname -r' (e.g. '6.1.0-10-cloud-amd64') + --kernelversion string Specify the kernel version for which to download/build the driver in the same format used by 'uname -v' (e.g. '#1 SMP PREEMPT_DYNAMIC Debian 6.1.38-2 (2023-07-27)') + +Global Flags: + --config string config file to be used for falcoctl (default "/etc/falcoctl/falcoctl.yaml") + --host-root string Driver host root to be used. (default "/") + --log-format string Set formatting for logs (color, text, json) (default "color") + --log-level string Set level for logs (info, warn, debug, trace) (default "info") + --name string Driver name to be used. (default "falco") + --repo strings Driver repo to be used. (default [https://download.falco.org/driver]) + --type string Driver type to be used (auto, ebpf, kmod, modern_ebpf) (default "kmod") + --version string Driver version to be used. +` + +var addAssertFailedBehavior = func(specificError string) { + It("check that fails and the usage is not printed", func() { + Expect(err).To(HaveOccurred()) + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(specificError))) + }) +} + +var addAssertOkBehavior = func(specificOut string) { + It("check that does not fail and the usage is not printed", func() { + Succeed() + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(specificOut))) + }) +} + +var _ = Describe("install", func() { + + var ( + driverCmd = "driver" + installCmd = "install" + ) + + // Each test gets its own root command and runs it. + // The err variable is asserted by each test. + JustBeforeEach(func() { + rootCmd = cmd.New(ctx, opt) + err = executeRoot(args) + }) + + JustAfterEach(func() { + Expect(output.Clear()).ShouldNot(HaveOccurred()) + }) + + Context("help message", func() { + BeforeEach(func() { + args = []string{driverCmd, installCmd, "--help"} + }) + + It("should match the saved one", func() { + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(driverInstallHelp))) + }) + }) + + // Here we are testing failure cases for installing a driver. + Context("failure", func() { + When("with empty driver version", func() { + BeforeEach(func() { + args = []string{driverCmd, installCmd, "--config", configFile} + }) + addAssertFailedBehavior(`ERROR version is mandatory and cannot be empty`) + }) + + When("with non absolute host-root", func() { + BeforeEach(func() { + args = []string{driverCmd, installCmd, "--config", configFile, "--host-root", "foo/", "--version", "1.0.0+driver"} + }) + addAssertFailedBehavior("ERROR host-root must be an absolute path (foo/)") + }) + + When("with invalid driver type", func() { + BeforeEach(func() { + args = []string{driverCmd, installCmd, "--config", configFile, "--type", "foo", "--version", "1.0.0+driver"} + }) + addAssertFailedBehavior(`ERROR invalid argument "foo" for "--type" flag: invalid argument "foo",` + + ` please provide one of (auto, ebpf, kmod, modern_ebpf)`) + }) + }) + + Context("nothing-to-do", func() { + When("with false download and compile", func() { + BeforeEach(func() { + args = []string{driverCmd, installCmd, "--config", configFile, "--download=false", "--compile=false", "--version", "1.0.0+driver"} + }) + addAssertOkBehavior("INFO Nothing to do: download and compile disabled.") + }) + }) +}) diff --git a/cmd/driver/printenv/printenv_suite_test.go b/cmd/driver/printenv/printenv_suite_test.go new file mode 100644 index 00000000..a48a9e26 --- /dev/null +++ b/cmd/driver/printenv/printenv_suite_test.go @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverprintenv_test + +import ( + "context" + "os" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + "github.com/spf13/cobra" + + "github.com/falcosecurity/falcoctl/cmd" + commonoptions "github.com/falcosecurity/falcoctl/pkg/options" + testutils "github.com/falcosecurity/falcoctl/pkg/test" +) + +var ( + ctx = context.Background() + output = gbytes.NewBuffer() + rootCmd *cobra.Command + opt *commonoptions.Common + configFile string + err error + args []string +) + +func TestPrintenv(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Printenv Suite") +} + +var _ = BeforeSuite(func() { + + // Create and configure the common options. + opt = commonoptions.NewOptions() + opt.Initialize(commonoptions.WithWriter(output)) + + // Create temporary directory used to save the configuration file. + configFile, err = testutils.CreateEmptyFile("falcoctl.yaml") + Expect(err).Should(Succeed()) +}) + +var _ = AfterSuite(func() { + configDir := filepath.Dir(configFile) + Expect(os.RemoveAll(configDir)).Should(Succeed()) +}) + +func executeRoot(args []string) error { + rootCmd.SetArgs(args) + rootCmd.SetOut(output) + return cmd.Execute(rootCmd, opt) +} diff --git a/cmd/driver/printenv/printenv_test.go b/cmd/driver/printenv/printenv_test.go new file mode 100644 index 00000000..a4e681cb --- /dev/null +++ b/cmd/driver/printenv/printenv_test.go @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2023 The Falco Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package driverprintenv_test + +import ( + "bufio" + "os" + "regexp" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/onsi/gomega/gbytes" + + "github.com/falcosecurity/falcoctl/cmd" +) + +var driverPrintenvHelp = `[Preview] Print variables used by driver as env vars. +** This command is in preview and under development. ** + +Usage: + falcoctl driver printenv [flags] + +Flags: + -h, --help help for printenv + +Global Flags: + --config string config file to be used for falcoctl (default "/etc/falcoctl/falcoctl.yaml") + --host-root string Driver host root to be used. (default "/") + --log-format string Set formatting for logs (color, text, json) (default "color") + --log-level string Set level for logs (info, warn, debug, trace) (default "info") + --name string Driver name to be used. (default "falco") + --repo strings Driver repo to be used. (default [https://download.falco.org/driver]) + --type string Driver type to be used (auto, ebpf, kmod, modern_ebpf) (default "kmod") + --version string Driver version to be used. +` + +var driverPrintenvDefaultConfig = `DRIVER="kmod" +DRIVERS_REPO="https:\/\/download\.falco\.org\/driver" +DRIVER_VERSION="1.0.0\+driver" +DRIVER_NAME="falco" +HOST_ROOT="\/" +TARGET_ID=".*" +ARCH="x86_64|aarch64" +KERNEL_RELEASE=".*" +KERNEL_VERSION=".*" +FIXED_KERNEL_RELEASE=".*" +FIXED_KERNEL_VERSION=".*" +` + +var addAssertFailedBehavior = func(specificError string) { + It("check that fails and the usage is not printed", func() { + Expect(err).To(HaveOccurred()) + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(specificError))) + }) +} + +var _ = Describe("printenv", func() { + + var ( + driverCmd = "driver" + printenvCmd = "printenv" + ) + + // Each test gets its own root command and runs it. + // The err variable is asserted by each test. + JustBeforeEach(func() { + rootCmd = cmd.New(ctx, opt) + err = executeRoot(args) + }) + + JustAfterEach(func() { + Expect(output.Clear()).ShouldNot(HaveOccurred()) + }) + + Context("help message", func() { + BeforeEach(func() { + args = []string{driverCmd, printenvCmd, "--help"} + }) + + It("should match the saved one", func() { + Expect(output).Should(gbytes.Say(regexp.QuoteMeta(driverPrintenvHelp))) + }) + }) + + // Here we are testing failure cases for cleaning a driver. + Context("failure", func() { + When("with empty driver version", func() { + BeforeEach(func() { + args = []string{driverCmd, printenvCmd, "--config", configFile} + }) + addAssertFailedBehavior(`ERROR version is mandatory and cannot be empty `) + }) + + When("with non absolute host-root", func() { + BeforeEach(func() { + args = []string{driverCmd, printenvCmd, "--config", configFile, "--host-root", "foo/", "--version", "1.0.0+driver"} + }) + addAssertFailedBehavior("ERROR host-root must be an absolute path (foo/)") + }) + + When("with invalid driver type", func() { + BeforeEach(func() { + args = []string{driverCmd, printenvCmd, "--config", configFile, "--type", "foo", "--version", "1.0.0+driver"} + }) + addAssertFailedBehavior(`ERROR invalid argument "foo" for "--type" flag: invalid argument "foo",` + + ` please provide one of (auto, ebpf, kmod, modern_ebpf)`) + }) + }) + + Context("success", func() { + When("with default config values", func() { + BeforeEach(func() { + args = []string{driverCmd, printenvCmd, "--config", configFile, "--version", "1.0.0+driver"} + }) + + It("should match the saved one", func() { + Succeed() + MatchRegexp(driverPrintenvDefaultConfig) + Expect(string(output.Contents())).To(MatchRegexp(driverPrintenvDefaultConfig)) + // Expect that output is bash setenv compatible + scanner := bufio.NewScanner(output) + for scanner.Scan() { + vals := strings.Split(scanner.Text(), "=") + Expect(vals).Should(HaveLen(2)) + err := os.Setenv(vals[0], vals[1]) + Expect(err).Should(BeNil()) + } + }) + }) + }) +})