cucumber-attic / cucumber-engine

Shared go binary that can be used by all language implementations
MIT License
6 stars 0 forks source link

Include plaintext (and possibly remove expressions) from generate-snippet #7

Open ciaranmcnulty opened 6 years ago

ciaranmcnulty commented 6 years ago

Currently a cucumber expression is sent in the generate snippets command, rather than leaving it to the language-specific program to generate the expression.

This will delay integration with cucumbers that don't currently support expressions, and ties us into using expressions. In Behat for instance we currently support regex and turnip expressions, and the user can select which one they want to use for the snippets. When we add cucumber expression support it's likely we'll still let users select the old syntax(es).

For this reason it'd be useful to have the full original step text in the command.

In the context of the general model, the language-specific program is going to need a cucumber expression parser (unless I've misunderstood) to do the step definition matching, therefore there's a possible source of errors where the runner generates an expression that the program can't then parse.

IMO it would be much cleaner to have all responsibility for expressions in the program and not build that knowledge into the runner.

aslakhellesoy commented 6 years ago

All Cucumber implementations built on top of the pickle runner (backend) will support Cucumber Expressions. They're parsed and matched in the pickle runner.

The logic for generating Cucumber Expressions from undefined steps takes into account what parameter types are registered. This logic sits inside the Cucumber Expressions library (inside the pickle runner), and it's somewhat complex. It's one of these things I'd rather not have to reimplement over and over again in different languages.

The language-specific program (frontent) does not need a Cucumber Expression parser - that's part of the rationale behind the pickle runner - less code to write for language-specific implementations.

The frontend sends the expressions to the backend. That's where the matching happens.

ciaranmcnulty commented 6 years ago

There are two parts to expressions:

  1. Matching steps to expressions
  2. Generating expressions (for snippets)

Unless I'm mistaken, at least 1. is going to be the responsibility of the program and will need to be implemented in each language.

charlierudolph commented 6 years ago

1 is taken care of in the pickle runner. 2 is left to the language

aslakhellesoy commented 6 years ago

2 is done in part by the pickle runner (who generates the snippets' Cucumber Expression), and by the front-end, which will take that expression and generate a language-specific nippet.

mattwynne commented 6 years ago

I personally think a more forward-compatible protocol would be to just say "I have a step that looks like this, can you run it?"

Having a protocol a bit like that in the Ruby one has allowed us to use this kind of step -> action mapping which is really useful in tests, and who knows what else people might do with that freedom?

mattwynne commented 6 years ago

Maybe the (1) matching steps to expressions could be done by a separate library that most cucumbers use, rather than baking all that responsibility into the runner.

ciaranmcnulty commented 6 years ago

@mattwynne Maybe, but it happens so frequently that there's a risk of performance issues / fragility due to lots of inter-process comms

ciaranmcnulty commented 6 years ago

Forward-compatibility is a good point actually; we'd need to ensure that the expression-generator has the same capabilities that the expression-matcher has somehow (versioning?)

aslakhellesoy commented 6 years ago

Maybe the (1) matching steps to expressions could be done by a separate library that most cucumbers use, rather than baking all that responsibility into the runner.

This is exactly what the Cucumber Expressions library does. It's got 4 implementations, which is hard work, so only keeping the Go one and doing it in the pickle runner makes perfect sense to me. Why are you suggesting duplicating this logic in all the language front ends?

mattwynne commented 6 years ago

I'm not suggesting duplicating the logic in the front-ends, just breaking apart the responsibilities.

mattwynne commented 6 years ago

I had a chat with @ciaranmcnulty about this f2f and I just wanted to rekindle this discussion as I think Ciaran had a good point which I've forgotten.

I'd personally like to see the engine be agnostic of any kind of step definition framework - cucumber expressions or otherwise. I think that the wire protocol, which simply asks the the front-end "I have a step there is a User can you do anything with that?" has worked well for us. It feels more future-proof to me than baking in an assumption about cucumber expressions being the last word in how to define steps.

charlierudolph commented 6 years ago

I don't think its worth making it agnostic at this point. My goal with this was to dramatically reduce how much effort goes into making a cucumber for a new language. Cucumber expressions are quite complex and porting it to go took me about a month.

We can try and be forward thinking but I'd like to ensure we solve today's problem while keeping tomorrows challenges in mind, but not let them limit us.

Even if we have cucumber-expressions built in to start, I think we could open it up after the fact. I really want to make initial adoption as easy as possible so we get cucumbers to use it and then we start iterating. Since this will be used internally by cucumber implementations it can have breaking changes and the different implementations can update when desired.

aslakhellesoy commented 6 years ago

@matt where are you suggesting matching steps against expressions should happen? In the engine or in the language front-end?

mattwynne commented 6 years ago

I'm suggesting that matching steps to code functions should happen in the language front-ends, whether they use expressions or some other mechanism for doing the matching.

mattwynne commented 6 years ago

I like your thinking Charlie. As much as future-proofing, what I'm also wondering about here is how we migrate in existing Cucumber implementations like Ruby and Behat. I'm thinking particularly about Ruby's wire protocol which I know quite a few people rely on.

Can you see a way we could support both? Make easy things easy but hards things possible and all that?

charlierudolph commented 6 years ago

@mattwynne if ruby switches to this, I think we should try and migrate users off the ruby wire protocol onto a wire protocol based directly off this. We should be able to design something that has an easy enough upgrade and moves the dependency from a ruby cli to a go binary (probably one that wraps the current engine).

Can you create a separate ticket for this that describes the problem / ruby's solution / what you think an idea API is?

We can probably get an additional wrapper around the current engine that is a quick and opinionated way to use cucumber in a new language

mattwynne commented 6 years ago

@mattwynne if ruby switches to this, I think we should try and migrate users off the ruby wire protocol onto a wire protocol based directly off this. We should be able to design something that has an easy enough upgrade and moves the dependency from a ruby cli to a go binary (probably one that wraps the current engine).

I think this message protocol will definitely become a kind of wire protocol v2.0 and that's a good vision to aim for long-term.

Is there a place the current message protocol / API is documented where I can look for what I think is missing?

aslakhellesoy commented 6 years ago

The message protocol will be based on protobuf. For the sake of simplicity we're defining all the messages in one place - in the cucumber/messages.

I think the next step should be to migrate the non-protobuf messages that are defined in cucumber-engine's dto directory.