Cuerdo (cuerdo v0.4.0)
Copy MarkdownCuerdo is an Arazzo workflow runner and automatic property-based testing tool written in Elixir.
Arazzo is a community-driven specification within the OpenAPI Initiative, a project part of the Linux Foundation Collaborative. OpenAPI describes REST APIs, and Arazzo specifies how to combine multiple individual OpenAPI endpoints as a "workflow". Workflows consist of one or more steps, where each step consists of either an HTTP request referencing an OpenAPI endpoint, or another workflow. For more information, refer to the Arazzo official site.
One of Cuerdo's primary goals is reducing the amount of hand-written integration tests
required to validate API workflows.
When used with Cuerdo.ArazzoCase, workflow inputs are automatically generated from the
JSON Schemas defined in the Arazzo document.
Each workflow is then executed multiple times with different generated inputs.
In addition to evaluating Arazzo successCriteria, Cuerdo validates that requests and responses conform to the OpenAPI contract associated with each operation. This includes schema validation, content type validation, required parameter checks, and response status code verification.
As a result, a single Arazzo document can serve both as executable workflow documentation and as a property-based test suite.
Quick Start
Define a arazzo_document_test in your test module
defmodule MyTest do
use Cuerdo.ArazzoCase
arazzo_document_test document: YamlElixir.read_from_file!("arazzo.yaml")
endOr execute a workflow directly
iex> inputs = %{"email" => "user@example.com", "password" => "securePassword"}
iex> document = YamlElixir.read_from_file!("arazzo.yaml")
iex> {:ok, context} = Cuerdo.Arazzo.run_workflow(inputs, "createUserWorkflow", document)
iex> Cuerdo.Arazzo.Context.workflow_outputs(context, "createUserWorkflow")
%{"token" => "userSessionToken"}Usage
Consider the following simple workflow. A single GET request with query parameters that queries "people" entities, and validates that the returned object matches the input filters
# specs/arazzo.yaml
- workflowId: getPeople
inputs:
type: object
additionalProperties: false
required: ["name"]
properties:
name:
type: string
minLength: 1
steps:
- stepId: getPeopleStep
operationId: getPeople
parameters:
- name: name
in: query
value: $inputs.name
successCriteria:
- condition: $statusCode == 200
- type: regex
context: $response.body#/0/name
condition: "^$inputs.name"
outputs:
firstMatchingName: $response.body#/0/nameDirectly in code
You can run the workflow directly with specific inputs via Cuerdo.Arazzo.run_workflow/3, for
example
inputs = %{"name" => "John"}
arazzo_document = YamlElixir.read_from_file!("path/to/arazzo.yaml")
{:ok, context} = Cuerdo.Arazzo.run_workflow(inputs, "getPeople", arazzo_document)On success, the function returns a Cuerdo.Arazzo.Context.t/0 containing workflow outputs,
step outputs, and request/response data for each executed step.
iex> Cuerdo.Arazzo.Context.step_outputs(context, "getPeople", "getPeopleStep")
%{"firstMatchingName" => "Johnathan"}ArazzoCase
You can execute the workflow(s) as part of a test suite, using Cuerdo.ArazzoCase.
Consider the same Arazzo workflow from above, you can define a test module
as follows
# test/myapp/get_people_test.exs
defmodule MyApp.GetPeopleTest do
use Cuerdo.ArazzoCase
arazzo_document_test document: YamlElixir.read_from_file!("path/to/arazzo.yaml")
endThe Cuerdo.ArazzoCase.arazzo_document_test/1 macro generates a test for each workflow with random
inputs generated by RockSolid.from_schema/2. To exclude specific workflows, apply transformation
functions, and other options refer to arazzo_document_test
Validations
On top of the validations defined by successCriteria field, the following non-Arazzo validations
are performed at every step:
- The workflow inptus match the
inputsschema in the Arazzo document - The request Content-Type header matches any of the Content-Type defined in the OpenAPI operation
- The request body matches the schema defined in the OpenAPI operation
- All required parameters defined in the OpenAPI operation are present in the step definition
- The response body matches any of the schemas defined in the OpenAPI operation based on the Content-Type response header and response status code