mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-13 00:42:49 -05:00
switch hto monorepo structure
This commit is contained in:
313
backend/internal/server/loginctl/manager_test.go
Normal file
313
backend/internal/server/loginctl/manager_test.go
Normal file
@@ -0,0 +1,313 @@
|
||||
package loginctl
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestManager_GetState(t *testing.T) {
|
||||
state := &SessionState{
|
||||
SessionID: "1",
|
||||
Locked: false,
|
||||
Active: true,
|
||||
IdleHint: false,
|
||||
SessionType: "wayland",
|
||||
SessionClass: "user",
|
||||
UserName: "testuser",
|
||||
}
|
||||
|
||||
manager := &Manager{
|
||||
state: state,
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
result := manager.GetState()
|
||||
assert.Equal(t, "1", result.SessionID)
|
||||
assert.False(t, result.Locked)
|
||||
assert.True(t, result.Active)
|
||||
assert.Equal(t, "wayland", result.SessionType)
|
||||
assert.Equal(t, "testuser", result.UserName)
|
||||
}
|
||||
|
||||
func TestManager_Subscribe(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &SessionState{},
|
||||
subscribers: make(map[string]chan SessionState),
|
||||
subMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
ch := manager.Subscribe("test-client")
|
||||
assert.NotNil(t, ch)
|
||||
assert.Equal(t, 64, cap(ch))
|
||||
|
||||
manager.subMutex.RLock()
|
||||
_, exists := manager.subscribers["test-client"]
|
||||
manager.subMutex.RUnlock()
|
||||
assert.True(t, exists)
|
||||
}
|
||||
|
||||
func TestManager_Unsubscribe(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &SessionState{},
|
||||
subscribers: make(map[string]chan SessionState),
|
||||
subMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
ch := manager.Subscribe("test-client")
|
||||
|
||||
manager.Unsubscribe("test-client")
|
||||
|
||||
_, ok := <-ch
|
||||
assert.False(t, ok)
|
||||
|
||||
manager.subMutex.RLock()
|
||||
_, exists := manager.subscribers["test-client"]
|
||||
manager.subMutex.RUnlock()
|
||||
assert.False(t, exists)
|
||||
}
|
||||
|
||||
func TestManager_Unsubscribe_NonExistent(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &SessionState{},
|
||||
subscribers: make(map[string]chan SessionState),
|
||||
subMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
// Unsubscribe a non-existent client should not panic
|
||||
assert.NotPanics(t, func() {
|
||||
manager.Unsubscribe("non-existent")
|
||||
})
|
||||
}
|
||||
|
||||
func TestManager_NotifySubscribers(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &SessionState{
|
||||
SessionID: "1",
|
||||
Locked: false,
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
subscribers: make(map[string]chan SessionState),
|
||||
subMutex: sync.RWMutex{},
|
||||
stopChan: make(chan struct{}),
|
||||
dirty: make(chan struct{}, 1),
|
||||
}
|
||||
manager.notifierWg.Add(1)
|
||||
go manager.notifier()
|
||||
|
||||
ch := make(chan SessionState, 10)
|
||||
manager.subMutex.Lock()
|
||||
manager.subscribers["test-client"] = ch
|
||||
manager.subMutex.Unlock()
|
||||
|
||||
manager.notifySubscribers()
|
||||
|
||||
select {
|
||||
case state := <-ch:
|
||||
assert.Equal(t, "1", state.SessionID)
|
||||
assert.False(t, state.Locked)
|
||||
case <-time.After(200 * time.Millisecond):
|
||||
t.Fatal("did not receive state update")
|
||||
}
|
||||
|
||||
close(manager.stopChan)
|
||||
manager.notifierWg.Wait()
|
||||
}
|
||||
|
||||
func TestManager_NotifySubscribers_Debounce(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &SessionState{
|
||||
SessionID: "1",
|
||||
Locked: false,
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
subscribers: make(map[string]chan SessionState),
|
||||
subMutex: sync.RWMutex{},
|
||||
stopChan: make(chan struct{}),
|
||||
dirty: make(chan struct{}, 1),
|
||||
}
|
||||
manager.notifierWg.Add(1)
|
||||
go manager.notifier()
|
||||
|
||||
ch := make(chan SessionState, 10)
|
||||
manager.subMutex.Lock()
|
||||
manager.subscribers["test-client"] = ch
|
||||
manager.subMutex.Unlock()
|
||||
|
||||
manager.notifySubscribers()
|
||||
manager.notifySubscribers()
|
||||
manager.notifySubscribers()
|
||||
|
||||
receivedCount := 0
|
||||
timeout := time.After(200 * time.Millisecond)
|
||||
for {
|
||||
select {
|
||||
case <-ch:
|
||||
receivedCount++
|
||||
case <-timeout:
|
||||
assert.Equal(t, 1, receivedCount, "should receive exactly one debounced update")
|
||||
close(manager.stopChan)
|
||||
manager.notifierWg.Wait()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestManager_Close(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &SessionState{},
|
||||
stateMutex: sync.RWMutex{},
|
||||
subscribers: make(map[string]chan SessionState),
|
||||
subMutex: sync.RWMutex{},
|
||||
stopChan: make(chan struct{}),
|
||||
}
|
||||
|
||||
ch1 := make(chan SessionState, 1)
|
||||
ch2 := make(chan SessionState, 1)
|
||||
manager.subMutex.Lock()
|
||||
manager.subscribers["client1"] = ch1
|
||||
manager.subscribers["client2"] = ch2
|
||||
manager.subMutex.Unlock()
|
||||
|
||||
manager.Close()
|
||||
|
||||
select {
|
||||
case <-manager.stopChan:
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Fatal("stopChan not closed")
|
||||
}
|
||||
|
||||
_, ok1 := <-ch1
|
||||
_, ok2 := <-ch2
|
||||
assert.False(t, ok1, "ch1 should be closed")
|
||||
assert.False(t, ok2, "ch2 should be closed")
|
||||
|
||||
assert.Len(t, manager.subscribers, 0)
|
||||
}
|
||||
|
||||
func TestManager_GetState_ThreadSafe(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &SessionState{
|
||||
SessionID: "1",
|
||||
Locked: false,
|
||||
Active: true,
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
done := make(chan bool)
|
||||
for i := 0; i < 10; i++ {
|
||||
go func() {
|
||||
state := manager.GetState()
|
||||
assert.Equal(t, "1", state.SessionID)
|
||||
assert.True(t, state.Active)
|
||||
done <- true
|
||||
}()
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatal("timeout waiting for goroutines")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateChangedMeaningfully(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
old *SessionState
|
||||
new *SessionState
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "no change",
|
||||
old: &SessionState{Locked: false, Active: true, IdleHint: false},
|
||||
new: &SessionState{Locked: false, Active: true, IdleHint: false},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "locked changed",
|
||||
old: &SessionState{Locked: false, Active: true, IdleHint: false},
|
||||
new: &SessionState{Locked: true, Active: true, IdleHint: false},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "active changed",
|
||||
old: &SessionState{Locked: false, Active: true, IdleHint: false},
|
||||
new: &SessionState{Locked: false, Active: false, IdleHint: false},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "idle hint changed",
|
||||
old: &SessionState{Locked: false, Active: true, IdleHint: false},
|
||||
new: &SessionState{Locked: false, Active: true, IdleHint: true},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "locked hint changed",
|
||||
old: &SessionState{Locked: false, Active: true, LockedHint: false},
|
||||
new: &SessionState{Locked: false, Active: true, LockedHint: true},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "preparing for sleep changed",
|
||||
old: &SessionState{Locked: false, Active: true, PreparingForSleep: false},
|
||||
new: &SessionState{Locked: false, Active: true, PreparingForSleep: true},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "non-meaningful change (username)",
|
||||
old: &SessionState{Locked: false, Active: true, UserName: "user1"},
|
||||
new: &SessionState{Locked: false, Active: true, UserName: "user2"},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := stateChangedMeaningfully(tt.old, tt.new)
|
||||
assert.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestManager_SnapshotState(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &SessionState{
|
||||
SessionID: "1",
|
||||
Locked: false,
|
||||
Active: true,
|
||||
UserName: "testuser",
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
snapshot := manager.snapshotState()
|
||||
assert.Equal(t, "1", snapshot.SessionID)
|
||||
assert.False(t, snapshot.Locked)
|
||||
assert.True(t, snapshot.Active)
|
||||
assert.Equal(t, "testuser", snapshot.UserName)
|
||||
|
||||
snapshot.Locked = true
|
||||
assert.False(t, manager.state.Locked)
|
||||
}
|
||||
|
||||
func TestNewManager(t *testing.T) {
|
||||
t.Run("attempts to create manager", func(t *testing.T) {
|
||||
manager, err := NewManager()
|
||||
if err != nil {
|
||||
assert.Nil(t, manager)
|
||||
} else {
|
||||
assert.NotNil(t, manager)
|
||||
assert.NotNil(t, manager.state)
|
||||
assert.NotNil(t, manager.subscribers)
|
||||
assert.NotNil(t, manager.stopChan)
|
||||
|
||||
manager.Close()
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user