go.temporal.io/server/temporaltest/server.go
172 LOC · 75 covered · 97 uncovered · 17 ranges · 24 concepts · 6 introducers · 7 tests
File neighbourhood
The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.
Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file
In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.
Graph controls are ready.
Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.
// Package temporaltest provides utilities for end to end Temporal server testing.
package temporaltest
import (
"context"
"fmt"
"math/rand"
"testing"
"time"
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/worker"
"go.temporal.io/server/common/dynamicconfig"
"go.temporal.io/server/common/log"
"go.temporal.io/server/temporal"
temporalite "go.temporal.io/server/temporaltest/internal"
)
// A TestServer is a Temporal server listening on a system-chosen port on the
// local loopback interface, for use in end-to-end tests.
//
// Methods on TestServer are not safe for concurrent use.
type TestServer struct {
server *temporalite.LiteServer
defaultTestNamespace string
defaultClient client.Client
clients []client.Client
workers []worker.Worker
t *testing.T
defaultClientOptions client.Options
defaultWorkerOptions worker.Options
serverOptions []temporal.ServerOption
}
func (ts *TestServer) fatal(err error) {
if ts.t == nil {
panic(err)
}
ts.t.Fatal(err)
}
// NewWorker registers and starts a Temporal worker on the specified task queue.
func (ts *TestServer) NewWorker(taskQueue string, registerFunc func(registry worker.Registry)) worker.Worker {
server.go ×1
return ts.NewWorkerWithOptions(taskQueue, registerFunc, ts.defaultWorkerOptions)
}
// NewWorkerWithOptions returns a Temporal worker on the specified task queue.
//
// WorkflowPanicPolicy is always set to worker.FailWorkflow so that workflow executions
// fail fast when workflow code panics or detects non-determinism.
func (ts *TestServer) NewWorkerWithOptions(taskQueue string, registerFunc func(registry worker.Registry), opts worker.Options) worker.Worker {
logger.go ×2
opts.WorkflowPanicPolicy = worker.FailWorkflow
w := worker.New(ts.GetDefaultClient(), taskQueue, opts)
registerFunc(w)
ts.workers = append(ts.workers, w)
if err := w.Start(); err != nil {
ts.fatal(err)
}
}
// GetDefaultClient returns the default Temporal client configured for making requests to the server.
//
// It is configured to use a pre-registered test namespace and will be closed on TestServer.Stop.
if ts.defaultClient == nil {
ts.defaultClient = ts.NewClientWithOptions(ts.defaultClientOptions)
}
return ts.defaultClient
}
// GetDefaultNamespace returns the randomly generated namespace which has been pre-registered with the test server.
return ts.defaultTestNamespace
}
// GetFrontendHostPort returns the host:port for this server.
//
// When constructing a Temporal client from within the same process,
// GetDefaultClient or NewClientWithOptions should be used instead.
func (ts *TestServer) GetFrontendHostPort() string {
return ts.server.FrontendHostPort()
}
// NewClientWithOptions returns a new Temporal client configured for making requests to the server.
//
// If no namespace option is set it will use a pre-registered test namespace.
// The returned client will be closed on TestServer.Stop.
func (ts *TestServer) NewClientWithOptions(opts client.Options) client.Client {
lite_server.go ×25
if opts.Namespace == "" {
opts.Namespace = ts.defaultTestNamespace
}
if opts.Logger == nil {
opts.Logger = &testLogger{ts.t}
}
defer cancel()
c, err := ts.server.NewClientWithOptions(ctx, opts)
if err != nil {
ts.fatal(fmt.Errorf("error creating client: %w", err))
}
return c
}
// Stop closes test clients and shuts down the server.
for _, w := range ts.workers {
}
c.Close()
}
if err := ts.server.Stop(); err != nil {
// Log instead of throwing error because there's no need to fail the test
// if it already succeeded.
ts.t.Logf("error shutting down Temporal server: %s", err)
}
}
// NewServer starts and returns a new TestServer.
//
// If not specifying the WithT option, the caller should execute Stop when finished to close
// the server and release resources.
testNamespace := fmt.Sprintf("temporaltest-%d", rand.Intn(1e6))
ts := TestServer{
defaultTestNamespace: testNamespace,
}
// Apply options
for _, opt := range opts {
opt.apply(&ts)
}
}
Namespaces: []string{ts.defaultTestNamespace},
Ephemeral: true,
Logger: log.NewNoopLogger(),
DynamicConfig: dynamicconfig.StaticClient{
dynamicconfig.ForceSearchAttributesCacheRefreshOnRead.Key(): []dynamicconfig.ConstrainedValue{{Value: true}},
},
// Disable "accept incoming network connections?" prompt on macOS
FrontendIP: "127.0.0.1",
}, ts.serverOptions...)
if err != nil {
ts.fatal(fmt.Errorf("error creating server: %w", err))
}
// Start does not block as long as InterruptOn is unset.
if err := s.Start(); err != nil {
ts.fatal(err)
}
// This sleep helps avoid a panic in github.com/temporalio/[email protected]/swim/labels.go:175
return &ts
}