You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
83 lines
2.8 KiB
83 lines
2.8 KiB
package mock
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"tera-clone/services/tera-api/internal/domain"
|
|
"tera-clone/services/tera-api/internal/systemtime"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type loginTimeController struct {
|
|
now *time.Time
|
|
calls int
|
|
fail bool
|
|
}
|
|
|
|
func (c *loginTimeController) Sync(_ context.Context, r systemtime.Request) (systemtime.Result, error) {
|
|
c.calls++
|
|
if c.fail {
|
|
return systemtime.Result{}, errors.New("unavailable")
|
|
}
|
|
*c.now = r.BrowserTime
|
|
return systemtime.Result{AppliedTime: r.BrowserTime, Timezone: r.Timezone}, nil
|
|
}
|
|
func TestFirstAuthorizedLoginSyncsClockBeforeIssuingSession(t *testing.T) {
|
|
now := time.Unix(300, 0).UTC()
|
|
controller := &loginTimeController{now: &now}
|
|
s, err := NewStoreWithOptions(func() time.Time { return now }, StoreOptions{TimeController: controller})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer s.Close()
|
|
target := time.Date(2026, 9, 8, 3, 0, 0, 0, time.UTC)
|
|
request := domain.AuthLoginRequest{Username: "admin", Password: "wrong", BrowserTime: target}
|
|
if _, err := s.Login(context.Background(), request); err == nil || controller.calls != 0 {
|
|
t.Fatal("invalid credentials changed clock")
|
|
}
|
|
if _, err := s.Login(context.Background(), domain.AuthLoginRequest{Username: "port-operator", Password: "mock-port-operator-secret", BrowserTime: target}); err != nil || controller.calls != 0 {
|
|
t.Fatal("port operator changed clock")
|
|
}
|
|
request.Password = "mock-admin-secret"
|
|
session, err := s.Login(context.Background(), request)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if controller.calls != 1 || !now.Equal(target) || !session.ExpiresAt.Equal(target.Add(8*time.Hour)) {
|
|
t.Fatalf("clock/session mismatch: calls=%d expires=%v", controller.calls, session.ExpiresAt)
|
|
}
|
|
if _, err = s.ActorBySession(context.Background(), session.SessionToken); err != nil {
|
|
t.Fatalf("session invalid after clock jump: %v", err)
|
|
}
|
|
request.BrowserTime = target.Add(time.Hour)
|
|
if _, err = s.Login(context.Background(), request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if controller.calls != 1 {
|
|
t.Fatal("subsequent login changed clock again")
|
|
}
|
|
}
|
|
func TestAutomaticLoginTimeSyncFailureRetriesWithoutBlockingLogin(t *testing.T) {
|
|
now := fixedClock()
|
|
controller := &loginTimeController{now: &now, fail: true}
|
|
s, err := NewStoreWithOptions(func() time.Time { return now }, StoreOptions{TimeController: controller})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer s.Close()
|
|
request := domain.AuthLoginRequest{Username: "admin", Password: "mock-admin-secret", BrowserTime: now.Add(time.Hour)}
|
|
if _, err = s.Login(context.Background(), request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if s.browserTimeSynced {
|
|
t.Fatal("failed sync marked successful")
|
|
}
|
|
controller.fail = false
|
|
if _, err = s.Login(context.Background(), request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if controller.calls != 2 || !s.browserTimeSynced {
|
|
t.Fatal("failed sync not retried")
|
|
}
|
|
}
|
|
|