Files
Dominik SchulzandAdriano Caloiaro 100194de58 Warn when keyring is unavailable (#3429)
* [UX] warn when system keyring is unavailable

Emit a one-time warning when age.usekeychain is enabled but no OS keyring
provider is available, so users understand why passphrase caching won't
persist across sessions. Also warn when writing a passphrase to the OS
keyring fails at runtime.

The cacher.Set and askPass.Passphrase signatures now accept a context.Context
to support the warning output. effectivePwCallback is updated accordingly.

Co-authored-by: Adriano Caloiaro <code@adriano.fyi>
Closes #3357

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>

* fix: address review feedback for PR #3357

- Fix osKeyring.Get to track the actual key in knownKeys instead of
  the package-level constant "age" (o.knownKeys[key] not o.knownKeys[name])
- Replace %%w with %%v in debug.Log calls where error wrapping is not
  applicable (debug.Log uses fmt.Fprintf internally)

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>

* fix: Fix whitespace error

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>

---------

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
Co-authored-by: Adriano Caloiaro <code@adriano.fyi>
2026-05-16 21:12:29 +02:00

88 lines
1.5 KiB
Go

package cache
import (
"strconv"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func nowFunc(ns int) func() time.Time {
return func() time.Time {
return time.Date(2000, 1, 1, 1, 1, 1, ns, time.UTC)
}
}
func TestTTL(t *testing.T) {
t.Parallel()
c := &InMemTTL[string, string]{
ttl: 4,
maxTTL: 5,
}
c.now = nowFunc(0)
val, found := c.Get("foo")
assert.Empty(t, val)
assert.False(t, found)
c.Set(t.Context(), "foo", "bar")
val, found = c.Get("foo")
assert.Equal(t, "bar", val)
assert.True(t, found)
c.now = nowFunc(4)
val, found = c.Get("foo")
assert.Equal(t, "bar", val)
assert.True(t, found)
c.now = nowFunc(6)
val, found = c.Get("foo")
assert.Empty(t, val)
assert.False(t, found)
c.Set(t.Context(), "bar", "baz")
val, found = c.Get("bar")
assert.Equal(t, "baz", val)
assert.True(t, found)
c.Remove("bar")
val, found = c.Get("bar")
assert.Empty(t, val)
assert.False(t, found)
c.Set(t.Context(), "foo", "bar")
c.Set(t.Context(), "bar", "baz")
val, found = c.Get("bar")
assert.Equal(t, "baz", val)
assert.True(t, found)
c.Purge()
val, found = c.Get("bar")
assert.Empty(t, val)
assert.False(t, found)
}
func TestPar(t *testing.T) {
t.Parallel()
c := NewInMemTTL[int, int](time.Minute, time.Minute)
c.now = nowFunc(0)
for i := range 32 {
for range 32 {
t.Run("set"+strconv.Itoa(i), func(t *testing.T) {
t.Parallel()
c.Set(t.Context(), i, i)
iv, found := c.Get(i)
assert.True(t, found)
assert.Equal(t, i, iv)
})
}
}
}