-
Notifications
You must be signed in to change notification settings - Fork 232
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
Add pdd protocol and multistream example as .md files for easier review and upgrade collaboratively #12
Add pdd protocol and multistream example as .md files for easier review and upgrade collaboratively #12
Changes from 1 commit
5404c81
fb1d7c7
7089715
fb5e87c
38a855e
21b6ce0
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,79 @@ | ||
# PDD for MultiStream (example/use case) | ||
|
||
## Protocol | ||
|
||
Defined here: | ||
- https://github.com/ipfs/specs/blob/wire/protocol/network/wire.md#multistream---self-describing-protocol-stream | ||
- https://github.com/ipfs/specs/blob/wire/protocol/network/wire.md#multistream-selector---self-describing-protocol-stream-selector | ||
|
||
## Protocol Compliance Tests Spec | ||
|
||
Given the protocol spec, an implementation of the multistream-select protocol has to comply with the following scenarios: | ||
|
||
#### 1 - push-stream | ||
|
||
In a push-stream example (one-way stream), we have two agents: | ||
|
||
- 'broadcast' - where messages are emited | ||
- 'silent' - listener to the messages emited by the broadcast counterparty | ||
|
||
Compliance test 1 (human readable format): | ||
``` | ||
# With a connection established between silent - broadcast | ||
< /multistream/1.0.0 # multistream header | ||
< /bird/3.2.1 # Protocol header | ||
< hey, how is it going? # First protocol message | ||
``` | ||
|
||
#### 2 - duplex-stream | ||
|
||
In a duplex-stream example (interactive conversation), we have two agents: | ||
|
||
- 'select' - waiting for connections, hosts several protocols from where a client can pick from | ||
- 'interactive' - connects to a select agent and queries that agent for a specific protocol | ||
|
||
Compliance test 2 (human readable format): | ||
``` | ||
# With a connection established between interactive - select | ||
< /multistream/1.0.0 | ||
> /multistream/1.0.0 | ||
> ls | ||
< ["/dogs/0.1.0","/cats/1.2.11"] | ||
> /mouse/1.1.0 | ||
< na | ||
> /dogs/0.1.0 | ||
< /dogs/0.1.0 | ||
> hey | ||
``` | ||
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. ideally the test could try to fuzz all possible message orderings. e.g.:
not sure if this is worth worrying about or not 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. On Thu, Jun 11, 2015 at 08:55:04PM -0700, Juan Batiz-Benet wrote:
How do you know what the possible message orderings are without a |
||
|
||
## Wire out | ||
|
||
Since this protocol is not fully plaintext, we have to capture the messages/packets that transmited by one of the agents to make sure we get the transformations right (and therefore doing development driven by what is going on in the wire, which is defined by the Protocol (PDD ftw!)) | ||
|
||
With a first implementation written, we can capture the messages switched on the wire, so that later, we can require other implementations to conform. For the multistream scenario, tests are organized by the following: | ||
|
||
``` | ||
tests | ||
├── comp # Where compliance tests live | ||
│ ├── compliance-test.js | ||
├── impl # Where specific implementation tests live, where we can get code coverage and all that good stuff | ||
│ ├── interactive-test.js | ||
│ └── one-way-test.js | ||
└── spec # Spec tests are the tests were what is passed on the wire is captured, so it can be used in the compliance tests for all the implementations | ||
├── capture.js | ||
├── interactive-test.js | ||
├── one-way-test.js | ||
└── pristine # The pristine folder were those captures live | ||
├── broadcast.in | ||
├── broadcast.out # A broadcast.out is the same as a silent.in, since there are only two agents in this exchange, | ||
├── interactive.in # the reason both files exist is to avoid mind bending when it is time to use the "in/out", it could get confusing | ||
├── interactive.out | ||
├── select.in | ||
├── select.out | ||
├── silent.in | ||
└── silent.out | ||
``` | ||
|
||
## Protocol Compliance Test Suit | ||
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. typo: Suite |
||
|
||
The protocol compliance test suit for multistream-select can be found on `tests/comp/compliance-test.js`, each agent is tested alone with the input we have prepared on the previous step for it, once that agent replies to all the messages, we compare (diff) both the output generated and its "pristine" counterpart, expecting to get 0 differences. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
RFC {protocol hash} - Protocol Driven Development | ||
==================================================================================== | ||
|
||
# Abstract | ||
|
||
# Introduction | ||
|
||
Cross compatibility through several implementations and runtimes is historically an hard goal to achieve. Each framework/language offers different testing suits and implement a different flavour of testing (BDD, TDD, RDD, etc). We need a better way to test compatibility across different implementations. | ||
|
||
Instead of the common API tests, we can achieve cross implementation testing by leveraging interfaces offered through the network and defined by the Protocol. We call this Protocol Driven Development. | ||
|
||
In order for a code artefact to be PDD compatible | ||
- Expose a connection (duplex stream) interface, may be synchronous (online, interactive) or asynchronous. | ||
- Implement a well defined Protocol spec | ||
|
||
## Objectives | ||
|
||
The objectives for Protocol Driven Development are: | ||
- Well defined process to test Protocol Spec implementations | ||
- Standard definition of implementation requirements to comply with a certain protocol | ||
- Automate cross implementation tests | ||
- Have a general purpose proxy for packet/message capture | ||
|
||
# Process | ||
|
||
In order to achieve compliance, we have to follow four main steps: | ||
1 - Define the desired Protocol Spec that is going to be implemented | ||
2 - Design the compliance tests that prove that a certain implementation conforms with the spec | ||
3 - Once an implementation is done, capture the messages traded on the wire using that implementation, so that the behaviour of both participants can be replicated without the agent | ||
4 - Create the Protocol Compliance Tests (consisting on injecting the packets/messages generated in the last step in the other implementations and comparing outputs) | ||
|
||
## Protocol Spec | ||
|
||
Should define the goals, motivation, messages traded between participants and some use cases. It should not cover language or framework specifics. | ||
|
||
## Protocol Compliance Tests Spec | ||
|
||
Defines what are the necessary “use stories” in which the Protocol implementation must be tested to assure it complies with the Protocol Spec. For e.g: | ||
|
||
``` | ||
# Protocol that should always ACK messages of type A and not messages of type B | ||
> A | ||
{< ACK} | ||
> B | ||
> B | ||
> B | ||
``` | ||
|
||
**Message Flow DSL:** | ||
- Indentation to communicate a dependency (a ACK of A can only come after A is sent for e.g) | ||
- [ ] for messages that might or not appear (e.g heartbeats should be passed on the wire from time to time, we know we should get some, but not sure how much and specifically when). | ||
- { } for messages that will arrive, we just can't make sure if before of the following messages described | ||
|
||
A test would pass if the messages transmitted by an implementation follow the expected format and order, defined by the message flow DSL. The test would fail if format and order are not respected, plus if any extra message is transmitted that is was not defined. | ||
|
||
Tests should be deterministic, so that different implementations produce the same results: | ||
``` | ||
┌─────────┐ ┌─────────┐ ┌───────────────┐ | ||
│input.txt│──┬─▶│go-impl │───▶│ output.go.txt │ | ||
└─────────┘ │ └─────────┘ └───────────────┘ | ||
│ ┌─────────┐ ┌───────────────┐ | ||
└─▶│node-impl├───▶│output.node.txt│ | ||
└─────────┘ └───────────────┘ | ||
``` | ||
|
||
So that a diff between two results should yield 0 results | ||
|
||
``` | ||
$ diff output.go.txt output.node.txt | ||
$ | ||
``` | ||
|
||
## Interchange Packet/Message Capture | ||
|
||
Since most of these protocols define leverage some type of encoded format for messages, we have to replicate the transformations applied to those messages before being sent. The other option is capturing the messages being sent by one of the implementations, which should suffice the majority of the scenarios. | ||
|
||
## Protocol Compliance Tests Suite | ||
|
||
These tests offer the last step to test different implementations independently. By sending the packets/messages and evaluating their responses and comparing across different implementations, we can infer that in fact they are compatible | ||
|
||
#### [Example use case - go-multistream and node-multistream tests](/PDD-multistream.md) |
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 super nice.
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.
On Fri, Jun 12, 2015 at 04:45:57PM -0700, Juan Batiz-Benet wrote:
This is the multistream-select view (because of the nested streams),
but for conversations like this where the streams are strictly nested
(e.g., no going back to an ancestor stream after saying something in a
child stream), you could also run this test against a non-multiplexed
(uniplexed?) multistream implementation. Elaborating on the
test-harness changes for the multiplexed transport:
multistream-select driver. We probably want a
‘/multistream-select/{version}’ handshake (or optimistic
broadcast?) to make sure we're speaking the same multistream-select
language (or at least can figure out what went wrong in a
brodcast-to-silent situation).
multistream-select driver.
responsible for creating the new stream) and attach the
multistream-1.0.0 driver.
While for the uniplexed transport, we'd have:
multistream-select driver. We probably want a
‘/multistream-select/{version}’ handshake (or optimistic
broadcast?) to make sure we're speaking the same multistream-select
language (or at least can figure out what went wrong in a
brodcast-to-silent situation).
multistream-select driver.
multistream-1.0.0 driver to the stream.
to the stream.
The test-suite's transport driver should have a IsMultiplexed() check
so it can decide which of these approaches to take (or so it can error
out if you ask it to run a multiplex-requiring transcript over a
uniplexed transport).