123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- /*
- * SonarQube
- * Copyright (C) 2009-2023 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.application.command;
-
- import com.google.common.collect.ImmutableMap;
- import com.tngtech.java.junit.dataprovider.DataProvider;
- import com.tngtech.java.junit.dataprovider.DataProviderRunner;
- import com.tngtech.java.junit.dataprovider.UseDataProvider;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Locale;
- import java.util.Map;
- import java.util.Properties;
- import java.util.Random;
- import java.util.stream.Collectors;
- import java.util.stream.IntStream;
- import java.util.stream.Stream;
- import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.sonar.process.MessageException;
- import org.sonar.process.Props;
-
- import static java.lang.String.valueOf;
- import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
- import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
- import static org.assertj.core.api.Assertions.assertThat;
- import static org.assertj.core.api.Assertions.assertThatThrownBy;
- import static org.assertj.core.api.Assertions.fail;
-
- @RunWith(DataProviderRunner.class)
- public class JvmOptionsTest {
-
- private final Random random = new Random();
- private final String randomPropertyName = randomAlphanumeric(3);
- private final String randomPrefix = "-" + randomAlphabetic(5).toLowerCase(Locale.ENGLISH);
- private final String randomValue = randomAlphanumeric(4).toLowerCase(Locale.ENGLISH);
- private final Properties properties = new Properties();
- private final JvmOptions underTest = new JvmOptions();
-
- @Test
- public void constructor_without_arguments_creates_empty_JvmOptions() {
- JvmOptions<JvmOptions> testJvmOptions = new JvmOptions<>();
-
- assertThat(testJvmOptions.getAll()).isEmpty();
- }
-
- @Test
- public void constructor_throws_NPE_if_argument_is_null() {
- expectJvmOptionNotNullNPE(() -> new JvmOptions(null));
- }
-
- @Test
- public void constructor_throws_NPE_if_any_option_prefix_is_null() {
- Map<String, String> mandatoryJvmOptions = shuffleThenToMap(
- Stream.of(
- IntStream.range(0, random.nextInt(10)).mapToObj(i -> new Option("-B", valueOf(i))),
- Stream.of(new Option(null, "value")))
- .flatMap(s -> s));
-
- assertThatThrownBy(() -> new JvmOptions(mandatoryJvmOptions))
- .isInstanceOf(NullPointerException.class)
- .hasMessage("JVM option prefix can't be null");
- }
-
- @Test
- @UseDataProvider("variousEmptyStrings")
- public void constructor_throws_IAE_if_any_option_prefix_is_empty(String emptyString) {
- Map<String, String> mandatoryJvmOptions = shuffleThenToMap(
- Stream.of(
- IntStream.range(0, random.nextInt(10)).mapToObj(i -> new Option("-B", valueOf(i))),
- Stream.of(new Option(emptyString, "value")))
- .flatMap(s -> s));
-
- assertThatThrownBy(() -> new JvmOptions(mandatoryJvmOptions))
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("JVM option prefix can't be empty");
- }
-
- @Test
- public void constructor_throws_IAE_if_any_option_prefix_does_not_start_with_dash() {
- String invalidPrefix = randomAlphanumeric(3);
- Map<String, String> mandatoryJvmOptions = shuffleThenToMap(
- Stream.of(
- IntStream.range(0, random.nextInt(10)).mapToObj(i -> new Option("-B", valueOf(i))),
- Stream.of(new Option(invalidPrefix, "value")))
- .flatMap(s -> s));
-
- expectJvmOptionNotEmptyAndStartByDashIAE(() -> new JvmOptions(mandatoryJvmOptions));
- }
-
- @Test
- public void constructor_throws_NPE_if_any_option_value_is_null() {
- Map<String, String> mandatoryJvmOptions = shuffleThenToMap(
- Stream.of(
- IntStream.range(0, random.nextInt(10)).mapToObj(i -> new Option("-B", valueOf(i))),
- Stream.of(new Option("-prefix", null)))
- .flatMap(s -> s));
-
- assertThatThrownBy(() -> new JvmOptions(mandatoryJvmOptions))
- .isInstanceOf(NullPointerException.class)
- .hasMessage("JVM option value can't be null");
- }
-
- @Test
- @UseDataProvider("variousEmptyStrings")
- public void constructor_accepts_any_empty_option_value(String emptyString) {
- Map<String, String> mandatoryJvmOptions = shuffleThenToMap(
- Stream.of(
- IntStream.range(0, random.nextInt(10)).mapToObj(i -> new Option("-B", valueOf(i))),
- Stream.of(new Option("-prefix", emptyString)))
- .flatMap(s -> s));
-
- new JvmOptions(mandatoryJvmOptions);
- }
-
- @Test
- public void add_throws_NPE_if_argument_is_null() {
- expectJvmOptionNotNullNPE(() -> underTest.add(null));
- }
-
- @Test
- @UseDataProvider("variousEmptyStrings")
- public void add_throws_IAE_if_argument_is_empty(String emptyString) {
- expectJvmOptionNotEmptyAndStartByDashIAE(() -> underTest.add(emptyString));
- }
-
- @Test
- public void add_throws_IAE_if_argument_does_not_start_with_dash() {
- expectJvmOptionNotEmptyAndStartByDashIAE(() -> underTest.add(randomAlphanumeric(3)));
-
- }
-
- @Test
- @UseDataProvider("variousEmptyStrings")
- public void add_adds_with_trimming(String emptyString) {
- underTest.add(emptyString + "-foo" + emptyString);
-
- assertThat(underTest.getAll()).containsOnly("-foo");
- }
-
- @Test
- public void add_throws_MessageException_if_option_starts_with_prefix_of_mandatory_option_but_has_different_value() {
- String[] optionOverrides = {
- randomPrefix,
- randomPrefix + randomAlphanumeric(1),
- randomPrefix + randomAlphanumeric(2),
- randomPrefix + randomAlphanumeric(3),
- randomPrefix + randomAlphanumeric(4),
- randomPrefix + randomValue.substring(1),
- randomPrefix + randomValue.substring(2),
- randomPrefix + randomValue.substring(3)
- };
-
- JvmOptions underTest = new JvmOptions(ImmutableMap.of(randomPrefix, randomValue));
-
- for (String optionOverride : optionOverrides) {
- try {
- underTest.add(optionOverride);
- fail("an MessageException should have been thrown");
- } catch (MessageException e) {
- assertThat(e.getMessage()).isEqualTo("a JVM option can't overwrite mandatory JVM options. " + optionOverride + " overwrites " + randomPrefix + randomValue);
- }
- }
- }
-
- @Test
- public void add_checks_against_mandatory_options_is_case_sensitive() {
- String[] optionOverrides = {
- randomPrefix,
- randomPrefix + randomAlphanumeric(1),
- randomPrefix + randomAlphanumeric(2),
- randomPrefix + randomAlphanumeric(3),
- randomPrefix + randomAlphanumeric(4),
- randomPrefix + randomValue.substring(1),
- randomPrefix + randomValue.substring(2),
- randomPrefix + randomValue.substring(3)
- };
-
- JvmOptions underTest = new JvmOptions(ImmutableMap.of(randomPrefix, randomValue));
-
- for (String optionOverride : optionOverrides) {
- underTest.add(optionOverride.toUpperCase(Locale.ENGLISH));
- }
- }
-
- @Test
- public void add_accepts_property_equal_to_mandatory_option_and_does_not_add_it_twice() {
- JvmOptions underTest = new JvmOptions(ImmutableMap.of(randomPrefix, randomValue));
-
- underTest.add(randomPrefix + randomValue);
-
- assertThat(underTest.getAll()).containsOnly(randomPrefix + randomValue);
- }
-
- @Test
- public void addFromMandatoryProperty_fails_with_IAE_if_property_does_not_exist() {
- expectMissingPropertyIAE(() -> underTest.addFromMandatoryProperty(new Props(properties), this.randomPropertyName), this.randomPropertyName);
- }
-
- @Test
- public void addFromMandatoryProperty_fails_with_IAE_if_property_contains_an_empty_value() {
- expectMissingPropertyIAE(() -> underTest.addFromMandatoryProperty(new Props(properties), randomPropertyName), this.randomPropertyName);
- }
-
- @Test
- @UseDataProvider("variousEmptyStrings")
- public void addFromMandatoryProperty_adds_single_option_of_property_with_trimming(String emptyString) {
- properties.put(randomPropertyName, emptyString + "-foo" + emptyString);
-
- underTest.addFromMandatoryProperty(new Props(properties), randomPropertyName);
-
- assertThat(underTest.getAll()).containsOnly("-foo");
- }
-
- @Test
- @UseDataProvider("variousEmptyStrings")
- public void addFromMandatoryProperty_fails_with_MessageException_if_property_does_not_start_with_dash_after_trimmed(String emptyString) {
- properties.put(randomPropertyName, emptyString + "foo -bar");
-
- expectJvmOptionNotEmptyAndStartByDashMessageException(() -> underTest.addFromMandatoryProperty(new Props(properties), randomPropertyName), randomPropertyName, "foo");
- }
-
- @Test
- @UseDataProvider("variousEmptyStrings")
- public void addFromMandatoryProperty_adds_options_of_property_with_trimming(String emptyString) {
- properties.put(randomPropertyName, emptyString + "-foo" + emptyString + " -bar" + emptyString + " -duck" + emptyString);
-
- underTest.addFromMandatoryProperty(new Props(properties), randomPropertyName);
-
- assertThat(underTest.getAll()).containsOnly("-foo", "-bar", "-duck");
- }
-
- @Test
- public void addFromMandatoryProperty_supports_spaces_inside_options() {
- properties.put(randomPropertyName, "-foo bar -duck");
-
- underTest.addFromMandatoryProperty(new Props(properties), randomPropertyName);
-
- assertThat(underTest.getAll()).containsOnly("-foo bar", "-duck");
- }
-
- @Test
- public void addFromMandatoryProperty_throws_IAE_if_option_starts_with_prefix_of_mandatory_option_but_has_different_value() {
- String[] optionOverrides = {
- randomPrefix,
- randomPrefix + randomValue.substring(1),
- randomPrefix + randomValue.substring(1),
- randomPrefix + randomValue.substring(2),
- randomPrefix + randomValue.substring(3),
- randomPrefix + randomValue.substring(3) + randomAlphanumeric(1),
- randomPrefix + randomValue.substring(3) + randomAlphanumeric(2),
- randomPrefix + randomValue.substring(3) + randomAlphanumeric(3),
- randomPrefix + randomValue + randomAlphanumeric(1)
- };
-
- JvmOptions underTest = new JvmOptions(ImmutableMap.of(randomPrefix, randomValue));
-
- for (String optionOverride : optionOverrides) {
- try {
- properties.put(randomPropertyName, optionOverride);
- underTest.addFromMandatoryProperty(new Props(properties), randomPropertyName);
- fail("an MessageException should have been thrown");
- } catch (MessageException e) {
- assertThat(e.getMessage())
- .isEqualTo("a JVM option can't overwrite mandatory JVM options. " +
- "The following JVM options defined by property '" + randomPropertyName + "' are invalid: " + optionOverride + " overwrites " + randomPrefix + randomValue);
- }
- }
- }
-
- @Test
- public void addFromMandatoryProperty_checks_against_mandatory_options_is_case_sensitive() {
- String[] optionOverrides = {
- randomPrefix,
- randomPrefix + randomValue.substring(1),
- randomPrefix + randomValue.substring(1),
- randomPrefix + randomValue.substring(2),
- randomPrefix + randomValue.substring(3),
- randomPrefix + randomValue.substring(3) + randomAlphanumeric(1),
- randomPrefix + randomValue.substring(3) + randomAlphanumeric(2),
- randomPrefix + randomValue.substring(3) + randomAlphanumeric(3),
- randomPrefix + randomValue + randomAlphanumeric(1)
- };
-
- JvmOptions underTest = new JvmOptions(ImmutableMap.of(randomPrefix, randomValue));
-
- for (String optionOverride : optionOverrides) {
- properties.setProperty(randomPropertyName, optionOverride.toUpperCase(Locale.ENGLISH));
- underTest.addFromMandatoryProperty(new Props(properties), randomPropertyName);
- }
- }
-
- @Test
- public void addFromMandatoryProperty_reports_all_overriding_options_in_single_exception() {
- String overriding1 = randomPrefix;
- String overriding2 = randomPrefix + randomValue + randomAlphanumeric(1);
- properties.setProperty(randomPropertyName, "-foo " + overriding1 + " -bar " + overriding2);
-
- JvmOptions underTest = new JvmOptions(ImmutableMap.of(randomPrefix, randomValue));
-
- assertThatThrownBy(() -> underTest.addFromMandatoryProperty(new Props(properties), randomPropertyName))
- .isInstanceOf(MessageException.class)
- .hasMessage("a JVM option can't overwrite mandatory JVM options. " +
- "The following JVM options defined by property '" + randomPropertyName + "' are invalid: " +
- overriding1 + " overwrites " + randomPrefix + randomValue + ", " + overriding2 + " overwrites " + randomPrefix + randomValue);
- }
-
- @Test
- public void addFromMandatoryProperty_accepts_property_equal_to_mandatory_option_and_does_not_add_it_twice() {
- JvmOptions underTest = new JvmOptions(ImmutableMap.of(randomPrefix, randomValue));
-
- properties.put(randomPropertyName, randomPrefix + randomValue);
- underTest.addFromMandatoryProperty(new Props(properties), randomPropertyName);
-
- assertThat(underTest.getAll()).containsOnly(randomPrefix + randomValue);
- }
-
- @Test
- public void toString_prints_all_jvm_options() {
- underTest.add("-foo").add("-bar");
-
- assertThat(underTest).hasToString("[-foo, -bar]");
- }
-
- private void expectJvmOptionNotNullNPE(ThrowingCallable callback) {
- assertThatThrownBy(callback)
- .isInstanceOf(NullPointerException.class)
- .hasMessage("a JVM option can't be null");
- }
-
- private void expectJvmOptionNotEmptyAndStartByDashIAE(ThrowingCallable callback) {
- assertThatThrownBy(callback)
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("a JVM option can't be empty and must start with '-'");
- }
-
- private void expectJvmOptionNotEmptyAndStartByDashMessageException(ThrowingCallable callback, String randomPropertyName, String option) {
- assertThatThrownBy(callback)
- .isInstanceOf(MessageException.class)
- .hasMessage("a JVM option can't be empty and must start with '-'. " +
- "The following JVM options defined by property '" + randomPropertyName + "' are invalid: " + option);
- }
-
- public void expectMissingPropertyIAE(ThrowingCallable callback, String randomPropertyName) {
- assertThatThrownBy(callback)
- .isInstanceOf(IllegalArgumentException.class)
- .hasMessage("Missing property: " + randomPropertyName);
- }
-
- @DataProvider()
- public static Object[][] variousEmptyStrings() {
- return new Object[][] {
- {""},
- {" "},
- {" "}
- };
- }
-
- private static Map<String, String> shuffleThenToMap(Stream<Option> stream) {
- List<Option> options = stream.collect(Collectors.toCollection(ArrayList::new));
- Collections.shuffle(options);
- Map<String, String> res = new HashMap<>(options.size());
- for (Option option : options) {
- res.put(option.getPrefix(), option.getValue());
- }
- return res;
- }
-
- private static final class Option {
- private final String prefix;
- private final String value;
-
- private Option(String prefix, String value) {
- this.prefix = prefix;
- this.value = value;
- }
-
- public String getPrefix() {
- return prefix;
- }
-
- public String getValue() {
- return value;
- }
-
- @Override
- public String toString() {
- return "[" + prefix + "-" + value + ']';
- }
- }
- }
|