[agent/codex:gpt-5.4-mini] Update the code against the AX design principles in docs/RFC... #19
8 changed files with 77 additions and 77 deletions
|
|
@ -36,7 +36,7 @@ func TestCoverage_New_Bad_SchemaConflict(t *testing.T) {
|
|||
|
||||
_, err = New(databasePath)
|
||||
require.Error(t, err, "New should fail when an index named entries already exists")
|
||||
assert.Contains(t, err.Error(), "store.New: schema")
|
||||
assert.Contains(t, err.Error(), "store.New: ensure schema")
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ The public surface is intentionally small. Names are descriptive, comments show
|
|||
- `Close() error` stops the background purge goroutine and closes the database.
|
||||
- `Get(group, key string) (string, error)` returns a stored value or `NotFoundError`.
|
||||
- `Set(group, key, value string) error` stores a value and clears any existing TTL.
|
||||
- `SetWithTTL(group, key, value string, ttl time.Duration) error` stores a value that expires after the supplied duration.
|
||||
- `SetWithTTL(group, key, value string, timeToLive time.Duration) error` stores a value that expires after the supplied duration.
|
||||
- `Delete(group, key string) error` removes one key.
|
||||
- `DeleteGroup(group string) error` removes every key in a group.
|
||||
- `Count(group string) (int, error)` counts non-expired keys in one group.
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ if err != nil {
|
|||
// renderedTemplate: {"pool":"pool.lthn.io:3333","wallet":"iz..."}
|
||||
```
|
||||
|
||||
Template parse errors and execution errors are both returned as wrapped errors with context (e.g., `store.Render: parse: ...` and `store.Render: exec: ...`).
|
||||
Template parse errors and execution errors are both returned as wrapped errors with context (e.g., `store.Render: parse template: ...` and `store.Render: execute template: ...`).
|
||||
|
||||
Missing template variables do not return an error by default -- Go's `text/template` renders them as `<no value>`. Applications requiring strict variable presence should validate data beforehand.
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ Added optional time-to-live for keys.
|
|||
### Changes
|
||||
|
||||
- `expires_at INTEGER` nullable column added to the key-value schema.
|
||||
- `SetWithTTL(group, key, value string, ttl time.Duration)` stores the current time plus TTL as a Unix millisecond timestamp in `expires_at`.
|
||||
- `SetWithTTL(group, key, value string, timeToLive time.Duration)` stores the current time plus TTL as a Unix millisecond timestamp in `expires_at`.
|
||||
- `Get()` performs lazy deletion: if a key is found with an `expires_at` in the past, it is deleted and `NotFoundError` is returned.
|
||||
- `Count()`, `GetAll()`, and `Render()` include `(expires_at IS NULL OR expires_at > ?)` in all queries, excluding expired keys from results.
|
||||
- `PurgeExpired()` public method deletes all physically stored expired rows and returns the count removed.
|
||||
|
|
@ -186,11 +186,11 @@ Renamed the internal SQLite schema to use descriptive names that are easier for
|
|||
|
||||
`coverage_test.go` exercises defensive error paths that integration tests cannot reach through normal usage:
|
||||
|
||||
- Schema conflict: pre-existing SQLite index named `entries` causes `New()` to return `store.New: schema: ...`.
|
||||
- `GetAll` scan error: NULL key in a row (requires manually altering the schema to remove the NOT NULL constraint).
|
||||
- `GetAll` rows iteration error: physically corrupting database pages mid-file to trigger `rows.Err()` during multi-page scans.
|
||||
- `Render` scan error: same NULL-key technique.
|
||||
- `Render` rows iteration error: same corruption technique.
|
||||
- Schema conflict: pre-existing SQLite index named `entries` causes `New()` to return `store.New: ensure schema: ...`.
|
||||
- `GetAll` scan error: NULL key in a row (requires manually altering the schema to remove the NOT NULL constraint) to trigger `store.All: scan row: ...`.
|
||||
- `GetAll` rows iteration error: physically corrupting database pages mid-file to trigger `store.All: rows iteration: ...`.
|
||||
- `Render` scan error: same NULL-key technique, surfaced as `store.All: scan row: ...`.
|
||||
- `Render` rows iteration error: same corruption technique, surfaced as `store.All: rows iteration: ...`.
|
||||
|
||||
These tests exercise correct defensive code. They must continue to pass but are not indicative of real failure modes in production.
|
||||
|
||||
|
|
|
|||
6
scope.go
6
scope.go
|
|
@ -29,7 +29,7 @@ type ScopedStore struct {
|
|||
// Usage example: `scopedStore, err := store.NewScoped(storeInstance, "tenant-a"); if err != nil { return }`
|
||||
func NewScoped(storeInstance *Store, namespace string) (*ScopedStore, error) {
|
||||
if !validNamespace.MatchString(namespace) {
|
||||
return nil, core.E("store.NewScoped", core.Sprintf("namespace %q is invalid (must be non-empty, alphanumeric + hyphens)", namespace), nil)
|
||||
return nil, core.E("store.NewScoped", core.Sprintf("namespace %q is invalid; use names like %q or %q", namespace, "tenant-a", "tenant-42"), nil)
|
||||
}
|
||||
scopedStore := &ScopedStore{storeInstance: storeInstance, namespace: namespace}
|
||||
return scopedStore, nil
|
||||
|
|
@ -68,11 +68,11 @@ func (scopedStore *ScopedStore) Set(group, key, value string) error {
|
|||
}
|
||||
|
||||
// Usage example: `if err := scopedStore.SetWithTTL("sessions", "token", "abc123", time.Hour); err != nil { return }`
|
||||
func (scopedStore *ScopedStore) SetWithTTL(group, key, value string, ttl time.Duration) error {
|
||||
func (scopedStore *ScopedStore) SetWithTTL(group, key, value string, timeToLive time.Duration) error {
|
||||
if err := scopedStore.checkQuota("store.ScopedStore.SetWithTTL", group, key); err != nil {
|
||||
return err
|
||||
}
|
||||
return scopedStore.storeInstance.SetWithTTL(scopedStore.namespacedGroup(group), key, value, ttl)
|
||||
return scopedStore.storeInstance.SetWithTTL(scopedStore.namespacedGroup(group), key, value, timeToLive)
|
||||
}
|
||||
|
||||
// Usage example: `if err := scopedStore.Delete("config", "theme"); err != nil { return }`
|
||||
|
|
|
|||
|
|
@ -157,9 +157,9 @@ func TestScope_ScopedStore_Good_GetAll(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
assert.Equal(t, map[string]string{"x": "1", "y": "2"}, all)
|
||||
|
||||
allB, err := betaStore.GetAll("items")
|
||||
betaEntries, err := betaStore.GetAll("items")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, map[string]string{"z": "3"}, allB)
|
||||
assert.Equal(t, map[string]string{"z": "3"}, betaEntries)
|
||||
}
|
||||
|
||||
func TestScope_ScopedStore_Good_All(t *testing.T) {
|
||||
|
|
|
|||
64
store.go
64
store.go
|
|
@ -47,7 +47,7 @@ type Store struct {
|
|||
func New(databasePath string) (*Store, error) {
|
||||
sqliteDatabase, err := sql.Open("sqlite", databasePath)
|
||||
if err != nil {
|
||||
return nil, core.E("store.New", "open", err)
|
||||
return nil, core.E("store.New", "open database", err)
|
||||
}
|
||||
// Serialise all access through a single connection. SQLite only supports
|
||||
// one writer at a time; using a pool causes SQLITE_BUSY under contention
|
||||
|
|
@ -56,15 +56,15 @@ func New(databasePath string) (*Store, error) {
|
|||
sqliteDatabase.SetMaxOpenConns(1)
|
||||
if _, err := sqliteDatabase.Exec("PRAGMA journal_mode=WAL"); err != nil {
|
||||
sqliteDatabase.Close()
|
||||
return nil, core.E("store.New", "WAL", err)
|
||||
return nil, core.E("store.New", "set WAL journal mode", err)
|
||||
}
|
||||
if _, err := sqliteDatabase.Exec("PRAGMA busy_timeout=5000"); err != nil {
|
||||
sqliteDatabase.Close()
|
||||
return nil, core.E("store.New", "busy_timeout", err)
|
||||
return nil, core.E("store.New", "set busy timeout", err)
|
||||
}
|
||||
if err := ensureSchema(sqliteDatabase); err != nil {
|
||||
sqliteDatabase.Close()
|
||||
return nil, err
|
||||
return nil, core.E("store.New", "ensure schema", err)
|
||||
}
|
||||
|
||||
purgeContext, cancel := context.WithCancel(context.Background())
|
||||
|
|
@ -95,11 +95,11 @@ func (storeInstance *Store) Get(group, key string) (string, error) {
|
|||
return "", core.E("store.Get", core.Concat(group, "/", key), NotFoundError)
|
||||
}
|
||||
if err != nil {
|
||||
return "", core.E("store.Get", "query", err)
|
||||
return "", core.E("store.Get", "query row", err)
|
||||
}
|
||||
if expiresAt.Valid && expiresAt.Int64 <= time.Now().UnixMilli() {
|
||||
if _, err := storeInstance.database.Exec("DELETE FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ? AND "+entryKeyColumn+" = ?", group, key); err != nil {
|
||||
return "", core.E("store.Get", "lazy delete", err)
|
||||
return "", core.E("store.Get", "delete expired row", err)
|
||||
}
|
||||
return "", core.E("store.Get", core.Concat(group, "/", key), NotFoundError)
|
||||
}
|
||||
|
|
@ -114,22 +114,22 @@ func (storeInstance *Store) Set(group, key, value string) error {
|
|||
group, key, value,
|
||||
)
|
||||
if err != nil {
|
||||
return core.E("store.Set", "exec", err)
|
||||
return core.E("store.Set", "execute upsert", err)
|
||||
}
|
||||
storeInstance.notify(Event{Type: EventSet, Group: group, Key: key, Value: value, Timestamp: time.Now()})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Usage example: `if err := storeInstance.SetWithTTL("session", "token", "abc123", time.Minute); err != nil { return }`
|
||||
func (storeInstance *Store) SetWithTTL(group, key, value string, ttl time.Duration) error {
|
||||
expiresAt := time.Now().Add(ttl).UnixMilli()
|
||||
func (storeInstance *Store) SetWithTTL(group, key, value string, timeToLive time.Duration) error {
|
||||
expiresAt := time.Now().Add(timeToLive).UnixMilli()
|
||||
_, err := storeInstance.database.Exec(
|
||||
"INSERT INTO "+entriesTableName+" ("+entryGroupColumn+", "+entryKeyColumn+", "+entryValueColumn+", expires_at) VALUES (?, ?, ?, ?) "+
|
||||
"ON CONFLICT("+entryGroupColumn+", "+entryKeyColumn+") DO UPDATE SET "+entryValueColumn+" = excluded."+entryValueColumn+", expires_at = excluded.expires_at",
|
||||
group, key, value, expiresAt,
|
||||
)
|
||||
if err != nil {
|
||||
return core.E("store.SetWithTTL", "exec", err)
|
||||
return core.E("store.SetWithTTL", "execute upsert with expiry", err)
|
||||
}
|
||||
storeInstance.notify(Event{Type: EventSet, Group: group, Key: key, Value: value, Timestamp: time.Now()})
|
||||
return nil
|
||||
|
|
@ -139,7 +139,7 @@ func (storeInstance *Store) SetWithTTL(group, key, value string, ttl time.Durati
|
|||
func (storeInstance *Store) Delete(group, key string) error {
|
||||
_, err := storeInstance.database.Exec("DELETE FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ? AND "+entryKeyColumn+" = ?", group, key)
|
||||
if err != nil {
|
||||
return core.E("store.Delete", "exec", err)
|
||||
return core.E("store.Delete", "delete row", err)
|
||||
}
|
||||
storeInstance.notify(Event{Type: EventDelete, Group: group, Key: key, Timestamp: time.Now()})
|
||||
return nil
|
||||
|
|
@ -153,7 +153,7 @@ func (storeInstance *Store) Count(group string) (int, error) {
|
|||
group, time.Now().UnixMilli(),
|
||||
).Scan(&count)
|
||||
if err != nil {
|
||||
return 0, core.E("store.Count", "query", err)
|
||||
return 0, core.E("store.Count", "count rows", err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ func (storeInstance *Store) Count(group string) (int, error) {
|
|||
func (storeInstance *Store) DeleteGroup(group string) error {
|
||||
_, err := storeInstance.database.Exec("DELETE FROM "+entriesTableName+" WHERE "+entryGroupColumn+" = ?", group)
|
||||
if err != nil {
|
||||
return core.E("store.DeleteGroup", "exec", err)
|
||||
return core.E("store.DeleteGroup", "delete group", err)
|
||||
}
|
||||
storeInstance.notify(Event{Type: EventDeleteGroup, Group: group, Timestamp: time.Now()})
|
||||
return nil
|
||||
|
|
@ -181,7 +181,7 @@ func (storeInstance *Store) GetAll(group string) (map[string]string, error) {
|
|||
entriesByKey := make(map[string]string)
|
||||
for entry, err := range storeInstance.All(group) {
|
||||
if err != nil {
|
||||
return nil, core.E("store.GetAll", "iterate", err)
|
||||
return nil, core.E("store.GetAll", "iterate rows", err)
|
||||
}
|
||||
entriesByKey[entry.Key] = entry.Value
|
||||
}
|
||||
|
|
@ -196,7 +196,7 @@ func (storeInstance *Store) All(group string) iter.Seq2[KeyValue, error] {
|
|||
group, time.Now().UnixMilli(),
|
||||
)
|
||||
if err != nil {
|
||||
yield(KeyValue{}, core.E("store.All", "query", err))
|
||||
yield(KeyValue{}, core.E("store.All", "query rows", err))
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
|
@ -204,7 +204,7 @@ func (storeInstance *Store) All(group string) iter.Seq2[KeyValue, error] {
|
|||
for rows.Next() {
|
||||
var entry KeyValue
|
||||
if err := rows.Scan(&entry.Key, &entry.Value); err != nil {
|
||||
if !yield(KeyValue{}, core.E("store.All", "scan", err)) {
|
||||
if !yield(KeyValue{}, core.E("store.All", "scan row", err)) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
|
|
@ -214,7 +214,7 @@ func (storeInstance *Store) All(group string) iter.Seq2[KeyValue, error] {
|
|||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
yield(KeyValue{}, core.E("store.All", "rows", err))
|
||||
yield(KeyValue{}, core.E("store.All", "rows iteration", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -242,18 +242,18 @@ func (storeInstance *Store) Render(templateSource, group string) (string, error)
|
|||
templateData := make(map[string]string)
|
||||
for entry, err := range storeInstance.All(group) {
|
||||
if err != nil {
|
||||
return "", core.E("store.Render", "iterate", err)
|
||||
return "", core.E("store.Render", "iterate rows", err)
|
||||
}
|
||||
templateData[entry.Key] = entry.Value
|
||||
}
|
||||
|
||||
renderTemplate, err := template.New("render").Parse(templateSource)
|
||||
if err != nil {
|
||||
return "", core.E("store.Render", "parse", err)
|
||||
return "", core.E("store.Render", "parse template", err)
|
||||
}
|
||||
builder := core.NewBuilder()
|
||||
if err := renderTemplate.Execute(builder, templateData); err != nil {
|
||||
return "", core.E("store.Render", "exec", err)
|
||||
return "", core.E("store.Render", "execute template", err)
|
||||
}
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
|
@ -274,7 +274,7 @@ func (storeInstance *Store) CountAll(groupPrefix string) (int, error) {
|
|||
).Scan(&count)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, core.E("store.CountAll", "query", err)
|
||||
return 0, core.E("store.CountAll", "count rows", err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
|
@ -309,7 +309,7 @@ func (storeInstance *Store) GroupsSeq(groupPrefix string) iter.Seq2[string, erro
|
|||
)
|
||||
}
|
||||
if err != nil {
|
||||
yield("", core.E("store.GroupsSeq", "query", err))
|
||||
yield("", core.E("store.GroupsSeq", "query group names", err))
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
|
@ -317,7 +317,7 @@ func (storeInstance *Store) GroupsSeq(groupPrefix string) iter.Seq2[string, erro
|
|||
for rows.Next() {
|
||||
var groupName string
|
||||
if err := rows.Scan(&groupName); err != nil {
|
||||
if !yield("", core.E("store.GroupsSeq", "scan", err)) {
|
||||
if !yield("", core.E("store.GroupsSeq", "scan group name", err)) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
|
|
@ -327,7 +327,7 @@ func (storeInstance *Store) GroupsSeq(groupPrefix string) iter.Seq2[string, erro
|
|||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
yield("", core.E("store.GroupsSeq", "rows", err))
|
||||
yield("", core.E("store.GroupsSeq", "rows iteration", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -346,11 +346,11 @@ func (storeInstance *Store) PurgeExpired() (int64, error) {
|
|||
deleteResult, err := storeInstance.database.Exec("DELETE FROM "+entriesTableName+" WHERE expires_at IS NOT NULL AND expires_at <= ?",
|
||||
time.Now().UnixMilli())
|
||||
if err != nil {
|
||||
return 0, core.E("store.PurgeExpired", "exec", err)
|
||||
return 0, core.E("store.PurgeExpired", "delete expired rows", err)
|
||||
}
|
||||
removedRows, rowsAffectedErr := deleteResult.RowsAffected()
|
||||
if rowsAffectedErr != nil {
|
||||
return 0, core.E("store.PurgeExpired", "rows affected", rowsAffectedErr)
|
||||
return 0, core.E("store.PurgeExpired", "count deleted rows", rowsAffectedErr)
|
||||
}
|
||||
return removedRows, nil
|
||||
}
|
||||
|
|
@ -431,21 +431,21 @@ const createEntriesTableSQL = `CREATE TABLE IF NOT EXISTS entries (
|
|||
func ensureSchema(database *sql.DB) error {
|
||||
entriesTableExists, err := tableExists(database, entriesTableName)
|
||||
if err != nil {
|
||||
return core.E("store.New", "schema", err)
|
||||
return core.E("store.ensureSchema", "schema", err)
|
||||
}
|
||||
|
||||
legacyEntriesTableExists, err := tableExists(database, legacyKeyValueTableName)
|
||||
if err != nil {
|
||||
return core.E("store.New", "schema", err)
|
||||
return core.E("store.ensureSchema", "schema", err)
|
||||
}
|
||||
|
||||
if entriesTableExists {
|
||||
if err := ensureExpiryColumn(database); err != nil {
|
||||
return core.E("store.New", "migration", err)
|
||||
return core.E("store.ensureSchema", "migration", err)
|
||||
}
|
||||
if legacyEntriesTableExists {
|
||||
if err := migrateLegacyEntriesTable(database); err != nil {
|
||||
return core.E("store.New", "migration", err)
|
||||
return core.E("store.ensureSchema", "migration", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
@ -453,13 +453,13 @@ func ensureSchema(database *sql.DB) error {
|
|||
|
||||
if legacyEntriesTableExists {
|
||||
if err := migrateLegacyEntriesTable(database); err != nil {
|
||||
return core.E("store.New", "migration", err)
|
||||
return core.E("store.ensureSchema", "migration", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := database.Exec(createEntriesTableSQL); err != nil {
|
||||
return core.E("store.New", "schema", err)
|
||||
return core.E("store.ensureSchema", "schema", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ func TestStore_New_Good_Memory(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStore_New_Good_FileBacked(t *testing.T) {
|
||||
dbPath := testPath(t, "test.db")
|
||||
storeInstance, err := New(dbPath)
|
||||
databasePath := testPath(t, "test.db")
|
||||
storeInstance, err := New(databasePath)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, storeInstance)
|
||||
defer storeInstance.Close()
|
||||
|
|
@ -36,7 +36,7 @@ func TestStore_New_Good_FileBacked(t *testing.T) {
|
|||
require.NoError(t, storeInstance.Set("g", "k", "v"))
|
||||
require.NoError(t, storeInstance.Close())
|
||||
|
||||
reopenedStore, err := New(dbPath)
|
||||
reopenedStore, err := New(databasePath)
|
||||
require.NoError(t, err)
|
||||
defer reopenedStore.Close()
|
||||
|
||||
|
|
@ -55,10 +55,10 @@ func TestStore_New_Bad_InvalidPath(t *testing.T) {
|
|||
|
||||
func TestStore_New_Bad_CorruptFile(t *testing.T) {
|
||||
// A file that exists but is not a valid SQLite database should fail.
|
||||
dbPath := testPath(t, "corrupt.db")
|
||||
requireCoreOK(t, testFilesystem().Write(dbPath, "not a sqlite database"))
|
||||
databasePath := testPath(t, "corrupt.db")
|
||||
requireCoreOK(t, testFilesystem().Write(databasePath, "not a sqlite database"))
|
||||
|
||||
_, err := New(dbPath)
|
||||
_, err := New(databasePath)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "store.New")
|
||||
}
|
||||
|
|
@ -66,20 +66,20 @@ func TestStore_New_Bad_CorruptFile(t *testing.T) {
|
|||
func TestStore_New_Bad_ReadOnlyDir(t *testing.T) {
|
||||
// A path in a read-only directory should fail when SQLite tries to create the WAL file.
|
||||
dir := t.TempDir()
|
||||
dbPath := core.Path(dir, "readonly.db")
|
||||
databasePath := core.Path(dir, "readonly.db")
|
||||
|
||||
// Create a valid database first, then make the directory read-only.
|
||||
storeInstance, err := New(dbPath)
|
||||
storeInstance, err := New(databasePath)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, storeInstance.Close())
|
||||
|
||||
// Remove WAL/SHM files and make directory read-only.
|
||||
_ = testFilesystem().Delete(dbPath + "-wal")
|
||||
_ = testFilesystem().Delete(dbPath + "-shm")
|
||||
_ = testFilesystem().Delete(databasePath + "-wal")
|
||||
_ = testFilesystem().Delete(databasePath + "-shm")
|
||||
require.NoError(t, syscall.Chmod(dir, 0555))
|
||||
defer func() { _ = syscall.Chmod(dir, 0755) }() // restore for cleanup
|
||||
|
||||
_, err = New(dbPath)
|
||||
_, err = New(databasePath)
|
||||
// May or may not fail depending on OS/filesystem — just exercise the code path.
|
||||
if err != nil {
|
||||
assert.Contains(t, err.Error(), "store.New")
|
||||
|
|
@ -87,8 +87,8 @@ func TestStore_New_Bad_ReadOnlyDir(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStore_New_Good_WALMode(t *testing.T) {
|
||||
dbPath := testPath(t, "wal.db")
|
||||
storeInstance, err := New(dbPath)
|
||||
databasePath := testPath(t, "wal.db")
|
||||
storeInstance, err := New(databasePath)
|
||||
require.NoError(t, err)
|
||||
defer storeInstance.Close()
|
||||
|
||||
|
|
@ -789,8 +789,8 @@ func TestStore_GroupIsolation_Good(t *testing.T) {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
func TestStore_Concurrent_Good_ReadWrite(t *testing.T) {
|
||||
dbPath := testPath(t, "concurrent.db")
|
||||
storeInstance, err := New(dbPath)
|
||||
databasePath := testPath(t, "concurrent.db")
|
||||
storeInstance, err := New(databasePath)
|
||||
require.NoError(t, err)
|
||||
defer storeInstance.Close()
|
||||
|
||||
|
|
@ -955,8 +955,8 @@ func BenchmarkGetAll(benchmark *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkSet_FileBacked(benchmark *testing.B) {
|
||||
dbPath := testPath(benchmark, "bench.db")
|
||||
storeInstance, _ := New(dbPath)
|
||||
databasePath := testPath(benchmark, "bench.db")
|
||||
storeInstance, _ := New(databasePath)
|
||||
defer storeInstance.Close()
|
||||
|
||||
benchmark.ResetTimer()
|
||||
|
|
@ -1157,9 +1157,9 @@ func TestStore_PurgeExpired_Good_BackgroundPurge(t *testing.T) {
|
|||
storeInstance.cancelPurge()
|
||||
storeInstance.purgeWaitGroup.Wait()
|
||||
storeInstance.purgeInterval = 20 * time.Millisecond
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
purgeContext, cancel := context.WithCancel(context.Background())
|
||||
storeInstance.cancelPurge = cancel
|
||||
storeInstance.startBackgroundPurge(ctx)
|
||||
storeInstance.startBackgroundPurge(purgeContext)
|
||||
defer storeInstance.Close()
|
||||
|
||||
require.NoError(t, storeInstance.SetWithTTL("g", "ephemeral", "v", 1*time.Millisecond))
|
||||
|
|
@ -1181,16 +1181,16 @@ func TestStore_PurgeExpired_Good_BackgroundPurge(t *testing.T) {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
func TestStore_SchemaUpgrade_Good_ExistingDB(t *testing.T) {
|
||||
dbPath := testPath(t, "upgrade.db")
|
||||
databasePath := testPath(t, "upgrade.db")
|
||||
|
||||
// Open, write, close.
|
||||
initialStore, err := New(dbPath)
|
||||
initialStore, err := New(databasePath)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, initialStore.Set("g", "k", "v"))
|
||||
require.NoError(t, initialStore.Close())
|
||||
|
||||
// Reopen — the ALTER TABLE ADD COLUMN should be a no-op.
|
||||
reopenedStore, err := New(dbPath)
|
||||
reopenedStore, err := New(databasePath)
|
||||
require.NoError(t, err)
|
||||
defer reopenedStore.Close()
|
||||
|
||||
|
|
@ -1206,8 +1206,8 @@ func TestStore_SchemaUpgrade_Good_ExistingDB(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStore_SchemaUpgrade_Good_EntriesWithoutExpiryColumn(t *testing.T) {
|
||||
dbPath := testPath(t, "entries-no-expiry.db")
|
||||
database, err := sql.Open("sqlite", dbPath)
|
||||
databasePath := testPath(t, "entries-no-expiry.db")
|
||||
database, err := sql.Open("sqlite", databasePath)
|
||||
require.NoError(t, err)
|
||||
database.SetMaxOpenConns(1)
|
||||
_, err = database.Exec("PRAGMA journal_mode=WAL")
|
||||
|
|
@ -1223,7 +1223,7 @@ func TestStore_SchemaUpgrade_Good_EntriesWithoutExpiryColumn(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NoError(t, database.Close())
|
||||
|
||||
storeInstance, err := New(dbPath)
|
||||
storeInstance, err := New(databasePath)
|
||||
require.NoError(t, err)
|
||||
defer storeInstance.Close()
|
||||
|
||||
|
|
@ -1238,8 +1238,8 @@ func TestStore_SchemaUpgrade_Good_EntriesWithoutExpiryColumn(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStore_SchemaUpgrade_Good_LegacyAndCurrentTables(t *testing.T) {
|
||||
dbPath := testPath(t, "entries-and-legacy.db")
|
||||
database, err := sql.Open("sqlite", dbPath)
|
||||
databasePath := testPath(t, "entries-and-legacy.db")
|
||||
database, err := sql.Open("sqlite", databasePath)
|
||||
require.NoError(t, err)
|
||||
database.SetMaxOpenConns(1)
|
||||
_, err = database.Exec("PRAGMA journal_mode=WAL")
|
||||
|
|
@ -1265,7 +1265,7 @@ func TestStore_SchemaUpgrade_Good_LegacyAndCurrentTables(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.NoError(t, database.Close())
|
||||
|
||||
storeInstance, err := New(dbPath)
|
||||
storeInstance, err := New(databasePath)
|
||||
require.NoError(t, err)
|
||||
defer storeInstance.Close()
|
||||
|
||||
|
|
@ -1281,8 +1281,8 @@ func TestStore_SchemaUpgrade_Good_LegacyAndCurrentTables(t *testing.T) {
|
|||
func TestStore_SchemaUpgrade_Good_PreTTLDatabase(t *testing.T) {
|
||||
// Simulate a database created before the AX schema rename and TTL support.
|
||||
// The legacy key-value table has no expires_at column yet.
|
||||
dbPath := testPath(t, "pre-ttl.db")
|
||||
database, err := sql.Open("sqlite", dbPath)
|
||||
databasePath := testPath(t, "pre-ttl.db")
|
||||
database, err := sql.Open("sqlite", databasePath)
|
||||
require.NoError(t, err)
|
||||
database.SetMaxOpenConns(1)
|
||||
_, err = database.Exec("PRAGMA journal_mode=WAL")
|
||||
|
|
@ -1299,7 +1299,7 @@ func TestStore_SchemaUpgrade_Good_PreTTLDatabase(t *testing.T) {
|
|||
require.NoError(t, database.Close())
|
||||
|
||||
// Open with New — should migrate the legacy table into the descriptive schema.
|
||||
storeInstance, err := New(dbPath)
|
||||
storeInstance, err := New(databasePath)
|
||||
require.NoError(t, err)
|
||||
defer storeInstance.Close()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue