-
Notifications
You must be signed in to change notification settings - Fork 139
Implement static test runner #262
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
Changes from all commits
9d3c481
a1ccb75
ab68a1f
b7fa993
83fb455
feb16e3
29d214e
46efce7
575d5ac
1a1871d
82d3ec0
3b5faee
a1113a9
508cec7
6fd908a
5a8dc3d
d6eba93
3c5a353
71397a8
8c0290f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # HOWTO: Running static tests for a package | ||
|
|
||
| ## Introduction | ||
|
|
||
| Static tests allow you to verify if all static resources of the package are valid, e.g. are all fields of the `sample_event.json` documented. | ||
| They don't require any additional configuration (unless you would like to skip them). | ||
|
|
||
| ## Coverage | ||
|
|
||
| Static tests cover the following resources: | ||
|
|
||
| 1. Sample event for a data stream - verification if the file uses only documented fields. | ||
|
|
||
| ## Running static tests | ||
|
|
||
| Static tests don't require the Elastic stack to be up and running. Simply navigate to the package's root folder | ||
| (or any sub-folder under it) and run the following command. | ||
|
|
||
| ``` | ||
| elastic-package test static | ||
| ``` | ||
|
|
||
| If you want to run pipeline tests for **specific data streams** in a package, navigate to the package's root folder | ||
| (or any sub-folder under it) and run the following command. | ||
|
|
||
| ``` | ||
| elastic-package test static --data-streams <data stream 1>[,<data stream 2>,...] | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| // 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 static | ||
|
|
||
| import ( | ||
| "io/ioutil" | ||
| "os" | ||
| "path/filepath" | ||
|
|
||
| "github.com/pkg/errors" | ||
|
|
||
| "github.com/elastic/elastic-package/internal/fields" | ||
| "github.com/elastic/elastic-package/internal/logger" | ||
| "github.com/elastic/elastic-package/internal/testrunner" | ||
| ) | ||
|
|
||
| const sampleEventJSON = "sample_event.json" | ||
|
|
||
| type runner struct { | ||
| options testrunner.TestOptions | ||
| } | ||
|
|
||
| var _ testrunner.TestRunner = new(runner) | ||
|
|
||
| func init() { | ||
| testrunner.RegisterRunner(&runner{}) | ||
| } | ||
|
|
||
| const ( | ||
| // TestType defining asset loading tests | ||
| TestType testrunner.TestType = "static" | ||
| ) | ||
|
|
||
| func (r runner) Type() testrunner.TestType { | ||
| return TestType | ||
| } | ||
|
|
||
| func (r runner) String() string { | ||
| return "static files" | ||
| } | ||
|
|
||
| func (r runner) Run(options testrunner.TestOptions) ([]testrunner.TestResult, error) { | ||
| r.options = options | ||
| return r.run() | ||
| } | ||
|
|
||
| func (r runner) run() ([]testrunner.TestResult, error) { | ||
| result := testrunner.NewResultComposer(testrunner.TestResult{ | ||
| TestType: TestType, | ||
| Package: r.options.TestFolder.Package, | ||
| DataStream: r.options.TestFolder.DataStream, | ||
| }) | ||
|
|
||
| testConfig, err := newConfig(r.options.TestFolder.Path) | ||
| if err != nil { | ||
| return result.WithError(errors.Wrap(err, "unable to load asset loading test config file")) | ||
| } | ||
|
|
||
| if testConfig != nil && testConfig.Skip != nil { | ||
| logger.Warnf("skipping %s test for %s: %s (details: %s)", | ||
| TestType, r.options.TestFolder.Package, | ||
| testConfig.Skip.Reason, testConfig.Skip.Link.String()) | ||
| return result.WithSkip(testConfig.Skip) | ||
| } | ||
|
|
||
| var results []testrunner.TestResult | ||
| results = append(results, r.verifySampleEvent()...) | ||
| return results, nil | ||
| } | ||
|
|
||
| func (r runner) verifySampleEvent() []testrunner.TestResult { | ||
| dataStreamPath := filepath.Join(r.options.PackageRootPath, "data_stream", r.options.TestFolder.DataStream) | ||
| sampleEventPath := filepath.Join(dataStreamPath, sampleEventJSON) | ||
| _, err := os.Stat(sampleEventPath) | ||
| if os.IsNotExist(err) { | ||
| return []testrunner.TestResult{} // nothing to succeed, nothing to skip | ||
| } | ||
|
|
||
| resultComposer := testrunner.NewResultComposer(testrunner.TestResult{ | ||
| Name: "Verify " + sampleEventJSON, | ||
| TestType: TestType, | ||
| Package: r.options.TestFolder.Package, | ||
| DataStream: r.options.TestFolder.DataStream, | ||
| }) | ||
|
|
||
| if err != nil { | ||
| results, _ := resultComposer.WithError(errors.Wrap(err, "stat file failed")) | ||
| return results | ||
| } | ||
|
|
||
| fieldsValidator, err := fields.CreateValidatorForDataStream( | ||
| dataStreamPath, | ||
| fields.WithDefaultNumericConversion()) | ||
| if err != nil { | ||
| results, _ := resultComposer.WithError(errors.Wrap(err, "creating fields validator for data stream failed")) | ||
| return results | ||
| } | ||
|
|
||
| content, err := ioutil.ReadFile(sampleEventPath) | ||
| if err != nil { | ||
| results, _ := resultComposer.WithError(errors.Wrap(err, "can't read file")) | ||
| return results | ||
| } | ||
|
|
||
| multiErr := fieldsValidator.ValidateDocumentBody(content) | ||
| if len(multiErr) > 0 { | ||
| results, _ := resultComposer.WithError(testrunner.ErrTestCaseFailed{ | ||
| Reason: "one or more errors found in document", | ||
| Details: multiErr.Error(), | ||
| }) | ||
| return results | ||
| } | ||
|
|
||
| results, _ := resultComposer.WithSuccess() | ||
| return results | ||
| } | ||
|
|
||
| func (r runner) TearDown() error { | ||
| return nil // it's a static test runner, no state is stored | ||
| } | ||
|
|
||
| func (r runner) CanRunPerDataStream() bool { | ||
| return true | ||
| } | ||
|
|
||
| func (r *runner) TestFolderRequired() bool { | ||
| return false | ||
| } |
| 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 static | ||
|
|
||
| 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(staticTestFolderPath string) (*testConfig, error) { | ||
| configFilePath := filepath.Join(staticTestFolderPath, "config.yml") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we define this as part of the package spec, as an optional file?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, I totally forgot about the package-spec. BTW Should I wait with this PR until you'll merge #260 or do you prefer the other way round?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just merged #260 so you'll need to rebase this PR on top of |
||
|
|
||
| // Test configuration file is optional for static 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 static 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 static loading test configuration file: %s", configFilePath) | ||
| } | ||
| if err := cfg.Unpack(&c); err != nil { | ||
| return nil, errors.Wrapf(err, "unable to unpack static loading test configuration file: %s", configFilePath) | ||
| } | ||
|
|
||
| return &c, nil | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.