testutil

package
v0.0.0-...-36d6306 Latest Latest
Warning

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

Go to latest
Published: Jul 5, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var CommonZeroValueTests = struct {
	Int32Cases []ZeroValueTestCase[int32]
	Int64Cases []ZeroValueTestCase[int64]
}{
	Int32Cases: []ZeroValueTestCase[int32]{
		{Name: "positive_to_zero", InitialValue: 5, ZeroValue: 0},
		{Name: "large_to_zero", InitialValue: 1000, ZeroValue: 0},
	},
	Int64Cases: []ZeroValueTestCase[int64]{
		{Name: "positive_to_zero", InitialValue: 5, ZeroValue: 0},
		{Name: "large_to_zero", InitialValue: 1000, ZeroValue: 0},
	},
}

CommonZeroValueTests provides pre-built test cases for common field types.

Functions

func Assert

func Assert[c comparable](t *testing.T, expected, got c)

func AssertFatal

func AssertFatal[c comparable](t *testing.T, expected, got c)

func AssertNot

func AssertNot[c comparable](t *testing.T, not, got c)

func AssertNotFatal

func AssertNotFatal[c comparable](t *testing.T, not, got c)

func VerifySyncParity

func VerifySyncParity[CollItem any, SyncItem any](t *testing.T, cfg SyncParityTestConfig[CollItem, SyncItem])

VerifySyncParity verifies that the data returned by a Collection endpoint matches the data pushed by a Sync endpoint.

func VerifyZeroValueSync

func VerifyZeroValueSync[FieldType any, SyncItem any](
	t *testing.T,
	cfg ZeroValueSyncTestConfig[FieldType, SyncItem],
	testCase ZeroValueTestCase[FieldType],
)

VerifyZeroValueSync verifies that zero values are correctly handled in sync events. This is a regression test framework for the common bug pattern:

if value != 0 {  // BUG: excludes zero values!
    update.Field = &value
}

The test: 1. Sets a non-zero value and verifies it syncs 2. Sets zero value and verifies it ALSO syncs (this is what the bug would break) 3. Verifies the actual persisted value matches

func VerifyZeroValueSyncMultiple

func VerifyZeroValueSyncMultiple[FieldType any, SyncItem any](
	t *testing.T,
	cfgFactory func(t *testing.T) ZeroValueSyncTestConfig[FieldType, SyncItem],
	testCases []ZeroValueTestCase[FieldType],
)

VerifyZeroValueSyncMultiple runs VerifyZeroValueSync for multiple field types/values. Useful for testing all numeric fields on a model.

Types

type BaseDBQueries

type BaseDBQueries struct {
	Queries *gen.Queries
	DB      *sql.DB
	// contains filtered or unexported fields
}

func CreateBaseDB

func CreateBaseDB(ctx context.Context, t *testing.T) *BaseDBQueries

func CreateBaseDBWithFK

func CreateBaseDBWithFK(ctx context.Context, t *testing.T) *BaseDBQueries

CreateBaseDBWithFK is like CreateBaseDB but enables SQLite foreign-key enforcement (PRAGMA foreign_keys = ON) so that ON DELETE CASCADE constraints fire. The connection pool is limited to one connection so the PRAGMA applies to every query executed on the returned DB.

func (BaseDBQueries) Close

func (b BaseDBQueries) Close()

func (BaseDBQueries) GetBaseServices

func (c BaseDBQueries) GetBaseServices() BaseTestServices

func (BaseDBQueries) Logger

func (b BaseDBQueries) Logger() *slog.Logger

type BaseTestServices

type BaseTestServices struct {
	Queries              *gen.Queries
	DB                   *sql.DB
	UserService          suser.UserService
	WorkspaceService     sworkspace.WorkspaceService
	WorkspaceUserService sworkspace.UserService
	HttpService          shttp.HTTPService
	FlowService          sflow.FlowService
	FlowVariableService  sflow.FlowVariableService
}

func (BaseTestServices) CreateTempCollection

func (b BaseTestServices) CreateTempCollection(ctx context.Context, userID idwrap.IDWrap, name string) (idwrap.IDWrap, error)

type ConcurrencyTestConfig

type ConcurrencyTestConfig struct {
	// NumGoroutines is the number of concurrent operations to run.
	// Default: 20
	NumGoroutines int

	// Timeout is the maximum duration for each operation.
	// If an operation takes longer, it's counted as a timeout (potential deadlock).
	// Default: 3 seconds
	Timeout time.Duration

	// ExpectSuccess indicates whether operations should succeed.
	// Default: true
	ExpectSuccess bool
}

ConcurrencyTestConfig holds parameters for concurrency tests.

type ConcurrencyTestResult

type ConcurrencyTestResult struct {
	// SuccessCount is the number of operations that completed successfully.
	SuccessCount int

	// ErrorCount is the number of operations that returned errors.
	ErrorCount int

	// TimeoutCount is the number of operations that exceeded the timeout.
	// This indicates potential deadlocks or blocking issues.
	TimeoutCount int

	// AverageDuration is the mean duration of all operations.
	AverageDuration time.Duration

	// MaxDuration is the longest operation duration.
	MaxDuration time.Duration

	// MinDuration is the shortest operation duration.
	MinDuration time.Duration
}

ConcurrencyTestResult captures the outcome of concurrency tests.

func RunConcurrentDeletes

func RunConcurrentDeletes[T any](
	ctx context.Context,
	t *testing.T,
	config ConcurrencyTestConfig,
	setupData func(i int) T,
	executeDelete func(ctx context.Context, data T) error,
) ConcurrencyTestResult

RunConcurrentDeletes executes multiple delete operations concurrently. See RunConcurrentInserts for detailed documentation.

func RunConcurrentInserts

func RunConcurrentInserts[T any](
	ctx context.Context,
	t *testing.T,
	config ConcurrencyTestConfig,
	setupData func(i int) T,
	executeInsert func(ctx context.Context, data T) error,
) ConcurrencyTestResult

RunConcurrentInserts executes multiple insert operations concurrently and detects timeouts/deadlocks. This is useful for testing that database operations handle concurrent requests without SQLite deadlocks.

Parameters:

  • ctx: Context to use for all operations (e.g., with auth)
  • t: Testing context
  • config: Configuration for the concurrency test
  • setupData: Function to prepare test data for each goroutine (index i)
  • executeInsert: Function to execute the insert operation

Returns:

  • ConcurrencyTestResult with success/error/timeout counts and timing stats

Example:

result := testutil.RunConcurrentInserts(ctx, t, config,
    func(i int) *MyData {
        return &MyData{ID: i}
    },
    func(ctx context.Context, data *MyData) error {
        return service.Insert(ctx, data)
    },
)
assert.Equal(t, 0, result.TimeoutCount, "No deadlocks expected")

func RunConcurrentUpdates

func RunConcurrentUpdates[T any](
	ctx context.Context,
	t *testing.T,
	config ConcurrencyTestConfig,
	setupData func(i int) T,
	executeUpdate func(ctx context.Context, data T) error,
) ConcurrencyTestResult

RunConcurrentUpdates executes multiple update operations concurrently. See RunConcurrentInserts for detailed documentation.

type SyncParityTestConfig

type SyncParityTestConfig[CollItem any, SyncItem any] struct {
	// Setup performs any necessary setup (e.g., creating base entities) and returns a cleanup function if needed.
	Setup func(t *testing.T) (context.Context, func())

	// TriggerUpdate performs an action that should trigger a sync event (e.g., inserting or updating a record).
	// It should return the ID of the item being tested.
	TriggerUpdate func(ctx context.Context, t *testing.T)

	// GetCollection calls the Collection RPC and returns the list of items.
	GetCollection func(ctx context.Context, t *testing.T) []CollItem

	// StartSync starts the Sync stream and returns a channel of sync items.
	// The function should run the sync stream in a goroutine and push items to the channel.
	// It should return a cancel function to stop the stream.
	StartSync func(ctx context.Context, t *testing.T) (<-chan SyncItem, func())

	// Compare performs assertions to verify that the collection item matches the sync item.
	Compare func(t *testing.T, collItem CollItem, syncItem SyncItem)
}

SyncParityTestConfig defines the configuration for a sync parity test.

type ZeroValueSyncTestConfig

type ZeroValueSyncTestConfig[FieldType any, SyncItem any] struct {
	// Setup performs any necessary setup (e.g., creating base entities) and returns:
	// - context for the test
	// - cleanup function
	Setup func(t *testing.T) (context.Context, func())

	// StartSync starts the Sync stream and returns a channel of sync items.
	// The function should run the sync stream in a goroutine and push items to the channel.
	// It should return a cancel function to stop the stream.
	StartSync func(ctx context.Context, t *testing.T) (<-chan SyncItem, func())

	// TriggerUpdate performs an update with the given field value.
	// This should call the actual RPC or service method that triggers sync events.
	TriggerUpdate func(ctx context.Context, t *testing.T, value FieldType)

	// GetActualValue retrieves the actual persisted value from the database/collection.
	// This is used to verify the value was actually saved, not just synced.
	GetActualValue func(ctx context.Context, t *testing.T) FieldType

	// ExtractSyncedValue extracts the field value from a sync item.
	// Returns the value and whether it was present in the sync message.
	ExtractSyncedValue func(t *testing.T, syncItem SyncItem) (value FieldType, present bool)

	// CompareValues compares two values for equality.
	// If nil, uses require.Equal.
	CompareValues func(t *testing.T, expected, actual FieldType)
}

ZeroValueSyncTestConfig defines the configuration for testing zero-value sync handling. This catches bugs where `if value != 0` logic incorrectly excludes zero from sync events.

type ZeroValueTestCase

type ZeroValueTestCase[T any] struct {
	// Name is the human-readable test case name
	Name string

	// InitialValue is the initial (typically non-zero) value to set
	InitialValue T

	// ZeroValue is the zero value that should be correctly persisted
	ZeroValue T
}

ZeroValueTestCase defines a test case for zero-value field handling.

Jump to

Keyboard shortcuts

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