main 6af0a61

configure_system_handler_test.go RawHistoryFolder

1package handlers
2
3import (
4	"context"
5	"testing"
6
7	"github.com/bnema/archup/internal/application/commands"
8	"github.com/bnema/archup/internal/domain/ports/mocks"
9	"go.uber.org/mock/gomock"
10)
11
12func TestXkbLayoutFromKeymap(t *testing.T) {
13	tests := []struct {
14		keymap   string
15		expected string
16	}{
17		{"us", "us"},
18		{"fr", "fr"},
19		{"de", "de"},
20		{"de-nodeadkeys", "de"},
21		{"fr-latin9", "fr"},
22		{"", ""},
23	}
24	for _, tt := range tests {
25		got := xkbLayoutFromKeymap(tt.keymap)
26		if got != tt.expected {
27			t.Errorf("xkbLayoutFromKeymap(%q) = %q, want %q", tt.keymap, got, tt.expected)
28		}
29	}
30}
31
32func TestConfigureSystemHandler_Handle_FrenchKeymap(t *testing.T) {
33	ctrl := gomock.NewController(t)
34	defer ctrl.Finish()
35
36	mockFS := mocks.NewMockFileSystem(ctrl)
37	mockChrExec := mocks.NewMockChrootExecutor(ctrl)
38	mockLogger := mocks.NewMockLogger(ctrl)
39
40	mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes()
41	mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes()
42	mockLogger.EXPECT().LogPath().Return("/var/log/archup-install.log").AnyTimes()
43	mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
44	mockChrExec.EXPECT().ExecuteInChrootWithStdin(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
45	mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
46	mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
47
48	// Expect 00-keyboard.conf to be written with "fr" layout
49	x11ConfPath := "/mnt/etc/X11/xorg.conf.d/00-keyboard.conf"
50	mockFS.EXPECT().WriteFile(gomock.Eq(x11ConfPath), gomock.Any(), gomock.Any()).DoAndReturn(
51		func(path string, content []byte, perm interface{}) error {
52			if !containsString(string(content), `Option "XkbLayout" "fr"`) {
53				t.Errorf("expected XkbLayout fr in 00-keyboard.conf, got: %s", string(content))
54			}
55			return nil
56		},
57	)
58	// All other WriteFile calls
59	mockFS.EXPECT().WriteFile(gomock.Not(gomock.Eq(x11ConfPath)), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
60
61	handler := NewConfigureSystemHandler(mockFS, mockChrExec, mockLogger)
62
63	cmd := commands.ConfigureSystemCommand{
64		MountPoint:   "/mnt",
65		Hostname:     "myarch",
66		Timezone:     "Europe/Paris",
67		Locale:       "fr_FR.UTF-8",
68		Keymap:       "fr",
69		Username:     "testuser",
70		UserShell:    "/bin/bash",
71		UserPassword: "testpass123",
72		RootPassword: "rootpass456",
73	}
74
75	result, err := handler.Handle(context.Background(), cmd)
76	if err != nil {
77		t.Fatalf("expected no error, got %v", err)
78	}
79	if !result.Success {
80		t.Error("expected success")
81	}
82}
83
84func containsString(s, substr string) bool {
85	return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsSubstring(s, substr))
86}
87
88func containsSubstring(s, substr string) bool {
89	for i := 0; i <= len(s)-len(substr); i++ {
90		if s[i:i+len(substr)] == substr {
91			return true
92		}
93	}
94	return false
95}
96
97func TestConfigureSystemHandler_Handle_Success(t *testing.T) {
98	ctrl := gomock.NewController(t)
99	defer ctrl.Finish()
100
101	mockFS := mocks.NewMockFileSystem(ctrl)
102	mockChrExec := mocks.NewMockChrootExecutor(ctrl)
103	mockLogger := mocks.NewMockLogger(ctrl)
104
105	mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes()
106	mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes()
107	mockLogger.EXPECT().LogPath().Return("/var/log/archup-install.log").AnyTimes()
108	mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
109	mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
110	mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
111	mockChrExec.EXPECT().ExecuteInChrootWithStdin(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
112	mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
113
114	handler := NewConfigureSystemHandler(mockFS, mockChrExec, mockLogger)
115
116	cmd := commands.ConfigureSystemCommand{
117		MountPoint:   "/mnt",
118		Hostname:     "myarch",
119		Timezone:     "UTC",
120		Locale:       "en_US.UTF-8",
121		Keymap:       "us",
122		Username:     "testuser",
123		UserShell:    "/bin/bash",
124		UserPassword: "testpass123",
125		RootPassword: "rootpass456",
126	}
127
128	result, err := handler.Handle(context.Background(), cmd)
129
130	if err != nil {
131		t.Fatalf("expected no error, got %v", err)
132	}
133
134	if !result.Success {
135		t.Error("expected success")
136	}
137
138	if result.Hostname != "myarch" {
139		t.Errorf("expected hostname myarch, got %s", result.Hostname)
140	}
141
142	if result.Timezone != "UTC" {
143		t.Errorf("expected timezone UTC, got %s", result.Timezone)
144	}
145
146	if result.Username != "testuser" {
147		t.Errorf("expected username testuser, got %s", result.Username)
148	}
149}
150
151func TestConfigureSystemHandler_Handle_InvalidHostname(t *testing.T) {
152	ctrl := gomock.NewController(t)
153	defer ctrl.Finish()
154
155	mockFS := mocks.NewMockFileSystem(ctrl)
156	mockChrExec := mocks.NewMockChrootExecutor(ctrl)
157	mockLogger := mocks.NewMockLogger(ctrl)
158
159	mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes()
160	mockLogger.EXPECT().Error(gomock.Any(), gomock.Any(), gomock.Any()).Times(1)
161
162	handler := NewConfigureSystemHandler(mockFS, mockChrExec, mockLogger)
163
164	cmd := commands.ConfigureSystemCommand{
165		MountPoint:   "/mnt",
166		Hostname:     "", // Empty hostname
167		Timezone:     "UTC",
168		Locale:       "en_US.UTF-8",
169		Keymap:       "us",
170		Username:     "testuser",
171		UserShell:    "/bin/bash",
172		UserPassword: "testpass123",
173		RootPassword: "rootpass456",
174	}
175
176	result, err := handler.Handle(context.Background(), cmd)
177
178	if err == nil {
179		t.Error("expected error for invalid hostname")
180	}
181
182	if result.Success {
183		t.Error("expected failure for invalid hostname")
184	}
185}
186
187func TestConfigureSystemHandler_Handle_InvalidUser(t *testing.T) {
188	ctrl := gomock.NewController(t)
189	defer ctrl.Finish()
190
191	mockFS := mocks.NewMockFileSystem(ctrl)
192	mockChrExec := mocks.NewMockChrootExecutor(ctrl)
193	mockLogger := mocks.NewMockLogger(ctrl)
194
195	mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes()
196	mockLogger.EXPECT().Error(gomock.Any(), gomock.Any(), gomock.Any()).Times(1)
197
198	handler := NewConfigureSystemHandler(mockFS, mockChrExec, mockLogger)
199
200	cmd := commands.ConfigureSystemCommand{
201		MountPoint:   "/mnt",
202		Hostname:     "myarch",
203		Timezone:     "UTC",
204		Locale:       "en_US.UTF-8",
205		Keymap:       "us",
206		Username:     "", // Empty username
207		UserShell:    "/bin/bash",
208		UserPassword: "testpass123",
209		RootPassword: "rootpass456",
210	}
211
212	result, err := handler.Handle(context.Background(), cmd)
213
214	if err == nil {
215		t.Error("expected error for invalid username")
216	}
217
218	if result.Success {
219		t.Error("expected failure for invalid username")
220	}
221}
222
223func TestConfigureSystemHandler_Handle_InvalidPassword(t *testing.T) {
224	ctrl := gomock.NewController(t)
225	defer ctrl.Finish()
226
227	mockFS := mocks.NewMockFileSystem(ctrl)
228	mockChrExec := mocks.NewMockChrootExecutor(ctrl)
229	mockLogger := mocks.NewMockLogger(ctrl)
230
231	mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes()
232	mockLogger.EXPECT().Error(gomock.Any(), gomock.Any(), gomock.Any()).Times(1)
233
234	handler := NewConfigureSystemHandler(mockFS, mockChrExec, mockLogger)
235
236	cmd := commands.ConfigureSystemCommand{
237		MountPoint:   "/mnt",
238		Hostname:     "myarch",
239		Timezone:     "UTC",
240		Locale:       "en_US.UTF-8",
241		Keymap:       "us",
242		Username:     "testuser",
243		UserShell:    "/bin/bash",
244		UserPassword: "testpass123",
245		RootPassword: "testpass123", // Same as user password
246	}
247
248	result, err := handler.Handle(context.Background(), cmd)
249
250	if err == nil {
251		t.Error("expected error for same passwords")
252	}
253
254	if result.Success {
255		t.Error("expected failure for same passwords")
256	}
257}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 0

    ↑↓ moveenter openesc close