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

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")
}
}