- Add TEST_RELIABILITY_PLAN.md documenting test strategy - Add devices_test.go with device handler tests - Add device_auth_test.go with device authentication middleware tests
203 lines
5.6 KiB
Go
203 lines
5.6 KiB
Go
package handlers
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestDeviceInfo_DeviceTypeSyncURLs(t *testing.T) {
|
|
baseURL := "http://localhost:8080"
|
|
|
|
tests := []struct {
|
|
name string
|
|
deviceType string
|
|
authToken string
|
|
expectedURLs map[string]string
|
|
expectedHasURLs bool
|
|
}{
|
|
{
|
|
name: "Kobo device",
|
|
deviceType: "kobo",
|
|
authToken: "dev_abc123",
|
|
expectedURLs: map[string]string{
|
|
"sync_url": "http://localhost:8080/api/sync/kobo/dev_abc123",
|
|
"markup": "http://localhost:8080/api/sync/kobo/dev_abc123/markup",
|
|
"bookmark": "http://localhost:8080/api/sync/kobo/dev_abc123/bookmark",
|
|
"init": "http://localhost:8080/api/sync/kobo/dev_abc123/v1/initialization",
|
|
},
|
|
expectedHasURLs: true,
|
|
},
|
|
{
|
|
name: "KOReader device",
|
|
deviceType: "koreader",
|
|
authToken: "dev_xyz789",
|
|
expectedURLs: map[string]string{
|
|
"progress": "http://localhost:8080/api/sync/koreader/progress",
|
|
"metadata": "http://localhost:8080/api/sync/koreader/metadata",
|
|
"bookmarks": "http://localhost:8080/api/sync/koreader/bookmarks",
|
|
},
|
|
expectedHasURLs: true,
|
|
},
|
|
{
|
|
name: "Unknown device type",
|
|
deviceType: "unknown",
|
|
authToken: "dev_test",
|
|
expectedURLs: map[string]string{},
|
|
expectedHasURLs: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Build sync URLs as done in RegenerateDeviceToken
|
|
syncURLs := map[string]string{}
|
|
|
|
switch tt.deviceType {
|
|
case "kobo":
|
|
syncURLs["sync_url"] = baseURL + "/api/sync/kobo/" + tt.authToken
|
|
syncURLs["markup"] = baseURL + "/api/sync/kobo/" + tt.authToken + "/markup"
|
|
syncURLs["bookmark"] = baseURL + "/api/sync/kobo/" + tt.authToken + "/bookmark"
|
|
syncURLs["init"] = baseURL + "/api/sync/kobo/" + tt.authToken + "/v1/initialization"
|
|
case "koreader":
|
|
syncURLs["progress"] = baseURL + "/api/sync/koreader/progress"
|
|
syncURLs["metadata"] = baseURL + "/api/sync/koreader/metadata"
|
|
syncURLs["bookmarks"] = baseURL + "/api/sync/koreader/bookmarks"
|
|
}
|
|
|
|
if tt.expectedHasURLs {
|
|
assert.Len(t, syncURLs, len(tt.expectedURLs))
|
|
for key, expectedURL := range tt.expectedURLs {
|
|
actualURL, ok := syncURLs[key]
|
|
assert.True(t, ok, "URL key %s should exist", key)
|
|
assert.Equal(t, expectedURL, actualURL)
|
|
}
|
|
} else {
|
|
assert.Empty(t, syncURLs)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenerateDeviceToken(t *testing.T) {
|
|
// Test that generateDeviceToken produces valid tokens
|
|
tokens := make(map[string]bool)
|
|
|
|
// Generate multiple tokens and verify they're unique
|
|
for i := 0; i < 100; i++ {
|
|
token, err := generateDeviceToken()
|
|
assert.NoError(t, err, "Should generate token without error")
|
|
assert.NotEmpty(t, token, "Token should not be empty")
|
|
|
|
// Verify token starts with "dev_"
|
|
assert.True(t, len(token) > 4, "Token should be longer than prefix")
|
|
assert.Contains(t, token, "dev_", "Token should start with dev_ prefix")
|
|
|
|
// Verify tokens are unique
|
|
assert.False(t, tokens[token], "Token should be unique")
|
|
tokens[token] = true
|
|
}
|
|
|
|
// Verify we got 100 unique tokens
|
|
assert.Len(t, tokens, 100, "All generated tokens should be unique")
|
|
}
|
|
|
|
func TestDeviceInfo_SyncEnabledValidation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
syncEnabled bool
|
|
syncEnabledValid bool
|
|
expectedFinalValue bool
|
|
}{
|
|
{
|
|
name: "Sync enabled and valid",
|
|
syncEnabled: true,
|
|
syncEnabledValid: true,
|
|
expectedFinalValue: true,
|
|
},
|
|
{
|
|
name: "Sync disabled but valid",
|
|
syncEnabled: false,
|
|
syncEnabledValid: true,
|
|
expectedFinalValue: false,
|
|
},
|
|
{
|
|
name: "Sync enabled but not valid",
|
|
syncEnabled: true,
|
|
syncEnabledValid: false,
|
|
expectedFinalValue: false,
|
|
},
|
|
{
|
|
name: "Sync disabled and not valid",
|
|
syncEnabled: false,
|
|
syncEnabledValid: false,
|
|
expectedFinalValue: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Simulate the logic in RegenerateDeviceToken
|
|
finalValue := tt.syncEnabled && tt.syncEnabledValid
|
|
assert.Equal(t, tt.expectedFinalValue, finalValue)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeviceInfo_IDParsing(t *testing.T) {
|
|
// Test UUID parsing logic from device ID
|
|
deviceID := uuid.New()
|
|
deviceIDBytes := [16]byte(deviceID)
|
|
|
|
// Verify we can convert back
|
|
parsedUUID := uuid.UUID(deviceIDBytes)
|
|
assert.Equal(t, deviceID, parsedUUID, "UUID should be preserved through byte array conversion")
|
|
|
|
// Test that we can get the string representation
|
|
deviceIDStr := deviceID.String()
|
|
assert.NotEmpty(t, deviceIDStr, "UUID string should not be empty")
|
|
|
|
// Test that parsing the string gives us the same UUID
|
|
parsedFromStr, err := uuid.Parse(deviceIDStr)
|
|
assert.NoError(t, err, "Should parse UUID string without error")
|
|
assert.Equal(t, deviceID, parsedFromStr, "Parsed UUID should match original")
|
|
}
|
|
|
|
func TestDeviceUpdateRequest_Validation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
syncFrequency int32
|
|
expectedValid bool
|
|
}{
|
|
{
|
|
name: "Valid sync frequency",
|
|
syncFrequency: 5,
|
|
expectedValid: true,
|
|
},
|
|
{
|
|
name: "Zero sync frequency",
|
|
syncFrequency: 0,
|
|
expectedValid: true,
|
|
},
|
|
{
|
|
name: "High sync frequency",
|
|
syncFrequency: 1440, // 1 day
|
|
expectedValid: true,
|
|
},
|
|
{
|
|
name: "Negative sync frequency",
|
|
syncFrequency: -1,
|
|
expectedValid: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Simulate validation logic
|
|
isValid := tt.syncFrequency >= 0
|
|
assert.Equal(t, tt.expectedValid, isValid)
|
|
})
|
|
}
|
|
}
|