Skip to content

Extending E2Engine

E2Engine separates its testing model from the infrastructure used to store resources, schedule work, and execute tests.

These boundaries make it possible to replace or extend parts of the system without changing the Environment, Test, TestSuite, or execution models.

E2Engine Core
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
Repository Scheduler Runner
│
┌─────────┴─────────┐
│ │
▼ ▼
Services Routing
│
▼
Protocol execution

Not every extension requires changing E2Engine Core. Most infrastructure-specific behavior belongs behind one of these boundaries.

E2Engine Core accesses resources and execution state through repository contracts.

E2Engine Core
│
▼
Repository contracts
│
▼
Repository implementation
│
▼
Storage

Repository implementations are responsible for persistence operations involving resources such as:

  • Environments;
  • Tests;
  • TestSuites;
  • TestExecutions;
  • TestSuiteExecutions.

The core does not need to know how these records are physically stored.

A custom repository can therefore use a different storage system while preserving the same E2Engine resource and execution models.

Repository implementations are also responsible for the persistence semantics required by the core, such as resource lookup, listing, creation, deletion, and execution state updates.

Execution coordination is separated from execution delivery.

After E2Engine resolves the resources for a run and creates the corresponding execution records, it publishes test execution work through a scheduler.

E2Engine Core
│
│ resolved execution job
▼
Scheduler
│
▼
Runner

The scheduler boundary determines how execution work reaches a runner.

The default local setup uses a lightweight scheduler suitable for local execution, but the core execution lifecycle does not depend on that particular transport.

A different scheduler can therefore change how jobs are delivered without changing Test resources or the execution model.

A runner consumes scheduled test work and performs the runtime execution.

Its responsibilities include:

Receive execution job
│
▼
Acquire runtime Environment
│
▼
Mark execution running
│
▼
Execute Test
│
▼
Persist execution result
│
▼
Release runtime Environment

The local runner provides the standard execution infrastructure and can process multiple test jobs concurrently.

Runner infrastructure is separate from E2Engine Core so that execution placement and worker behavior do not become part of the testing model.

A different runner implementation can change where or how tests execute while preserving the same execution jobs and results.

An Environment service is converted into a runtime service when an Environment instance is acquired.

The service provider selects an implementation from the service definition:

ServiceSpec
│
├── HTTP + real ──▶ runtime service
├── HTTP + mocked ──▶ runtime service
├── gRPC + real ──▶ runtime service
└── gRPC + mocked ──▶ runtime service

Runtime services implement the behavior necessary to represent real or mocked dependencies during execution.

This boundary separates the declarative service definition from the infrastructure needed to provide that service at runtime.

Extending service support therefore belongs in the runtime layer rather than in Test execution orchestration.

The runtime Environment also uses a router abstraction.

For each Environment service, E2Engine registers a route containing its service identity, protocol, configured address, and runtime address.

Environment service
│
▼
Route
│
▼
Router
│
▼
Runtime service

The standard router provides protocol-specific HTTP and gRPC routing and records calls passing through modeled service boundaries.

A router implementation is responsible for mounting and unmounting those routes while preserving the Environment’s service-address model.

Keeping routing behind its own boundary separates service topology from the mechanism used to expose that topology during execution.

Test execution contains protocol-specific components for sending requests and evaluating behavior.

Test
│
┌───────┴───────┐
│ │
▼ ▼
HTTP gRPC
│ │
▼ ▼
Executor Executor
│ │
▼ ▼
Evaluation Evaluation

Protocol executors perform the request defined by a Test.

Protocol-specific evaluators compare responses and observed calls with the corresponding expectations.

The surrounding execution lifecycle remains independent of these details:

runtime setup
│
▼
protocol execution
│
▼
evaluation
│
▼
structured result

This separation keeps protocol behavior localized rather than spreading HTTP- or gRPC-specific logic throughout the execution engine.

Adding another protocol would require corresponding runtime, execution, observation, and evaluation support while preserving the common TestExecution lifecycle.

Infrastructure components can have their own operational configuration.

Examples include:

  • repository settings;
  • scheduler settings;
  • runner worker configuration;
  • execution and publishing timeouts;
  • runtime service provider settings.

These settings belong to E2Engine configuration rather than Environment or Test resources.

Test model Runtime configuration
Environment Repository
Test + Scheduler
TestSuite Runner
Workers
Providers

This allows the same test definitions to run with different infrastructure configurations.

When extending E2Engine, the component being changed should usually determine where the extension belongs.

Requirement Extension area
Store resources in another system Repository
Deliver execution work differently Scheduler
Execute jobs in different infrastructure Runner
Change how Environment services are provided Runtime services
Change how service addresses are exposed or routed Router
Support protocol-specific execution behavior Protocol executor/evaluator

The Environment, Test, TestSuite, TestExecution, and TestSuiteExecution models should remain independent of these infrastructure choices.

An extension should preserve the structured contracts between components whenever possible.

For example, changing execution infrastructure should not require changing a Test from:

spec:
request:
http:
method: GET
url: http://127.0.0.1:8080/health
expect:
http:
status: 200

The Test describes behavior.

The repository, scheduler, runner, router, and workers determine how E2Engine stores and executes that behavior.

Keeping those concerns separate allows infrastructure to evolve without coupling test specifications to a particular E2Engine deployment.

See Architecture overview for the relationship between these components and Design principles for the principles behind these extension boundaries.