thrifttest

package
v0.9.17 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 22, 2024 License: BSD-3-Clause Imports: 12 Imported by: 0

Documentation

Overview

Package thrifttest contains objects and utility methods to aid with testing code using Thrift clients and servers.

Index

Examples

Constants

View Source
const (
	// DefaultClientMaxConnections is used when ServerConfig.ClientConfig.MaxConnections
	// is not set.
	DefaultClientMaxConnections = 10

	// DefaultClientConnectTimeout is used when ServerConfig.ClientConfig.ConnectTimeout
	// is not set.
	//
	// We use a relatively large number as the default timeout because we often
	// run tests from virtual environments with very limited resources.
	DefaultClientConnectTimeout = 500 * time.Millisecond

	// DefaultClientSocketTimeout is used when ServerConfig.ClientConfig.SocketTimeout
	// is not set.
	//
	// We use a relatively large number as the default timeout because we often
	// run tests from virtual environments with very limited resources.
	DefaultClientSocketTimeout = 500 * time.Millisecond

	// DefaultServiceSlug is used when ServerConfig.ClientConfig.ServiceSlug
	// is not set.
	DefaultServiceSlug = "testing"

	// InitialClientConnections is the value that is always used for
	// ServerConfig.ClientConfig.InitialConnections.
	//
	// We default to 0 becaues the service is not started in NewBaseplateServer so
	// we do not want to try to connect to it when initializing the ClientPool.
	InitialClientConnections = 0

	// ReportClientPoolStats is the value that is always used for
	// ServerConfig.ClientConfig.ReportPoolStats.
	//
	// Deprecated: deprecated with the server config field.
	ReportClientPoolStats = false
)

Variables

This section is empty.

Functions

func CopyTStruct

func CopyTStruct(ctx context.Context, dst, src thrift.TStruct) error

CopyTStruct is a helper function that can be used to implement MockCall.

In thrift.TClient and MockCall interfaces, the result is passed in as an arg to the function, so you can't directly assign a result to it. Instead, you'll need to use this helper function to copy a constructed result to the arg.

Example:

myMockClient.AddMockCall(
  "myEndpoint",
  func(ctx context.Context, args, result thrift.TStruct) error {
    return thrifttest.CopyTStruct(
      ctx,
      result,
      &myservice.MyServiceMyEndpointResult{
        Success: &myservice.MyEndpointResponse{
          // Set the response fields.
        },
      },
    )
  },
)

func GetMockTProcessorName

func GetMockTProcessorName(ctx context.Context) (string, bool)

GetMockTProcessorName gets the "name" of the TProcessorFunction to call on a MockTProcessor when calling Process.

func SetMockTProcessorName

func SetMockTProcessorName(ctx context.Context, name string) context.Context

SetMockTProcessorName sets the "name" of the TProcessorFunction to call on a MockTProcessor when calling Process.

In a normal TProcessor, the request name is read from the request itself which happens in TProcessor.Process, so it is not passed into the call to Process itself, to get around this, MockTProcessor calls GetMockTProcessorName to get the name to use from the context object.

Types

type MockCall

type MockCall func(ctx context.Context, args, result thrift.TStruct) (thrift.ResponseMeta, error)

MockCall is a mock function that can be registered to a method in a MockClient.

type MockClient

type MockClient struct {
	FailUnregisteredMethods bool
	// contains filtered or unexported fields
}

MockClient implements thrift.TClient and Client, and can be used to mock out thrift calls in testing by using it as the base client rather than a real client.

If a MockCall is registered to a method, then Call will return the result of that MockCall when that method is Call-ed. If no MockCall is registered to a method, Call will simply return nil when FailUnregisteredMethods is false, or an error when FailUnregisteredMethods is true.

MockClient is provided to help with unit testing and should not be used in production code.

func (*MockClient) AddMockCall

func (c *MockClient) AddMockCall(method string, mock MockCall)

AddMockCall registers the given MockCall to the given method.

If a mock is already registered to that method, it will be replaced with the new mock.

AddMockCall is not thread-safe.

func (*MockClient) AddNopMockCalls

func (c *MockClient) AddNopMockCalls(methods ...string)

AddNopMockCalls registers the nop MockCall to the given methods.

A nop MockCall is a MockCall implementation that does nothing and returns nil error.

func (*MockClient) Call

func (c *MockClient) Call(ctx context.Context, method string, args, result thrift.TStruct) (thrift.ResponseMeta, error)

Call implements the thrift.TClient interface.

It will return the result of the MockCall registered to method if one exists. If the method is not registered, it returns an error when FailUnregisteredMethods is true, nil otherwise.

func (MockClient) Close

func (MockClient) Close() error

Close implements Client and is a nop that always returns nil.

func (MockClient) IsOpen

func (MockClient) IsOpen() bool

IsOpen implements Client and is a nop that always returns true.

type MockClientPool

type MockClientPool struct {
	Exhausted    bool
	CreateClient func() (thriftbp.Client, error)
}

MockClientPool is a ClientPool implementation can be used in test code.

func (MockClientPool) Call

func (m MockClientPool) Call(ctx context.Context, method string, args, result thrift.TStruct) (thrift.ResponseMeta, error)

Call implements TClient.

If Exhausted is set to true, it returns clientpool.ErrExhausted as the error.

If Exhausted is set to false, it creates a new client using the CreateClient field if it's set or uses default MockClient otherwise and uses that to implement Call.

func (MockClientPool) Close

func (MockClientPool) Close() error

Close is nop and always returns nil error.

func (MockClientPool) IsExhausted

func (m MockClientPool) IsExhausted() bool

IsExhausted returns Exhausted field.

func (MockClientPool) TClient added in v0.9.0

func (m MockClientPool) TClient() thrift.TClient

TClient implements thriftbp.ClientPool.

type MockTProcessor

type MockTProcessor struct {
	// contains filtered or unexported fields
}

MockTProcessor can be used to create a mock object that fufills the BaseplateProcessor interface in testing.

func NewMockTProcessor

func NewMockTProcessor(tb testing.TB, processorMap map[string]thrift.TProcessorFunction) *MockTProcessor

NewMockTProcessor returns a pointer to a new MockTProcessor object with the internal processor map initialized to the one passed in.

If the passed in map is nil, an empty map will be initialized and passed in to the new object so it is safe to add to.

func (*MockTProcessor) AddToProcessorMap

func (p *MockTProcessor) AddToProcessorMap(name string, processorFunc thrift.TProcessorFunction)

AddToProcessorMap adds the given TProcessorFunction to the internal processor map with the given name as the key.

func (*MockTProcessor) Process

func (p *MockTProcessor) Process(ctx context.Context, in, out thrift.TProtocol) (bool, thrift.TException)

Process calls the TProcessorFunction assigned to the "name" set on the context object by SetMockTProcessorName.

If no name is set on the context or there is no TProcessorFunction mapped to that name, the call will fail the test.

func (*MockTProcessor) ProcessorMap

func (p *MockTProcessor) ProcessorMap() map[string]thrift.TProcessorFunction

ProcessorMap returns the internal processor map.

type RecordedCall

type RecordedCall struct {
	Ctx    context.Context
	Method string
	// contains filtered or unexported fields
}

RecordedCall records the inputs passed to RecordedClient.RecordedCall.

type RecordedClient

type RecordedClient struct {
	// contains filtered or unexported fields
}

RecordedClient implements the thrift.TClient interface and records the inputs to each Call.

RecordedClient is provided to help with unit testing and should not be used in production code.

RecordedClient is not thread-safe.

func NewRecordedClient

func NewRecordedClient(c thrift.TClient) *RecordedClient

NewRecordedClient returns a pointer to a new RecordedClient that wraps the provided client.

func (*RecordedClient) Call

func (c *RecordedClient) Call(ctx context.Context, method string, args, result thrift.TStruct) (thrift.ResponseMeta, error)

Call fufills the thrift.TClient interface. It will record the inputs to Call and either return the result of the inner client.Call or nil if the inner client is nil.

func (RecordedClient) Calls

func (c RecordedClient) Calls() []RecordedCall

Calls returns a copy of all of recorded Calls.

Calls is not thread-safe and may panic if used across threads if the number of calls changes between the copy buffer being intialized and copied.

type Server added in v0.2.1

type Server struct {
	baseplate.Server

	// ClientPool provides a thriftbp.ClientPool that connects to this Server and
	// can be used for making Thrift client objects to interact with this Server.
	ClientPool thriftbp.ClientPool
}

Server is a test server returned by NewBaseplateServer. It contains both the baseplate.Server and a ClientPool to use to interact with the server.

Server implements baseplate.Server.

func NewBaseplateServer added in v0.2.1

func NewBaseplateServer(cfg ServerConfig) (*Server, error)

NewBaseplateServer returns a new, Baseplate thrift server listening on the local loopback interface and a Baseplate ClientPool for use with that server.

This is inspired by httptest.NewServer from the go standard library and can be used to test a thrift service.

Example

This example demonstrates how to write an unit test with mocked thrift server using NewBaseplateServer.

package main

import (
	"context"
	"testing"

	baseplatethrift "github.com/reddit/baseplate.go/internal/gen-go/reddit/baseplate"
	"github.com/reddit/baseplate.go/secrets"
	"github.com/reddit/baseplate.go/thriftbp/thrifttest"
)

type mockedBaseplateService struct {
	Fail bool
	Err  error
}

func (srv mockedBaseplateService) IsHealthy(ctx context.Context, req *baseplatethrift.IsHealthyRequest) (r bool, err error) {
	return !srv.Fail, srv.Err
}

// In real test this function needs to be named TestService instead,
// but doing that will break this example.
func ServiceTest(t *testing.T) {
	// Initialize this properly in a real test,
	// usually via secrets.NewTestSecrets.
	var store *secrets.Store

	ctx, cancel := context.WithCancel(context.Background())
	t.Cleanup(cancel)

	processor := baseplatethrift.NewBaseplateServiceV2Processor(mockedBaseplateService{})
	server, err := thrifttest.NewBaseplateServer(thrifttest.ServerConfig{
		Processor:   processor,
		SecretStore: store,
	})
	if err != nil {
		t.Fatal(err)
	}
	// cancelling the context will close the server.
	server.Start(ctx)

	client := baseplatethrift.NewBaseplateServiceV2Client(server.ClientPool.TClient())
	got, err := client.IsHealthy(ctx, &baseplatethrift.IsHealthyRequest{
		Probe: baseplatethrift.IsHealthyProbePtr(baseplatethrift.IsHealthyProbe_READINESS),
	})

	if err != nil {
		t.Errorf("expected no error, got %v", err)
	}

	const want = true
	if got != want {
		t.Errorf("success mismatch, want %v, got %v", want, got)
	}
}

// This example demonstrates how to write an unit test with mocked thrift server
// using NewBaseplateServer.
func main() {
	// The real example is in ServiceTest function.
}
Output:

func (*Server) Close added in v0.2.1

func (s *Server) Close() error

Close the underying Server and Baseplate as well as the thriftbp.ClientPool.

func (*Server) Start added in v0.2.1

func (s *Server) Start(ctx context.Context)

Start starts the server using baseplate.Serve in a background goroutine and waits for a short period of time to give the server time to start up.

The server can be shut down manually using server.Close, with the shutdown commands defined in runtimebp, or by cancelling the given context.

type ServerConfig added in v0.2.1

type ServerConfig struct {
	// Required, the processor to handle endpoints.
	Processor thrift.TProcessor

	// Required, the secret store.
	SecretStore *secrets.Store

	// ServerConfig is an optional value, sane defaults will be chosen where
	// appropriate.
	//
	// ServerConfig.Socket will always be replaced with one created in
	// NewBaseplateServer using the local loopback address.
	ServerConfig baseplate.Config

	// ClientConfig is an optional value, sane defaults will be chosen where
	// appropriate.
	//
	// Addr will always be set to the address of the test server.
	ClientConfig thriftbp.ClientPoolConfig

	// Optional, additional ClientMiddleware to wrap the client with.
	ClientMiddlewares []thrift.ClientMiddleware

	// Optional, additional ProcessorMiddleware to wrap the server with.
	ProcessorMiddlewares []thrift.ProcessorMiddleware

	// Optional, the ErrorSpanSuppressor used to create InjectServerSpan
	// middleware.
	ErrorSpanSuppressor errorsbp.Suppressor

	// Optional, the edge context implementation.
	//
	// If it's not set, ecinterface.Mock() will be used instead.
	EdgeContextImpl ecinterface.Interface
}

ServerConfig can be used to pass in custom configuration options for the server and/or client created by NewBaseplateServer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL