Skip to content

Commit

Permalink
Make gator root command
Browse files Browse the repository at this point in the history
Per decision in weekly meeting, make the "gator" root command and "test"
the subcommand in charge of running the tests. This frees us up to add
other subcommands that we want to do later.

Signed-off-by: Will Beason <willbeason@google.com>
  • Loading branch information
Will Beason committed Jun 25, 2021
1 parent 18b47c9 commit 7b9bb17
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 124 deletions.
112 changes: 0 additions & 112 deletions cmd/gatekeeper-test-alpha/gatekeeper-test-alpha.go

This file was deleted.

32 changes: 32 additions & 0 deletions cmd/gator/gator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"fmt"
"os"

"github.com/open-policy-agent/gatekeeper/cmd/gator/test"
"github.com/spf13/cobra"
)

const version = "alpha"

func init() {
rootCmd.AddCommand(test.Cmd)
}

var rootCmd = &cobra.Command{
Use: "gator subcommand",
Short: "gator is a suite of authorship tools for Gatekeeper",
Version: version,
RunE: func(cmd *cobra.Command, args []string) error {
return nil
},
}

func main() {
err := rootCmd.Execute()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
114 changes: 114 additions & 0 deletions cmd/gator/test/test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package test

import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"

"github.com/open-policy-agent/gatekeeper/pkg/gktest"
"github.com/spf13/cobra"
)

const (
examples = ` # Run all tests in label-tests.yaml
gator test label-tests.yaml
# Run all suites whose names contain "forbid-labels".
gator test tests/... --run forbid-labels//
# Run all tests whose names contain "nginx-deployment".
gator test tests/... --run //nginx-deployment
# Run all tests whose names exactly match "nginx-deployment".
gator test tests/... --run '//^nginx-deployment$'
# Run all tests that are either named "forbid-labels" or are
# in suites named "forbid-labels".
gator test tests/... --run '^forbid-labels$'`
)

var run string

func init() {
Cmd.Flags().StringVarP(&run, "run", "r", "",
`regular expression which filters tests to run by name`)
}

// Cmd is the gator test subcommand.
var Cmd = &cobra.Command{
Use: "test path [--run=name]",
Short: "test runs suites of tests on Gatekeeper Constraints",
Example: examples,
Args: cobra.ExactArgs(1),
RunE: runE,
}

func runE(_ *cobra.Command, args []string) error {
path := args[0]

// Convert path to be absolute. Allowing for relative and absolute paths
// everywhere in the code leads to unnecessary complexity, so the first
// thing we do on encountering a path is to convert it to an absolute path.
var err error
if !filepath.IsAbs(path) {
path, err = filepath.Abs(path)
if err != nil {
return fmt.Errorf("getting absolute path: %w", err)
}
}

// Create the base file system. We use fs.FS rather than direct calls to
// os.ReadFile or filepath.WalkDir to make testing easier and keep logic
// os-independent.
fileSystem := getFS(path)

suites, err := gktest.ReadSuites(fileSystem, path)
if err != nil {
return fmt.Errorf("listing test files: %w", err)
}
filter, err := gktest.NewFilter(run)
if err != nil {
return fmt.Errorf("compiling filter: %w", err)
}

return runSuites(fileSystem, suites, filter)
}

func runSuites(fileSystem fs.FS, suites []gktest.Suite, filter gktest.Filter) error {
isFailure := false
for _, s := range suites {
if !filter.MatchesSuite(s) {
continue
}

results := s.Run(fileSystem)
for _, result := range results {
if result.IsFailure() {
isFailure = true
}
fmt.Println(result.String())
}
}

if isFailure {
// At least one test failed or there was a problem executing tests in at
// least one file.
return errors.New("FAIL")
}
return nil
}

func getFS(path string) fs.FS {
// TODO(#1397): Check that this produces the correct file system string on
// Windows. We may need to add a trailing `/` for fs.FS to function properly.
root := filepath.VolumeName(path)
if root == "" {
// We are running on a unix-like filesystem without volume names, so the
// file system root is `/`.
root = "/"
}

return os.DirFS(root)
}
2 changes: 1 addition & 1 deletion pkg/controller/config/config_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ func TestReconcile(t *testing.T) {
g.Expect(syncNotExcludedPod).Should(gomega.BeFalse())
g.Expect(err).To(gomega.BeNil())

// Test finalizer removal
// MatchesTest finalizer removal

testMgrStopped()
cs.Stop()
Expand Down
20 changes: 10 additions & 10 deletions pkg/gktest/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,28 @@ type Filter struct{}
// Matches tests in suites containing the string "require-foo-label" and tests
// containing the string "missing-label". So this would match all of the
// following:
// - Suite: "require-foo-label", Test: "missing-label"
// - Suite: "not-require-foo-label, Test: "not-missing-label"
// - Suite: "require-foo-label-and-bar-annotation", Test: "missing-label-and-annotation"
// - Suite: "require-foo-label", MatchesTest: "missing-label"
// - Suite: "not-require-foo-label, MatchesTest: "not-missing-label"
// - Suite: "require-foo-label-and-bar-annotation", MatchesTest: "missing-label-and-annotation"
//
// 2) NewFilter("missing-label")
// Matches tests which either have a name containing "missing-label" or which
// are in a suite containing "missing-label". Matches the following:
// - Suite: "forbid-missing-label", Test: "with-foo-label"
// - Suite: "required-labels", Test: "missing-label"
// - Suite: "forbid-missing-label", MatchesTest: "with-foo-label"
// - Suite: "required-labels", MatchesTest: "missing-label"
//
// 3) NewFilter("^require-foo-label$//")
// Matches tests in suites which exactly match "require-foo-label". Matches the
// following:
// - Suite: "require-foo-label", Test: "with-foo-label"
// - Suite: "require-foo-label", Test: "no-labels"
// - Suite: "require-foo-label", MatchesTest: "with-foo-label"
// - Suite: "require-foo-label", MatchesTest: "no-labels"
//
// 4) NewFilter("//empty-object")
// Matches tests whose names contain the string "empty-object". Matches the
// following:
// - Suite: "forbid-foo-label", Test: "empty-object"
// - Suite: "forbid-foo-label", Test: "another-empty-object"
// - Suite: "require-bar-annotation", Test: "empty-object"
// - Suite: "forbid-foo-label", MatchesTest: "empty-object"
// - Suite: "forbid-foo-label", MatchesTest: "another-empty-object"
// - Suite: "require-bar-annotation", MatchesTest: "empty-object"
func NewFilter(run string) (Filter, error) {
return Filter{}, nil
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/watch/manager_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ loop:
delete(expectNames, req.Name)
}
if len(expectNames) == 0 {
// Test successful
// MatchesTest successful
break loop
}
}
Expand Down

0 comments on commit 7b9bb17

Please sign in to comment.