-
Notifications
You must be signed in to change notification settings - Fork 127
Add benchmark validate command for static validation #1718
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
Conversation
|
This is a great first step for validation. Did you test what kind of error is returned if you made an error in the template itself that the template is invalid instead of the JSON? |
@ruflin In this case the error looks like this: |
|
@flash1293 Neat, that already gives a lot more details on what goes wrong and makes it easy to debug. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding this! This is going to be really useful when preparing benchmarks.
I wonder if we could add this as part of elastic-package test static, this is used now to validate sample documents, and the stream subcommand is kind-of an automation for the same thing. We could also validate fields there.
cmd/benchmark.go
Outdated
| validateCmd := getValidateCommand() | ||
| cmd.AddCommand(validateCmd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of adding this as a new subcommand, I think we could add this as part of one of the subcommands we have now for validation. This would have the benefit of being executed by CI.
I think a good place could be in elastic-package test static, there we are only checking the sample events, but checking the events generated by stream could also fit there.
Other place could be elastic-package check, but this is more concerned about the structure of the package than its behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes sense to me to test as much as possible via a central command - I added this to test static, but IMHO there is value in having a dedicated command as well to be able to iterate on only the benchmark config.
What do you think about the most recent version that wires up the same logic in both places?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is value in having a dedicated command as well to be able to iterate on only the benchmark config.
We don't have this kind of granularity in other cases, and the test asset subcommand is pretty fast, so even when iterating on data generation only the asset tests can still be used to test them.
Additionally, we had discussions regarding whether data generation features, such as the stream subcommand, belong to benchmark, because these features could be used in other cases.
So I would prefer to add it only in test static. We can consider adding an specific subcommand later it there is some reason that makes test static unsuitable for this.
| // check whether the generated event is valid json | ||
| var event map[string]any | ||
| err = json.Unmarshal(buf.Bytes(), &event) | ||
| if err != nil { | ||
| return fmt.Errorf("[%s] failed to unmarshal json event: %w, generated output: %s", scenarioName, err, buf.String()) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be also nice to validate the fields, as we do in tests and when validating the sample documents, for example here:
| multiErr := fieldsValidator.ValidateDocumentBody(content) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into this, but the fields validator partially depends on test configurations like numeric_keyword_fields which might not be available / can't be matched properly to the benchmark config.
I would like to split that part out of this PR if you don't mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, we can add this later. We would indeed need to find a solution for the settings you mention.
| "github.com/elastic/elastic-package/internal/signal" | ||
| ) | ||
|
|
||
| const numberOfEvents = 10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
beware that 10 events might not be enough to check an error in a template
for example this template: https://github.com/elastic/integrations/blob/main/packages/aws/_dev/benchmark/rally/ec2metrics-benchmark/template.ndjson#L117-L210
here we render different content according the the value of $dimensionType: https://github.com/elastic/integrations/blob/main/packages/aws/_dev/benchmark/rally/ec2metrics-benchmark/config.yml#L4-L12
there is 1/40 possibility that a specific content will be rendered
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I bumped it to 100, the generation is fairly quick, it shouldn't matter. Is this enough or should we go even higher?
|
Thanks @aspacca and @jsoriano for review, could you have another look? |
|
I'm seeing the same test failure on other PRs a well, I'm not sure it is related. |
|
/test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking to this change makes me think that we should move benchmarks from the root of the package to each data stream, as they are so far specific to data streams. Having benchmarks disconnected from data streams is going to cause problems, as the ones I mention of running repeated tests if we integrate this validation into test subcommands.
An option to progress with this change before these refactors could be to add this StaticValidation as a fail fast mechanism to benchmark rally and benchmark stream. Developers could use benchmark stream to quickly validate the generated data.
cmd/benchmark.go
Outdated
| validateCmd := getValidateCommand() | ||
| cmd.AddCommand(validateCmd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is value in having a dedicated command as well to be able to iterate on only the benchmark config.
We don't have this kind of granularity in other cases, and the test asset subcommand is pretty fast, so even when iterating on data generation only the asset tests can still be used to test them.
Additionally, we had discussions regarding whether data generation features, such as the stream subcommand, belong to benchmark, because these features could be used in other cases.
So I would prefer to add it only in test static. We can consider adding an specific subcommand later it there is some reason that makes test static unsuitable for this.
| // check whether the generated event is valid json | ||
| var event map[string]any | ||
| err = json.Unmarshal(buf.Bytes(), &event) | ||
| if err != nil { | ||
| return fmt.Errorf("[%s] failed to unmarshal json event: %w, generated output: %s", scenarioName, err, buf.String()) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, we can add this later. We would indeed need to find a solution for the settings you mention.
| ctx, stop := signal.Enable(ctx, logger.Info) | ||
| defer stop() | ||
|
|
||
| err := stream.StaticValidation(ctx, stream.NewOptions(withOpts...)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a test package where this validation fails? This would need to be added to the false_positives directory, where expected errors can be defined.
|
|
||
| func (r runner) verifyStreamConfig(ctx context.Context, packageRootPath string) []testrunner.TestResult { | ||
| resultComposer := testrunner.NewResultComposer(testrunner.TestResult{ | ||
| Name: "Verify benchmark config (if available)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice if these results are only in the output if they are actually available.
This looks now like this in packages without benchmarks:
╭─────────┬─────────────┬───────────┬────────────────────────────────────────┬────────┬──────────────╮
│ PACKAGE │ DATA STREAM │ TEST TYPE │ TEST NAME │ RESULT │ TIME ELAPSED │
├─────────┼─────────────┼───────────┼────────────────────────────────────────┼────────┼──────────────┤
│ apache │ access │ static │ Verify benchmark config (if available) │ PASS │ 508.237µs │
│ apache │ access │ static │ Verify sample_event.json │ PASS │ 84.524208ms │
│ apache │ error │ static │ Verify benchmark config (if available) │ PASS │ 638.916µs │
│ apache │ error │ static │ Verify sample_event.json │ PASS │ 76.622388ms │
│ apache │ status │ static │ Verify benchmark config (if available) │ PASS │ 642.803µs │
│ apache │ status │ static │ Verify sample_event.json │ PASS │ 64.9535ms │
╰─────────┴─────────────┴───────────┴────────────────────────────────────────┴────────┴──────────────╯
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment all benchmarks are named <data stream>-benchmark. We could maybe follow this convention here to check if the config is available and to run the checks per data-stream.
Update: they are actually also bound to data streams in their configs, a data stream name is mandatory:
elastic-package/internal/benchrunner/runners/stream/scenario.go
Lines 73 to 75 in a44250e
| if c.DataStream.Name == "" { | |
| return nil, errors.New("can't read data stream name from benchmark configuration: empty") | |
| } |
|
@jsoriano It would be nice to still have the option for a quick win here without requiring refactoring to data streams to have validation. |
Yep, agree, this is why I propose to do the validation as a pre-check in the commands that use these files, it is pretty fast.
|
|
Thanks for the discussion @jsoriano and @ruflin Agreed that having the benchmark config defined on the stream level looks like it makes sense, but of course it's a bigger refactoring.
We can start with that, but I really like the point you brought up about this being checked in CI - having it as part of rally and stream would only marginally speed up these commands failing. Two other thoughts: What do you think about making the What do you think about adding this check to a new test command ( |
I would be cautious about adding these features, we would be circumventing current tech debt, by adding more tech debt. Current benchmark scenarios are already bound to data streams, they require a data stream name in their configs, we don't really need to support them at the package level. What do you think about my comment here? We could read the scenarios, and from them know if there is any scenario for a given data stream, and if there are, validate only them. This would allow to include this in the current |
As they are already bound to the data stream this way I agree, let's do it like that. I will update the PR. |
|
@jsoriano could you take another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great now, thanks!
|
Thanks @jsoriano , updated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
💚 Build Succeeded
History
|
Context: I'm mostly working on this to familiarize myself with the elastic-package project (and golang in the first place).
Related to #1610
This PR adds a
validatecommand to benchmarks to statically validate the benchmark generator is configured properly:In this example there is a missing
{for the data_stream object in the template of one out of multiple templates:It generates 10 events using each generator and checks whether the result is valid JSON.
This does not require a running elasticsearch instance, it's purely checking the benchmark configuration. This implementation validates the following things:
Implementation details
As this is very close to the existing stream logic, I made it part of that module. I pondered to split the necessary bits out into a common and validation-specific bit, but it seemed overkill.
The existing
setUproutine is talking to Elasticsearch already, so I split out the static parts into aninitializefunction which can be called for the validation before actually querying the generators.@ruflin feel free to add the right people as reviewers