Skip to content

TestingHost architecture

The Microsoft.Orleans.TestingHost package composes real silo and client hosts with test-oriented discovery, transport, statistics, directory, and lifecycle controls. It is an integration harness, not a mock grain runtime. Grain activation, scheduling, serialization, messaging, placement, and most provider behavior execute through the same runtime components as a hosted cluster.

This page describes the harness internals. For practical setup, fixture patterns, topology changes, and guidance on choosing mocks or a cluster, see Test Orleans applications.

Rendering diagram.

InProcessTestClusterBuilder accumulates host, silo, and client delegates. Build passes its options to an InProcessTestCluster; the cluster retains that mutable options object. DeployAsync starts the configured silo hosts and initializes the client when requested. With client initialization enabled, it performs a best-effort initial membership-view check but can continue after warning that views have not stabilized. Each InProcessSiloHandle owns one Generic Host and exposes its service provider for test inspection.

The processes are shared, but the hosts and dependency-injection containers are not. Static process state can still leak between silos, which is one reason production code should not use static mutable state for silo-local behavior.

API: InProcessTestClusterBuilder, InProcessTestCluster, and InProcessSiloHandle. Implementation: builder, cluster, and silo handle.

InProcessTestClusterBuilder defaults to:

SettingDefault
InProcessTestClusterOptions.InitialSilosCount2
InProcessTestClusterOptions.ClusterIdNewly generated
InProcessTestClusterOptions.ServiceIdNewly generated GUID
InProcessTestClusterOptions.InitializeClientOnDeploytrue
Test-cluster membershiptrue
Test-cluster grain directorytrue
InProcessTestClusterOptions.UseDistributedGrainDirectoryfalse
InProcessTestClusterOptions.GatewayPerSilotrue
InProcessTestClusterOptions.UseRealEnvironmentStatisticsfalse
Connection transportIn-memory

Simulated environment statistics make resource-based tests deterministic, but they do not reproduce operating-system CPU or memory pressure. Opt into real statistics only when the test specifically needs those signals.

These defaults are defined by InProcessTestClusterBuilder and InProcessTestClusterOptions; see their builder and options implementations.

The builder separates three scopes:

Delegates run for each relevant host. A singleton registered by a silo delegate is singleton within that silo’s container, not across the cluster. A concrete instance captured by a delegate is shared because the test supplied the same object.

StartAdditionalSiloAsync and StartSilosAsync create new hosts using the cluster’s current options and configuration delegates. StopSiloAsync, StopSilosAsync, StopAllSilosAsync, WaitForLivenessToStabilizeAsync, and WaitForClusterManifestToStabilizeAsync coordinate membership and manifest transitions for failure and elasticity tests.

The overloads which take startAdditionalSiloOnNewPort are obsolete. Tests should use the parameterless StartAdditionalSilo overloads or StartSilosAsync. Lower-level StartSiloAsync overloads remain available when a test must supply an instance number or configuration overrides.

Stopping a host gracefully exercises shutdown. Disposing or terminating a handle without graceful membership update is a different failure mode and should be chosen deliberately when testing failure detection.

Class-configurator test cluster and custom silo creation

Section titled “Class-configurator test cluster and custom silo creation ”

TestClusterBuilder is the class-configurator-based harness. It defaults to two silos, in-memory transport, generated cluster identity, test membership, client initialization, file logging, and homogeneous-silo assumptions. It also installs ConfigureDistributedGrainDirectory, so its silos opt into the experimental distributed grain directory instead of the production runtime’s default LocalGrainDirectory.

ISiloConfigurator, IHostConfigurator, and IClientBuilderConfigurator are serializable configuration identities which can be applied to every host. Assigning TestClusterBuilder.CreateSiloAsync sets TestClusterOptions.ConnectionTransport to TcpSocket, so the built-in client uses its TCP transport instead of the harness’s in-memory transport. The delegate bypasses DefaultCreateSiloAsync and cannot access the harness’s private in-memory transport hub, so it must configure the custom silo host with a compatible transport.

TestCluster supports suites built around SiloHandle and configurator types. It does not use separate application domains; its hosts run in-process unless a custom silo creation path provides different isolation.

API: TestClusterBuilder, TestCluster, and TestClusterOptions. Implementation: builder, cluster, and options.

TestingHost deliberately substitutes infrastructure. Tests must account for those boundaries:

  • in-memory transport does not reproduce sockets, TLS, packet loss, or network buffers;
  • test membership does not prove a production membership provider’s transaction behavior;
  • the test grain directory can bypass production directory edge cases;
  • simulated statistics do not reproduce load shedding;
  • one process shares thread-pool and static state; and
  • graceful stop does not model abrupt process or machine loss.

Use the smallest substitution which keeps the invariant under test real. Directory, membership, transport, and provider contract tests often need their production component explicitly enabled.

Repository fixtures such as BaseInProcessTestClusterFixture wrap cluster setup and disposal, while specialized suites configure the component being exercised. For example, AQStreamingTests uses ConfigureHost, ConfigureSilo, and ConfigureClient to combine real Azure Queue adapters with an in-process Orleans cluster.