testconn

package
v0.0.0-...-8a190bf Latest Latest
Warning

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

Go to latest
Published: Aug 29, 2026 License: MIT Imports: 16 Imported by: 0

README

Package testconn

Purpose

This package provides base test case for creating Test Suites.

Description

Most common connector methods can be tested using:

  • testconn.Read - Read
  • testconn.Write - Write
  • testconn.Metadata - ListObjectMetadata
  • testconn.Delete - Delete
  • testconn.BatchWrite - BatchWrite

They can be used as a template to declare your unique test case type. The main difference among them is

  • input type
  • output type
  • tested method

Below is the example of the run method:

// Declaration
func (r Read) Run(t *testing.T, builder ConnectorBuilder[connectors.ReadConnector]) {
t.Helper()
conn := builder.Build(t, r.Name) // builder will return Connector of certain type
readParams := prepareReadParams(r.Server.URL, r.Input) // substitute BaseURL with MockServerURL
output, err := conn.Read(context.Background(), readParams) // select a method that you want to test and pass input
ReadType(r).Validate(t, err, output) // invoke TestCase[InputType,OutputType].Validate(...)
}

// Example calling method
tt.Run(t, func () (connectors.ReadConnector, error) {
return constructTestConnector(tt.Server.URL)
})
TestCase

A Test case consists of:

  • InputType: captures all inputs to the tested method. Inside the Run method, it is wired and passed as arguments required by the method.
  • OutputType: represents the result of a successful method execution, which is then compared against TestCase.Expected using TestCase.Comparatorfor equality check (or deep equal if none specified).

A test case can also include TestCase.ExpectedErrs, which ensures that all expected errors are present in the returned error (checked as a subset, not strict equality).

type Read TestCase[common.ReadParams, *common.ReadResult]

func TestRead(t *testing.T) {
  t.Parallel()
  
  // Common test setup
  // ...

  // Suite definition
  tests := []testconn.Read{
    {
      Name:         "Title of the test",
      Input:        &common.ReadParams{} // This object represents `InputType`
      Server:       mockserver.Dummy(),  // Configure mock server to respond on requests.
      Comparator:   func (baseURL string, actual, expected *common.ReadResult) bool {
        return true // Custom function to compare expected vs given `OutputType`.
      },
      ExpectedErrs: []error{common.ErrMissingObjects}, // List of expected errors to be inside error object 
      Expected:     &common.ReadResult{} // This object represents `OutputType`
    },
    
    // ... other test cases ...

  }
  
  // Running tests in the loop
  // ...
}
Comparator

In most cases, an exact comparison can make test cases overly large and noisy. Comparing just a few objects or a subset of fields is often sufficient. For example:

{
    Name: "Incremental read of conversations via search",
    Input: common.ReadParams{...},
    Server: mockserver.Conditional{...}.Server(),
    Comparator: testconn.ComparatorSubsetRead,
    Expected: &common.ReadResult{
        Rows: 1,
        Data: []common.ReadResultRow{{
            Fields: map[string]any{
                "id":    "5",
                "state": "open",
                "title": "What is return policy?",
            },
            Raw: map[string]any{
                "ai_agent_participated": false,
            },
        }},
        NextPage: testconn.URLTestServer + "/conversations/search?starting_after=WzE3MjY3NTIxNDUwMDAsNSwyXQ==",
        Done:     false,
    },
    ExpectedErrs: nil,
}

This approach ensures the test is concise while still validating the critical aspects of the behavior. It's important to note that any reference to the original connector BaseURL should be replaced with testconn.URLTestServer either in ReadResult or ReadParams. During runtime, this value will be correctly substituted, satisfying the intended behavior.

Documentation

Overview

Package testconn holds a collection of common test procedures. They provide a framework to write mock tests.

Index

Constants

View Source
const URLTestServer = "{{testServerURL}}"

URLTestServer is an alias to mock server BaseURL. For usage please refer to ComparatorPagination.

Variables

This section is empty.

Functions

func ComparatorPagination

func ComparatorPagination(
	serverURL string, actual *common.ReadResult, expected *common.ReadResult,
) *testutils.CompareResult

ComparatorPagination will check pagination related fields. Note: you may use an alias for Mock-Server-URL which will be dynamically resolved at runtime. Example:

	common.ReadResult{
		NextPage: testconn.URLTestServer + "/v3/contacts?cursor=bGltaXQ9MSZuZXh0PTI="
 }

At runtime this may look as follows: http://127.0.0.1:38653/v3/contacts?cursor=bGltaXQ9MSZuZXh0PTI=. The query parameters in URL can be in different order, encoding could differ as soon as the URL content matches the check will conclude that pagination matches.

func ComparatorSortedSubsetReadByIds

func ComparatorSortedSubsetReadByIds(serverURL string,
	actual, expected []common.ReadResultRow,
) *testutils.CompareResult

ComparatorSortedSubsetReadByIds compares two slices of ReadResultRow as a subset, ignoring order and focusing only on relevant fields: raw data, associations, and identifiers.

The `actual` slice is sorted by ID to ensure consistent output. The `expected` slice must be pre-sorted in the desired order. We intentionally do not sort `expected` so that mismatch logs can correctly report the index positions that differ.

Sort: Ascending order of common.ReadResultRow.Id.

func ComparatorSubscriptionSuccess

func ComparatorSubscriptionSuccess(
	_ string, actual, _ *common.SubscriptionResult,
) *testutils.CompareResult

ComparatorSubscriptionSuccess verifies the operation returned a successful subscription result.

func ComparatorSubscriptionWithoutResult

func ComparatorSubscriptionWithoutResult(
	_ string, actual, expected *common.SubscriptionResult,
) *testutils.CompareResult

ComparatorSubscriptionWithoutResult compares subscription results without inspecting the nested Result payload. It is useful when the Result field is irrelevant for the test case.

If Result data structure should be compared use ComparatorSubscriptionWithResult.

func ComparatorSubsetBatchWrite

func ComparatorSubsetBatchWrite(_ string, actual, expected *common.BatchWriteResult) *testutils.CompareResult

ComparatorSubsetBatchWrite compares two BatchWriteResult objects, performing subset matching for individual WriteResult entries while ensuring batch-level metrics (Status, SuccessCount, FailureCount) match exactly.

Error comparison is normalized, allowing flexible matches between strings, Go errors, and mockutils.JSONErrorWrapper values—useful when top-level or per-record errors are represented as structs or JSON.

This enables expressive, stable tests that verify meaningful fields without enforcing strict structural equality across the entire batch.

func ComparatorSubsetMetadata

func ComparatorSubsetMetadata(_ string, actual, expected *common.ListObjectMetadataResult) *testutils.CompareResult

ComparatorSubsetMetadata will check a subset of fields is present. Errors could be an exact match for each object or subset can be used as well. This must be done by specifying expected errors using mockutils.ExpectedSubsetErrors. Then errors.Is() will be applied for each error.

For if this is the case refer to the example below:

Errors: map[string]error{
	"arsenal": mockutils.ExpectedSubsetErrors{ 						// Is doing a subset match.
		common.ErrCaller,
		errors.New(string(unsupportedResponse)),
	},
	"arsenal": common.NewHTTPError(http.StatusBadRequest,		// Is doing exact match.
		headers, body, fmt.Errorf("%w: %s", common.ErrCaller, string(unsupportedResponse))),
},

func ComparatorSubsetRead

func ComparatorSubsetRead(serverURL string, actual, expected *common.ReadResult) *testutils.CompareResult

ComparatorSubsetRead ensures that a subset of fields or raw data is present in the response. This is convenient for cases where the returned data is large, allowing for a more concise test that still validates the desired behavior.

func ComparatorSubsetReadSorted

func ComparatorSubsetReadSorted(serverURL string, actual, expected *common.ReadResult) *testutils.CompareResult

ComparatorSubsetReadSorted is similar to ComparatorSubsetRead but the actual Rows are sorted using the identifiers. This ensures that the rows returned by connector are in the same order for the testing purposes. The test expectation should follow this imposed order. This is important to preserve the indexes of the test reports.

Sort: Ascending order of common.ReadResultRow.Id.

func ComparatorSubsetUpsertMetadata

func ComparatorSubsetUpsertMetadata(_ string, actual, expected *common.UpsertMetadataResult) *testutils.CompareResult

ComparatorSubsetUpsertMetadata compares two UpsertMetadataResult objects, ensuring structural equality for core result properties while allowing subset matching for metadata contents.

Comparison rules:

  • Success must match exactly between actual and expected.
  • The number of top-level field groups must match.
  • For every expected property and field:
  • The property and field must exist in the actual result.
  • FieldName and Action must match exactly.
  • Warnings must match exactly (DeepEqual comparison).
  • Metadata is compared using subset semantics — all key/value pairs defined in expected.Metadata must be present in actual.Metadata, but actual may contain additional entries.

func ComparatorSubsetWrite

func ComparatorSubsetWrite(_ string, actual, expected *common.WriteResult) *testutils.CompareResult

ComparatorSubsetWrite compares two WriteResult objects, allowing partial (subset) matching for Data fields while requiring exact matches for Success and RecordId.

It provides flexible error comparison logic:

  • Errors are normalized before comparison, allowing strings, Go error types, and mockutils.JSONErrorWrapper values (for JSON-based or struct comparison) to be treated uniformly.

This comparator is typically used when only a subset of Data fields needs verification rather than a full equality check.

func ResolveTestServerURL

func ResolveTestServerURL(urlTemplate string, serverURL string) string

Types

type Comparator

type Comparator[Output any] func(serverURL string, actual, expected Output) *testutils.CompareResult

Comparator is an equality function with custom rules for specific test scenarios. Takes server URL actual output, expected output, and returns detailed comparison result.

This package provides the most commonly used comparators like ComparatorSubsetRead, ComparatorPagination, ComparatorSubsetWrite, ComparatorSubsetMetadata for partial field matching in large API responses.

func ComparatorSubscriptionWithResult

func ComparatorSubscriptionWithResult[R any](
	resultComparator func(expectedResult, actualResult *R) *testutils.CompareResult,
) Comparator[*common.SubscriptionResult]

ComparatorSubscriptionWithResult returns a comparator for subscription results that first compares the common SubscriptionResult fields and then compares the nested Result values with the provided resultComparator.

The generic type parameter R represents the concrete Result payload type.

Both expected.Result and actual.Result must be pointers. Otherwise, this is not a valid connector implementation. If Result is of no importance use ComparatorSubscriptionWithoutResult.

func ComparatorSubsetMetadataWithMissingFields

func ComparatorSubsetMetadataWithMissingFields(
	missingFields map[string][]string,
) Comparator[*common.ListObjectMetadataResult]

ComparatorSubsetMetadataWithMissingFields returns a comparator that checks metadata using ComparatorSubsetMetadata and also verifies that selected fields are absent from the returned object metadata.

Use missingFields to specify object names and the fields that must not be present in either Result[objectName].Fields. Result[objectName].FieldsMap are supported for backwards compatability.

type ConnectorBuilder

type ConnectorBuilder[Conn any] func() (Conn, error)

ConnectorBuilder is a callback method to construct and configure connector for testing. This is a factory method called for every test suite.

func (ConnectorBuilder[C]) Build

func (builder ConnectorBuilder[C]) Build(t *testing.T, testCaseName string) C

type DeleteSubscriptionParams

type DeleteSubscriptionParams struct {
	Params         common.SubscribeParams
	PreviousResult *common.SubscriptionResult
}

type InputMutator

type InputMutator[Input any] func(server *httptest.Server, input Input) Input

InputMutator optionally transforms the test input before it is passed to the method under test.

It is useful when the input needs to depend on the mock server state, for example when embedding the server URL into request bodies, headers, or other fields that cannot be known until the test server is created.

If nil, the original Input value is used unchanged.

type None

type None struct{}

None can be used to indicate no Input or no Output type.

type Proxy

type Proxy struct {
	Name                string
	Builder             ConnectorBuilder[connectors.ProxyConnector]
	ExpectedProxy       *connectors.ProxyConfig
	ExpectedModuleProxy *connectors.ProxyConfig
}

Proxy is a test suite useful for testing connectors.ProxyConnector interface.

func (Proxy) Run

func (r Proxy) Run(t *testing.T)

Run provides a procedure to test connectors.ReadConnector

type ReadByIdsParams

type ReadByIdsParams struct {
	ObjectName   string
	RecordIds    []string
	Fields       []string
	Associations []string
}

type SubscriptionEventExpected

type SubscriptionEventExpected struct {
	Data SubscriptionEventExpectedData
	Err  SubscriptionEventExpectedErr
}

type SubscriptionEventExpectedData

type SubscriptionEventExpectedData struct {
	EventType          common.SubscriptionEventType
	RawEventName       string
	ObjectName         string
	Workspace          string
	RecordId           string
	EventTimeStampNano int64
	UpdatedFields      []string
}

type SubscriptionEventExpectedErr

type SubscriptionEventExpectedErr struct {
	EventType          error
	RawEventName       error
	ObjectName         error
	Workspace          error
	RecordId           error
	EventTimeStampNano error
	UpdatedFields      error
}

type TestCase

type TestCase[Input any, Output any] struct {
	// Name of the test suite.
	Name string
	// Input passed to the tested method.
	Input Input
	// InputMutator optionally transforms the input using the mock server before
	// the test executes. Call PrepareInput to obtain the final input with this
	// transformation applied.
	InputMutator InputMutator[Input]
	// Mock Server which connector will call.
	Server *httptest.Server
	// Custom Comparator of how expected output agrees with actual output.
	Comparator Comparator[Output]
	// Expected return value.
	Expected Output
	// ExpectedErrs is a list of errors that must be present in error output.
	ExpectedErrs []error
}

TestCase describes major components that are used to test any Connector methods. It is universal and generic `Input` data type is what the tested method accepts, while `Output` value represents the data type of the expected output.

func (TestCase[Input, Output]) Close

func (c TestCase[Input, Output]) Close()

func (TestCase[Input, Output]) PrepareInput

func (c TestCase[Input, Output]) PrepareInput() Input

func (TestCase[Input, Output]) Validate

func (c TestCase[Input, Output]) Validate(t *testing.T, err error, output Output)

Validate checks if supplied input conforms to the test intention.

type TestCaseBatchWrite

type TestCaseBatchWrite batchWriteType

TestCaseBatchWrite is a test suite useful for testing connectors.BatchWriteConnector interface.

func (TestCaseBatchWrite) Run

Run provides a procedure to test connectors.BatchWriteConnector

type TestCaseDelete

type TestCaseDelete deleteType

TestCaseDelete is a test suite useful for testing connectors.DeleteConnector interface.

func (TestCaseDelete) Run

Run provides a procedure to test connectors.DeleteConnector

type TestCaseDeleteMetadata

type TestCaseDeleteMetadata deleteMetadataType

TestCaseDeleteMetadata is a test suite useful for testing connectors.DeleteMetadataConnector interface.

func (TestCaseDeleteMetadata) Run

Run provides a procedure to test connectors.DeleteMetadataConnector.

func (TestCaseDeleteMetadata) RunWithContext

RunWithContext provides a procedure to test connectors.DeleteMetadataConnector.

type TestCaseDeleteSubscription

type TestCaseDeleteSubscription deleteSubscriptionType

TestCaseDeleteSubscription is a test suite useful for testing part of connectors.SubscribeConnector interface.

func (TestCaseDeleteSubscription) Run

Run provides a procedure to test connectors.SubscribeConnector

type TestCaseGetPostAuthInfo

type TestCaseGetPostAuthInfo postAuthInfoType

TestCaseGetPostAuthInfo is a test suite useful for testing connectors.AuthMetadataConnector interface.

func (TestCaseGetPostAuthInfo) Run

Run provides a procedure to test connectors.AuthMetadataConnector

type TestCaseGetRecordsByIds

type TestCaseGetRecordsByIds readByIdsType

TestCaseGetRecordsByIds is a test suite useful for testing connectors.BatchRecordReaderConnector interface.

func (TestCaseGetRecordsByIds) Run

Run provides a procedure to test connectors.BatchRecordReaderConnector

type TestCaseListObjectMetadata

type TestCaseListObjectMetadata metadataType

TestCaseListObjectMetadata is a test suite useful for testing connectors.ObjectMetadataConnector interface.

func (TestCaseListObjectMetadata) Run

Run provides a procedure to test connectors.ObjectMetadataConnector

type TestCaseRead

type TestCaseRead readType

TestCaseRead is a test suite useful for testing connectors.ReadConnector interface.

func (TestCaseRead) Run

Run provides a procedure to test connectors.ReadConnector

type TestCaseSearch

type TestCaseSearch searchType

TestCaseSearch is a test suite useful for testing connectors.SearchConnector interface.

func (TestCaseSearch) Run

Run provides a procedure to test connectors.SearchConnector

type TestCaseSubscribe

type TestCaseSubscribe createSubscriptionType

TestCaseSubscribe is a test suite useful for testing part of connectors.SubscribeConnector interface.

func (TestCaseSubscribe) Run

Run provides a procedure to test connectors.SubscribeConnector

type TestCaseSubscriptionEvent

type TestCaseSubscriptionEvent struct {
	Name                     string
	Input                    common.Event
	Expected                 []SubscriptionEventExpected
	SubscriptionEventListErr error
}

func (TestCaseSubscriptionEvent) Run

type TestCaseUpdateSubscription

type TestCaseUpdateSubscription updateSubscriptionType

TestCaseUpdateSubscription is a test suite useful for testing part of connectors.SubscribeConnector interface.

func (TestCaseUpdateSubscription) Run

Run provides a procedure to test connectors.SubscribeConnector

type TestCaseUpsertMetadata

type TestCaseUpsertMetadata upsertMetadataType

TestCaseUpsertMetadata is a test suite useful for testing connectors.UpsertMetadataConnector interface.

func (TestCaseUpsertMetadata) Run

Run provides a procedure to test connectors.UpsertMetadataConnector.

func (TestCaseUpsertMetadata) RunWithContext

RunWithContext provides a procedure to test connectors.UpsertMetadataConnector.

type TestCaseVerifyWebhookMessage

type TestCaseVerifyWebhookMessage webhookMessageVerificationType

TestCaseVerifyWebhookMessage is a test suite useful for testing connectors.WebhookVerifierConnector interface.

func (TestCaseVerifyWebhookMessage) Run

Run provides a procedure to test connectors.WebhookVerifierConnector

type TestCaseWrite

type TestCaseWrite writeType

TestCaseWrite is a test suite useful for testing connectors.WriteConnector interface.

func (TestCaseWrite) Run

Run provides a procedure to test connectors.WriteConnector

type TestableBatchReader

type TestableBatchReader interface {
	GetRecordsByIds(
		ctx context.Context,
		objectName string,
		recordIds []string,
		fields []string,
		associations []string,
	) ([]common.ReadResultRow, error)
}

TestableBatchReader is the minimal interface for a connector that can batch read records.

type TestableBatchWriter

type TestableBatchWriter interface {
	BatchWrite(ctx context.Context, params *common.BatchWriteParam) (*common.BatchWriteResult, error)
}

TestableBatchWriter is the minimal interface for a connector that can batch write records.

type TestableDeleter

type TestableDeleter interface {
	Delete(ctx context.Context, params common.DeleteParams) (*common.DeleteResult, error)
}

TestableDeleter is the minimal interface for a connector that can delete records.

type TestableMetadataDeleter

type TestableMetadataDeleter interface {
	DeleteMetadata(ctx context.Context, params *common.DeleteMetadataParams) (*common.DeleteMetadataResult, error)
}

TestableMetadataDeleter is the minimal interface for a connector that can delete metadata.

type TestableMetadataReader

type TestableMetadataReader interface {
	ListObjectMetadata(ctx context.Context, objectNames []string) (*common.ListObjectMetadataResult, error)
}

TestableMetadataReader is the minimal interface for a connector that can read metadata.

type TestableMetadataUpdater

type TestableMetadataUpdater interface {
	UpsertMetadata(ctx context.Context, params *common.UpsertMetadataParams) (*common.UpsertMetadataResult, error)
}

TestableMetadataUpdater is the minimal interface for a connector that can update metadata.

type TestablePostAuthMetadata

type TestablePostAuthMetadata interface {
	GetPostAuthInfo(ctx context.Context) (*common.PostAuthInfo, error)
}

TestablePostAuthMetadata is the minimal interface for a connector that returns post auth metadata.

type TestableReader

type TestableReader interface {
	Read(ctx context.Context, params common.ReadParams) (*common.ReadResult, error)
}

TestableReader is the minimal interface for a connector that can read records.

type TestableSearcher

type TestableSearcher interface {
	Search(ctx context.Context, params *common.SearchParams) (*common.SearchResult, error)
}

TestableSearcher is the minimal interface for a connector that can search records.

type TestableSubscriptionCreator

type TestableSubscriptionCreator interface {
	Subscribe(
		ctx context.Context,
		params common.SubscribeParams,
	) (*common.SubscriptionResult, error)
}

TestableSubscriptionCreator is the minimal interface for a connector that can create subscriptions.

type TestableSubscriptionRemover

type TestableSubscriptionRemover interface {
	DeleteSubscription(
		ctx context.Context,
		previousResult common.SubscriptionResult,
	) error
}

TestableSubscriptionRemover is the minimal interface for a connector that can delete subscriptions.

type TestableSubscriptionUpdater

type TestableSubscriptionUpdater interface {
	UpdateSubscription(
		ctx context.Context,
		params common.SubscribeParams,
		previousResult *common.SubscriptionResult,
	) (*common.SubscriptionResult, error)
}

TestableSubscriptionUpdater is the minimal interface for a connector that can update subscriptions.

type TestableWebhookMessageVerifier

type TestableWebhookMessageVerifier interface {
	VerifyWebhookMessage(
		ctx context.Context,
		request *common.WebhookRequest,
		params *common.VerificationParams,
	) (bool, error)
}

TestableWebhookMessageVerifier is the minimal interface for a connector that can verify webhook messages.

type TestableWriter

type TestableWriter interface {
	Write(ctx context.Context, params common.WriteParams) (*common.WriteResult, error)
}

TestableWriter is the minimal interface for a connector that can write records.

type UpdateSubscriptionParams

type UpdateSubscriptionParams struct {
	Params         common.SubscribeParams
	PreviousResult *common.SubscriptionResult
}

type WebhookMessageVerificationParams

type WebhookMessageVerificationParams struct {
	Request *common.WebhookRequest
	Params  *common.VerificationParams
}

Jump to

Keyboard shortcuts

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