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:
581
backend/internal/server/freedesktop/handlers_test.go
Normal file
581
backend/internal/server/freedesktop/handlers_test.go
Normal file
@@ -0,0 +1,581 @@
|
||||
package freedesktop
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
mockdbus "github.com/AvengeMedia/DankMaterialShell/backend/internal/mocks/github.com/godbus/dbus/v5"
|
||||
"github.com/AvengeMedia/DankMaterialShell/backend/internal/server/models"
|
||||
"github.com/godbus/dbus/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type mockNetConn struct {
|
||||
net.Conn
|
||||
readBuf *bytes.Buffer
|
||||
writeBuf *bytes.Buffer
|
||||
closed bool
|
||||
}
|
||||
|
||||
func newMockNetConn() *mockNetConn {
|
||||
return &mockNetConn{
|
||||
readBuf: &bytes.Buffer{},
|
||||
writeBuf: &bytes.Buffer{},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mockNetConn) Read(b []byte) (n int, err error) {
|
||||
return m.readBuf.Read(b)
|
||||
}
|
||||
|
||||
func (m *mockNetConn) Write(b []byte) (n int, err error) {
|
||||
return m.writeBuf.Write(b)
|
||||
}
|
||||
|
||||
func (m *mockNetConn) Close() error {
|
||||
m.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func mockGetAllAccountsProperties() *dbus.Call {
|
||||
props := map[string]dbus.Variant{
|
||||
"IconFile": dbus.MakeVariant("/path/to/icon.png"),
|
||||
"RealName": dbus.MakeVariant("Test"),
|
||||
"UserName": dbus.MakeVariant("test"),
|
||||
"AccountType": dbus.MakeVariant(int32(0)),
|
||||
"HomeDirectory": dbus.MakeVariant("/home/test"),
|
||||
"Shell": dbus.MakeVariant("/bin/bash"),
|
||||
"Email": dbus.MakeVariant(""),
|
||||
"Language": dbus.MakeVariant(""),
|
||||
"Location": dbus.MakeVariant(""),
|
||||
"Locked": dbus.MakeVariant(false),
|
||||
"PasswordMode": dbus.MakeVariant(int32(1)),
|
||||
}
|
||||
return &dbus.Call{Err: nil, Body: []interface{}{props}}
|
||||
}
|
||||
|
||||
func TestRespondError_Freedesktop(t *testing.T) {
|
||||
conn := newMockNetConn()
|
||||
models.RespondError(conn, 123, "test error")
|
||||
|
||||
var resp models.Response[any]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Equal(t, "test error", resp.Error)
|
||||
assert.Nil(t, resp.Result)
|
||||
}
|
||||
|
||||
func TestRespond_Freedesktop(t *testing.T) {
|
||||
conn := newMockNetConn()
|
||||
result := SuccessResult{Success: true, Message: "test"}
|
||||
models.Respond(conn, 123, result)
|
||||
|
||||
var resp models.Response[SuccessResult]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Empty(t, resp.Error)
|
||||
require.NotNil(t, resp.Result)
|
||||
assert.True(t, resp.Result.Success)
|
||||
assert.Equal(t, "test", resp.Result.Message)
|
||||
}
|
||||
|
||||
func TestHandleGetState(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{
|
||||
Accounts: AccountsState{
|
||||
Available: true,
|
||||
UserName: "testuser",
|
||||
RealName: "Test User",
|
||||
UID: 1000,
|
||||
},
|
||||
Settings: SettingsState{
|
||||
Available: true,
|
||||
ColorScheme: 1,
|
||||
},
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{ID: 123, Method: "freedesktop.getState"}
|
||||
|
||||
handleGetState(conn, req, manager)
|
||||
|
||||
var resp models.Response[FreedeskState]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Empty(t, resp.Error)
|
||||
require.NotNil(t, resp.Result)
|
||||
assert.True(t, resp.Result.Accounts.Available)
|
||||
assert.Equal(t, "testuser", resp.Result.Accounts.UserName)
|
||||
assert.True(t, resp.Result.Settings.Available)
|
||||
assert.Equal(t, uint32(1), resp.Result.Settings.ColorScheme)
|
||||
}
|
||||
|
||||
func TestHandleSetIconFile(t *testing.T) {
|
||||
t.Run("missing path parameter", func(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.setIconFile",
|
||||
Params: map[string]interface{}{},
|
||||
}
|
||||
|
||||
handleSetIconFile(conn, req, manager)
|
||||
|
||||
var resp models.Response[any]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Contains(t, resp.Error, "missing or invalid 'path' parameter")
|
||||
})
|
||||
|
||||
t.Run("successful set icon file", func(t *testing.T) {
|
||||
mockAccountsObj := mockdbus.NewMockBusObject(t)
|
||||
mockCall := &dbus.Call{Err: nil}
|
||||
mockAccountsObj.EXPECT().Call("org.freedesktop.Accounts.User.SetIconFile", dbus.Flags(0), "/path/to/icon.png").Return(mockCall)
|
||||
mockAccountsObj.EXPECT().CallWithContext(mock.Anything, "org.freedesktop.DBus.Properties.GetAll", dbus.Flags(0), "org.freedesktop.Accounts.User").Return(mockGetAllAccountsProperties())
|
||||
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{
|
||||
Accounts: AccountsState{
|
||||
Available: true,
|
||||
},
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
accountsObj: mockAccountsObj,
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.setIconFile",
|
||||
Params: map[string]interface{}{
|
||||
"path": "/path/to/icon.png",
|
||||
},
|
||||
}
|
||||
|
||||
handleSetIconFile(conn, req, manager)
|
||||
|
||||
var resp models.Response[SuccessResult]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Empty(t, resp.Error)
|
||||
require.NotNil(t, resp.Result)
|
||||
assert.True(t, resp.Result.Success)
|
||||
assert.Equal(t, "icon file set", resp.Result.Message)
|
||||
})
|
||||
|
||||
t.Run("accounts not available", func(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{
|
||||
Accounts: AccountsState{
|
||||
Available: false,
|
||||
},
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.setIconFile",
|
||||
Params: map[string]interface{}{
|
||||
"path": "/path/to/icon.png",
|
||||
},
|
||||
}
|
||||
|
||||
handleSetIconFile(conn, req, manager)
|
||||
|
||||
var resp models.Response[SuccessResult]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Contains(t, resp.Error, "accounts service not available")
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandleSetRealName(t *testing.T) {
|
||||
t.Run("missing name parameter", func(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.setRealName",
|
||||
Params: map[string]interface{}{},
|
||||
}
|
||||
|
||||
handleSetRealName(conn, req, manager)
|
||||
|
||||
var resp models.Response[any]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Contains(t, resp.Error, "missing or invalid 'name' parameter")
|
||||
})
|
||||
|
||||
t.Run("successful set real name", func(t *testing.T) {
|
||||
mockAccountsObj := mockdbus.NewMockBusObject(t)
|
||||
mockCall := &dbus.Call{Err: nil}
|
||||
mockAccountsObj.EXPECT().Call("org.freedesktop.Accounts.User.SetRealName", dbus.Flags(0), "New Name").Return(mockCall)
|
||||
mockAccountsObj.EXPECT().CallWithContext(mock.Anything, "org.freedesktop.DBus.Properties.GetAll", dbus.Flags(0), "org.freedesktop.Accounts.User").Return(mockGetAllAccountsProperties())
|
||||
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{
|
||||
Accounts: AccountsState{
|
||||
Available: true,
|
||||
},
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
accountsObj: mockAccountsObj,
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.setRealName",
|
||||
Params: map[string]interface{}{
|
||||
"name": "New Name",
|
||||
},
|
||||
}
|
||||
|
||||
handleSetRealName(conn, req, manager)
|
||||
|
||||
var resp models.Response[SuccessResult]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Empty(t, resp.Error)
|
||||
require.NotNil(t, resp.Result)
|
||||
assert.True(t, resp.Result.Success)
|
||||
assert.Equal(t, "real name set", resp.Result.Message)
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandleSetEmail(t *testing.T) {
|
||||
t.Run("missing email parameter", func(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.setEmail",
|
||||
Params: map[string]interface{}{},
|
||||
}
|
||||
|
||||
handleSetEmail(conn, req, manager)
|
||||
|
||||
var resp models.Response[any]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Contains(t, resp.Error, "missing or invalid 'email' parameter")
|
||||
})
|
||||
|
||||
t.Run("successful set email", func(t *testing.T) {
|
||||
mockAccountsObj := mockdbus.NewMockBusObject(t)
|
||||
mockCall := &dbus.Call{Err: nil}
|
||||
mockAccountsObj.EXPECT().Call("org.freedesktop.Accounts.User.SetEmail", dbus.Flags(0), "test@example.com").Return(mockCall)
|
||||
mockAccountsObj.EXPECT().CallWithContext(mock.Anything, "org.freedesktop.DBus.Properties.GetAll", dbus.Flags(0), "org.freedesktop.Accounts.User").Return(mockGetAllAccountsProperties())
|
||||
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{
|
||||
Accounts: AccountsState{
|
||||
Available: true,
|
||||
},
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
accountsObj: mockAccountsObj,
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.setEmail",
|
||||
Params: map[string]interface{}{
|
||||
"email": "test@example.com",
|
||||
},
|
||||
}
|
||||
|
||||
handleSetEmail(conn, req, manager)
|
||||
|
||||
var resp models.Response[SuccessResult]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Empty(t, resp.Error)
|
||||
require.NotNil(t, resp.Result)
|
||||
assert.True(t, resp.Result.Success)
|
||||
assert.Equal(t, "email set", resp.Result.Message)
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandleSetLanguage(t *testing.T) {
|
||||
t.Run("missing language parameter", func(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.setLanguage",
|
||||
Params: map[string]interface{}{},
|
||||
}
|
||||
|
||||
handleSetLanguage(conn, req, manager)
|
||||
|
||||
var resp models.Response[any]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Contains(t, resp.Error, "missing or invalid 'language' parameter")
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandleSetLocation(t *testing.T) {
|
||||
t.Run("missing location parameter", func(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.setLocation",
|
||||
Params: map[string]interface{}{},
|
||||
}
|
||||
|
||||
handleSetLocation(conn, req, manager)
|
||||
|
||||
var resp models.Response[any]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Contains(t, resp.Error, "missing or invalid 'location' parameter")
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandleGetUserIconFile(t *testing.T) {
|
||||
t.Run("missing username parameter", func(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.getUserIconFile",
|
||||
Params: map[string]interface{}{},
|
||||
}
|
||||
|
||||
handleGetUserIconFile(conn, req, manager)
|
||||
|
||||
var resp models.Response[any]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Contains(t, resp.Error, "missing or invalid 'username' parameter")
|
||||
})
|
||||
|
||||
t.Run("accounts not available", func(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{
|
||||
Accounts: AccountsState{
|
||||
Available: false,
|
||||
},
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.accounts.getUserIconFile",
|
||||
Params: map[string]interface{}{
|
||||
"username": "testuser",
|
||||
},
|
||||
}
|
||||
|
||||
handleGetUserIconFile(conn, req, manager)
|
||||
|
||||
var resp models.Response[SuccessResult]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Contains(t, resp.Error, "accounts service not available")
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandleGetColorScheme(t *testing.T) {
|
||||
t.Run("settings not available", func(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{
|
||||
Settings: SettingsState{
|
||||
Available: false,
|
||||
},
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{ID: 123, Method: "freedesktop.settings.getColorScheme"}
|
||||
|
||||
handleGetColorScheme(conn, req, manager)
|
||||
|
||||
var resp models.Response[map[string]uint32]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Contains(t, resp.Error, "settings portal not available")
|
||||
})
|
||||
|
||||
t.Run("successful get color scheme", func(t *testing.T) {
|
||||
mockSettingsObj := mockdbus.NewMockBusObject(t)
|
||||
mockCall := &dbus.Call{
|
||||
Err: nil,
|
||||
Body: []interface{}{dbus.MakeVariant(uint32(1))},
|
||||
}
|
||||
mockSettingsObj.EXPECT().Call("org.freedesktop.portal.Settings.ReadOne", dbus.Flags(0), "org.freedesktop.appearance", "color-scheme").Return(mockCall)
|
||||
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{
|
||||
Settings: SettingsState{
|
||||
Available: true,
|
||||
},
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
settingsObj: mockSettingsObj,
|
||||
}
|
||||
|
||||
conn := newMockNetConn()
|
||||
req := Request{ID: 123, Method: "freedesktop.settings.getColorScheme"}
|
||||
|
||||
handleGetColorScheme(conn, req, manager)
|
||||
|
||||
var resp models.Response[map[string]uint32]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Empty(t, resp.Error)
|
||||
require.NotNil(t, resp.Result)
|
||||
assert.Equal(t, uint32(1), (*resp.Result)["colorScheme"])
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandleRequest(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &FreedeskState{
|
||||
Accounts: AccountsState{
|
||||
Available: true,
|
||||
UserName: "testuser",
|
||||
},
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
}
|
||||
|
||||
t.Run("unknown method", func(t *testing.T) {
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.unknown",
|
||||
}
|
||||
|
||||
HandleRequest(conn, req, manager)
|
||||
|
||||
var resp models.Response[any]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Contains(t, resp.Error, "unknown method")
|
||||
})
|
||||
|
||||
t.Run("valid method - getState", func(t *testing.T) {
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: "freedesktop.getState",
|
||||
}
|
||||
|
||||
HandleRequest(conn, req, manager)
|
||||
|
||||
var resp models.Response[FreedeskState]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
assert.Empty(t, resp.Error)
|
||||
})
|
||||
|
||||
t.Run("all method routes", func(t *testing.T) {
|
||||
tests := []string{
|
||||
"freedesktop.accounts.setIconFile",
|
||||
"freedesktop.accounts.setRealName",
|
||||
"freedesktop.accounts.setEmail",
|
||||
"freedesktop.accounts.setLanguage",
|
||||
"freedesktop.accounts.setLocation",
|
||||
"freedesktop.accounts.getUserIconFile",
|
||||
"freedesktop.settings.getColorScheme",
|
||||
}
|
||||
|
||||
for _, method := range tests {
|
||||
conn := newMockNetConn()
|
||||
req := Request{
|
||||
ID: 123,
|
||||
Method: method,
|
||||
Params: map[string]interface{}{},
|
||||
}
|
||||
|
||||
HandleRequest(conn, req, manager)
|
||||
|
||||
var resp models.Response[any]
|
||||
err := json.NewDecoder(conn.writeBuf).Decode(&resp)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 123, resp.ID)
|
||||
// Will have errors due to missing params or service unavailable
|
||||
// but the method routing should work
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user