From c8d599a0ee672ee5e7c5db2d88cb1b6482d65db7 Mon Sep 17 00:00:00 2001 From: Viktor Vorona Date: Wed, 9 Oct 2024 09:53:38 +0200 Subject: [PATCH] SONAR-23188 MQR Mode setting --- .../main/js/api/mocks/SettingsServiceMock.ts | 4 +- .../CalculationChangeMessage-test.tsx | 2 +- .../__tests__/ComponentMeasures-it.tsx | 4 +- .../branches/__tests__/BranchOverview-it.tsx | 4 +- .../__tests__/ProjectActivityApp-it.tsx | 2 +- .../components/__tests__/PageSidebar-test.tsx | 4 +- .../__tests__/ProjectCard-test.tsx | 4 +- .../sonar-web/src/main/js/queries/settings.ts | 4 +- .../sonar-web/src/main/js/types/settings.ts | 2 +- .../platformlevel/PlatformLevel4.java | 2 + .../TelemetryMQRModePropertyProvider.java | 67 +++++++++++++++++ .../TelemetryMQRModePropertyProviderTest.java | 71 +++++++++++++++++++ .../core/config/CorePropertyDefinitions.java | 1 + .../sonar/core/config/MQRModeConstants.java | 31 ++++++++ .../sonar/core/config/MQRModeProperties.java | 55 ++++++++++++++ .../core/config/MQRModePropertiesTest.java | 31 ++++++++ 16 files changed, 273 insertions(+), 15 deletions(-) create mode 100644 server/sonar-webserver/src/main/java/org/sonar/server/platform/telemetry/TelemetryMQRModePropertyProvider.java create mode 100644 server/sonar-webserver/src/test/java/org/sonar/server/platform/telemetry/TelemetryMQRModePropertyProviderTest.java create mode 100644 sonar-core/src/main/java/org/sonar/core/config/MQRModeConstants.java create mode 100644 sonar-core/src/main/java/org/sonar/core/config/MQRModeProperties.java create mode 100644 sonar-core/src/test/java/org/sonar/core/config/MQRModePropertiesTest.java diff --git a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts index 49d90bfbdf5..70822c677ee 100644 --- a/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts +++ b/server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts @@ -138,8 +138,8 @@ export default class SettingsServiceMock { value: 'true', }, { - key: 'sonar.old_world', - value: 'false', + key: SettingsKey.MQRMode, + value: 'true', }, ]; diff --git a/server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx index 5996490ba0d..737f980634a 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/CalculationChangeMessage-test.tsx @@ -54,7 +54,7 @@ it.each([ ['Project', '/projects', ComponentQualifier.Project], ['Portfolios', '/portfolios', ComponentQualifier.Portfolio], ])('should not render on %s page if isLegacy', (_, path, qualifier) => { - settingsHandler.set(SettingsKey.LegacyMode, 'true'); + settingsHandler.set(SettingsKey.MQRMode, 'false'); render(path); expect(ui.alert.get()).toBeInTheDocument(); expect(ui.alertText(qualifier).get()).toBeInTheDocument(); diff --git a/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx b/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx index 01043b60288..c3eecceb27b 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx @@ -106,7 +106,7 @@ describe('rendering', () => { }); it('should correctly render the default overview and navigation in legacy mode', async () => { - settingsHandler.set(SettingsKey.LegacyMode, 'true'); + settingsHandler.set(SettingsKey.MQRMode, 'false'); const { ui, user } = getPageObject(); renderMeasuresApp(); @@ -212,7 +212,7 @@ describe('rendering', () => { }); it('should show old measures and no flag message if no rating measures and legacy mode', async () => { - settingsHandler.set(SettingsKey.LegacyMode, 'true'); + settingsHandler.set(SettingsKey.MQRMode, 'false'); measuresHandler.deleteComponentMeasure( 'foo', MetricKey.software_quality_maintainability_rating, diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx index 4979f7546be..e4fc40a4682 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx @@ -487,7 +487,7 @@ describe('project overview', () => { }); it('should display old measures if in legacy mode', async () => { - settingsHandler.set(SettingsKey.LegacyMode, 'true'); + settingsHandler.set(SettingsKey.MQRMode, 'false'); const { user, ui } = getPageObjects(); renderBranchOverview(); @@ -526,7 +526,7 @@ describe('project overview', () => { MetricKey.software_quality_maintainability_rating, ); measuresHandler.deleteComponentMeasure('foo', MetricKey.software_quality_reliability_rating); - settingsHandler.set(SettingsKey.LegacyMode, 'true'); + settingsHandler.set(SettingsKey.MQRMode, 'false'); const { user, ui } = getPageObjects(); renderBranchOverview(); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx index e8132d76bef..ce6c00ae23e 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx @@ -687,7 +687,7 @@ describe('ratings', () => { }); it('should not show gaps message and metric change button in legacy mode', async () => { - settingsHandler.set(SettingsKey.LegacyMode, 'true'); + settingsHandler.set(SettingsKey.MQRMode, 'false'); timeMachineHandler.setMeasureHistory([ mockMeasureHistory({ metric: MetricKey.reliability_rating, diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx index 927df18e7aa..c1d41c9b149 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageSidebar-test.tsx @@ -85,7 +85,7 @@ it('should allow to clear all filters', async () => { }); it('should show legacy filters', async () => { - settingsHandler.set(SettingsKey.LegacyMode, 'true'); + settingsHandler.set(SettingsKey.MQRMode, 'false'); renderPageSidebar(); expect(await screen.findAllByText(/projects.facets.rating_option/)).toHaveLength(20); @@ -96,7 +96,7 @@ it('should show legacy filters', async () => { }); it('should show non legacy filters', async () => { - settingsHandler.set(SettingsKey.LegacyMode, 'false'); + settingsHandler.set(SettingsKey.MQRMode, 'true'); renderPageSidebar(); expect(await screen.findAllByText(/projects.facets.rating_option/)).toHaveLength(20); diff --git a/server/sonar-web/src/main/js/apps/projects/components/project-card/__tests__/ProjectCard-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/project-card/__tests__/ProjectCard-test.tsx index f2754c4aeaf..b6bd24cf673 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/project-card/__tests__/ProjectCard-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/project-card/__tests__/ProjectCard-test.tsx @@ -310,7 +310,7 @@ describe('upgrade scenario (awaiting scan)', () => { }); it('should not display awaiting analysis badge if legacy mode is enabled', async () => { - settingsHandler.set(SettingsKey.LegacyMode, 'true'); + settingsHandler.set(SettingsKey.MQRMode, 'false'); renderProjectCard({ ...PROJECT, measures: { @@ -329,7 +329,7 @@ describe('upgrade scenario (awaiting scan)', () => { }); it('should not display new values if legacy mode is enabled', async () => { - settingsHandler.set(SettingsKey.LegacyMode, 'true'); + settingsHandler.set(SettingsKey.MQRMode, 'false'); measuresHandler.registerComponentMeasures({ [PROJECT.key]: { ...newRatings, diff --git a/server/sonar-web/src/main/js/queries/settings.ts b/server/sonar-web/src/main/js/queries/settings.ts index 89c77ea30d7..83d02cbaf81 100644 --- a/server/sonar-web/src/main/js/queries/settings.ts +++ b/server/sonar-web/src/main/js/queries/settings.ts @@ -59,8 +59,8 @@ export const useGetValueQuery = createQueryHook( export const useIsLegacyCCTMode = () => { return useGetValueQuery( - { key: SettingsKey.LegacyMode }, - { staleTime: Infinity, select: (data) => data?.value === 'true' }, + { key: SettingsKey.MQRMode }, + { staleTime: Infinity, select: (data) => data?.value === 'false' }, ); }; diff --git a/server/sonar-web/src/main/js/types/settings.ts b/server/sonar-web/src/main/js/types/settings.ts index ce12260c3c3..4276fda7d15 100644 --- a/server/sonar-web/src/main/js/types/settings.ts +++ b/server/sonar-web/src/main/js/types/settings.ts @@ -28,7 +28,7 @@ export const enum SettingsKey { LicenceRemainingLocNotificationThreshold = 'sonar.license.notifications.remainingLocThreshold', TokenMaxAllowedLifetime = 'sonar.auth.token.max.allowed.lifetime', QPAdminCanDisableInheritedRules = 'sonar.qualityProfiles.allowDisableInheritedRules', - LegacyMode = 'sonar.legacy.ratings.mode.enabled', + MQRMode = 'sonar.multi-quality-mode.enabled', CodeSuggestion = 'sonar.ai.suggestions.enabled', } diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index a947a254e31..920bab6fbd1 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -190,6 +190,7 @@ import org.sonar.server.platform.WebCoreExtensionsInstaller; import org.sonar.server.platform.db.CheckAnyonePermissionsAtStartup; import org.sonar.server.platform.telemetry.ProjectCppAutoconfigTelemetryProvider; import org.sonar.server.platform.telemetry.TelemetryFipsEnabledProvider; +import org.sonar.server.platform.telemetry.TelemetryMQRModePropertyProvider; import org.sonar.server.platform.telemetry.TelemetryNclocProvider; import org.sonar.server.platform.telemetry.TelemetryPortfolioConfidentialFlagProvider; import org.sonar.server.platform.telemetry.TelemetryUserEnabledProvider; @@ -675,6 +676,7 @@ public class PlatformLevel4 extends PlatformLevel { // new telemetry metrics ProjectCppAutoconfigTelemetryProvider.class, TelemetryVersionProvider.class, + TelemetryMQRModePropertyProvider.class, TelemetryNclocProvider.class, TelemetryUserEnabledProvider.class, TelemetryFipsEnabledProvider.class, diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/telemetry/TelemetryMQRModePropertyProvider.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/telemetry/TelemetryMQRModePropertyProvider.java new file mode 100644 index 00000000000..ed1e6ab34fe --- /dev/null +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/telemetry/TelemetryMQRModePropertyProvider.java @@ -0,0 +1,67 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.telemetry; + +import java.util.Optional; +import org.sonar.db.DbClient; +import org.sonar.db.property.PropertyDto; +import org.sonar.telemetry.core.Dimension; +import org.sonar.telemetry.core.Granularity; +import org.sonar.telemetry.core.TelemetryDataProvider; +import org.sonar.telemetry.core.TelemetryDataType; + +import static org.sonar.core.config.MQRModeConstants.MULTI_QUALITY_MODE_ENABLED; +import static org.sonar.telemetry.core.Dimension.INSTALLATION; +import static org.sonar.telemetry.core.Granularity.WEEKLY; +import static org.sonar.telemetry.core.TelemetryDataType.BOOLEAN; + +public class TelemetryMQRModePropertyProvider implements TelemetryDataProvider { + private final DbClient dbClient; + + public TelemetryMQRModePropertyProvider(DbClient dbClient) { + this.dbClient = dbClient; + } + + @Override + public String getMetricKey() { + return "multi_quality_rule_mode_enabled"; + } + + @Override + public Dimension getDimension() { + return INSTALLATION; + } + + @Override + public Granularity getGranularity() { + return WEEKLY; + } + + @Override + public TelemetryDataType getType() { + return BOOLEAN; + } + + @Override + public Optional getValue() { + PropertyDto property = dbClient.propertiesDao().selectGlobalProperty(MULTI_QUALITY_MODE_ENABLED); + return Optional.of(property != null && Boolean.parseBoolean(property.getValue())); + } +} diff --git a/server/sonar-webserver/src/test/java/org/sonar/server/platform/telemetry/TelemetryMQRModePropertyProviderTest.java b/server/sonar-webserver/src/test/java/org/sonar/server/platform/telemetry/TelemetryMQRModePropertyProviderTest.java new file mode 100644 index 00000000000..66a93111d8c --- /dev/null +++ b/server/sonar-webserver/src/test/java/org/sonar/server/platform/telemetry/TelemetryMQRModePropertyProviderTest.java @@ -0,0 +1,71 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.telemetry; + +import java.util.Optional; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.sonar.db.DbClient; +import org.sonar.db.property.PropertiesDao; +import org.sonar.db.property.PropertyDto; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.sonar.core.config.MQRModeConstants.MULTI_QUALITY_MODE_ENABLED; +import static org.sonar.telemetry.core.Dimension.INSTALLATION; +import static org.sonar.telemetry.core.Granularity.WEEKLY; +import static org.sonar.telemetry.core.TelemetryDataType.BOOLEAN; + +class TelemetryMQRModePropertyProviderTest { + private final DbClient dbClient = mock(); + private final PropertiesDao propertiesDao = mock(); + private final TelemetryMQRModePropertyProvider underTest = new TelemetryMQRModePropertyProvider(dbClient); + + @ParameterizedTest + @MethodSource("getValues") + void getter_should_return_correct_values(Boolean value, Boolean expected) { + when(dbClient.propertiesDao()).thenReturn(propertiesDao); + if (value == null) { + when(dbClient.propertiesDao().selectGlobalProperty(MULTI_QUALITY_MODE_ENABLED)) + .thenReturn(null); + } else { + when(dbClient.propertiesDao().selectGlobalProperty(MULTI_QUALITY_MODE_ENABLED)) + .thenReturn(new PropertyDto().setValue(value.toString())); + } + + assertEquals("multi_quality_rule_mode_enabled", underTest.getMetricKey()); + assertEquals(INSTALLATION, underTest.getDimension()); + assertEquals(WEEKLY, underTest.getGranularity()); + assertEquals(BOOLEAN, underTest.getType()); + assertEquals(Optional.of(expected), underTest.getValue()); + } + + public static Stream getValues() { + return Stream.of( + Arguments.of(true, true), + Arguments.of(false, false), + Arguments.of(null, false) + ); + } + +} diff --git a/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java b/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java index 758efac19cd..538964a8117 100644 --- a/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java +++ b/sonar-core/src/main/java/org/sonar/core/config/CorePropertyDefinitions.java @@ -68,6 +68,7 @@ public class CorePropertyDefinitions { defs.addAll(PurgeProperties.all()); defs.addAll(EmailSettings.definitions()); defs.addAll(ScannerProperties.all()); + defs.addAll(MQRModeProperties.all()); defs.addAll(asList( PropertyDefinition.builder(CoreProperties.MODULE_LEVEL_ARCHIVED_SETTINGS) diff --git a/sonar-core/src/main/java/org/sonar/core/config/MQRModeConstants.java b/sonar-core/src/main/java/org/sonar/core/config/MQRModeConstants.java new file mode 100644 index 00000000000..3a89d92b523 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/config/MQRModeConstants.java @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.core.config; + +public class MQRModeConstants { + + public static final String UI_MODE = "Mode"; + public static final String UI_MODE_SUB_CATEGORY = "Mode"; + public static final String MULTI_QUALITY_MODE_ENABLED = "sonar.multi-quality-mode.enabled"; + + private MQRModeConstants() { + //class cannot be instantiated + } +} diff --git a/sonar-core/src/main/java/org/sonar/core/config/MQRModeProperties.java b/sonar-core/src/main/java/org/sonar/core/config/MQRModeProperties.java new file mode 100644 index 00000000000..aee71806cf8 --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/config/MQRModeProperties.java @@ -0,0 +1,55 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.core.config; + +import java.util.Collections; +import java.util.List; +import org.sonar.api.PropertyType; +import org.sonar.api.config.PropertyDefinition; + +import static org.sonar.core.config.MQRModeConstants.UI_MODE; +import static org.sonar.core.config.MQRModeConstants.UI_MODE_SUB_CATEGORY; +import static org.sonar.core.config.MQRModeConstants.MULTI_QUALITY_MODE_ENABLED; + +public final class MQRModeProperties { + + private MQRModeProperties() { + } + + public static List all() { + return Collections.singletonList( + PropertyDefinition.builder(MULTI_QUALITY_MODE_ENABLED) + .defaultValue(Boolean.FALSE.toString()) + .name("Enable Multi-Quality Rule Mode") + .description("Aims to more accurately represent the impact software has on all software qualities. " + + "It does this by mapping rules to every software quality they can impact, not just the one " + + "they impact most significantly. Each rule has a separate severity " + + "for the impact it has on each quality that it has been mapped to. \n" + + "This approach focuses on ensuring the impact on all software qualities is clear, " + + "not just the most severe one.") + .type(PropertyType.BOOLEAN) + .category(UI_MODE) + .subCategory(UI_MODE_SUB_CATEGORY) + .index(1) + .build() + ); + + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/config/MQRModePropertiesTest.java b/sonar-core/src/test/java/org/sonar/core/config/MQRModePropertiesTest.java new file mode 100644 index 00000000000..78435aeccf4 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/config/MQRModePropertiesTest.java @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.core.config; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class MQRModePropertiesTest { + @Test + void all_shouldGetProperties() { + assertThat(MQRModeProperties.all()).hasSize(1); + } +} -- 2.39.5