- Priority 1: Test NewSendEmailTask + NewSendPushTask (5 tests) - Priority 2: Test customHTTPErrorHandler — all 15+ branches (21 tests) - Priority 3: Extract Enqueuer interface + payload builders in worker pkg (5 tests) - Priority 4: Extract ClassifyFile/ComputeRelPath in migrate-encrypt (6 tests) - Priority 5: Define Handler interfaces, refactor to accept them, mock-based tests (14 tests) - Fix .gitignore: /worker instead of worker to stop ignoring internal/worker/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
223 lines
5.8 KiB
Go
223 lines
5.8 KiB
Go
package middleware
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestTimezoneMiddleware_IANATimezone(t *testing.T) {
|
|
mw := TimezoneMiddleware()
|
|
e := echo.New()
|
|
handler := mw(func(c echo.Context) error {
|
|
loc := GetUserTimezone(c)
|
|
return c.String(http.StatusOK, loc.String())
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/test/", nil)
|
|
req.Header.Set(TimezoneHeader, "America/New_York")
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
err := handler(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "America/New_York", rec.Body.String())
|
|
}
|
|
|
|
func TestTimezoneMiddleware_UTCOffset(t *testing.T) {
|
|
mw := TimezoneMiddleware()
|
|
e := echo.New()
|
|
handler := mw(func(c echo.Context) error {
|
|
loc := GetUserTimezone(c)
|
|
// Just verify it's not UTC (if offset is non-zero)
|
|
return c.String(http.StatusOK, loc.String())
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/test/", nil)
|
|
req.Header.Set(TimezoneHeader, "-05:00")
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
err := handler(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "-05:00", rec.Body.String())
|
|
}
|
|
|
|
func TestTimezoneMiddleware_NoHeader_DefaultsToUTC(t *testing.T) {
|
|
mw := TimezoneMiddleware()
|
|
e := echo.New()
|
|
handler := mw(func(c echo.Context) error {
|
|
loc := GetUserTimezone(c)
|
|
return c.String(http.StatusOK, loc.String())
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/test/", nil)
|
|
// No X-Timezone header
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
err := handler(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "UTC", rec.Body.String())
|
|
}
|
|
|
|
func TestTimezoneMiddleware_InvalidTimezone_DefaultsToUTC(t *testing.T) {
|
|
mw := TimezoneMiddleware()
|
|
e := echo.New()
|
|
handler := mw(func(c echo.Context) error {
|
|
loc := GetUserTimezone(c)
|
|
return c.String(http.StatusOK, loc.String())
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/test/", nil)
|
|
req.Header.Set(TimezoneHeader, "Invalid/Timezone")
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
err := handler(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "UTC", rec.Body.String())
|
|
}
|
|
|
|
func TestTimezoneMiddleware_SetsUserNow(t *testing.T) {
|
|
mw := TimezoneMiddleware()
|
|
e := echo.New()
|
|
|
|
var capturedNow time.Time
|
|
handler := mw(func(c echo.Context) error {
|
|
capturedNow = GetUserNow(c)
|
|
return c.String(http.StatusOK, "ok")
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/test/", nil)
|
|
req.Header.Set(TimezoneHeader, "America/Chicago")
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
err := handler(c)
|
|
require.NoError(t, err)
|
|
|
|
// The "now" should be the start of the day in the user's timezone
|
|
assert.Equal(t, 0, capturedNow.Hour())
|
|
assert.Equal(t, 0, capturedNow.Minute())
|
|
assert.Equal(t, 0, capturedNow.Second())
|
|
}
|
|
|
|
func TestTimezoneMiddleware_SetsTimezoneName(t *testing.T) {
|
|
mw := TimezoneMiddleware()
|
|
e := echo.New()
|
|
|
|
handler := mw(func(c echo.Context) error {
|
|
name := GetTimezoneName(c)
|
|
return c.String(http.StatusOK, name)
|
|
})
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/test/", nil)
|
|
req.Header.Set(TimezoneHeader, "Europe/London")
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
err := handler(c)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Europe/London", rec.Body.String())
|
|
}
|
|
|
|
func TestGetUserTimezone_NotSet_ReturnsUTC(t *testing.T) {
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
// No timezone set in context
|
|
loc := GetUserTimezone(c)
|
|
assert.Equal(t, time.UTC, loc)
|
|
}
|
|
|
|
func TestGetUserTimezone_WrongType_ReturnsUTC(t *testing.T) {
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
c.Set(TimezoneKey, "not-a-location")
|
|
loc := GetUserTimezone(c)
|
|
assert.Equal(t, time.UTC, loc)
|
|
}
|
|
|
|
func TestGetUserNow_NotSet_ReturnsUTCNow(t *testing.T) {
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
before := time.Now().UTC()
|
|
now := GetUserNow(c)
|
|
after := time.Now().UTC()
|
|
|
|
assert.True(t, !now.Before(before.Add(-time.Second)), "now should be roughly after before")
|
|
assert.True(t, !now.After(after.Add(time.Second)), "now should be roughly before after")
|
|
}
|
|
|
|
func TestGetUserNow_WrongType_ReturnsUTCNow(t *testing.T) {
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
c.Set(UserNowKey, "not-a-time")
|
|
now := GetUserNow(c)
|
|
assert.NotNil(t, now)
|
|
}
|
|
|
|
func TestIsTimezoneChanged_NoChange_ReturnsFalse(t *testing.T) {
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
c.Set(TimezoneChangedKey, false)
|
|
assert.False(t, IsTimezoneChanged(c))
|
|
}
|
|
|
|
func TestIsTimezoneChanged_Changed_ReturnsTrue(t *testing.T) {
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
c.Set(TimezoneChangedKey, true)
|
|
assert.True(t, IsTimezoneChanged(c))
|
|
}
|
|
|
|
func TestIsTimezoneChanged_NotSet_ReturnsFalse(t *testing.T) {
|
|
e := echo.New()
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
rec := httptest.NewRecorder()
|
|
c := e.NewContext(req, rec)
|
|
|
|
// Not set at all
|
|
assert.False(t, IsTimezoneChanged(c))
|
|
}
|
|
|
|
func TestParseTimezone_UTCOffsetWithoutColon(t *testing.T) {
|
|
loc := parseTimezone("-0800")
|
|
assert.NotEqual(t, time.UTC, loc)
|
|
assert.Equal(t, "-0800", loc.String())
|
|
}
|
|
|
|
func TestParseTimezone_PositiveOffset(t *testing.T) {
|
|
loc := parseTimezone("+05:30")
|
|
assert.NotEqual(t, time.UTC, loc)
|
|
assert.Equal(t, "+05:30", loc.String())
|
|
}
|
|
|
|
func TestParseTimezone_UTC(t *testing.T) {
|
|
loc := parseTimezone("UTC")
|
|
assert.Equal(t, time.UTC, loc)
|
|
}
|