Git Product home page Git Product logo

polymorphicdsl's Introduction

Polymorphic Domain Specific Language Framework

An incredibly powerful framework for scaling testing across multiple applications and platforms.

Getting Started

Start with the manual.

The documentation directory of this project has a "Getting Started" guide as well as other information we expect you'll find helpful!

Contributing

Legal

See CONTRIBUTING.md.

License

Apache 2.0; see LICENSE for details.

Running

Many ANTLR4 .g4 files are used to generate code used at runtime. There is separate code for both the Gherkin Parser used in the library and the grammars used for the tests. To make this all work an additional maven test profile is used in the project.

mvn clean install will probably fail during the test phase because it is expecting this code to be generated. This can be solved by first running mvn clean antlr4:antlr4 -P test to generate the test classes.

Running mvn clean at this point will destroy all of the generated code, so to install do the following operations:

mvn clean antlr4:antlr4 -P test
mvn antlr4:antlr4 install

At this point you can use mvn anltr4:antlr4 <some lifecycle> up until you run mvn clean again. If you do that you will need to regenerate the source code using the -P test profile as shown above.

Deployment

Deploying to Remote Repository

Google has a nexus repository. Only Google employees are able to access it.

A release can be staged at the repository using the following command:

mvn clean antlr4:antlr4 && mvn antlr4:antlr4 -Ptest && mvn antlr4:antlr4 deploy -Prelease

This command generates the Gherkin parser, then the parsers needed for testing and finally runs the deploy (which is also when the tests will execute).

Deploying to staging will require removing the -SNAPSHOT postfix from the POM as well as having a cryptographic signature available to sign the application.

Making a local JAR

A fat JAR with all the dependencies is made with the shade plugin, but currently it won't work unless the shade:shade lifecycle is explicitly called:

mvn clean antlr4:antlr4 -P test && mvn antlr4:antlr4 package shade:shade

Deploy to Google's Nexus Repository

Disclaimer

This project is not an official Google project. It is not supported by Google and Google specifically disclaims all warranties as to its quality, merchantability, or fitness for a particular purpose.

polymorphicdsl's People

Contributors

incident-recipient avatar yuriichukhrai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

polymorphicdsl's Issues

Remove technical debt

The rush to produce features increased the technical debt (redundant imports, etc)

In particular we need to remove hashes of URLs to URIs for performance reasons

Expose TestCase in PDSL Executable

Some 3rd party tools will work better with PDSL if they have the sentences that were run in the test case.

If the TestCase is visible they can grab the Filtered Context off of the test case to get the phrases.

Broken [dependency management model]

I am guessing you uploaded the uber/fat jar to the Maven central.
In that case the supplier of you framework/dependency is not able to exclude some dependency (transitive) that can came from your repo.
And regular maven mechanism to exclude dependencies does not work, and is required to implement some work around (re-pack your artifact and delete some classes)

This approach does not work with the uber/fat jar:

   <dependency>
      <groupId>com.google.pdsl</groupId>
      <artifactId>pdsl</artifactId>
      <version>${pdsl.version}</version>
      <exclusions>

        <exclusion>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
        </exclusion>

        <exclusion>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-classic</artifactId>
        </exclusion>

        <exclusion>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-core</artifactId>
        </exclusion>

        <exclusion>
          <groupId>org.jacoco</groupId>
          <artifactId>jacoco-maven-plugin</artifactId>
        </exclusion>

        <exclusion>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
        </exclusion>

        <exclusion>
          <groupId>org.sonatype.sisu</groupId>
          <artifactId>sisu-guice</artifactId>
        </exclusion>

      </exclusions>
    </dependency>

Maven documentation:
Dependency management - this allows project authors to directly specify the versions of artifacts to be used when they are encountered in transitive dependencies or in dependencies where no version has been specified. In the example in the preceding section a dependency was directly added to A even though it is not directly used by A. Instead, A can include D as a dependency in its dependencyManagement section and directly control which version of D is used when, or if, it is ever referenced.

Stop using the shade plugin

Shade breaks dependency management for other users who use our library.
We used shade because it didn't force users to import every dependency PDSL uses, but this is having unacceptable side effects for our users.

Build the library in a way that allows it to use transitive dependencies while simultaneously not requiring users to import every dependency we rely on ourselves.

Adjust ANTLR4 to generate a new interface that provides stubbed implementations for rules we don't care about

For Gherkin-style tests ANTLR4 gives us two choices for the listener: an abstract class with empty implementations for everything or an interface.

The problem with the abstract class is it is too easy for the grammar to change and other clients will not realize they need to provide an implementation. This can lead to false positives.

The interface requires implementing a lot of methods that have no value (such as the exit methods).

It would be great to have a third option that provided an empty implementation for all exit methods as well as any rules that follow some convention (such as a '_' character at the end of the rule name. In this manner the user will only need to provide implementations for the enter methods of consequence and changes will allow other clients to see they need to add new functionality.

Maven surefire report generation stage interruption [FailedTestResults.getStackTrace].

We are observing the interruption in Maven surefire report generation stages.
If the TC pass, it all goes fine, but if the TC FAILED we see this stackTrace:

# Created at 2023-04-13T20:49:17.349
org.apache.maven.surefire.testset.TestSetFailedException: Test mechanism :: null
	at org.apache.maven.surefire.common.junit4.JUnit4RunListener.rethrowAnyTestMechanismFailures(JUnit4RunListener.java:223)
	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:167)
	at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:384)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:345)
	at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:126)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:418)
Caused by: java.lang.NullPointerException
	at com.pdsl.reports.TestRunResults$FailedTestResults.getStackTrace(TestRunResults.java:49)
	at org.apache.maven.surefire.report.SmartStackTraceParser.<init>(SmartStackTraceParser.java:62)
	at org.apache.maven.surefire.common.junit4.JUnit4StackTraceWriter.smartTrimmedStackTrace(JUnit4StackTraceWriter.java:98)
	at org.apache.maven.surefire.booter.ForkingRunListener.encode(ForkingRunListener.java:409)
	at org.apache.maven.surefire.booter.ForkingRunListener.encode(ForkingRunListener.java:393)
	at org.apache.maven.surefire.booter.ForkingRunListener.toString(ForkingRunListener.java:348)
	at org.apache.maven.surefire.booter.ForkingRunListener.testError(ForkingRunListener.java:171)
	at org.apache.maven.surefire.common.junit4.JUnit4RunListener.testFailure(JUnit4RunListener.java:128)
	at org.junit.runner.notification.SynchronizedRunListener.testFailure(SynchronizedRunListener.java:94)
	at org.junit.runner.notification.RunNotifier$6.notifyListener(RunNotifier.java:177)
	at org.junit.runner.notification.RunNotifier$SafeNotifier.run(RunNotifier.java:72)
	at org.junit.runner.notification.RunNotifier.fireTestFailures(RunNotifier.java:173)
	at org.junit.runner.notification.RunNotifier.fireTestFailure(RunNotifier.java:167)
	at org.apache.maven.surefire.common.junit4.Notifier.fireTestFailure(Notifier.java:114)
	at com.pdsl.runners.junit.PdslGherkinJUnit4Runner.runChild(PdslGherkinJUnit4Runner.java:233)
	at com.pdsl.runners.junit.PdslGherkinJUnit4Runner.run(PdslGherkinJUnit4Runner.java:190)
	at com.pdsl.runners.PdslTestSuite.runChild(PdslTestSuite.java:172)
	at com.pdsl.runners.PdslTestSuite.runChild(PdslTestSuite.java:27)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
	at org.junit.rules.RunRules.evaluate(RunRules.java:20)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at com.pdsl.runners.PdslTestSuite.run(PdslTestSuite.java:148)
	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:365)
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:273)
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:238)
	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:159)
	... 4 more

Better error messages on parser/lexer problems

Currently the PDSL framework produces poor, unreadable error messages when it encounters a sentence it doesn't recognize. It also produces errors and noise when behaving as expected.

We need to handle the following scenarios properly

  1. We've added a new phrase to the grammar but the old test doesn't recognize it
    • Produce an error message explaining clearly where the lexer/parser error is
    • Halt execution
  2. We've got garbage in our grammar
    • Produce an error message explaining clearly where the lexer/parser error is
    • Halt execution
  3. The phrase is in the grammar BUT we want to filter it out
    • Don't produce any error messages for the sentence we're intentionally filtering out

I suspect we'll need to return to an earlier API design where we have a listener that is aware of all valid rules and is responsible for checking syntax and a 2nd listener that actually executes on a sub-dialect of the grammar.

Find a secure way to log to the console

System.out can be used by malicious attackers to gather information for a future attack.

We somewhat mitigated this by introducting the PdslThreadSafeOutputStream as the default printer, however this class has a vulnerability in its static constructor. Because we manually associate a handler with it we have a risk (albeit lower than previously) of a security exploit.

We might be able to get around this by writing our own logger or something else. We might just accept the risk as it is admittedly low.

Perform static code analysis

The rushed initial commits do not have sufficient code health. There is a general need for cleanup as the codebase exists today.

Provide a way to verify test resource follows arbitrary syntactic structure

The current implementation requires phrases to be broken up individually and matched.Our TestSpecificationFactory essentially breaks up the input into sentences and then uses a rule that can match any of them and goes from there. This doesn't really constitute much of a grammar.

For example, the following nonsensical example is legal:

Given I shut the door
When I walk through the door
Then I can open the door

A grammar rule can be invoked that could require that the DSL we are testing be more formal. It could be empowered to complain when it encounters the above example to require a door to be opened before it is walked through, or open before it is shut.

Make test names displayed by JUnit4 shorter

The names are unique, but too long. Create a short display name.

We can perhaps cache the names of all tests and shorten them to the scenario name unless there is a conflict.

Natively support traceability reports

The PDSL framework is unique in that a test specification can apply to integration, API, component and unit tests. Because of that failures can be easily isolated to a specific tier of an application.

The TestRunResults should be capable of producing a user friendly report that is useful for root cause analysis

IntelliJ prints first phrase strangely in output

The terminal output looks fine, but in intellJ it is preceeded by a bunch of 0 characters: It appears to appear as whitespace in the terminal (and in this message), but if you highlight the text before "Given a new customer" you'll notice a bunch of characters. IntelliJ apparently renders these as '0'
Given a new customer

Then the customer receives an order confirmation

And the new customer has successfully created an account for future purchases

JUnit runner displays test suites strangely

The JUnit runner essentially treats each annotated method as a test suite. The tests run and are displayed correctly, but there is an empty result posted for the test suite itself. This is difficult to interpret and may be mistaken for noise.

Make PdslExecutable use suppliers instead of concrete instances

Some users of the framework ran into dependency injection trouble because when we create the PdslExecutable we call the suppliers eagerly to construct the test.

Other people wanted to have the JUnit5 hooks call before the visitor/listener suppliers were. We did a release for this, but we should lazily evaluate the executor and anything else we can sanely delay.

Adjust framework to be multi-lingual and modular

A python and typescript implementation of PDSL is going to be necessary. At a minimum the proto files and the gherkin parser need to be broken out into their own project.

In addition to this we should probably break the JUnit4 and JUnit5 implementations into their own repository as well.

This will produce breaking changes. While we're at it we should do other housekeeping tasks.

One would be to replace providers with suppliers instead. This will remove the need for a library and allow us to use a native (and more flexible) feature in the standard library instead.

Listeners should have visitErrorNode throw an exception by default

It is possible to get a false positive if errorNodes are encountered. The default implementation is to do nothing. The user can implement an exception to be thrown manually, but I'm concerned that it will be easy to forget and lead to difficult to diagnose bugs.

I'm going to see if this can be built into the generated code ANTLR produces with its "tool" code.

Support pairwise testing natively

Pairwise testing becomes a necessity when testing large permutations of data.

The requirement is to create an extension to the gherkin protocol that allows for specifying equivalence classes, inclusions and exclusions.

Automatically generate 'polymorphicDslAllRules' grammar from interpreter file

The DefaultPolymorphicDslPhraseFilter (mostly) requires creating another grammar on top of the grammar we actually care about. It also has a verbose constructor.

If possible we could compile the grammars at run time and generate the "meta" parser to remove this overhead. This way we could just write visitors/listeners for the parser we care about at less cost.

Se currently have the beginning of this in the InterpreterBasedPhraseFilter, however we haven't solved the problem of how to get the new context objects to work with the listeners generated from the original grammar (they are incompatible)

This problem may be large enough that we may need to abandon the effort.

One potentials way to solve this would be by generating code that used some form of method forwarding to invoke the listeners properly. This would require the ability to convert the "meta" context to the original parser context

Another might be to generate code that just has a walker call the corresponding rule with the encountered parse tree.

In either case it seems will need to find a way to wrap the original parser in the meta-parser some way if it is ever going to work.

5 - fix protocol buffers

Some minor bugs exist in the proto file we created that prevent the objects from being created in the proper package

JUnit4 @Before and @After aren't working

The JUnit4 methodBlock method associates @before and @after from parent classes with the test. PDSL creates many tests from one method, but the tests aren't getting the hooks.

Associate the hooks in runChild with each PDSL test.

JUnit4. Interpreters. Implement metadata processing

The method `com.pdsl.executors.DefaultPolymorphicDslTestExecutor#runTestsWithMetadata(java.util.Collection<com.pdsl.testcases.SharedTestCase>, java.lang.String)' should be able to process the metadata (@tags) in the feature file.

Enable URL searching in directory tree via RegEx

Many other BDD tools allow files to be discovered with a regular expression. Create a class that will locate files in a similar manner and produce a collection of URLs that can be used by a TestSpecificationFactory

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.