Cross-Backend Acceptance Test Framework
Overview
We've built a comprehensive table-driven, cross-backend acceptance test framework that validates interface compliance across all backend implementations using property-based testing with random data.
Test Results
✅ All Tests Passing
Test Run Summary:
- Test Cases: 10 comprehensive scenarios
- Backends Tested: 3 (Redis, MemStore, PostgreSQL)
- Total Test Runs: 30 (10 tests × 3 backends)
- Pass Rate: 100%
- Duration: ~0.53s
Test Matrix
| Test Case | Redis | MemStore | PostgreSQL |
|---|---|---|---|
| Set_Get_Random_Data | ✅ PASS | ✅ PASS | ✅ PASS |
| Set_Get_Binary_Random_Data | ✅ PASS | ✅ PASS | ✅ PASS |
| Multiple_Random_Keys | ✅ PASS | ✅ PASS | ✅ PASS |
| Overwrite_With_Random_Data | ✅ PASS | ✅ PASS | ✅ PASS |
| Delete_Random_Keys | ✅ PASS | ✅ PASS | ✅ PASS |
| Exists_Random_Keys | ✅ PASS | ✅ PASS | ✅ PASS |
| Large_Random_Values | ✅ PASS | ✅ PASS | ✅ PASS |
| Empty_And_Null_Values | ✅ PASS | ✅ PASS | ✅ PASS |
| Special_Characters_In_Keys | ✅ PASS | ✅ PASS | ✅ PASS |
| Rapid_Sequential_Operations | ✅ PASS | ✅ PASS | ✅ PASS |
Test Framework Features
1. Table-Driven Testing
type TestCase struct {
Name string
Setup func(t *testing.T, driver KeyValueBasicDriver)
Run func(t *testing.T, driver KeyValueBasicDriver)
Verify func(t *testing.T, driver KeyValueBasicDriver)
Cleanup func(t *testing.T, driver KeyValueBasicDriver)
SkipBackend map[string]bool
}
Tests are defined once and automatically run against all backends.
2. Property-Based Testing with Random Data
type RandomDataGenerator struct{}
// Methods:
- RandomString(length int) string
- RandomKey(testName string) string
- RandomBytes(length int) []byte
- RandomHex(length int) string
- RandomInt(min, max int) int
Every test run uses completely random data:
- No hardcoded test values
- Different data every execution
- Discovers edge cases through randomization
- Validates real-world data patterns
3. Backend Isolation
Each backend runs in its own isolated testcontainer:
- Redis:
redis:7-alpine - PostgreSQL:
postgres:16-alpine - MemStore: In-memory (no container needed)
Containers are:
- Started fresh for each test suite
- Shared across tests within a suite (for performance)
- Automatically cleaned up after tests complete
- Completely isolated from each other
4. Interface Compliance Verification
All backends must implement KeyValueBasicInterface:
type KeyValueBasicInterface interface {
Set(key string, value []byte, ttlSeconds int64) error
Get(key string) ([]byte, bool, error)
Delete(key string) error
Exists(key string) (bool, error)
}
Tests verify that data written through one backend can be read back correctly, ensuring true interface compliance.
Test Scenarios
1. Set_Get_Random_Data
- Generates random 100-character string
- Writes to random key
- Reads back and verifies match
- Validates: Basic write-read cycle
2. Set_Get_Binary_Random_Data
- Generates 256 bytes of random binary data
- Writes to random key
- Reads back and verifies byte-perfect match
- Validates: Binary data handling
3. Multiple_Random_Keys
- Creates 10-50 random keys (randomized count)
- Each key gets random value (10-200 bytes)
- Writes all keys
- Reads all keys back and verifies
- Validates: Bulk operations, no data loss
4. Overwrite_With_Random_Data
- Writes initial random value
- Overwrites with different random value
- Verifies only latest value is retrieved
- Validates: Update semantics
5. Delete_Random_Keys
- Creates 5-15 random keys
- Deletes random subset
- Verifies deleted keys are gone
- Verifies non-deleted keys remain
- Validates: Deletion correctness
6. Exists_Random_Keys
- Creates one key
- Checks existence (should return true)
- Checks non-existent random key (should return false)
- Validates: Existence checks