diff --git a/src/libcalamares/GlobalStorage.cpp b/src/libcalamares/GlobalStorage.cpp index 717b8fff77a5d9b80fb199f6572e3a9c2cd106c0..0c78201d333c9508c984582e2a456afb171ed80c 100644 --- a/src/libcalamares/GlobalStorage.cpp +++ b/src/libcalamares/GlobalStorage.cpp @@ -88,6 +88,13 @@ GlobalStorage::remove( const QString& key ) return nItems; } +void +GlobalStorage::clear() +{ + WriteLock l( this ); + m.clear(); +} + QVariant GlobalStorage::value( const QString& key ) const { diff --git a/src/libcalamares/GlobalStorage.h b/src/libcalamares/GlobalStorage.h index a0a1940f24c34c7e1105642308ad09c3d6ddb1d1..da17243d3ea742039a3ba309c77a4ec16cf96dc9 100644 --- a/src/libcalamares/GlobalStorage.h +++ b/src/libcalamares/GlobalStorage.h @@ -70,6 +70,9 @@ public: */ int remove( const QString& key ); + /// @brief Clears all keys in this GS object + void clear(); + /** @brief dump keys and values to the debug log * * All the keys and their values are written to the debug log. diff --git a/src/modules/partition/Config.cpp b/src/modules/partition/Config.cpp index 4a84046b36f68fde15566b58dc567715da5d6d62..0962e960375c5e14f5a743c888ccfdfaf5852a01 100644 --- a/src/modules/partition/Config.cpp +++ b/src/modules/partition/Config.cpp @@ -274,39 +274,66 @@ fillGSConfigurationEFI( Calamares::GlobalStorage* gs, const QVariantMap& configu QString firmwareType( PartUtils::isEfiSystem() ? QStringLiteral( "efi" ) : QStringLiteral( "bios" ) ); gs->insert( "firmwareType", firmwareType ); - gs->insert( "efiSystemPartition", - Calamares::getString( configurationMap, "efiSystemPartition", QStringLiteral( "/boot/efi" ) ) ); + bool ok = false; + auto efiConfiguration = Calamares::getSubMap( configurationMap, "efi", ok ); - // Read and parse key efiSystemPartitionSize - if ( configurationMap.contains( "efiSystemPartitionSize" ) ) + // Mount Point { - const QString sizeString = Calamares::getString( configurationMap, "efiSystemPartitionSize" ); - Calamares::Partition::PartitionSize part_size = Calamares::Partition::PartitionSize( sizeString ); - if ( part_size.isValid() ) + const auto efiSystemPartition = Calamares::getString( + efiConfiguration, + "mountPoint", + Calamares::getString( configurationMap, "efiSystemPartition", QStringLiteral( "/boot/efi" ) ) ); + // This specific GS key is also used by bootloader and grubcfg modules, + // as well as partition module internalls. + gs->insert( "efiSystemPartition", efiSystemPartition ); + } + + // Sizes + { + const auto efiRecommendedSize = Calamares::getString( + efiConfiguration, "recommendedSize", Calamares::getString( configurationMap, "efiSystemPartitionSize" ) ); + if ( !efiRecommendedSize.isEmpty() ) { - // Insert once as string, once as a size-in-bytes; - // changes to these keys should be synchronized with PartUtils.cpp - gs->insert( "efiSystemPartitionSize", sizeString ); - gs->insert( "efiSystemPartitionSize_i", part_size.toBytes() ); - - // Assign long long int to long unsigned int to prevent compilation warning - auto byte_part_size = part_size.toBytes(); - if ( byte_part_size != PartUtils::efiFilesystemMinimumSize() ) + Calamares::Partition::PartitionSize part_size = Calamares::Partition::PartitionSize( efiRecommendedSize ); + if ( part_size.isValid() ) { - cWarning() << "EFI partition size" << sizeString << "has been adjusted to" - << PartUtils::efiFilesystemMinimumSize() << "bytes"; + gs->insert( PartUtils::efiFilesystemRecommendedSizeGSKey(), part_size.toBytes() ); + + // Assign long long int to long unsigned int to prevent compilation warning, + // checks for loss-of-precision in the conversion. + auto byte_part_size = part_size.toBytes(); + if ( byte_part_size != PartUtils::efiFilesystemRecommendedSize() ) + { + cWarning() << "EFI partition size" << efiRecommendedSize << "has been adjusted to" + << PartUtils::efiFilesystemRecommendedSize() << "bytes"; + } + } + else + { + cWarning() << "EFI partition size" << efiRecommendedSize << "is invalid, ignored"; } } - else + + const auto efiMinimumSize = Calamares::getString( efiConfiguration, "minimumSize" ); + if ( !efiMinimumSize.isEmpty() ) { - cWarning() << "EFI partition size" << sizeString << "is invalid, ignored"; + Calamares::Partition::PartitionSize part_size = Calamares::Partition::PartitionSize( efiMinimumSize ); + if ( part_size.isValid() ) + { + gs->insert( PartUtils::efiFilesystemMinimumSizeGSKey(), part_size.toBytes() ); + } } } - // Read and parse key efiSystemPartitionName - if ( configurationMap.contains( "efiSystemPartitionName" ) ) + // Name (label) of partition { - gs->insert( "efiSystemPartitionName", Calamares::getString( configurationMap, "efiSystemPartitionName" ) ); + const auto efiLabel = Calamares::getString( + efiConfiguration, "label", Calamares::getString( configurationMap, "efiSystemPartitionName" ) ); + + if ( !efiLabel.isEmpty() ) + { + gs->insert( "efiSystemPartitionName", efiLabel ); + } } } diff --git a/src/modules/partition/PartitionViewStep.cpp b/src/modules/partition/PartitionViewStep.cpp index a012938bfb0bfee1a69ed6fb8bf0f39dc11bbe7b..9bf9e26422e573f60a78190964afd310a40c4994 100644 --- a/src/modules/partition/PartitionViewStep.cpp +++ b/src/modules/partition/PartitionViewStep.cpp @@ -527,8 +527,8 @@ PartitionViewStep::onLeave() Logger::Once o; const bool okType = esp && PartUtils::isEfiFilesystemSuitableType( esp ); - const bool okRecommendedSize = esp && PartUtils::isEfiFilesystemSuitableSize( esp ); - const bool okMinimumSize = esp && PartUtils::isEfiFilesystemSuitableMinimumSize( esp ); + const bool okRecommendedSize = esp && PartUtils::isEfiFilesystemRecommendedSize( esp ); + const bool okMinimumSize = esp && PartUtils::isEfiFilesystemMinimumSize( esp ); const bool okFlag = esp && PartUtils::isEfiBootable( esp ); const bool espExistsButIsWrong = esp && !( okType && okMinimumSize && okFlag ); @@ -552,24 +552,21 @@ PartitionViewStep::onLeave() const QString wrongFlagMessage = tr( "The filesystem must have flag <strong>%1</strong> set." ) .arg( PartitionTable::flagName( PartitionTable::Flag::Boot ) ); - // Three flavors of size-is-wrong - using Calamares::Units::operator""_MiB; - - const qint64 atLeastBytes = static_cast< qint64 >( PartUtils::efiFilesystemMinimumSize() ); - const auto atLeastMiB = Calamares::BytesToMiB( atLeastBytes ); + const auto recommendedMiB = Calamares::BytesToMiB( PartUtils::efiFilesystemRecommendedSize() ); + const auto minimumMiB = Calamares::BytesToMiB( PartUtils::efiFilesystemMinimumSize() ); + // Three flavors of size-is-wrong const QString requireConfiguredSize - = tr( "The filesystem must be at least %1 MiB in size." ).arg( atLeastMiB ); + = tr( "The filesystem must be at least %1 MiB in size." ).arg( recommendedMiB ); const QString requiredMinimumSize - = tr( "The filesystem must be at least %1 MiB in size." ).arg( Calamares::BytesToMiB( 32_MiB ) ); + = tr( "The filesystem must be at least %1 MiB in size." ).arg( minimumMiB ); const QString suggestConfiguredSize - = tr( "The minimum recommended size for the filesystem is %1 MiB." ).arg( atLeastMiB ); - + = tr( "The minimum recommended size for the filesystem is %1 MiB." ).arg( recommendedMiB ); const QString mayFail = tr( "You can continue without setting up an EFI system " "partition but your system may fail to start." ); const QString possibleFail = tr( "You can continue with this EFI system " - "partition configuration but your system may fail to start." ); + "partition configuration but your system may fail to start." ); const QString startList = QStringLiteral( "<br/><br/><ul>" ); const QString endList = QStringLiteral( "</ul><br/><br/>" ); diff --git a/src/modules/partition/core/PartUtils.cpp b/src/modules/partition/core/PartUtils.cpp index ad39bba3753889521ccfdc37159c1ff28df7b27d..bc3e6f5a027b6b98f6c023f12aa6300ece1e1ae2 100644 --- a/src/modules/partition/core/PartUtils.cpp +++ b/src/modules/partition/core/PartUtils.cpp @@ -35,6 +35,10 @@ using Calamares::Partition::isPartitionFreeSpace; using Calamares::Partition::isPartitionNew; +using Calamares::Units::operator""_MiB; + +static constexpr qint64 efiSpecificationHardMinimumSize = 32_MiB; + namespace PartUtils { @@ -471,7 +475,7 @@ isEfiFilesystemSuitableType( const Partition* candidate ) } bool -isEfiFilesystemSuitableSize( const Partition* candidate ) +isEfiFilesystemRecommendedSize( const Partition* candidate ) { auto size = candidate->capacity(); // bytes if ( size <= 0 ) @@ -479,7 +483,7 @@ isEfiFilesystemSuitableSize( const Partition* candidate ) return false; } - if ( size >= efiFilesystemMinimumSize() ) + if ( size >= efiFilesystemRecommendedSize() ) { return true; } @@ -491,7 +495,7 @@ isEfiFilesystemSuitableSize( const Partition* candidate ) } bool -isEfiFilesystemSuitableMinimumSize( const Partition* candidate ) +isEfiFilesystemMinimumSize( const Partition* candidate ) { using Calamares::Units::operator""_MiB; @@ -500,8 +504,12 @@ isEfiFilesystemSuitableMinimumSize( const Partition* candidate ) { return false; } + if ( size < efiSpecificationHardMinimumSize ) + { + return false; + } - if ( size >= 32_MiB ) + if ( size >= efiFilesystemMinimumSize() ) { return true; } @@ -522,28 +530,63 @@ isEfiBootable( const Partition* candidate ) return flags.testFlag( KPM_PARTITION_FLAG_ESP ); } -// TODO: this is configurable via the config file **already** +QString +efiFilesystemRecommendedSizeGSKey() +{ + return QStringLiteral( "efiSystemPartitionSize_i" ); +} + qint64 -efiFilesystemMinimumSize() +efiFilesystemRecommendedSize() { - using Calamares::Units::operator""_MiB; + const QString key = efiFilesystemRecommendedSizeGSKey(); qint64 uefisys_part_sizeB = 300_MiB; // The default can be overridden; the key used here comes // from the partition module Config.cpp auto* gs = Calamares::JobQueue::instance()->globalStorage(); - if ( gs->contains( "efiSystemPartitionSize_i" ) ) + if ( gs->contains( key ) ) + { + qint64 v = gs->value( key ).toLongLong(); + uefisys_part_sizeB = v > 0 ? v : 0; + } + // There is a lower limit of what can be configured + if ( uefisys_part_sizeB < efiSpecificationHardMinimumSize ) + { + uefisys_part_sizeB = efiSpecificationHardMinimumSize; + } + return uefisys_part_sizeB; +} + +QString +efiFilesystemMinimumSizeGSKey() +{ + return QStringLiteral( "efiSystemPartitionMinimumSize_i" ); +} + +qint64 +efiFilesystemMinimumSize() +{ + const QString key = efiFilesystemMinimumSizeGSKey(); + + qint64 uefisys_part_sizeB = efiFilesystemRecommendedSize(); + + // The default can be overridden; the key used here comes + // from the partition module Config.cpp + auto* gs = Calamares::JobQueue::instance()->globalStorage(); + if ( gs->contains( key ) ) { - qint64 v = gs->value( "efiSystemPartitionSize_i" ).toLongLong(); + qint64 v = gs->value( key ).toLongLong(); uefisys_part_sizeB = v > 0 ? v : 0; } // There is a lower limit of what can be configured - if ( uefisys_part_sizeB < 32_MiB ) + if ( uefisys_part_sizeB < efiSpecificationHardMinimumSize ) { - uefisys_part_sizeB = 32_MiB; + uefisys_part_sizeB = efiSpecificationHardMinimumSize; } return uefisys_part_sizeB; + return efiSpecificationHardMinimumSize; } QString diff --git a/src/modules/partition/core/PartUtils.h b/src/modules/partition/core/PartUtils.h index 98a1c1ab3736de73366ee77501ea03acbfeab64c..7813a98c475cd487abb2449ae9d14d284f7f41f5 100644 --- a/src/modules/partition/core/PartUtils.h +++ b/src/modules/partition/core/PartUtils.h @@ -95,15 +95,15 @@ bool isEfiFilesystemSuitableType( const Partition* candidate ); /** * @brief Is the @p partition suitable as an EFI boot partition? - * Checks for filesystem size (300MiB, see efiFilesystemMinimumSize). + * Checks for filesystem size (300MiB, see efi.recommendedSize). */ -bool isEfiFilesystemSuitableSize( const Partition* candidate ); +bool isEfiFilesystemRecommendedSize( const Partition* candidate ); /** * @brief Is the @p candidate suitable as an EFI boot partition? - * This checks the bonkers-small minimum of 32MiB. + * Checks for filesystem size (32MiB at least, see efi.minimumSize). */ -bool isEfiFilesystemSuitableMinimumSize( const Partition* candidate ); +bool isEfiFilesystemMinimumSize( const Partition* candidate ); /** @brief Returns the minimum size of an EFI boot partition in bytes. * @@ -113,13 +113,25 @@ bool isEfiFilesystemSuitableMinimumSize( const Partition* candidate ); * by the standard and how all of those are different). * * This can be configured through the `partition.conf` file, - * key *efiSystemPartitionSize*, which will then apply to both + * key *efi.recommendedSize*, which will then apply to both * automatic partitioning **and** the warning for manual partitioning. * * A minimum of 32MiB (which is bonkers-small) is enforced. */ +qint64 efiFilesystemRecommendedSize(); + +// Helper for consistency: the GS key used to share the recommended size +QString efiFilesystemRecommendedSizeGSKey(); + +/** @brief Returns the hard-minimum size of an EFI boot partition in bytes. + * + * This is 32MiB, based on the FAT32 standard and EFI documentation. + */ qint64 efiFilesystemMinimumSize(); +// Helper for consistency: the GS key used to share the minimum size +QString efiFilesystemMinimumSizeGSKey(); + /** * @brief Is the given @p partition bootable in EFI? Depending on * the partition table layout, this may mean different flags. diff --git a/src/modules/partition/core/PartitionActions.cpp b/src/modules/partition/core/PartitionActions.cpp index 25e4a01a5b112a8c17a723fd5c5cbd6a0c840c42..b5fb0cafb00140b3bf1284f53a3e97ea43d21396 100644 --- a/src/modules/partition/core/PartitionActions.cpp +++ b/src/modules/partition/core/PartitionActions.cpp @@ -118,7 +118,7 @@ doAutopartition( PartitionCoreModule* core, Device* dev, Choices::AutoPartitionO if ( isEfi ) { - qint64 uefisys_part_sizeB = PartUtils::efiFilesystemMinimumSize(); + qint64 uefisys_part_sizeB = PartUtils::efiFilesystemRecommendedSize(); qint64 efiSectorCount = Calamares::bytesToSectors( uefisys_part_sizeB, dev->logicalSize() ); Q_ASSERT( efiSectorCount > 0 ); diff --git a/src/modules/partition/partition.conf b/src/modules/partition/partition.conf index 13b6a1b92d3496777012bc4bde1b26ecde15d77c..59b7db2d80b6db1b1f0c2bb0c4ca787793142bef 100644 --- a/src/modules/partition/partition.conf +++ b/src/modules/partition/partition.conf @@ -1,26 +1,49 @@ # SPDX-FileCopyrightText: no # SPDX-License-Identifier: CC0-1.0 # -# This setting specifies the mount point of the EFI system partition. Some -# distributions (Fedora, Debian, Manjaro, etc.) use /boot/efi, others (KaOS, -# etc.) use just /boot. -# -# Defaults to "/boot/efi", may be empty (but weird effects ensue) -efiSystemPartition: "/boot/efi" -# This optional setting specifies the size of the EFI system partition. -# If nothing is specified, the default size of 300MiB will be used. -# -# This size applies both to automatic partitioning and the checks -# during manual partitioning. A minimum of 32MiB is enforced, -# 300MiB is the default, M is treated as MiB, and if you really want -# one-million (10^6) bytes, use MB. -# -# efiSystemPartitionSize: 300M +# Options for EFI system partition. +# +# - *mountPoint* +# This setting specifies the mount point of the EFI system partition. Some +# distributions (Fedora, Debian, Manjaro, etc.) use /boot/efi, others (KaOS, +# etc.) use just /boot. +# +# Defaults to "/boot/efi", may be empty (but weird effects ensue) +# - *recommendedSize* +# This optional setting specifies the size of the EFI system partition. +# If nothing is specified, the default size of 300MiB will be used. +# When writing quantities here, M is treated as MiB, and if you really +# want one-million (10^6) bytes, use MB. +# - *minimumSize* +# This optional setting specifies the absolute minimum size of the EFI +# system partition. If nothing is specified, the *recommendedSize* +# is used instead. +# - *label* +# This optional setting specifies the name of the EFI system partition (see +# PARTLABEL; gpt only; requires KPMCore >= 4.2.0). +# If nothing is specified, the partition name is left unset. +# +# Going below the *recommended* size is allowed, but the user will +# get a warning that it might not work. Going below the *minimum* +# size is not allowed and the user will be told it will not work. +# +# Both quantities must be at least 32MiB, this is enforced by the EFI +# spec. If minimum is not specified, it defaults to the recommended +# size. Distro's that allow more user latitude can set the minimum lower. +efi: + mountPoint: "/boot/efi" + recommendedSize: 300MiB + minimumSize: 32MiB + label: "EFI" -# This optional setting specifies the name of the EFI system partition (see -# PARTLABEL; gpt only; requires KPMCore >= 4.2.0). -# If nothing is specified, the partition name is left unset. +# Deprecated alias of efi.mountPoint +# efiSystemPartition: "/boot/efi" + +# Deprecated alias of efi.recommendedSize +# efiSystemPartitionSize: 300MiB + +# Deprecated alias of efi.label # efiSystemPartitionName: EFI # In autogenerated partitioning, allow the user to select a swap size? diff --git a/src/modules/partition/partition.schema.yaml b/src/modules/partition/partition.schema.yaml index 5207c03722a10edbfc10ebd756cd0ff64809e07c..769c1abae56a4fe44e7838923b9d6e3027530602 100644 --- a/src/modules/partition/partition.schema.yaml +++ b/src/modules/partition/partition.schema.yaml @@ -7,9 +7,18 @@ $id: https://calamares.io/schemas/partition additionalProperties: false type: object properties: - efiSystemPartition: { type: string } # Mount point - efiSystemPartitionSize: { type: string } - efiSystemPartitionName: { type: string } + efiSystemPartition: { type: string } # Deprecated alias of efi.mountPoint + efiSystemPartitionSize: { type: string } # Deprecated alias of efi.recommendedSize + efiSystemPartitionName: { type: string } # Deprecated alias of efi.label + + efi: + type: object + properties: + recommendedSize: { type: string } + minimumSize: { type: string } + label: { type: string } + mountPoint: { type: string } + additionalProperties: false userSwapChoices: { type: array, items: { type: string, enum: [ none, reuse, small, suspend, file ] } } # ensureSuspendToDisk: { type: boolean, default: true } # Legacy @@ -34,5 +43,4 @@ properties: requiredStorage: { type: number } required: - - efiSystemPartition - userSwapChoices diff --git a/src/modules/partition/tests/1a-legacy.conf b/src/modules/partition/tests/1a-legacy.conf new file mode 100644 index 0000000000000000000000000000000000000000..f3435a262cffbc7ba60b9acebaee48298cd405c9 --- /dev/null +++ b/src/modules/partition/tests/1a-legacy.conf @@ -0,0 +1,2 @@ +--- +efiSystemPartitionSize: 100MiB diff --git a/src/modules/partition/tests/1b-legacy.conf b/src/modules/partition/tests/1b-legacy.conf new file mode 100644 index 0000000000000000000000000000000000000000..9792e815579e2374a58dac655a19a7610fbc99b3 --- /dev/null +++ b/src/modules/partition/tests/1b-legacy.conf @@ -0,0 +1,2 @@ +--- +efiSystemPartitionSize: 100MB diff --git a/src/modules/partition/tests/2a-legacy.conf b/src/modules/partition/tests/2a-legacy.conf new file mode 100644 index 0000000000000000000000000000000000000000..47111a66fb91ef4296570829268e20d339c47cc5 --- /dev/null +++ b/src/modules/partition/tests/2a-legacy.conf @@ -0,0 +1,9 @@ +--- +# Deprecated alias of efi.mountPoint +efiSystemPartition: "/boot/thisisatest" + +# Deprecated alias of efi.recommendedSize +efiSystemPartitionSize: 75MiB + +# Deprecated alias of efi.label +efiSystemPartitionName: testLabel diff --git a/src/modules/partition/tests/2b-modern.conf b/src/modules/partition/tests/2b-modern.conf new file mode 100644 index 0000000000000000000000000000000000000000..5b6a6ddf641a4b5933269f5531dfe4bc534098da --- /dev/null +++ b/src/modules/partition/tests/2b-modern.conf @@ -0,0 +1,6 @@ +--- +efi: + mountPoint: "/boot/thisismodern" + recommendedSize: 80MiB + minimumSize: 65MiB + label: "UEFI" diff --git a/src/modules/partition/tests/2c-mixed.conf b/src/modules/partition/tests/2c-mixed.conf new file mode 100644 index 0000000000000000000000000000000000000000..f472ebef6ba48d3bcb20923d66269881de9450f2 --- /dev/null +++ b/src/modules/partition/tests/2c-mixed.conf @@ -0,0 +1,7 @@ +--- +efi: + mountPoint: "/boot/thisismixed" + minimumSize: 80MiB + +efiSystemPartitionSize: 175MiB +efiSystemPartitionName: legacy diff --git a/src/modules/partition/tests/2d-overlap.conf b/src/modules/partition/tests/2d-overlap.conf new file mode 100644 index 0000000000000000000000000000000000000000..9ddfa56df00bf32f4abea62bff40100a760797a7 --- /dev/null +++ b/src/modules/partition/tests/2d-overlap.conf @@ -0,0 +1,9 @@ +--- +efi: + mountPoint: "/boot/thisoverlaps" + minimumSize: 100MiB + recommendedSize: 300MiB + +efiSystemPartition: "/boot/ignored" +efiSystemPartitionSize: 175MiB +efiSystemPartitionName: legacy diff --git a/src/modules/partition/tests/CMakeLists.txt b/src/modules/partition/tests/CMakeLists.txt index 9c5dd32575204d19d8bfc755158993ae917c5271..17b79265fb1bb6cc2db91e77a8f995621d5337bd 100644 --- a/src/modules/partition/tests/CMakeLists.txt +++ b/src/modules/partition/tests/CMakeLists.txt @@ -61,3 +61,16 @@ calamares_add_test( LIBRARIES calamares::kpmcore DEFINITIONS ${_partition_defs} ) + +calamares_add_test( + partitionconfigtest + SOURCES + ConfigTests.cpp + ${PartitionModule_SOURCE_DIR}/core/DeviceModel.cpp + ${PartitionModule_SOURCE_DIR}/core/PartitionInfo.cpp + ${PartitionModule_SOURCE_DIR}/core/PartUtils.cpp + ${PartitionModule_SOURCE_DIR}/Config.cpp + LIBRARIES calamares::kpmcore Calamares::calamaresui + DEFINITIONS + ${_partition_defs} +) diff --git a/src/modules/partition/tests/ConfigTests.cpp b/src/modules/partition/tests/ConfigTests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee815050184555eb6fc8090a31963ad9c1dee2d5 --- /dev/null +++ b/src/modules/partition/tests/ConfigTests.cpp @@ -0,0 +1,203 @@ +/* === This file is part of Calamares - <https://calamares.io> === + * + * SPDX-FileCopyrightText: 2023 Adriaan de Groot <groot@kde.org> + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + */ + +#include "Config.h" + +#include "core/PartUtils.h" + +#include "GlobalStorage.h" +#include "JobQueue.h" +#include "utils/Logger.h" +#include "utils/System.h" +#include "utils/Yaml.h" + +#include <QObject> +#include <QtTest/QtTest> + +using Calamares::Units::operator""_MiB; + +class ConfigTests : public QObject +{ + Q_OBJECT + +public: + ConfigTests(); + +private Q_SLOTS: + void initTestCase(); + void testEmptyConfig(); + void testLegacySize(); + void testAll(); +}; + +ConfigTests::ConfigTests() = default; + +void +ConfigTests::initTestCase() +{ + Logger::setupLogLevel( Logger::LOGVERBOSE ); + + // Ensure we have a system object, expect it to be a "bogus" one + Calamares::System* system = Calamares::System::instance(); + QVERIFY( system ); + QVERIFY( system->doChroot() ); + + // Ensure we have a system-wide GlobalStorage with /tmp as root + if ( !Calamares::JobQueue::instance() ) + { + cDebug() << "Creating new JobQueue"; + (void)new Calamares::JobQueue(); + } + Calamares::GlobalStorage* gs + = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr; + QVERIFY( gs ); +} + + +void +ConfigTests::testEmptyConfig() +{ + Config c( nullptr ); + c.setConfigurationMap( {} ); + + const auto* gs = Calamares::JobQueue::instanceGlobalStorage(); + QVERIFY( gs ); + + QVERIFY( c.initialInstallChoice() == Config::InstallChoice::NoChoice ); + QVERIFY( !gs->value( PartUtils::efiFilesystemRecommendedSizeGSKey() ).isValid() ); // Nothing filled in + QCOMPARE( PartUtils::efiFilesystemRecommendedSize(), 300_MiB ); // Default value + QCOMPARE( PartUtils::efiFilesystemMinimumSize(), 300_MiB ); // Default value + + const auto firmware = gs->value( "firmwareType" ).toString(); + QVERIFY( firmware == "efi" || firmware == "bios" ); + + QCOMPARE( gs->value( "efiSystemPartition" ).toString(), "/boot/efi" ); // Default +} + +void +ConfigTests::testLegacySize() +{ + Config c( nullptr ); + + auto* gs = Calamares::JobQueue::instanceGlobalStorage(); + QVERIFY( gs ); + + + // Config with just one legacy key + { + const auto file = QStringLiteral( BUILD_AS_TEST "/1a-legacy.conf" ); + bool ok = false; + c.setConfigurationMap( Calamares::YAML::load( file, &ok ) ); + + cDebug() << "Tried to load" << file << "success?" << ok; + + QVERIFY( ok ); + + QVERIFY( gs->value( PartUtils::efiFilesystemRecommendedSizeGSKey() ).isValid() ); // Something was filled in + QCOMPARE( PartUtils::efiFilesystemRecommendedSize(), 100_MiB ); // From config + QCOMPARE( PartUtils::efiFilesystemMinimumSize(), 100_MiB ); // Taken from config + } + + // Different legacy key value + { + bool ok = false; + c.setConfigurationMap( Calamares::YAML::load( QStringLiteral( BUILD_AS_TEST "/1b-legacy.conf" ), &ok ) ); + + QVERIFY( ok ); + + QCOMPARE( PartUtils::efiFilesystemRecommendedSize(), 100000000 ); // From config, MB + QCOMPARE( PartUtils::efiFilesystemMinimumSize(), 100000000 ); // Taken from config + } +} + +void +ConfigTests::testAll() +{ + Config c( nullptr ); + + auto* gs = Calamares::JobQueue::instanceGlobalStorage(); + QVERIFY( gs ); + + + // Legacy only + { + gs->clear(); + const auto file = QStringLiteral( BUILD_AS_TEST "/2a-legacy.conf" ); + bool ok = false; + c.setConfigurationMap( Calamares::YAML::load( file, &ok ) ); + + cDebug() << "Tried to load" << file << "success?" << ok; + + QVERIFY( ok ); + + QVERIFY( gs->value( PartUtils::efiFilesystemRecommendedSizeGSKey() ).isValid() ); // Something was filled in + QCOMPARE( PartUtils::efiFilesystemRecommendedSize(), 75_MiB ); // From config + QCOMPARE( PartUtils::efiFilesystemMinimumSize(), 75_MiB ); // No separate setting + + QCOMPARE( gs->value( "efiSystemPartition" ).toString(), QStringLiteral( "/boot/thisisatest" ) ); + QCOMPARE( gs->value( "efiSystemPartitionName" ).toString(), QStringLiteral( "testLabel" ) ); + } + + // Modern only + { + gs->clear(); + bool ok = false; + c.setConfigurationMap( Calamares::YAML::load( QStringLiteral( BUILD_AS_TEST "/2b-modern.conf" ), &ok ) ); + + QVERIFY( ok ); + + QVERIFY( PartUtils::efiFilesystemRecommendedSizeGSKey() != PartUtils::efiFilesystemMinimumSizeGSKey() ); + QCOMPARE( gs->value( PartUtils::efiFilesystemRecommendedSizeGSKey() ).toString(), + QStringLiteral( "83886080" ) ); + QCOMPARE( gs->value( PartUtils::efiFilesystemMinimumSizeGSKey() ).toString(), QStringLiteral( "68157440" ) ); + + QCOMPARE( PartUtils::efiFilesystemRecommendedSize(), 80_MiB ); // From config + QCOMPARE( PartUtils::efiFilesystemMinimumSize(), 65_MiB ); // Taken from config + + QCOMPARE( gs->value( "efiSystemPartition" ).toString(), QStringLiteral( "/boot/thisismodern" ) ); + QCOMPARE( gs->value( "efiSystemPartitionName" ).toString(), QStringLiteral( "UEFI" ) ); + } + + // Mixed settings + { + gs->clear(); + bool ok = false; + c.setConfigurationMap( Calamares::YAML::load( QStringLiteral( BUILD_AS_TEST "/2c-mixed.conf" ), &ok ) ); + + QVERIFY( ok ); + + QCOMPARE( PartUtils::efiFilesystemRecommendedSize(), 175_MiB ); // From config + QCOMPARE( PartUtils::efiFilesystemMinimumSize(), 80_MiB ); // Taken from config + + QCOMPARE( gs->value( "efiSystemPartition" ).toString(), QStringLiteral( "/boot/thisismixed" ) ); + QCOMPARE( gs->value( "efiSystemPartitionName" ).toString(), QStringLiteral( "legacy" ) ); + } + + // Mixed settings with overlap + { + gs->clear(); + bool ok = false; + c.setConfigurationMap( Calamares::YAML::load( QStringLiteral( BUILD_AS_TEST "/2d-overlap.conf" ), &ok ) ); + + QVERIFY( ok ); + + QCOMPARE( PartUtils::efiFilesystemRecommendedSize(), 300_MiB ); // From modern config + QCOMPARE( PartUtils::efiFilesystemMinimumSize(), 100_MiB ); // Taken from modern config, legacy ignored + + QCOMPARE( gs->value( "efiSystemPartition" ).toString(), QStringLiteral( "/boot/thisoverlaps" ) ); + QCOMPARE( gs->value( "efiSystemPartitionName" ).toString(), QStringLiteral( "legacy" ) ); + } +} + + +QTEST_GUILESS_MAIN( ConfigTests ) + +#include "utils/moc-warnings.h" + +#include "ConfigTests.moc"