/** * ### 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; }