Documentation
¶
Index ¶
- Variables
- func Assert[c comparable](t *testing.T, expected, got c)
- func AssertFatal[c comparable](t *testing.T, expected, got c)
- func AssertNot[c comparable](t *testing.T, not, got c)
- func AssertNotFatal[c comparable](t *testing.T, not, got c)
- func VerifySyncParity[CollItem any, SyncItem any](t *testing.T, cfg SyncParityTestConfig[CollItem, SyncItem])
- func VerifyZeroValueSync[FieldType any, SyncItem any](t *testing.T, cfg ZeroValueSyncTestConfig[FieldType, SyncItem], ...)
- func VerifyZeroValueSyncMultiple[FieldType any, SyncItem any](t *testing.T, ...)
- type BaseDBQueries
- type BaseTestServices
- type ConcurrencyTestConfig
- type ConcurrencyTestResult
- func RunConcurrentDeletes[T any](ctx context.Context, t *testing.T, config ConcurrencyTestConfig, ...) ConcurrencyTestResult
- func RunConcurrentInserts[T any](ctx context.Context, t *testing.T, config ConcurrencyTestConfig, ...) ConcurrencyTestResult
- func RunConcurrentUpdates[T any](ctx context.Context, t *testing.T, config ConcurrencyTestConfig, ...) ConcurrencyTestResult
- type SyncParityTestConfig
- type ZeroValueSyncTestConfig
- type ZeroValueTestCase
Constants ¶
This section is empty.
Variables ¶
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
}
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.