1package handlers
2
3import (
4 "context"
5 "testing"
6
7 "github.com/bnema/archup/internal/application/commands"
8 "github.com/bnema/archup/internal/domain/disk"
9 "github.com/bnema/archup/internal/domain/ports/mocks"
10 "go.uber.org/mock/gomock"
11)
12
13func TestPartitionHandler_Handle_Success(t *testing.T) {
14 ctrl := gomock.NewController(t)
15 defer ctrl.Finish()
16
17 mockExec := mocks.NewMockCommandExecutor(ctrl)
18 mockLogger := mocks.NewMockLogger(ctrl)
19
20 mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes()
21 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
22 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
23 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
24 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
25 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
26 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
27
28 handler := NewPartitionHandler(mockExec, mockLogger)
29
30 cmd := commands.PartitionDiskCommand{
31 TargetDisk: "/dev/sda",
32 RootSizeGB: 50,
33 BootSizeGB: 1,
34 EncryptionType: disk.EncryptionTypeNone,
35 EncryptionPassword: "",
36 FilesystemType: disk.FilesystemExt4,
37 WipeDisks: true,
38 }
39
40 result, err := handler.Handle(context.Background(), cmd)
41
42 if err != nil {
43 t.Fatalf("expected no error, got %v", err)
44 }
45
46 if !result.Success {
47 t.Errorf("expected success, got error: %s", result.ErrorDetail)
48 }
49
50 if result.TargetDisk != "/dev/sda" {
51 t.Errorf("expected target disk /dev/sda, got %s", result.TargetDisk)
52 }
53
54 if len(result.Partitions) != 2 {
55 t.Errorf("expected 2 partitions, got %d", len(result.Partitions))
56 }
57
58 // Check boot partition
59 if len(result.Partitions) > 0 && result.Partitions[0].MountPoint != "/boot" {
60 t.Errorf("expected first partition mount point /boot, got %s", result.Partitions[0].MountPoint)
61 }
62
63 // Check root partition
64 if len(result.Partitions) > 1 && result.Partitions[1].MountPoint != "/" {
65 t.Errorf("expected second partition mount point /, got %s", result.Partitions[1].MountPoint)
66 }
67}
68
69func TestPartitionHandler_Handle_InvalidDisk(t *testing.T) {
70 ctrl := gomock.NewController(t)
71 defer ctrl.Finish()
72
73 mockExec := mocks.NewMockCommandExecutor(ctrl)
74 mockLogger := mocks.NewMockLogger(ctrl)
75
76 mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes()
77 mockLogger.EXPECT().Error(gomock.Any(), gomock.Any(), gomock.Any()).Times(1)
78 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
79 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
80 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
81 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
82 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
83 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
84 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
85 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
86 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
87 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
88 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
89 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
90 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
91 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
92
93 handler := NewPartitionHandler(mockExec, mockLogger)
94
95 cmd := commands.PartitionDiskCommand{
96 TargetDisk: "",
97 RootSizeGB: 50,
98 BootSizeGB: 1,
99 EncryptionType: disk.EncryptionTypeNone,
100 FilesystemType: disk.FilesystemExt4,
101 }
102
103 result, err := handler.Handle(context.Background(), cmd)
104
105 if err == nil {
106 t.Error("expected error for invalid disk")
107 }
108
109 if result.Success {
110 t.Error("expected result to indicate failure")
111 }
112}
113
114func TestPartitionHandler_Handle_RootPartitionTooSmall(t *testing.T) {
115 ctrl := gomock.NewController(t)
116 defer ctrl.Finish()
117
118 mockExec := mocks.NewMockCommandExecutor(ctrl)
119 mockLogger := mocks.NewMockLogger(ctrl)
120
121 mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes()
122 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
123 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
124 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
125 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
126 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
127 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
128 mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes()
129
130 handler := NewPartitionHandler(mockExec, mockLogger)
131
132 cmd := commands.PartitionDiskCommand{
133 TargetDisk: "/dev/sda",
134 RootSizeGB: 1, // Too small
135 BootSizeGB: 1,
136 EncryptionType: disk.EncryptionTypeNone,
137 FilesystemType: disk.FilesystemExt4,
138 }
139
140 result, err := handler.Handle(context.Background(), cmd)
141
142 if err != nil {
143 t.Fatalf("expected no error, got %v", err)
144 }
145
146 if !result.Success {
147 t.Errorf("expected success, got error: %s", result.ErrorDetail)
148 }
149}
150
151func TestPartitionHandler_SetupLUKSEncryption_UsesStdinForPassword(t *testing.T) {
152 ctrl := gomock.NewController(t)
153 defer ctrl.Finish()
154
155 mockExec := mocks.NewMockCommandExecutor(ctrl)
156 mockLogger := mocks.NewMockLogger(ctrl)
157
158 password := "pa'ss$word !"
159
160 mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes()
161 mockExec.EXPECT().Execute(gomock.Any(), "wipefs", "-af", "/dev/sda2").Return([]byte{}, nil)
162 mockExec.EXPECT().ExecuteWithStdin(
163 gomock.Any(),
164 password,
165 "cryptsetup",
166 "luksFormat",
167 "--type", "luks2",
168 "--batch-mode",
169 "--pbkdf", "argon2id",
170 "--iter-time", "2000",
171 "--label", "ARCHUP_LUKS",
172 "--key-file=-",
173 "/dev/sda2",
174 ).Return([]byte{}, nil)
175 mockExec.EXPECT().ExecuteWithStdin(
176 gomock.Any(),
177 password,
178 "cryptsetup",
179 "open",
180 "--key-file=-",
181 "/dev/sda2",
182 "cryptroot",
183 ).Return([]byte{}, nil)
184
185 handler := NewPartitionHandler(mockExec, mockLogger)
186
187 cryptDevice, err := handler.setupLUKSEncryption(context.Background(), "/dev/sda2", password)
188 if err != nil {
189 t.Fatalf("expected no error, got %v", err)
190 }
191
192 if cryptDevice != "/dev/mapper/cryptroot" {
193 t.Fatalf("expected cryptroot mapper path, got %q", cryptDevice)
194 }
195}