Skip to content
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

docs: add concepts for transactions and environments #1559

Merged
merged 2 commits into from
Nov 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,9 @@ generate-server:
rm -rf $(BASE)/tmp

cd $(BASE); go fmt ./...

serve-docs:
docker build -t tracetest-docs -f docs-Dockerfile .
docker run --network host tracetest-docs
sleep 1
open http://localhost:8000
15 changes: 15 additions & 0 deletions docs-Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Dockerfile to build and serve the documentation files locally
# for testing purposes.
FROM python:3-alpine

WORKDIR /app

# install mkdocs and dependencies
RUN pip install mkdocs mkdocs-material mkdocs-render-swagger-plugin

COPY ./mkdocs.yml .
COPY docs/ ./docs/

EXPOSE 8000

CMD [ "python3", "-m", "mkdocs", "serve" ]
46 changes: 46 additions & 0 deletions docs/concepts/environments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Environments

A common use case for tests is to assert the same behavior across multiple environments (dev, staging, and production, for example). To make sure all environments will have the same behavior, it is important that the tests executed against those environments test the same aspects. To reduce the risks of diverging tests, Tracetest allows you to organize different environments configurations using global objects called **Environments**.

## How Environments Work

Environments are objects containing variables that can be referenced by tests. You can use a single test and provide the information on which environment object will be used to run the test. To illustrate this, consider an app that is deployed in three stages: `dev`, `staging`, and `production`. We can execute the same test in all those environments, however, both `URL` and `credentials` change from environment to environment. To run the same test against the three deployments of the app, you can create three environments:

```dotenv
# dev.env
URL=https://app-dev.com
API_TOKEN=dev-key
```

```dotenv
# staging.env
URL=https://app-staging.com
API_TOKEN=staging-key
```

```dotenv
# production.env
URL=https://app-prod.com
API_TOKEN=prod-key
```

Now consider the following test:

```yaml
type: Test
specs:
name: Test user creation
trigger:
type: http
httpRequest:
url: "${env:URL}/api/users"
method: POST
body: '{}'
authentication:
type: bearer
bearer:
token: "${env:API_TOKEN}"
```

Both `env:URL` and `env:API_TOKEN` would be replaced by the variables defined in the chosen environment where the test will run. So, if the chosen environment was `dev.env`, its values would be replaced by `https://app-dev.com` and `dev-key`, respectively.

50 changes: 25 additions & 25 deletions docs/advanced-selectors.md → docs/concepts/selectors.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Advanced Selectors
# Selectors

If you find yourself in a position where you cannot select complex spans, you can use our advanced selectors to help with that task. Advanced selectors enable selecting spans that are impossible to select using just basic selectors.

Expand Down Expand Up @@ -30,7 +30,7 @@ flowchart LR
start -->|1. Close order| cart-api
cart-api-->|5. send buy action| purchase-api
purchase-api --> |7. Send notification to user|notification-api
purchase-api -->|6. can product be bought by user?| auth-api
purchase-api -->|6. can product be bought by user?| auth-api
auth-api --> auth-storage
cart-api -->|2. is product available?| product-api
product-api -->|4. can user view product?| auth-api
Expand All @@ -47,7 +47,7 @@ And it generates the following trace:
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -87,7 +87,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -163,7 +163,7 @@ This would select the following spans:
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -203,7 +203,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -284,7 +284,7 @@ This would select the following spans:
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -324,7 +324,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -401,7 +401,7 @@ This would select the following spans:
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -441,7 +441,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -528,7 +528,7 @@ This would select the same spans as the previous example:
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -568,7 +568,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -659,7 +659,7 @@ This will select the following spans:
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -699,7 +699,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -778,7 +778,7 @@ span[tracetest.span.type="http"]:first
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -818,7 +818,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -897,7 +897,7 @@ span[tracetest.span.type="http"]:last
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -937,7 +937,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -1016,7 +1016,7 @@ span[tracetest.span.type="http"]:nth_child(3)
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -1056,7 +1056,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -1145,7 +1145,7 @@ Will return:
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -1185,7 +1185,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -1263,7 +1263,7 @@ This would find the parent span and only select the spans that are descedents of
flowchart TD
A[" id: 1
close order

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -1303,7 +1303,7 @@ flowchart TD
"]
F[" id: 6
purchase products

attributes:
service.name: cart-api
tracetest.span.type: http
Expand Down Expand Up @@ -1365,4 +1365,4 @@ flowchart TD

class F parentSpan
class G selectedSpan
```
```
60 changes: 60 additions & 0 deletions docs/concepts/transactions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Transactions

Most End-to-End tests are not simple to run. They require some setup before the actual test is run. Actions like creating a new user, removing all items from a cart, etc. So, it's important that you can execute multiple steps as part of your test suite. Tracetest introduces the concept of **Transactions** to achieve this goal.

## What is a transaction?
A transaction is defined as a group of steps that are executed in the defined order and can access information exported by previous step executions. Each step is a test.

## Chaining Tests
The main benefit of using transactions is to be able to chain tests together and use values obtained from a test in a subsequent test.

### How Values are Shared by Tests
When a transaction is run, a context object is created with information about that specific run. One of those pieces of information is an `environment variables` object, which is empty by default. If the transaction is run when referencing an [environment](environments.md), all values from the selected environments will be copied to the `environment variables` object.

When a test is executed within a transaction, if it generates any outputs, its outputs will be injected into the transaction context environment variables object. After the outputs are injected, all subsequent tests to be run within the transaction will be able to reference those values.

> :information_source: Outputs generated by steps don't modify the selected [environment](environments.md). It only modifies the transaction run context object.

Consider you have 3 tests within a transaction: A, B, and C. Transactions A and B generate outputs called A_OUTPUT and B_OUTPUT, respectively. When running the transaction, we provide an environment which contains a `HOST` environment variable. The execution of test A would only be able to reference `env:HOST`. B would be able to reference `env:HOST`, and `env:A_OUTPUT`. While C would be able to reference all three environment variables: `env:HOST`, `env:A_OUTPUT`, `env:B_OUTPUT`.

> :information_source: A single test can contain as many outputs as you like.

### Exposing Values from a Test to Other Tests
Since version v0.8, Tracetest allows tests to declare `outputs`. An output is a value that is extracted from a trace by providing a [selector](selectors.md) to choose which spans to use to get the information from, and an [expression](../expressions.md) to get the value from the selected spans. For example, consider that you want to expose the time a specific job was taken from a queue and began executing. An output would look something like the following:

```yaml
outputs:
- name: TIME_CANCEL_SUBSCRIPTION_MESSAGE_OBTAINED
selector: span[name = "Process request from cancel subscription queue"]
expression: attr:tracetest.time.start
```

This would create an output called `TIME_CANCEL_SUBSCRIPTION_MESSAGE_OBTAINED` that is obtained by reading the attribute `tracetest.time.start` from the span with `name` equal to `Process request from cancel subscription queue`. This value would would then be injected into the environment variables of that transaction to be accessed by other tests within the same transaction run.

### Transactions Execution Flow

Transaction steps are executed sequentially. A next step is only executed after the previous step finishes executing successfully. A successful step is one which managed to trigger an operation and received a trace back from the data store. Failing assertions do not make a transaction stop executing the next steps.

Examples:

### Transaction where one step didn't get executed:

* Step 1 (Finished)
* Step 2 (Failed to fetch trace)
* Step 3 (not executed)

Result: **FAILED**

### Transaction where all steps were executed, but the assertions failed:
* Step 1 (Finished)
* Step 2 (Finished)
* Step 3 (Failed assertions)

Result: **FAILED**

### Transaction where all steps succeeded:
* Step 1 (Finished)
* Step 2 (Finished)
* Step 3 (Finished)

Result: **FINISHED**
2 changes: 1 addition & 1 deletion docs/test-definition-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Available functions:
## **Assertions**
Assertions are as important as how you trigger your test. Without them, your test is just a fancy way of executing a request using a CLI command. In this section, we will discuss how you can declare your assertions in your definition file.

Before we start, there are two concepts that you must understand to write your tests: [selectors](advanced-selectors.md) and assertions.
Before we start, there are two concepts that you must understand to write your tests: [selectors](concepts/selectors.md) and assertions.

**Selectors** are queries that are executed against your trace tree and select a set of spans based on some attributes. They are responsible for defining which spans will be tested against your assertions.

Expand Down
4 changes: 3 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ nav:
- Concepts:
- Introduction to Trace-Based Testing: introduction.md
- Architecture: architecture.md
- Specifying Selectors: advanced-selectors.md
- Selectors: concepts/selectors.md
- Transactions: concepts/transactions.md
- Environments: concepts/environments.md
- Expressions: expressions.md
- Getting Started:
- Supported Backends: supported-backends.md
Expand Down