-
Notifications
You must be signed in to change notification settings - Fork 106
Feature/Cucumber Messages #233
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
|
FYI, github Build is failing b/c one produced component (FileSinkPlugin) gets published only to my local Nuget store. It can then not be found by the build pipeline in github. |
|
First end-to-end working scenario is operational.
Next:
|
364e466 to
1f2f1e6
Compare
|
Build is failing b/c I have a private build of Cucumber Messages nuget package. When the next release of that comes out, I will patch up the nuget references in this branch. |
This is fine. We have feed https://www.myget.org/feed/Packages/reqnroll-unstable where we could publish interim releases (of dependencies as well) and I think this feed is added to the nuget sources, so the build would be able to resolve it though them. But I never tested this model yet. |
5962ab0 to
4ccd7ae
Compare
|
In order to fix the System.Text.Json loading problem I have found a fix: We need to ensure that the necessary System.Text.Json related assemblies are packaged with our generator, so that they can be loaded in frameworks that does not have this version. In order to do that, you need to add these lines to the |
|
@clrudolphi while working on the diagnosis of this, I noticed that there is now a generic catch in We would need to find a way to propagate these errors (should we really catch?), or at least somehow make sure that it is possible to figure out what is wrong without debugging. (Now I found them by putting a |
|
Thanks for pointing that out. |
|
I believe this is now ready for a shakedown and code review. I've fixed the issues that I'm aware of and completed my punch-list. Documentation is updated. I've tested it with multiple Features running in parallel and desk-checked it for thread safety for the upcoming Scenario parallel execution model. |
|
It looks like Cucumber Messages schemas are changing in an upcoming release PR102. This will require some changes to logic within the Messages implementation. |
Messages v27 and CCK updates have been published. Today's commits update our Messages implementation to support this release. This adds a HookType enumeration for Hooks and a TestRunStartedId attribute to the TestRunStarted and TestRunFinished messages. |
|
Behavior Question: Retry and Undefined Steps. When experimenting with xRetry.Reqnroll, I find that this framework does not behave that way. It does not recognize the undefined step failure and proceeds with retries (up to to its configured limit). Question: which component should be responsible for ensuring compatibility with Cucumber Messages expectations? Should we expect each Retry implementation to behave as expected by Cucumber? Or, should the Messages implementation recognize the Undefined step situation and ignore any subsequent retry executions of that Test Case? NB - curiously, the CCK is silent on the expected behavior of tests containing PENDING steps. One would think the same rule would apply (no need to retry something doomed to fail). |
|
Retry and TestCaseFinished messages -- non-compliance with CCK. When a TestCase completes, Messages writes a TestCaseFinished message, such as this: {"testCaseFinished":{"testCaseStartedId":"54","timestamp":{"seconds":1737648321,"nanos":361094000},"willBeRetried":false}}Note the "willBeRetried" boolean flag at the end. Ideally, we would be aware at run-time whether failed test case executions might be retried and emit an appropriate value here. Unfortunately, the responsibility for retries is outside the control of Reqnroll (either built in to the test framework (such as with VSTest and nUnit) or the responsibility of a Reqnroll plugin. Since we'll never know beforehand whether a failed execution will be retried, this message field is hard-coded to "false". The current implementation writes out a Test Case's worth of Messages upon receipt of a ScenarioFinishedEvent. A retry of that testcase involves Reqnroll publishing another set of ScenarioStarted, StepStarted/Finished, ScenarioFinished. So we recognize that a retry is being attempted when a ScenarioStarted event is processed for a scenario that we've already executed. But by then the Messages for that prior execution have already been written out. With some extensive work, we might be able to queue them up and only write them upon receipt of the AfterTestRun event (and take that opportunity to patch up 'willBeRetried' values for any test cases that were retried.) How important is it for our Messages implementation to be compliant on this point? Is it worth the refactoring work? EDIT: Resolved. 'willBeRetried' supported by deferring publication until end of test run allowing us to identify retries and patch up the 'willBeRetried' value. |
|
First of all, those are great finds. Good job on such thorough investigation. Onto the problem itself: ideally, a good API design prevents invalid states, but in this instance, I would suggest we allow plug-ins to publish messages that would be considered invalid. We're treating Cucumber Messages as a mechanism for providing visibility of test execution and if the plugin causes invalid messages to be published, it's on the plugin to decide whether it's important to its users to be fully compatible with the spec. It may be completely compatible with the tools in use by the plugin users! The alternative would be to fail, either loudly causing a runtime failure for a user of the retry plugin, or silently and make the whole problem really opaque. I don't believe either of those are desirable failure modes, as both cause issues for the end-user that either stop them running tests or give them mysteriously incomplete output. |
An alternative that occurred to me is to create an Interface that retry plugins must implement that we would call upon during handling of ScenarioFinished event. The interface would allow the retry plugins the opportunity to tell us whether a failed test case would be retried. I would implement a Null implementation of this interface and register it in the global container. Retry plugins would implement the interface and replace the null impl with their own in the global container. Thoughts? Too complicated? EDIT: resolved - see comment below |
Updated the configuration.md file. Modified the constants file to make use of 'Directory' consistent across the configuration and constants.
…uired refactoring and duplication of the retry feature and expected results.
…o that actual Messages are sorted by PickleID of the test case(Scenario). This will ensure that Attempt counts are properly compared.
Reqnroll/Formatters/Configuration/FormattersConfigurationProvider.cs
Outdated
Show resolved
Hide resolved
Renamed test class to reflect naming of Disabled environment variable.
This commit introduces the `FormattersForcedDisabledOverrideProvider` class, which implements the `IFormattersConfigurationDisableOverrideProvider` interface and always returns `true` for the `Disabled` method. Additionally, the `BindingProviderService.cs` file has been updated to register this new provider in the dependency injection container so that the formatters do not run when only binding discovery is being run.
…rnalDataPlugin, the Location.Line of each row is the line of the HeaderRow (if not zero/null) or the last line of the Steps (plus 1).
…sed formatters easier
|
@clrudolphi I have reviewed the "Anything particular you want feedback on?" section and as far as I can tell, the solutions that are chosen for the PR are good for now. Some notes.
I keep doing some testing / review on initialization and performance, but I will make comments on it separately. |
Introduce `DeterministicIdGenerator` for generating deterministic GUIDs using SHA-1 hashing and UUIDv5. This supports the need for Test Class generation to render the exact same source string if the Feature text hasn't changed. Update `CucumberMessagesConverter` to make `ConvertToCucumberMessagesSource` static for improved usability. Modify `UnitTestFeatureGenerator` to utilize the static method. Add `UUIDv5` class for UUID version 5 generation.
Introduce ShortGuidIdGenerator class implementing IIdGenerator to generate unique, URL-safe Base64 strings. Update DefaultDependencyProvider to register the new generator and remove the old GuidIdGenerator. Add unit tests to ensure ID uniqueness, non-emptiness, and safe disposal behavior.
I have some feedback regarding this, useful or not but I hope it gives some pointers :) I've ran around 800 tests on 20 cores in under 1 second according to stats in html output (latest ci package) so at the moment performance doesn't seem any issue at all. This was, by the way, executed with TUnit and "Start Without Debugging". |
It seems the react component just uses the same ordering in the produced .ndjson file, I just compared the rendered html with that file. So this should mean that you actually can control the ordering as you already wait for the whole run to complete? Another approach would be to raise this an feature request at cucumber/react-components to allow controlling ordering via the component, somehow. |
I'm not surprised. The assumption about ordering of the Messages is that they are emitted as a stream, that is, in time-series order of when the event occurred. So the list of Features is presumably ordered in the sequence in which the test engine undertook to execute the first test within each Feature. That is not guaranteed to be in alphabetical order or even the order in which Features appear in a project. That is up to the executing Test framework. I like the idea of submitting a feature request to Cucumber/ReactComponents. I'm sure you're not the first to see this. |
Updated FeatureExecutionTracker constructor to check for GherkinDocument instead of Pickles in the FeatureCucumberMessageInfo structure, which should be faster. Refactored GenerateStaticMessages to use List.Add instead of yield return. In ContainerBuilder.cs, made the Cucumber message publisher initialization conditional based on configuration settings.
…e how/when StepStartedEvent is fired (such that BeforeStep hook events get fired before the StepStartedEvent). Fixed mapping error in the MessageFactory.
gasparnagy
left a comment
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.
This is good to merge. Any further changes can be done via additional PRs.
Thx @clrudolphi for the great work!
Adds support for creation of Cucumber Messages during the execution of Reqnroll generated tests.
See Cucumber Message for information about the output format.
🤔 What's changed?
Changes are in three main area:
Messages are strings serialized from the CucumberMessage Envelope format.
Configuration support is added as a new section of the reqnroll.json configuration file. (Without interfering with the existing configuration schema and config reading mechanisms). Configuration settings can also be overridden by use of environment variables.
⚡️ What's your motivation?
To provide future compatibility with the broader Cucumber eco-system of tooling.
To provide the input to a future implementation of a Reqnroll replacement to LivingDocs.
🏷️ What kind of change is this?
♻️ Anything particular you want feedback on?
Scope
Other options might include:
-- Publish (to Cucumber's publicly hosted anonymous report site; I have a prototype of this working so easy to add)
-- json (an older format the preceded Messages, but might be useful for those using older reporting/tracking mechanisms)
Testing
There are two types of integration tests. BASIC tests simply execute a feature with very little validation. I wrote those during development so that I could quickly see what the code-generator was doing; and later used them as quick smoke tests. The other tests, most of which are based off of the Cucumber Messages CCK, use approval style testing in that the output of the run is compared against a golden copy of the expected output. Should BASIC tests be moved to approval style tests or simply eliminated now that they're not as valuable?
The Approval-style tests are largely based upon the CCK and broken into three categories: CCKScenarios (these pass), NonCompliantCCKScenarios(scenarios from the CCK that Reqnroll can't support), and NonCCKScenarios (scenarios that Reqnroll does support but for which there are no corresponding CCK Scenarios)
What generation scenarios are missing?
What runtime scenarios or combinations are missing?
Should the Attachments non-passing CCK scenario be reworked into a passing non-CCK scenario?
Should compatibility with attachment handling by all three Test Frameworks be tested?
Which areas are missing Unit Tests that need them?
The BASIC and Approval tests use the SystemTest framework, which runs using MsTest. Should some testing be conducted under the other Test Frameworks for compatibility testing?
Unit Tests: Unit tests have been created for the more complicated classes that have significant behavior. There are other data holding classes (some with simple behaviors) that do not have tests.
Writing the unit tests has highlighted a high-degree of coupling between classes and complicated flows. Would appreciate any ideas/suggestions for simplification of the design.
Runtime
Configuration
reqnroll_report.ndjson. Should the Assembly name be prefixed to this? (This might? be needed to avoid conflicts when running multiple assemblies simultaneously as described in parallel-by-process in the docs)Generation
Compliance/Features
Other:
📋 Checklist: