package handlers import ( "context" "testing" "github.com/bnema/archup/internal/application/commands" "github.com/bnema/archup/internal/domain/disk" "github.com/bnema/archup/internal/domain/ports/mocks" "go.uber.org/mock/gomock" ) func TestPartitionHandler_Handle_Success(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockExec := mocks.NewMockCommandExecutor(ctrl) mockLogger := mocks.NewMockLogger(ctrl) mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() handler := NewPartitionHandler(mockExec, mockLogger) cmd := commands.PartitionDiskCommand{ TargetDisk: "/dev/sda", RootSizeGB: 50, BootSizeGB: 1, EncryptionType: disk.EncryptionTypeNone, EncryptionPassword: "", FilesystemType: disk.FilesystemExt4, WipeDisks: true, } result, err := handler.Handle(context.Background(), cmd) if err != nil { t.Fatalf("expected no error, got %v", err) } if !result.Success { t.Errorf("expected success, got error: %s", result.ErrorDetail) } if result.TargetDisk != "/dev/sda" { t.Errorf("expected target disk /dev/sda, got %s", result.TargetDisk) } if len(result.Partitions) != 2 { t.Errorf("expected 2 partitions, got %d", len(result.Partitions)) } // Check boot partition if len(result.Partitions) > 0 && result.Partitions[0].MountPoint != "/boot" { t.Errorf("expected first partition mount point /boot, got %s", result.Partitions[0].MountPoint) } // Check root partition if len(result.Partitions) > 1 && result.Partitions[1].MountPoint != "/" { t.Errorf("expected second partition mount point /, got %s", result.Partitions[1].MountPoint) } } func TestPartitionHandler_Handle_InvalidDisk(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockExec := mocks.NewMockCommandExecutor(ctrl) mockLogger := mocks.NewMockLogger(ctrl) mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() mockLogger.EXPECT().Error(gomock.Any(), gomock.Any(), gomock.Any()).Times(1) mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() 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() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() 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() handler := NewPartitionHandler(mockExec, mockLogger) cmd := commands.PartitionDiskCommand{ TargetDisk: "", RootSizeGB: 50, BootSizeGB: 1, EncryptionType: disk.EncryptionTypeNone, FilesystemType: disk.FilesystemExt4, } result, err := handler.Handle(context.Background(), cmd) if err == nil { t.Error("expected error for invalid disk") } if result.Success { t.Error("expected result to indicate failure") } } func TestPartitionHandler_Handle_RootPartitionTooSmall(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockExec := mocks.NewMockCommandExecutor(ctrl) mockLogger := mocks.NewMockLogger(ctrl) mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() 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() handler := NewPartitionHandler(mockExec, mockLogger) cmd := commands.PartitionDiskCommand{ TargetDisk: "/dev/sda", RootSizeGB: 1, // Too small BootSizeGB: 1, EncryptionType: disk.EncryptionTypeNone, FilesystemType: disk.FilesystemExt4, } result, err := handler.Handle(context.Background(), cmd) if err != nil { t.Fatalf("expected no error, got %v", err) } if !result.Success { t.Errorf("expected success, got error: %s", result.ErrorDetail) } } func TestPartitionHandler_SetupLUKSEncryption_UsesStdinForPassword(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockExec := mocks.NewMockCommandExecutor(ctrl) mockLogger := mocks.NewMockLogger(ctrl) password := "pa'ss$word !" mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() mockExec.EXPECT().Execute(gomock.Any(), "wipefs", "-af", "/dev/sda2").Return([]byte{}, nil) mockExec.EXPECT().ExecuteWithStdin( gomock.Any(), password, "cryptsetup", "luksFormat", "--type", "luks2", "--batch-mode", "--pbkdf", "argon2id", "--iter-time", "2000", "--label", "ARCHUP_LUKS", "--key-file=-", "/dev/sda2", ).Return([]byte{}, nil) mockExec.EXPECT().ExecuteWithStdin( gomock.Any(), password, "cryptsetup", "open", "--key-file=-", "/dev/sda2", "cryptroot", ).Return([]byte{}, nil) handler := NewPartitionHandler(mockExec, mockLogger) cryptDevice, err := handler.setupLUKSEncryption(context.Background(), "/dev/sda2", password) if err != nil { t.Fatalf("expected no error, got %v", err) } if cryptDevice != "/dev/mapper/cryptroot" { t.Fatalf("expected cryptroot mapper path, got %q", cryptDevice) } }