From 82370f3555b328565f90e5ad4188f9fed5d5d5fc Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sun, 24 May 2020 17:43:42 +0200 Subject: [PATCH] [#321] platformtest: generate test case list + coverage tooling --- .circleci/config.yml | 4 +- Makefile | 71 +++++++++---- README.md | 12 ++- build/go.mod | 1 + build/go.sum | 2 + build/tools.go | 1 + go.mod | 1 + go.sum | 1 + lazy.sh | 3 +- platformtest/harness/harness.go | 45 +++++---- platformtest/harness/harness_test.go | 16 ++- platformtest/platformtest_zpool.go | 12 +++ platformtest/tests/gen/gen.go | 140 ++++++++++++++++++++++++++ platformtest/tests/generated_cases.go | 22 ++++ platformtest/tests/tests.go | 20 +--- 15 files changed, 284 insertions(+), 67 deletions(-) create mode 100644 platformtest/tests/gen/gen.go create mode 100644 platformtest/tests/generated_cases.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 7befa9c..3c58063 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -60,10 +60,10 @@ jobs: - run: make zrepl-bin - run: make vet - - run: make test - run: make lint - run: make release - + - run: make test-go + # cannot run test-platform because circle-ci runs in linux containers - store_artifacts: path: ./artifacts/release diff --git a/Makefile b/Makefile index 6038420..30c8755 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,8 @@ GO_EXTRA_BUILDFLAGS := GO_BUILDFLAGS := $(GO_MOD_READONLY) $(GO_EXTRA_BUILDFLAGS) GO_BUILD := $(GO_ENV_VARS) $(GO) build $(GO_BUILDFLAGS) -ldflags $(GO_LDFLAGS) GOLANGCI_LINT := golangci-lint +GOCOVMERGE := gocovmerge + ifneq ($(GOARM),) ZREPL_TARGET_TUPLE := $(GOOS)-$(GOARCH)v$(GOARM) else @@ -45,7 +47,7 @@ printvars: release: clean # no cross-platform support for target test - $(MAKE) test + $(MAKE) test-go $(MAKE) bins-all $(MAKE) noarch $(MAKE) wrapup-and-checksum @@ -99,9 +101,9 @@ clean: docs-clean rm -rf "$(ARTIFACTDIR)" ##################### BINARIES ##################### -.PHONY: bins-all lint test vet zrepl-bin platformtest-bin +.PHONY: bins-all lint test-go test-platform cover-merge cover-html vet zrepl-bin test-platform-bin generate-platform-test-list -BINS_ALL_TARGETS := zrepl-bin platformtest-bin vet lint +BINS_ALL_TARGETS := zrepl-bin test-platform-bin vet lint GO_SUPPORTS_ILLUMOS := $(shell $(GO) version | gawk -F '.' '/^go version /{split($$0, comps, " "); split(comps[3], v, "."); if (v[1] == "go1" && v[2] >= 13) { print "illumos"; } else { print "noillumos"; }}') bins-all: $(MAKE) $(BINS_ALL_TARGETS) GOOS=freebsd GOARCH=amd64 @@ -122,27 +124,34 @@ endif lint: $(GO_ENV_VARS) $(GOLANGCI_LINT) run ./... -test: - $(GO_ENV_VARS) $(GO) test $(GO_BUILDFLAGS) ./... + vet: $(GO_ENV_VARS) $(GO) vet $(GO_BUILDFLAGS) ./... +test-go: $(ARTIFACTDIR) + rm -f "$(ARTIFACTDIR)/gotest.cover" +ifeq ($(COVER),1) + $(GO_ENV_VARS) $(GO) test $(GO_BUILDFLAGS) \ + -coverpkg github.com/zrepl/zrepl/... \ + -covermode atomic \ + -coverprofile "$(ARTIFACTDIR)/gotest.cover" \ + ./... +else + $(GO_ENV_VARS) $(GO) test $(GO_BUILDFLAGS) \ + ./... +endif + zrepl-bin: $(GO_BUILD) -o "$(ARTIFACTDIR)/zrepl-$(ZREPL_TARGET_TUPLE)" -platformtest-bin: - $(GO_BUILD) -o "$(ARTIFACTDIR)/platformtest-$(ZREPL_TARGET_TUPLE)" ./platformtest/harness +generate-platform-test-list: + $(GO_BUILD) -o $(ARTIFACTDIR)/generate-platform-test-list ./platformtest/tests/gen -##################### DEV TARGETS ##################### -# not part of the build, must do that manually -.PHONY: generate format platformtest - -generate: - protoc -I=replication/logic/pdu --go_out=plugins=grpc:replication/logic/pdu replication/logic/pdu/pdu.proto - $(GO_ENV_VARS) $(GO) generate $(GO_BUILDFLAGS) -x ./... - -format: - goimports -srcdir . -local 'github.com/zrepl/zrepl' -w $(shell find . -type f -name '*.go' -not -path "./vendor/*" -not -name '*.pb.go' -not -name '*_enumer.go') +test-platform-bin: + $(GO_ENV_VARS) $(GO) test $(GO_BUILDFLAGS) \ + -c -o "$(ARTIFACTDIR)/platformtest-$(ZREPL_TARGET_TUPLE)" \ + -covermode=atomic -cover -coverpkg github.com/zrepl/zrepl/... \ + ./platformtest/harness ZREPL_PLATFORMTEST_POOLNAME := zreplplatformtest ZREPL_PLATFORMTEST_IMAGEPATH := /tmp/zreplplatformtest.pool.img @@ -150,16 +159,42 @@ ZREPL_PLATFORMTEST_MOUNTPOINT := /tmp/zreplplatformtest.pool ZREPL_PLATFORMTEST_ZFS_LOG := /tmp/zreplplatformtest.zfs.log # ZREPL_PLATFORMTEST_STOP_AND_KEEP := -failure.stop-and-keep-pool ZREPL_PLATFORMTEST_ARGS := -platformtest: # do not track dependency on platformtest-bin to allow build of platformtest outside of test VM +test-platform: $(ARTIFACTDIR) # do not track dependency on test-platform-bin to allow build of platformtest outside of test VM rm -f "$(ZREPL_PLATFORMTEST_ZFS_LOG)" + rm -f "$(ARTIFACTDIR)/platformtest.cover" platformtest/logmockzfs/logzfsenv "$(ZREPL_PLATFORMTEST_ZFS_LOG)" `which zfs` \ "$(ARTIFACTDIR)/platformtest-$(ZREPL_TARGET_TUPLE)" \ + -test.coverprofile "$(ARTIFACTDIR)/platformtest.cover" \ + -test.v \ + __DEVEL--i-heard-you-like-tests \ -poolname "$(ZREPL_PLATFORMTEST_POOLNAME)" \ -imagepath "$(ZREPL_PLATFORMTEST_IMAGEPATH)" \ -mountpoint "$(ZREPL_PLATFORMTEST_MOUNTPOINT)" \ $(ZREPL_PLATFORMTEST_STOP_AND_KEEP) \ $(ZREPL_PLATFORMTEST_ARGS) +cover-merge: $(ARTIFACTDIR) + $(GOCOVMERGE) $(ARTIFACTDIR)/platformtest.cover $(ARTIFACTDIR)/gotest.cover > $(ARTIFACTDIR)/merged.cover +cover-html: cover-merge + $(GO) tool cover -html "$(ARTIFACTDIR)/merged.cover" -o "$(ARTIFACTDIR)/merged.cover.html" + +test-full: + test "$$(id -u)" = "0" || echo "MUST RUN AS ROOT" 1>&2 + $(MAKE) test-go COVER=1 + $(MAKE) test-platform + $(MAKE) cover-html + +##################### DEV TARGETS ##################### +# not part of the build, must do that manually +.PHONY: generate format + +generate: generate-platform-test-list + protoc -I=replication/logic/pdu --go_out=plugins=grpc:replication/logic/pdu replication/logic/pdu/pdu.proto + $(GO_ENV_VARS) $(GO) generate $(GO_BUILDFLAGS) -x ./... + +format: + goimports -srcdir . -local 'github.com/zrepl/zrepl' -w $(shell find . -type f -name '*.go' -not -path "./vendor/*" -not -name '*.pb.go' -not -name '*_enumer.go') + ##################### NOARCH ##################### .PHONY: noarch $(ARTIFACTDIR)/bash_completion $(ARTIFACTDIR)/_zrepl.zsh_completion $(ARTIFACTDIR)/go_env.txt docs docs-clean diff --git a/README.md b/README.md index 632432f..c58fa81 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Check out the *Coding Workflow* section below for details. * Ship other material provided in `./dist`, e.g. in `/usr/share/zrepl/`. * Use `make release ZREPL_VERSION='mydistro-1.2.3_1'` * Your distro's name and any versioning supplemental to zrepl's (e.g. package revision) should be in this string -* Use `make platformtest` **on a test system** to validate that zrepl's abstractions on top of ZFS work with the system ZFS. +* Use `sudo make test-platform` **on a test system** to validate that zrepl's abstractions on top of ZFS work with the system ZFS. * Make sure you are informed about new zrepl versions, e.g. by subscribing to GitHub's release RSS feed. ## Developer Documentation @@ -47,10 +47,18 @@ Check out the *Coding Workflow* section below for details. zrepl is written in [Go](https://golang.org) and uses [Go modules](https://github.com/golang/go/wiki/Modules) to manage dependencies. The documentation is written in [ReStructured Text](http://docutils.sourceforge.net/rst.html) using the [Sphinx](https://www.sphinx-doc.org) framework. -To get started, run `./lazy.sh devsetup` to easily install build dependencies and read `docs/installation.rst -> Compiling from Source`. +Install **build dependencies** using `./lazy.sh devsetup`. `lazy.sh` uses `python3-pip` to fetch the build dependencies for the docs - you might want to use a [venv](https://docs.python.org/3/library/venv.html). If you just want to install the Go dependencies, run `./lazy.sh godep`. +The **test suite** is split into pure **Go tests** (`make test-go`) and **platform tests** that interact with ZFS and thus generally **require root privileges** (`sudo make test-platform`). +Platform tests run on their own pool with the name `zreplplatformtest`, which is created using the file vdev in `/tmp`. + +For a full **code coverage** profile, run `make test-go COVER=1 && sudo make test-platform && make cover-merge`. +An HTML report can be generated using `make cover-html`. + +**Code generation** is triggered by `make generate`. Generated code is committed to the source tree. + ### Project Structure ``` diff --git a/build/go.mod b/build/go.mod index 05112ee..09d0953 100644 --- a/build/go.mod +++ b/build/go.mod @@ -28,6 +28,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/viper v1.3.2 // indirect github.com/stretchr/testify v1.4.0 // indirect + github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad // indirect golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 // indirect golang.org/x/sys v0.0.0-20191010194322-b09406accb47 // indirect golang.org/x/tools v0.0.0-20190524210228-3d17549cdc6b diff --git a/build/go.sum b/build/go.sum index ed967d4..528c130 100644 --- a/build/go.sum +++ b/build/go.sum @@ -214,6 +214,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad h1:W0LEBv82YCGEtcmPA3uNZBI33/qF//HAAs3MawDjRa0= +github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad/go.mod h1:Hy8o65+MXnS6EwGElrSRjUzQDLXreJlzYLlWiHtt8hM= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/build/tools.go b/build/tools.go index a3c7870..cb80a78 100644 --- a/build/tools.go +++ b/build/tools.go @@ -6,6 +6,7 @@ import ( _ "github.com/alvaroloes/enumer" _ "github.com/golang/protobuf/protoc-gen-go" _ "github.com/golangci/golangci-lint/cmd/golangci-lint" + _ "github.com/wadey/gocovmerge" _ "golang.org/x/tools/cmd/goimports" _ "golang.org/x/tools/cmd/stringer" ) diff --git a/go.mod b/go.mod index e6b4929..e88055a 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require ( golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 golang.org/x/sync v0.0.0-20190423024810-112230192c58 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 + golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e gonum.org/v1/gonum v0.7.0 // indirect google.golang.org/grpc v1.17.0 ) diff --git a/go.sum b/go.sum index 78038fb..e4404ea 100644 --- a/go.sum +++ b/go.sum @@ -351,6 +351,7 @@ golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20181205014116-22934f0fdb62/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e h1:Io7mpb+aUAGF0MKxbyQ7HQl1VgB+cL6ZJZUFaFNqVV4= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190213192042-740235f6c0d8/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= diff --git a/lazy.sh b/lazy.sh index 0297679..b90714e 100755 --- a/lazy.sh +++ b/lazy.sh @@ -36,9 +36,10 @@ godep() { go build -v -mod=readonly -o "$GOPATH/bin/enumer" github.com/alvaroloes/enumer go build -v -mod=readonly -o "$GOPATH/bin/goimports" golang.org/x/tools/cmd/goimports go build -v -mod=readonly -o "$GOPATH/bin/golangci-lint" github.com/golangci/golangci-lint/cmd/golangci-lint + go build -v -mod=readonly -o "$GOPATH/bin/gocovmerge" github.com/wadey/gocovmerge set +x popd - if ! type stringer || ! type protoc-gen-go || ! type enumer || ! type goimports || ! type golangci-lint; then + if ! type stringer || ! type protoc-gen-go || ! type enumer || ! type goimports || ! type golangci-lint || ! type gocovmerge; then echo "Installed dependencies but can't find them in \$PATH, adjust it to contain \$GOPATH/bin" 1>&2 exit 1 fi diff --git a/platformtest/harness/harness.go b/platformtest/harness/harness.go index 5a39bea..01d538c 100644 --- a/platformtest/harness/harness.go +++ b/platformtest/harness/harness.go @@ -24,33 +24,36 @@ var bold = color.New(color.Bold) var boldRed = color.New(color.Bold, color.FgHiRed) var boldGreen = color.New(color.Bold, color.FgHiGreen) -var args struct { - createArgs platformtest.ZpoolCreateArgs - stopAndKeepPoolOnFail bool - - run string - runRE *regexp.Regexp -} +const DefaultPoolImageSize = 200 * (1 << 20) func main() { - if err := doMain(); err != nil { + + var args HarnessArgs + + flag.StringVar(&args.CreateArgs.PoolName, "poolname", "", "") + flag.StringVar(&args.CreateArgs.ImagePath, "imagepath", "", "") + flag.Int64Var(&args.CreateArgs.ImageSize, "imagesize", DefaultPoolImageSize, "") + flag.StringVar(&args.CreateArgs.Mountpoint, "mountpoint", "", "") + flag.BoolVar(&args.StopAndKeepPoolOnFail, "failure.stop-and-keep-pool", false, "if a test case fails, stop test execution and keep pool as it was when the test failed") + flag.StringVar(&args.Run, "run", "", "") + flag.Parse() + + if err := HarnessRun(args); err != nil { os.Exit(1) } } var exitWithErr = fmt.Errorf("exit with error") -func doMain() error { +type HarnessArgs struct { + CreateArgs platformtest.ZpoolCreateArgs + StopAndKeepPoolOnFail bool + Run string +} - flag.StringVar(&args.createArgs.PoolName, "poolname", "", "") - flag.StringVar(&args.createArgs.ImagePath, "imagepath", "", "") - flag.Int64Var(&args.createArgs.ImageSize, "imagesize", 200*(1<<20), "") - flag.StringVar(&args.createArgs.Mountpoint, "mountpoint", "", "") - flag.BoolVar(&args.stopAndKeepPoolOnFail, "failure.stop-and-keep-pool", false, "if a test case fails, stop test execution and keep pool as it was when the test failed") - flag.StringVar(&args.run, "run", "", "") - flag.Parse() +func HarnessRun(args HarnessArgs) error { - args.runRE = regexp.MustCompile(args.run) + runRE := regexp.MustCompile(args.Run) outlets := logger.NewOutlets() outlet, level, err := logging.ParseOutlet(config.LoggingOutletEnum{Ret: &config.StdoutLoggingOutlet{ @@ -65,7 +68,7 @@ func doMain() error { outlets.Add(outlet, level) logger := logger.NewLogger(outlets, 1*time.Second) - if err := args.createArgs.Validate(); err != nil { + if err := args.CreateArgs.Validate(); err != nil { logger.Error(err.Error()) panic(err) } @@ -81,7 +84,7 @@ func doMain() error { invocations := make([]*invocation, 0, len(tests.Cases)) for _, c := range tests.Cases { - if args.runRE.MatchString(c.String()) { + if runRE.MatchString(c.String()) { invocations = append(invocations, &invocation{runFunc: c}) } } @@ -90,7 +93,7 @@ func doMain() error { bold.Printf("BEGIN TEST CASE %s\n", inv.runFunc.String()) - pool, err := platformtest.CreateOrReplaceZpool(ctx, ex, args.createArgs) + pool, err := platformtest.CreateOrReplaceZpool(ctx, ex, args.CreateArgs) if err != nil { panic(errors.Wrap(err, "create test pool")) } @@ -106,7 +109,7 @@ func doMain() error { fmt.Printf("%+v\n", res.failedStack) // print with stack trace } - if res.failed && args.stopAndKeepPoolOnFail { + if res.failed && args.StopAndKeepPoolOnFail { boldRed.Printf("STOPPING TEST RUN AT FAILING TEST PER USER REQUEST\n") return exitWithErr } diff --git a/platformtest/harness/harness_test.go b/platformtest/harness/harness_test.go index 08f002b..3589610 100644 --- a/platformtest/harness/harness_test.go +++ b/platformtest/harness/harness_test.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "os" "strings" "testing" @@ -21,22 +22,29 @@ import ( // https://github.com/wadey/gocovmerge func TestMain(t *testing.T) { + fmt.Println("incoming args: ", os.Args) + var ( - args []string - run bool + args []string + run bool + startCaptureArgs bool ) - for _, arg := range os.Args { + for i, arg := range os.Args { switch { case arg == "__DEVEL--i-heard-you-like-tests": run = true + startCaptureArgs = true case strings.HasPrefix(arg, "-test"): case strings.HasPrefix(arg, "__DEVEL"): - default: + case i == 0: + args = append(args, arg) + case startCaptureArgs: args = append(args, arg) } } os.Args = args + fmt.Println("using args: ", os.Args) if run { main() diff --git a/platformtest/platformtest_zpool.go b/platformtest/platformtest_zpool.go index 1e3a099..f31d6f3 100644 --- a/platformtest/platformtest_zpool.go +++ b/platformtest/platformtest_zpool.go @@ -58,6 +58,14 @@ func CreateOrReplaceZpool(ctx context.Context, e Execer, args ZpoolCreateArgs) ( } } + // clear the mountpoint dir + if err := os.RemoveAll(args.Mountpoint); err != nil { + return nil, errors.Wrapf(err, "remove mountpoint dir %q", args.Mountpoint) + } + if err := os.Mkdir(args.Mountpoint, 0700); err != nil { + return nil, errors.Wrapf(err, "create mountpoint dir %q", args.Mountpoint) + } + // idempotently (re)create the pool image image, err := os.OpenFile(args.ImagePath, os.O_CREATE|os.O_RDWR, 0600) if err != nil { @@ -93,5 +101,9 @@ func (p *Zpool) Destroy(ctx context.Context, e Execer) error { return errors.Wrapf(err, "remove pool image") } + if err := os.RemoveAll(p.args.Mountpoint); err != nil { + return errors.Wrapf(err, "remove mountpoint dir %q", p.args.Mountpoint) + } + return nil } diff --git a/platformtest/tests/gen/gen.go b/platformtest/tests/gen/gen.go new file mode 100644 index 0000000..4d75871 --- /dev/null +++ b/platformtest/tests/gen/gen.go @@ -0,0 +1,140 @@ +package main + +import ( + "bytes" + "go/ast" + "go/format" + "go/parser" + "go/token" + "io/ioutil" + "os" + "sort" + "strings" + "text/template" + + "golang.org/x/tools/go/packages" +) + +func check(err error) { + if err != nil { + panic(err) + } +} + +type platformtestFuncDeclFinder struct { + pkg *packages.Package + testFuncs []*ast.FuncDecl +} + +func isPlatformtestFunc(n *ast.FuncDecl) bool { + if !n.Name.IsExported() { + return false + } + if n.Recv != nil { + return false + } + if n.Type.Results.NumFields() != 0 { + return false + } + if n.Type.Params.NumFields() != 1 { + return false + } + se, ok := n.Type.Params.List[0].Type.(*ast.StarExpr) + if !ok { + return false + } + sel, ok := se.X.(*ast.SelectorExpr) + if !ok { + return false + } + x, ok := sel.X.(*ast.Ident) + if !ok { + return false + } + if x.Name != "platformtest" || sel.Sel.Name != "Context" { + return false + } + return true +} + +func (e *platformtestFuncDeclFinder) Visit(n2 ast.Node) ast.Visitor { + switch n := n2.(type) { + case *ast.File: + return e + case *ast.FuncDecl: + if isPlatformtestFunc(n) { + e.testFuncs = append(e.testFuncs, n) + } + return nil + default: + return nil + } +} + +func main() { + + // TODO safeguards that prevent us from deleting non-generated generated_cases.go + os.Remove("generated_cases.go") + // (no error handling to easily cover the case where the file doesn't exist) + + pkgs, err := packages.Load( + &packages.Config{ + Mode: packages.LoadFiles, + Tests: false, + }, + os.Args[1], + ) + check(err) + + if len(pkgs) != 1 { + panic(pkgs) + } + + p := pkgs[0] + + var tests []*ast.FuncDecl + + for _, f := range p.GoFiles { + s := token.NewFileSet() + a, err := parser.ParseFile(s, f, nil, parser.AllErrors) + check(err) + finder := &platformtestFuncDeclFinder{ + pkg: p, + } + ast.Walk(finder, a) + tests = append(tests, finder.testFuncs...) + } + + sort.Slice(tests, func(i, j int) bool { + return strings.Compare(tests[i].Name.Name, tests[j].Name.Name) < 0 + }) + + { + casesTemplate := ` +// Code generated by zrepl tooling; DO NOT EDIT. + +package tests + +var Cases = []Case { +{{- range . -}} + {{ .Name }}, +{{ end -}} +} + + ` + t, err := template.New("CaseFunc").Parse(casesTemplate) + check(err) + + var buf bytes.Buffer + err = t.Execute(&buf, tests) + check(err) + + formatted, err := format.Source(buf.Bytes()) + check(err) + + err = ioutil.WriteFile("generated_cases.go", formatted, 0664) + check(err) + + } + +} diff --git a/platformtest/tests/generated_cases.go b/platformtest/tests/generated_cases.go new file mode 100644 index 0000000..3499008 --- /dev/null +++ b/platformtest/tests/generated_cases.go @@ -0,0 +1,22 @@ +// Code generated by zrepl tooling; DO NOT EDIT. + +package tests + +var Cases = []Case{BatchDestroy, + CreateReplicationCursor, + GetNonexistent, + IdempotentBookmark, + IdempotentDestroy, + IdempotentHold, + ListFilesystemVersionsFilesystemNotExist, + ListFilesystemVersionsTypeFilteringAndPrefix, + ListFilesystemVersionsUserrefs, + ListFilesystemVersionsZeroExistIsNotAnError, + ListFilesystemsNoFilter, + ResumableRecvAndTokenHandling, + ResumeTokenParsing, + SendArgsValidationEncryptedSendOfUnencryptedDatasetForbidden, + SendArgsValidationResumeTokenDifferentFilesystemForbidden, + SendArgsValidationResumeTokenEncryptionMismatchForbidden, + UndestroyableSnapshotParsing, +} diff --git a/platformtest/tests/tests.go b/platformtest/tests/tests.go index 89c7098..4b16441 100644 --- a/platformtest/tests/tests.go +++ b/platformtest/tests/tests.go @@ -13,22 +13,4 @@ func (c Case) String() string { return runtime.FuncForPC(reflect.ValueOf(c).Pointer()).Name() } -var Cases = []Case{ - BatchDestroy, - UndestroyableSnapshotParsing, - GetNonexistent, - CreateReplicationCursor, - IdempotentHold, - IdempotentBookmark, - IdempotentDestroy, - ResumeTokenParsing, - ResumableRecvAndTokenHandling, - SendArgsValidationEncryptedSendOfUnencryptedDatasetForbidden, - SendArgsValidationResumeTokenEncryptionMismatchForbidden, - SendArgsValidationResumeTokenDifferentFilesystemForbidden, - ListFilesystemVersionsTypeFilteringAndPrefix, - ListFilesystemVersionsFilesystemNotExist, - ListFilesystemVersionsFilesystemNotExist, - ListFilesystemVersionsUserrefs, - ListFilesystemsNoFilter, -} +//go:generate ../../artifacts/generate-platform-test-list github.com/zrepl/zrepl/platformtest/tests