Skip to content

Add ability to skip tests #221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
79e2647
Adding skipped to reporters
ycombinator Jan 15, 2021
255cdbc
Adding skipped to pipeline test runner
ycombinator Jan 15, 2021
514e05e
Adding skipped to system test runner
ycombinator Jan 15, 2021
be3c26c
Adding skipped field to test result
ycombinator Jan 15, 2021
35aa187
Add skip configuration for asset loading tests
ycombinator Jan 26, 2021
078963c
Refactoring: extracting result composer for reuse in multiple packages
ycombinator Jan 26, 2021
71e99e3
Use result composer in asset loading test runner
ycombinator Jan 26, 2021
706263f
Adding godoc
ycombinator Jan 26, 2021
a994a4d
Refactoring: extract skip config struct
ycombinator Jan 26, 2021
a9d89f8
Adding license header + struct godoc
ycombinator Jan 26, 2021
1513b04
Account for no test config
ycombinator Jan 26, 2021
fb6b90e
Fix error message
ycombinator Jan 26, 2021
9feae09
Adding skip section to test package
ycombinator Jan 26, 2021
5ba06fb
Add warning logs for skipped tests
ycombinator Jan 26, 2021
c409d93
Include test result
ycombinator Jan 26, 2021
feadfbe
Stringify link
ycombinator Jan 26, 2021
3998403
Using result
ycombinator Jan 26, 2021
1c9dc9a
Fixing format
ycombinator Jan 27, 2021
91b97ed
Make skipped optional
ycombinator Jan 27, 2021
9e66712
Add skip reason and link
ycombinator Jan 27, 2021
4e25215
Introducing SkippableConfig
ycombinator Jan 29, 2021
d93be29
Introducing constructor for ResultComposer
ycombinator Jan 29, 2021
322c835
Temporarily commenting out skip so test runs again
ycombinator Jan 29, 2021
cec86cf
Making test fail with bad path
ycombinator Jan 29, 2021
0fbf9ad
Putting back skip section
ycombinator Jan 29, 2021
b195c06
Merge branch 'master' into test-skip
ycombinator Jan 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions internal/testrunner/reporters/formats/human.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ func reportHumanFormat(results []testrunner.TestResult) (string, error) {
result = fmt.Sprintf("ERROR: %s", r.ErrorMsg)
} else if r.FailureMsg != "" {
result = fmt.Sprintf("FAIL: %s", r.FailureMsg)
} else if r.Skipped != nil {
result = r.Skipped.String()
} else {
result = "PASS"
}
Expand Down
22 changes: 19 additions & 3 deletions internal/testrunner/reporters/formats/xunit.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type testSuite struct {
NumTests int `xml:"tests,attr,omitempty"`
NumFailures int `xml:"failures,attr,omitempty"`
NumErrors int `xml:"errors,attr,omitempty"`
NumSkipped int `xml:"skipped,attr,omitempty"`

Suites []testSuite `xml:"testsuite,omitempty"`
Cases []testCase `xml:"testcase,omitempty"`
Expand All @@ -42,15 +43,20 @@ type testCase struct {
ClassName string `xml:"classname,attr"`
TimeInSeconds float64 `xml:"time,attr"`

Error string `xml:"error,omitempty"`
Failure string `xml:"failure,omitempty"`
Error string `xml:"error,omitempty"`
Failure string `xml:"failure,omitempty"`
Skipped *skipped `xml:"skipped,omitempty"`
}

type skipped struct {
Message string `xml:"message,attr"`
}

func reportXUnitFormat(results []testrunner.TestResult) (string, error) {
// test type => package => data stream => test cases
tests := map[string]map[string]map[string][]testCase{}

var numTests, numFailures, numErrors int
var numTests, numFailures, numErrors, numSkipped int
for _, r := range results {
testType := string(r.TestType)
if _, exists := tests[testType]; !exists {
Expand Down Expand Up @@ -79,6 +85,10 @@ func reportXUnitFormat(results []testrunner.TestResult) (string, error) {
numErrors++
}

if r.Skipped != nil {
numSkipped++
}

name := fmt.Sprintf("%s test", r.TestType)
if r.Name != "" {
name += ": " + r.Name
Expand All @@ -91,6 +101,11 @@ func reportXUnitFormat(results []testrunner.TestResult) (string, error) {
Error: r.ErrorMsg,
Failure: failure,
}

if r.Skipped != nil {
c.Skipped = &skipped{r.Skipped.String()}
}

numTests++

tests[testType][r.Package][r.DataStream] = append(tests[testType][r.Package][r.DataStream], c)
Expand All @@ -107,6 +122,7 @@ func reportXUnitFormat(results []testrunner.TestResult) (string, error) {
NumTests: numTests,
NumFailures: numFailures,
NumErrors: numErrors,
NumSkipped: numSkipped,

Cases: make([]testCase, 0),
}
Expand Down
62 changes: 30 additions & 32 deletions internal/testrunner/runners/asset/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"fmt"
"path/filepath"
"strings"
"time"

es "github.com/elastic/go-elasticsearch/v7"
"github.com/pkg/errors"
Expand Down Expand Up @@ -63,43 +62,39 @@ func (r runner) Run(options testrunner.TestOptions) ([]testrunner.TestResult, er
}

func (r *runner) run() ([]testrunner.TestResult, error) {
result := testrunner.TestResult{
result := testrunner.NewResultComposer(testrunner.TestResult{
TestType: TestType,
Package: r.testFolder.Package,
}
})

startTime := time.Now()
resultsWith := func(tr testrunner.TestResult, err error) ([]testrunner.TestResult, error) {
tr.TimeElapsed = time.Now().Sub(startTime)
if err == nil {
return []testrunner.TestResult{tr}, nil
}
testConfig, err := newConfig(r.testFolder.Path)
if err != nil {
return result.WithError(errors.Wrap(err, "unable to load asset loading test config file"))

if tcf, ok := err.(testrunner.ErrTestCaseFailed); ok {
tr.FailureMsg = tcf.Reason
tr.FailureDetails = tcf.Details
return []testrunner.TestResult{tr}, nil
}
}

tr.ErrorMsg = err.Error()
return []testrunner.TestResult{tr}, err
if testConfig != nil && testConfig.Skip != nil {
logger.Warnf("skipping %s test for %s: %s (details: %s)",
TestType, r.testFolder.Package,
testConfig.Skip.Reason, testConfig.Skip.Link.String())
return result.WithSkip(testConfig.Skip)
}

pkgManifest, err := packages.ReadPackageManifest(filepath.Join(r.packageRootPath, packages.PackageManifestFile))
if err != nil {
return resultsWith(result, errors.Wrap(err, "reading package manifest failed"))
return result.WithError(errors.Wrap(err, "reading package manifest failed"))
}

// Install package
kib, err := kibana.NewClient()
if err != nil {
return resultsWith(result, errors.Wrap(err, "could not create kibana client"))
return result.WithError(errors.Wrap(err, "could not create kibana client"))
}

logger.Debug("installing package...")
actualAssets, err := kib.InstallPackage(*pkgManifest)
if err != nil {
return resultsWith(result, errors.Wrap(err, "could not install package"))
return result.WithError(errors.Wrap(err, "could not install package"))
}
r.removePackageHandler = func() error {
logger.Debug("removing package...")
Expand All @@ -111,26 +106,29 @@ func (r *runner) run() ([]testrunner.TestResult, error) {

expectedAssets, err := packages.LoadPackageAssets(r.packageRootPath)
if err != nil {
return resultsWith(result, errors.Wrap(err, "could not load expected package assets"))
return result.WithError(errors.Wrap(err, "could not load expected package assets"))
}

results := make([]testrunner.TestResult, 0, len(expectedAssets))
for _, e := range expectedAssets {
result := testrunner.TestResult{
Name: fmt.Sprintf("%s %s is loaded", e.Type, e.ID),
Package: pkgManifest.Name,
DataStream: e.DataStream,
TestType: TestType,
TimeElapsed: time.Now().Sub(startTime),
}

rc := testrunner.NewResultComposer(testrunner.TestResult{
Name: fmt.Sprintf("%s %s is loaded", e.Type, e.ID),
Package: pkgManifest.Name,
DataStream: e.DataStream,
TestType: TestType,
})

var r []testrunner.TestResult
if !findActualAsset(actualAssets, e) {
result.FailureMsg = "could not find expected asset"
result.FailureDetails = fmt.Sprintf("could not find %s asset \"%s\". Assets loaded:\n%s", e.Type, e.ID, formatAssetsAsString(actualAssets))
r, _ = rc.WithError(testrunner.ErrTestCaseFailed{
Reason: "could not find expected asset",
Details: fmt.Sprintf("could not find %s asset \"%s\". Assets loaded:\n%s", e.Type, e.ID, formatAssetsAsString(actualAssets)),
})
} else {
r, _ = rc.WithSuccess()
}

results = append(results, result)
startTime = time.Now()
results = append(results, r[0])
}

return results, nil
Expand Down
47 changes: 47 additions & 0 deletions internal/testrunner/runners/asset/test_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.

package asset

import (
"io/ioutil"
"os"
"path/filepath"

"github.com/elastic/go-ucfg"
"github.com/elastic/go-ucfg/yaml"
"github.com/pkg/errors"

"github.com/elastic/elastic-package/internal/testrunner"
)

type testConfig struct {
testrunner.SkippableConfig `config:",inline"`
}

func newConfig(assetTestFolderPath string) (*testConfig, error) {
configFilePath := filepath.Join(assetTestFolderPath, "config.yml")

// Test configuration file is optional for asset loading tests. If it
// doesn't exist, we can return early.
if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
return nil, nil
}

data, err := ioutil.ReadFile(configFilePath)
if err != nil {
return nil, errors.Wrapf(err, "could not load asset loading test configuration file: %s", configFilePath)
}

var c testConfig
cfg, err := yaml.NewConfig(data, ucfg.PathSep("."))
if err != nil {
return nil, errors.Wrapf(err, "unable to load asset loading test configuration file: %s", configFilePath)
}
if err := cfg.Unpack(&c); err != nil {
return nil, errors.Wrapf(err, "unable to unpack asset loading test configuration file: %s", configFilePath)
}

return &c, nil
}
17 changes: 17 additions & 0 deletions internal/testrunner/runners/pipeline/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ func (r *runner) run() ([]testrunner.TestResult, error) {
}
tr.Name = tc.name

if tc.config.Skip != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I have a general concern, but I'm sure if it can be solved. I'm worried that one day we'll add a new test runner, in which we'll forget to add the "Skip" config section. Maybe we should limit this to minimum. Do we need a skip check for assets tests (same for install)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good point. Maybe this goes well with your other suggestion of a commonTestConfig. Let me try something and update this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In 4e25215, I introduced a SkippableConfig struct that could be embedded in any test config structs that allow skipping. This doesn't necessarily address the concern you are bringing up (a future test runner forgetting to include the skip config section) but I think it can help make it a bit easier to add a skip config section to a future test runner. I think to truly address your concern a larger refactor might be needed which would allow a higher-level generic test runner of some sort to handle skipping before delegating the actual running of a test to specific types of test runners.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think to truly address your concern a larger refactor might be needed which would allow a higher-level generic test runner of some sort to handle skipping before delegating the actual running of a test to specific types of test runners.

... and we may think about such refactoring exercise soon, as we have a better clarity of what do we expect from test runners and what kind of tests we need. Definitely we can postpone it at the moment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Added #238 to track the refactoring.

logger.Warnf("skipping %s test for %s/%s: %s (details: %s)",
TestType, r.options.TestFolder.Package, r.options.TestFolder.DataStream,
tc.config.Skip.Reason, tc.config.Skip.Link.String())

tr.Skipped = tc.config.Skip
results = append(results, tr)
continue
}

result, err := simulatePipelineProcessing(r.options.ESClient, entryPipeline, tc)
if err != nil {
err := errors.Wrap(err, "simulating pipeline processing failed")
Expand Down Expand Up @@ -170,6 +180,13 @@ func (r *runner) loadTestCaseFile(testCaseFile string) (*testCase, error) {
return nil, errors.Wrapf(err, "reading config for test case failed (testCasePath: %s)", testCasePath)
}

if config.Skip != nil {
return &testCase{
name: testCaseFile,
config: &config,
}, nil
}

ext := filepath.Ext(testCaseFile)

var entries []json.RawMessage
Expand Down
4 changes: 4 additions & 0 deletions internal/testrunner/runners/pipeline/test_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ import (
"path/filepath"

"github.com/pkg/errors"

"github.com/elastic/elastic-package/internal/testrunner"
)

const configTestSuffix = "-config.json"

type testConfig struct {
testrunner.SkippableConfig `config:",inline"`

Multiline *multiline `json:"multiline"`
Fields map[string]interface{} `json:"fields"`
DynamicFields map[string]string `json:"dynamic_fields"`
Expand Down
Loading