This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
package cached
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/go-webauthn/webauthn/metadata"
|
||||
)
|
||||
|
||||
func TestDoOpenOrCreate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
setup func(t *testing.T) string
|
||||
expectedCreated bool
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "ShouldCreateNewFile",
|
||||
setup: func(t *testing.T) string {
|
||||
t.Helper()
|
||||
|
||||
return filepath.Join(t.TempDir(), "new-file.json")
|
||||
},
|
||||
expectedCreated: true,
|
||||
},
|
||||
{
|
||||
name: "ShouldOpenExistingFile",
|
||||
setup: func(t *testing.T) string {
|
||||
t.Helper()
|
||||
|
||||
path := filepath.Join(t.TempDir(), "existing-file.json")
|
||||
|
||||
f, err := os.Create(path)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.Close())
|
||||
|
||||
return path
|
||||
},
|
||||
expectedCreated: false,
|
||||
},
|
||||
{
|
||||
name: "ShouldFailInvalidPath",
|
||||
setup: func(t *testing.T) string {
|
||||
t.Helper()
|
||||
|
||||
return filepath.Join(t.TempDir(), "nonexistent-dir", "subdir", "file.json")
|
||||
},
|
||||
err: "no such file or directory",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
path := tc.setup(t)
|
||||
|
||||
f, created, err := doOpenOrCreate(path)
|
||||
|
||||
if tc.err != "" {
|
||||
assert.Nil(t, f)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tc.err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, f)
|
||||
assert.Equal(t, tc.expectedCreated, created)
|
||||
|
||||
require.NoError(t, f.Close())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoTruncateCopyAndSeekStart(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
initialContent string
|
||||
copyContent string
|
||||
expectedContent string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "ShouldTruncateAndCopy",
|
||||
initialContent: "old content that should be replaced",
|
||||
copyContent: "new data",
|
||||
expectedContent: "new data",
|
||||
},
|
||||
{
|
||||
name: "ShouldHandleEmptyInitialContent",
|
||||
initialContent: "",
|
||||
copyContent: "fresh content",
|
||||
expectedContent: "fresh content",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "test-file.json")
|
||||
|
||||
f, err := os.Create(path)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = f.WriteString(tc.initialContent)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = f.Seek(0, io.SeekStart)
|
||||
require.NoError(t, err)
|
||||
|
||||
rc := io.NopCloser(bytes.NewReader([]byte(tc.copyContent)))
|
||||
|
||||
err = doTruncateCopyAndSeekStart(f, rc)
|
||||
|
||||
if tc.err != "" {
|
||||
assert.EqualError(t, err, tc.err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
|
||||
content, err := io.ReadAll(f)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedContent, string(content))
|
||||
}
|
||||
|
||||
require.NoError(t, f.Close())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultNew(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
have *metadata.Metadata
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "ShouldSucceedWithEmptyMetadata",
|
||||
have: &metadata.Metadata{
|
||||
Parsed: metadata.Parsed{
|
||||
NextUpdate: time.Now().Add(time.Hour * 24),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ShouldSucceedWithEntries",
|
||||
have: &metadata.Metadata{
|
||||
Parsed: metadata.Parsed{
|
||||
NextUpdate: time.Now().Add(time.Hour * 24),
|
||||
Entries: []metadata.Entry{
|
||||
{
|
||||
AaGUID: uuid.MustParse("2369d4d0-13ce-48cb-9f26-f7ed8c9a6068"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
provider, err := defaultNew(tc.have)
|
||||
|
||||
if tc.err == "" {
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, provider)
|
||||
} else {
|
||||
assert.EqualError(t, err, tc.err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderOutdated(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
have struct {
|
||||
update bool
|
||||
clockAt time.Time
|
||||
nextUpd time.Time
|
||||
}
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "ShouldBeOutdatedWhenPastNextUpdate",
|
||||
have: struct {
|
||||
update bool
|
||||
clockAt time.Time
|
||||
nextUpd time.Time
|
||||
}{
|
||||
update: true,
|
||||
clockAt: time.Date(2025, 6, 1, 0, 0, 0, 0, time.UTC),
|
||||
nextUpd: time.Date(2025, 5, 1, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "ShouldNotBeOutdatedWhenBeforeNextUpdate",
|
||||
have: struct {
|
||||
update bool
|
||||
clockAt time.Time
|
||||
nextUpd time.Time
|
||||
}{
|
||||
update: true,
|
||||
clockAt: time.Date(2025, 4, 1, 0, 0, 0, 0, time.UTC),
|
||||
nextUpd: time.Date(2025, 5, 1, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "ShouldNotBeOutdatedWhenUpdateDisabled",
|
||||
have: struct {
|
||||
update bool
|
||||
clockAt time.Time
|
||||
nextUpd time.Time
|
||||
}{
|
||||
update: false,
|
||||
clockAt: time.Date(2025, 6, 1, 0, 0, 0, 0, time.UTC),
|
||||
nextUpd: time.Date(2025, 5, 1, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
p := &Provider{
|
||||
update: tc.have.update,
|
||||
clock: &mockClock{now: tc.have.clockAt},
|
||||
}
|
||||
|
||||
mds := &metadata.Metadata{
|
||||
Parsed: metadata.Parsed{
|
||||
NextUpdate: tc.have.nextUpd,
|
||||
},
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.expected, p.outdated(mds))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type mockClock struct {
|
||||
now time.Time
|
||||
}
|
||||
|
||||
func (c *mockClock) Now() time.Time {
|
||||
return c.now
|
||||
}
|
||||
Reference in New Issue
Block a user