/**
* ### Background
* **Crank** is a BDD test automation framework for integrated SaaS. It's a CLI
* for scaffolding, testing, and independently running Cogs. Technically,
* `crank` (or portions of it) is just a grpc client that knows how to
* instantiate and communicate with Cog grpc servers.
*
* **Cogs** are like composable assertion libraries, each exposing steps and
* assertions for a particular platform or technology. Technically, a Cog is
* just a [grpc service](https://grpc.io/docs/guides/concepts/) that
* implements the `CogService` found in this documentation.
*
* Below, you will find API reference documentation for Cogs (meaning, the grpc
* service and all of the underlying protocol buffer message definitions).
*
* You may want to start with [the service definition](#automaton.cog.CogService).
*
* ---
*/
syntax = "proto3";
package automaton.cog;
import "google/protobuf/struct.proto";
/**
* Any grpc service that implements this interface is a Cog! There are only
* three methods to implement:
*/
service CogService {
/**
* Should return Cog metadata sufficient for Cog clients (like `crank`) to
* run your cog, including details like:
*
* - **name**: e.g. `myorg/my-system-cog`
* - **version**: e.g. `1.0.0`
* - **Authentication Fields**: An optional list of [Fields](#automaton.cog.FieldDefinition) (and their definitions) needed by your Cog to authenticate with the system under test.
* - **Step Definitions**: A list of [Steps](#automaton.cog.StepDefinition) (and their definitions) your Cog exposes.
*
* See [the CogManifest definition](#automaton.cog.CogManifest) for details.
*/
rpc GetManifest (ManifestRequest) returns (CogManifest) {}
/**
* Should take a [RunStepRequest](#automaton.cog.RunStepRequest), execute the
* step corresponding to the enclosed [Step](#automaton.cog.Step)'s `step_id`
* using the enclosed Step's `data`, and respond with a [RunStepResponse](#automaton.cog.RunStepResponse),
* including details like:
*
* - **outcome**: basically pass, fail, or error
* - **messageFormat**: message (including replacement tokens) to display to the user, describing the result of the step
* - **messageArgs**: an optional list of parameters to be substituted in the messageFormat above
*/
rpc RunStep (RunStepRequest) returns (RunStepResponse) {}
/**
* Should behave similarly to the `RunStep` method, but instead of taking a
* single `RunStepRequest`, this method takes a stream of `RunStepRequests`,
* and writes back a corresponding stream of `RunStepResponses`.
*
* Cog clients (like `crank`) are under no obligation to write
* `RunStepRequests` serially, but may. Your implementation is under no
* obligation to guarantee the order of responses on the `RunStepResponse`
* stream, but may.
*
* This method exists to support systems where running multiple steps and
* assertions in the same context or scope is advantageous or necessary.
* Systems with onerous authentication schemes would be one. Performing
* multiple assertions in the context of a single headless browser session
* would be another.
*/
rpc RunSteps (stream RunStepRequest) returns (stream RunStepResponse) {}
}
/**
* Represents a request to retrieve metadata about your Cog.
*
* This will always empty.
*/
message ManifestRequest {}
/**
* Represents metadata about your Cog.
*
* The details contained here are used by Cog clients (like `crank`) to run and
* interact with your Cog.
*/
message CogManifest {
/**
* The globally unique name of your Cog. Should match this Cog's docker image
* name if you intend to distribute it on docker hub.
*
* **An example**: `myorg/my-system-cog`
*/
string name = 1;
/**
* A human-friendly label for your Cog. Should most likely be the name of the
* underlying system that your Cog connects to.
*
* **An Example**: `My System`
*/
string label = 5;
/**
* The version of your Cog. Should adhere to semenatic versioning standards.
*
* **An example**: `1.0.0`
*/
string version = 2;
/**
* An optional URL representing the homepage for this Cog. Can be the Cog's
* GitHub or other source control page, Docker Hub page, etc.
*
* **An Example**: `https://github.com/your-org/your-cog`
*/
string homepage = 6;
/**
* A list of steps your Cog can run, including descriptions of data required
* by each step to run. Order does not matter.
*/
repeated StepDefinition step_definitions = 3;
/**
* A list of fields your Cog expects to be passed as metadata on each
* RunStep or RunSteps call. Order does not matter.
*/
repeated FieldDefinition auth_fields = 4;
/**
* An optional documentation URL where users can find further details about
* how to authenticate this Cog.
*/
string auth_help_url = 7;
}
/**
* A step represents an action, assertion, or validation that can be run
* against a system, e.g. creating an object, asserting that a field on an
* object has a certain value, or triggering an event or action in a system.
*
* The details provided on a StepDefinition are used by Cog clients (like
* `crank`) to run your Cog's specific steps.
*/
message StepDefinition {
/**
* A step's type.
*/
enum Type {
ACTION = 0; /// This step performs an action.
VALIDATION = 1; /// This step performs a validation (e.g. an assertion).
}
/**
* A unique identifier representing this step. This will be passed back as
* the Step.step_id on the Step passed to your RunStep(s) implementation. Use
* it to dispatch step-specific logic in response to a RunStepRequest.
*
* Note: Once defined, this should almost never be modified; if modified, the
* change should be accompanied by a major-version change on your
* CogManifest.version.
*
* **An example**: `AssertValueOfMySytemField`
*/
string step_id = 1;
/**
* A human-readable name for this step. This may be used as a way to
* represent this step to users in a UI or CLI, and may be shown in step run
* logs.
*
* **An example**: `Checks the Value of a Field`
*/
string name = 2;
/**
* An optional-but-encouraged string describing, in plain language, what this
* step does, and how you can expect to use it. This value may be used when
* automatically generating documentation for your Cog.
*
* **An example**: `This step loads the identified object from the system and checks the specified field's value.`
*/
string help = 6;
/**
* Categorizes this step as (for now) either an action or a validation. An
* action is generally assumed to have no FAILED state, only PASSED and ERROR
* states. A validation is generally assumed to be idempotent and can result
* in a PASSED, FAILED, or ERROR state.
*/
Type type = 5;
/**
* A string that can be evaluated as an ECMAScript-compatible regular
* expression. This is used to identify and evaluate this step in
* cucumber-like scenario files.
*
* You should ensure that this expression is globally unique, and would not
* be ambiguous with step expressions from other Cogs. An easy way to do this
* is to include the system/service your Cog integrates with in the
* expression text.
*
* You are encouraged to use named regex capturing groups whose names
* correspond to keys on the expected_fields field definitions defined on
* this step.
*
* Note: Once defined, this should almost never be modified; if modified, the
* change should be accompanied by an appropriate change to your
* CogManifest.version.
*
* **An example**: `the MySystem (?.+) field should have value
* (?.+)`
*
* Which would be matched by a step in a scenario file like:
* `Then the MySystem emailAddress field should have value test@example.com`
*
* And which would result in Step.data on a RunStepRequest looking like:
* `{ "fieldName": "emailAddress", "expectedValue": "test@example.com" }`
*/
string expression = 3;
/**
* A list of field definitions that this step needs in order to run. The key
* of each expected field will be used as a key on the map/dictionary passed
* in on Step.data on a RunStepRequest.
*/
repeated FieldDefinition expected_fields = 4;
/**
* A list of record definitions that this step may respond with alongside
* other step response data. The definitions provided here are used by Cog
* clients (like `crank`) to auto-generate step documentation, as well as
* provide dynamic token value substitution hints during the Scenario
* authoring process.
*/
repeated RecordDefinition expected_records = 7;
}
/**
* Represents metadata about a field that your Cog expects to run.
*
* Field definitions can be applied to both Steps (to define what data is
* required by the step to run) and the Cog itself (to define what
* authentication details are required for your Cog to run any steps).
*/
message FieldDefinition {
/**
* A field's optionality.
*/
enum Optionality {
OPTIONAL = 0; /// This field is optional.
REQUIRED = 1; /// This field is required.
}
/**
* A field's type.
*/
enum Type {
ANYSCALAR = 0; /// This field represents any scalar value.
STRING = 1; /// This field represents a string value.
BOOLEAN = 2; /// This field represents a boolean value.
NUMERIC = 3; /// This field represents any type of numeric value.
DATE = 4; /// This field represents a date.
DATETIME = 5; /// This field represents a date/time.
EMAIL = 6; /// This field represents an email address.
PHONE = 7; /// This field represents a phone number.
URL = 10; /// This field represents a URL
ANYNONSCALAR = 8; /// This field represents any non-scalar value.
MAP = 9; /// This field represents a map/dictionary/associative array/arbitrary key-value pair (conceptually like a JSON object)
}
/**
* The unique identifier for this field. This key will be used when a Cog
* client (like `crank`) passes data to your Cog.
*
*
* If this field represents an expected field on a StepDefinition, this will
* be used as the key on Step.data. If this field represents an
* authentication field on the Cog itself, it will be the key used to set
* metadata on the grpc call.
*
*
* **An example**: `mySystemAuthToken`
*/
string key = 1;
/**
* The optionality of this field (either optional or required).
*/
Optionality optionality = 2;
/**
* The type for this field. This is used by Cog clients (like `crank`) to
* infer validation rules and UX when presenting your cog and steps to users.
* It may also be used when serializing data that is passed to your Cog in
* RunStep(s) requests.
*/
Type type = 3;
/**
* The description of this field. This may be used by Cog clients (like
* crank) to help users understand what the field is and how it will be
* used.
*
*
* **An example**: `Token used to authenticate to MySystem`
*/
string description = 4;
/**
* An optional-but-encouraged string describing, in plain language, additional
* details about this field (like what it's used for, what format it might
* take, and where users might find it, depending on context). This value may
* be used when automatically generating documentation for your Cog.
*
* **An example**: `This token can be found in your user settings under "API Tokens"`
*/
string help = 5;
}
/**
* Represents the definition of a `StepRecord`'s schema. Metadata provided here
* informs Cog clients (like `crank`) of what records to expect and what form
* they will take. This metadata is used to improve step documentation and
* enable dynamic token hinting in the Scenario authoring process.
*/
message RecordDefinition {
/**
* A response record's type.
*/
enum Type {
KEYVALUE = 0;
TABLE = 1;
BINARY = 2;
}
/**
* A unique identifier (alphanumeric and all lowercase) for this record. It
* should correspond to the id on the `StepRecord` that is provided on the
* `RunStepResponse` message.
*
* **An example**: `lead`
*/
string id = 1;
/**
* The type of structured data this record represents.
*/
Type type = 2;
/**
* Represents a list of fields (`FieldDefinition` objects) whose keys are
* guaranteed to be included on the Record's key/value object or in every
* table row. This list should be reserved for fields which will always be
* included (e.g. the ID or creation date of a Lead object).
*
* Note: only relevant for `StepRecord`s of type `KEYVALUE` or `TABLE`.
*/
repeated FieldDefinition guaranteed_fields = 3;
/**
* Set this to `true` if the list of `guaranteed_fields` provided on this
* record definition is non-exhausitve (meaning: the record may contain
* additional fields, but their keys and types are unknowable until run-time).
*
* Note: only relevant for `StepRecord`s of type `KEYVALUE` or `TABLE`.
*/
bool may_have_more_fields = 4;
}
/**
* Argument passed to the `RunStep` (or `RunSteps`) methods. Represents a
* request to your Cog to run a step.
*/
message RunStepRequest {
/**
* The step your Cog should run, identified by `step_id`, and including data
* as specified in your corresponding `StepDefinition`.
*/
Step step = 1;
/**
* Represents a string identifier that your Cog or step execution code can
* use to help understand the context of a request or as part of a cache key.
*
* For steps run via the `RunStep` (unary) method, this value will be
* different for every step. For steps run via the `RunSteps` (streaming)
* method, this value will be the same across all step requests for a single
* stream.
*/
string request_id = 2;
/**
* Represents a string identifier that your Cog or step execution code can
* use to help understand the context of a request or as part of a cache key.
*
* This value will be the same for every step on a single scenario run, but
* will differ across scenarios when run in the same session (e.g. when a
* folder of scenarios is run). If the same scenario is run twice, but via
* separate run invocations, this ID will be different for each run.
*/
string scenario_id = 3;
/**
* Represents a string identifier that your Cog or step execution code can
* use to help understand the context of a request or as part of a cache key.
*
* This value will be the same for every step on every scenario run by a
* given requestor. This value will be the same, even between separate run
* invocations.
*/
string requestor_id = 4;
}
/**
* Represents a Step your Cog should run.
*/
message Step {
/**
* Corresponds to the step_id you provided in your StepDefinition.
*/
string step_id = 1;
/**
* An arbitrary package of data your step needs to run. Should correspond to
* a map/dictionary of field values corresponding to the expected_fields you
* provided on your StepDefinition.
*/
google.protobuf.Struct data = 2;
}
/**
* Represents the response you send to the Cog client once your Step has
* finished running (on `RunStep` and `RunSteps` methods).
*/
message RunStepResponse {
/**
* The status of a completed step.
*/
enum Outcome {
PASSED = 0; /// Means this step completed successfully.
FAILED = 1; /// Means this step completed, but did not meet expectations.
ERROR = 2; /// Means this step could not be completed due to an error.
}
/**
* The outcome of this step.
*/
Outcome outcome = 1;
/**
* A message format, similar to a string suitable for use in printf, that
* represents the outcome of this step. Acceptable replacement tokens are:
*
* - `%s` for strings,
* - `%d` for numeric values of any kind, and
* - `%%` as a way to print a single percent sign.
*
* This message (and supplied arguments below) may be used by Cog clients
* (like `crank`) in step run logs. You will most likely want to vary this
* message based on the outcome of this step.
*
* **An example**: `Expected MySytem field %s to have value %s, but it was
* actually %s`
*/
string message_format = 2;
/**
* An optional list of arguments to be applied to the message_format. Will be
* used to replace tokens in the message_format, similar to printf.
*/
repeated google.protobuf.Value message_args = 3;
/**
* An optional list of structured data records that Cog clients (like `crank`)
* can render to help users diagnose failures and errors. A common example is
* to return a record representing the object being created or checked.
*
* Note: Structured data in these records will be used to populate dynamic
* token values that Scenario authors can include in their Scenario
* definitions. Well-defined and expected record definitions should be defined
* on the `expected_records` field on the `StepDefinition` message.
*/
repeated StepRecord records = 5;
/**
* This has no formal use in Cog clients and should be ignored. Use the
* records field instead.
*/
google.protobuf.Struct response_data = 4;
}
/**
* Represents a piece of structured data that may be included on a Step
* Response. Cog clients (like `crank`) will render this structured data in
* order to help users diagnose failures or errors. This data also forms the
* basis for dynamic token value substitution.
*/
message StepRecord {
/**
* A unique identifier (alphanumeric and all lowercase) for this record. It
* should correspond to the id on the corresponding `RecordDefinition` that
* you provide on the `StepDefinition` message.
*
* **An example**: `lead`
*/
string id = 1;
/**
* Represents a human-readable name or description of this record, which may
* be displayed along with the record value by Cog clients (like `crank`).
*
* **An example**: `The Lead Record That Was Checked`
*/
string name = 2;
/**
* Represents the record or data itself. Must conform to one of the defined
* message types representing structured data.
*/
oneof value {
/**
* Blargh.
*/
google.protobuf.Struct key_value = 3;
/**
* Blergh.
*/
TableRecord table = 4;
BinaryRecord binary = 5;
}
}
/**
* Represents a type of structured data record that a `RunStepResponse` may
* include. This record type is useful when you want to represent data which
* is multi-dimensional (e.g. has many rows/columns). In these situations, it's
* recommended to use this record type, rather than returning many instances of
* the Struct or Key/Value record type.
*/
message TableRecord {
/**
* A key/value map representing table headers. Each key should correspond to
* a key on each provided row, while the value represents the label shown to
* the user as the column header when rendered.
*/
google.protobuf.Struct headers = 1;
/**
* Represents the actual table rows to be rendered.
*/
repeated google.protobuf.Struct rows = 2;
}
/**
* Represents a type of structured data record that a `RunStepResponse` may
* include. This record type is useful for large, binary objects like images.
*/
message BinaryRecord {
/**
* The binary data itself.
*/
bytes data = 1;
/**
* A mime type that describes how the data can or should be rendered, e.g.
* `image/png`.
*/
string mime_type = 2;
}