Your first test
In this guide, you will create and run a minimal E2Engine test against a real HTTP service.
The service exposes one endpoint:
GET /ok → 200 OKYou will describe the service as an E2Engine Environment, define its expected behavior as a Test, execute it, and inspect the resulting TestExecution.
Before you start
Section titled “Before you start”Make sure E2Engine is installed and available:
e2engine versionFor this example, we also need a small HTTP service.
Create main.go:
package main
import ( "log" "net/http")
func main() { http.HandleFunc("/ok", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) })
if err := http.ListenAndServe(":9000", nil); err != nil { log.Fatal(err) }}Start the service:
go run main.goIt listens on port 9000 and returns HTTP 200 OK for GET /ok.
You can verify it directly:
curl -i http://127.0.0.1:9000/ok1. Describe the environment
Section titled “1. Describe the environment”An E2Engine environment describes the services that participate in a test.
Create environment.yml:
kind: Environmentversion: 1.0.0name: direct-real-httpdescription: one real HTTP service that returns 200 OK for /ok
spec: services: - id: direct-real-http kind: http mode: real address: 127.0.0.1:8083 http_target: http://127.0.0.1:9000This environment contains one service:
E2Engine │ │ 127.0.0.1:8083 ▼ direct-real-http │ │ forwards to ▼ http://127.0.0.1:9000 │ ▼ /okThe important distinction is between address and http_target.
address: 127.0.0.1:8083http_target: http://127.0.0.1:9000address is the endpoint exposed through E2Engine during the test.
http_target is the actual address of the real service.
Requests sent to 127.0.0.1:8083 are therefore observed by E2Engine and forwarded to the application listening on port 9000.
Create the environment:
e2engine create environment environment.ymlYou can inspect it with:
e2engine get environment direct-real-http2. Define the test
Section titled “2. Define the test”Create test.yml:
kind: Testversion: 1.0.0name: direct-real-httpdescription: verifies a request to a real HTTP service
spec: request: http: method: GET url: http://127.0.0.1:8083/ok
expect: http: status: 200
calls: - service_id: direct-real-http http: method: GET path: /okThe test describes both the request to execute and the behavior to verify.
The request:
request: http: method: GET url: http://127.0.0.1:8083/okis sent through the service address defined by the environment.
The first expectation:
expect: http: status: 200requires the test request to return HTTP 200.
The second expectation:
calls: - service_id: direct-real-http http: method: GET path: /okrequires E2Engine to observe a matching GET /ok interaction with the direct-real-http service.
Because count is not specified, the expectation means that a matching call must occur at least once.
Create the test:
e2engine create test test.ymlYou can inspect it with:
e2engine get test direct-real-http3. Run the test
Section titled “3. Run the test”Run the test in the environment:
e2engine run test direct-real-http direct-real-httpE2Engine creates a TestExecution:
created test execution with id: f5497dfbbf8392b4828f5323c07e4b5cc8026790caca7b3065350413bebbd4e3During the execution, the request follows this path:
Test │ │ GET http://127.0.0.1:8083/ok ▼E2Engine │ │ observes GET /ok │ │ forwards request ▼Real HTTP service127.0.0.1:9000 │ │ 200 OK ▼E2Engine │ ▼Test resultE2Engine can therefore verify both the externally visible response and the interaction with the real service.
4. Inspect the execution
Section titled “4. Inspect the execution”Use the execution ID returned by the previous command:
e2engine get testexecution f5497dfbbf8392b4828f5323c07e4b5cc8026790caca7b3065350413bebbd4e3You can also use the short resource name and a unique ID prefix:
e2engine get te f5497The result looks like this:
id: f5497dfbbf8392b4828f5323c07e4b5cc8026790caca7b3065350413bebbd4e3started_at: 2026-08-19T15:16:47.974744Zfinished_at: 2026-08-19T15:16:47.993394Zstatus: passed
environment_name: direct-real-httptest_name: direct-real-http
summary: request: http: method: GET url: http://127.0.0.1:8083/ok
response: http: status_code: 200
expect: http: status_code: 200 calls: - service_id: direct-real-http http: method: GET path: /ok
calls: - service_id: direct-real-http http: request: method: GET path: /ok headers: Accept-Encoding: - gzip User-Agent: - Go-http-client/1.1 response: status_code: 200 headers: Content-Length: - "0"The execution contains several distinct pieces of information.
Request
Section titled “Request”request: http: method: GET url: http://127.0.0.1:8083/okThis is the request E2Engine executed.
Response
Section titled “Response”response: http: status_code: 200This is the response that was actually observed.
Expectations
Section titled “Expectations”expect: http: status_code: 200 calls: - service_id: direct-real-http http: method: GET path: /okThese are the conditions defined by the test.
Observed calls
Section titled “Observed calls”calls: - service_id: direct-real-http http: request: method: GET path: /ok response: status_code: 200These are the service interactions E2Engine actually observed during execution.
Finally:
status: passedmeans the observed behavior satisfied the test expectations.
What just happened?
Section titled “What just happened?”This small example already exercises the core E2Engine model:
Environment │ ▼ Test │ ▼ Execution │ ▼ ResultThe Environment described a real HTTP service and how E2Engine could reach it.
The Test described the request, expected response, and expected service interaction.
The Execution ran that test inside the environment.
The Result recorded the request, response, expectations, and observed calls in a structured form.
The important part is that the test did not only assert:
GET /ok → 200It also verified that the expected interaction occurred across the service boundary.
Where to go next
Section titled “Where to go next”This example deliberately uses a single real HTTP service.
E2Engine environments can also combine:
- real and mocked services;
- HTTP and gRPC;
- response fixtures;
- external and internally defined protobuf services;
- interaction counts and request matching;
- multiple tests executed against the same environment.
The demo builds on exactly the same model with a Payment API that communicates with a mocked HTTP Fraud service, a real gRPC Account service, and a mocked gRPC Notification service.
The model stays the same. Only the environment becomes more interesting.

