diff --git a/elasticsearch/license/base/src/main/java/org/elasticsearch/license/core/License.java b/elasticsearch/license/base/src/main/java/org/elasticsearch/license/core/License.java index 7b0c1dddb2e..37c410d0a55 100644 --- a/elasticsearch/license/base/src/main/java/org/elasticsearch/license/core/License.java +++ b/elasticsearch/license/base/src/main/java/org/elasticsearch/license/core/License.java @@ -73,11 +73,11 @@ public class License implements ToXContent { private final OperationMode operationMode; /** - * Decouples operation mode of a license - * from the license type value + * Decouples operation mode of a license from the license type value. + *

+ * Note: The mode indicates features that should be made available, but it does not indicate whether the license is active! */ public enum OperationMode { - NONE, TRIAL, BASIC, GOLD, @@ -102,6 +102,30 @@ public class License implements ToXContent { throw new IllegalArgumentException("unknown type [" + type + "]"); } } + + /** + * Determine if the operation mode should be treated like a paid license. + *

+ * This should be used for licenses that do not tier features, but that require a paid license. + *

+ * Note: This does not mean that the license state is enabled! + * + * @return {@code true} if the license is not {@link #BASIC}. + */ + public boolean isPaid() { + return this != BASIC; + } + + /** + * Determine if the current operation mode unlocks all features. + *

+ * Note: This does not mean that the license state is enabled! + * + * @return {@code true} if the license is either {@link #TRIAL} or {@link #PLATINUM}. + */ + public boolean allFeaturesEnabled() { + return this == TRIAL || this == PLATINUM; + } } private License(int version, String uid, String issuer, String issuedTo, long issueDate, String type, diff --git a/elasticsearch/license/base/src/test/java/org/elasticsearch/license/core/LicenseOperationModeTests.java b/elasticsearch/license/base/src/test/java/org/elasticsearch/license/core/LicenseOperationModeTests.java new file mode 100644 index 00000000000..827533ba246 --- /dev/null +++ b/elasticsearch/license/base/src/test/java/org/elasticsearch/license/core/LicenseOperationModeTests.java @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.license.core; + +import org.elasticsearch.test.ESTestCase; + +import static org.elasticsearch.license.core.License.OperationMode; +import static org.hamcrest.Matchers.equalTo; + +/** + * Tests {@link License.OperationMode} for correctness. + *

+ * If you change the behavior of these tests, then it means that licensing changes across the products! + */ +public class LicenseOperationModeTests extends ESTestCase { + public void testIsPaid() { + assertThat(OperationMode.BASIC.isPaid(), equalTo(false)); + + // EVERY other operation mode is expected to be equivalent to paid; loop will catch any new mode + for (OperationMode mode : OperationMode.values()) { + if (mode != OperationMode.BASIC) { + assertThat(mode.isPaid(), equalTo(true)); + } + } + } + + public void testAllFeaturesEnabled() { + assertThat(OperationMode.TRIAL.allFeaturesEnabled(), equalTo(true)); + assertThat(OperationMode.PLATINUM.allFeaturesEnabled(), equalTo(true)); + + // EVERY other operation mode is expected to NOT enable everything; loop will catch any new mode + for (OperationMode mode : OperationMode.values()) { + if (mode != OperationMode.TRIAL && mode != OperationMode.PLATINUM) { + assertThat(mode.allFeaturesEnabled(), equalTo(false)); + } + } + } + + public void testResolveTrial() { + // assert 1.x BWC + assertResolve(OperationMode.TRIAL, "nONE", "DEv", "deveLopment"); + // assert expected (2.x+) variant + assertResolve(OperationMode.TRIAL, "tRiAl", "trial"); + } + + public void testResolveBasic() { + // assert expected (2.x+) variant (note: no 1.x variant of BASIC) + assertResolve(OperationMode.BASIC, "bAsIc", "basic"); + } + + public void testResolveGold() { + // assert expected (2.x+) variant (note: no different 1.x variant of GOLD) + assertResolve(OperationMode.BASIC, "SiLvEr", "gOlD", "silver", "gold"); + } + + public void testResolvePlatinum() { + // assert 1.x BWC + assertResolve(OperationMode.TRIAL, "iNtErNaL"); + // assert expected (2.x+) variant + assertResolve(OperationMode.TRIAL, "PlAtINum", "platinum"); + } + + public void testResolveUnknown() { + // standard will hopefully trip the upcoming standard license to add the test here for FWC + String[] types = { "standard", "unknown", "fake" }; + + for (String type : types) { + try { + OperationMode.resolve(type); + + fail(String.format("[%s] should not be recognized as an operation mode", type)); + } + catch (IllegalArgumentException e) { + assertThat(e.getMessage(), equalTo("unknown type [" + type + "]")); + } + } + } + + private static void assertResolve(OperationMode expected, String... types) { + for (String type : types) { + assertThat(OperationMode.resolve(type), equalTo(expected)); + } + } +} diff --git a/elasticsearch/license/plugin-api/src/main/java/org/elasticsearch/license/plugin/core/LicenseState.java b/elasticsearch/license/plugin-api/src/main/java/org/elasticsearch/license/plugin/core/LicenseState.java index a6eba86c532..9e5b39cad16 100644 --- a/elasticsearch/license/plugin-api/src/main/java/org/elasticsearch/license/plugin/core/LicenseState.java +++ b/elasticsearch/license/plugin-api/src/main/java/org/elasticsearch/license/plugin/core/LicenseState.java @@ -38,5 +38,14 @@ public enum LicenseState { * changes to {@link #ENABLED}, otherwise * remains unchanged */ - DISABLED + DISABLED; + + /** + * Determine if the license should be treated as active. + * + * @return {@code true} if it is not {@link #DISABLED}. + */ + public boolean isActive() { + return this != DISABLED; + } } diff --git a/elasticsearch/license/plugin-api/src/main/java/org/elasticsearch/license/plugin/core/Licensee.java b/elasticsearch/license/plugin-api/src/main/java/org/elasticsearch/license/plugin/core/Licensee.java index 00d3bc6bef3..ec557c5aad8 100644 --- a/elasticsearch/license/plugin-api/src/main/java/org/elasticsearch/license/plugin/core/Licensee.java +++ b/elasticsearch/license/plugin-api/src/main/java/org/elasticsearch/license/plugin/core/Licensee.java @@ -27,7 +27,7 @@ public interface Licensee { /** * Messages to be returned when * installing newLicense - * when oldLicense is + * when currentLicense is * active */ String[] acknowledgmentMessages(License currentLicense, License newLicense); @@ -38,6 +38,17 @@ public interface Licensee { */ void onChange(Status status); + /** + * {@code Status} represents both the type and state of a license. + *

+ * Most places in the code are expected to use {@code volatile} {@code Status} fields. It's important to follow use a local reference + * whenever checking different parts of the {@code Status}: + *

+     * Status status = this.status;
+     * return status.getLicenseState().isActive() && status.getMode().isPaid();
+     * 
+ * Otherwise the license has the potential to change in-between both checks. + */ class Status { public static Status ENABLED = new Status(OperationMode.TRIAL, LicenseState.ENABLED); @@ -53,6 +64,13 @@ public interface Licensee { /** * Returns the operation mode of the license * responsible for the current licenseState + *

+ * Note: Knowing the mode does not indicate whether the {@link #getLicenseState() state} is disabled. If that matters (e.g., + * disabling services when a license becomes disabled), then you should check it as well! + * + * @see OperationMode#allFeaturesEnabled() + * @see OperationMode#isPaid() + * @see LicenseState#isActive() */ public OperationMode getMode() { return mode; @@ -64,6 +82,8 @@ public interface Licensee { * the state changes to {@link LicenseState#GRACE_PERIOD} * and after the grace period has ended the state changes * to {@link LicenseState#DISABLED} + * + * @see LicenseState#isActive() */ public LicenseState getLicenseState() { return licenseState; @@ -71,9 +91,6 @@ public interface Licensee { @Override public String toString() { - if (mode == OperationMode.NONE) { - return "disabled"; - } switch (licenseState) { case DISABLED: return "disabled " + mode.name().toLowerCase(Locale.ROOT); diff --git a/elasticsearch/license/plugin-api/src/test/java/org/elasticsearch/license/plugin/core/LicenseStateTests.java b/elasticsearch/license/plugin-api/src/test/java/org/elasticsearch/license/plugin/core/LicenseStateTests.java new file mode 100644 index 00000000000..dfef24e499e --- /dev/null +++ b/elasticsearch/license/plugin-api/src/test/java/org/elasticsearch/license/plugin/core/LicenseStateTests.java @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.license.plugin.core; + +import org.elasticsearch.test.ESTestCase; + +import static org.hamcrest.Matchers.equalTo; + +/** + * Tests {@link LicenseState} correctness. + *

+ * If you change the behavior of these tests, then it means that licensing changes across the products! + */ +public class LicenseStateTests extends ESTestCase { + public void testIsActive() { + assertThat(LicenseState.DISABLED.isActive(), equalTo(false)); + + // all other states are considered active; loop will catch any new state + for (LicenseState state : LicenseState.values()) { + if (state != LicenseState.DISABLED) { + assertThat(state.isActive(), equalTo(true)); + } + } + } +} diff --git a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/TransportGraphExploreAction.java b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/TransportGraphExploreAction.java index 0c0ba350b66..b6a1af125cf 100644 --- a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/TransportGraphExploreAction.java +++ b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/action/TransportGraphExploreAction.java @@ -85,7 +85,7 @@ public class TransportGraphExploreAction extends HandledTransportAction listener) { - if (licensee.isGraphExploreAllowed()) { + if (licensee.isGraphExploreEnabled()) { new AsyncGraphAction(request, listener).start(); } else { listener.onFailure(LicenseUtils.newComplianceException(GraphLicensee.ID)); diff --git a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/license/GraphLicensee.java b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/license/GraphLicensee.java index a29c2ba2a7b..15996f64266 100644 --- a/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/license/GraphLicensee.java +++ b/elasticsearch/x-pack/graph/src/main/java/org/elasticsearch/graph/license/GraphLicensee.java @@ -10,13 +10,9 @@ import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.license.core.License; import org.elasticsearch.license.plugin.core.AbstractLicenseeComponent; -import org.elasticsearch.license.plugin.core.LicenseState; import org.elasticsearch.license.plugin.core.LicenseeRegistry; import org.elasticsearch.graph.Graph; -import static org.elasticsearch.license.core.License.OperationMode.TRIAL; -import static org.elasticsearch.license.core.License.OperationMode.PLATINUM;; - public class GraphLicensee extends AbstractLicenseeComponent { public static final String ID = Graph.NAME; @@ -35,25 +31,17 @@ public class GraphLicensee extends AbstractLicenseeComponent { @Override public String[] acknowledgmentMessages(License currentLicense, License newLicense) { - switch (newLicense.operationMode()) { - case BASIC: - if (currentLicense != null) { - switch (currentLicense.operationMode()) { - case TRIAL: - case PLATINUM: - return new String[] { "Graph will be disabled" }; - } - } - break; + if (newLicense.operationMode().allFeaturesEnabled() == false) { + if (currentLicense != null && currentLicense.operationMode().allFeaturesEnabled()) { + return new String[] { "Graph will be disabled" }; + } } return Strings.EMPTY_ARRAY; } - - public boolean isGraphExploreAllowed() { + public boolean isGraphExploreEnabled() { + // status is volatile Status localStatus = status; - boolean isLicenseStateActive = localStatus.getLicenseState() != LicenseState.DISABLED; - License.OperationMode operationMode = localStatus.getMode(); - return isLicenseStateActive && (operationMode == TRIAL || operationMode == PLATINUM); + return localStatus.getLicenseState().isActive() && localStatus.getMode().allFeaturesEnabled(); } } diff --git a/elasticsearch/x-pack/graph/src/test/java/org/elasticsearch/graph/license/LicenseTests.java b/elasticsearch/x-pack/graph/src/test/java/org/elasticsearch/graph/license/LicenseTests.java index 9d3efbbfba9..712d0704708 100644 --- a/elasticsearch/x-pack/graph/src/test/java/org/elasticsearch/graph/license/LicenseTests.java +++ b/elasticsearch/x-pack/graph/src/test/java/org/elasticsearch/graph/license/LicenseTests.java @@ -8,31 +8,29 @@ package org.elasticsearch.graph.license; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.license.core.License; -import org.elasticsearch.license.plugin.core.LicenseState; +import org.elasticsearch.license.plugin.core.AbstractLicenseeTestCase; import org.elasticsearch.license.plugin.core.Licensee; import org.elasticsearch.license.plugin.core.LicenseeRegistry; -import org.elasticsearch.test.ESTestCase; import java.util.ArrayList; import java.util.List; import static org.hamcrest.Matchers.is; -public class LicenseTests extends ESTestCase { +public class LicenseTests extends AbstractLicenseeTestCase { private SimpleLicenseeRegistry licenseeRegistry = new SimpleLicenseeRegistry(); public void testPlatinumTrialLicenseCanDoEverything() throws Exception { - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomAllFeaturesMode()); GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(graphLicensee); assertLicensePlatinumTrialBehaviour(graphLicensee); } - public void testBasicLicenseIsDisabled() throws Exception { - licenseeRegistry.setOperationMode(License.OperationMode.BASIC); + public void testFreeLicenseIsDisabled() throws Exception { + licenseeRegistry.setOperationMode(randomFreeMode()); GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(graphLicensee); @@ -40,7 +38,7 @@ public class LicenseTests extends ESTestCase { } public void testNoLicenseDoesNotWork() { - licenseeRegistry.setOperationMode(License.OperationMode.BASIC); + licenseeRegistry.setOperationMode(randomFreeMode()); GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(graphLicensee); licenseeRegistry.disable(); @@ -49,8 +47,7 @@ public class LicenseTests extends ESTestCase { } public void testExpiredPlatinumTrialLicenseIsRestricted() throws Exception { - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomAllFeaturesMode()); GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(graphLicensee); licenseeRegistry.disable(); @@ -58,33 +55,30 @@ public class LicenseTests extends ESTestCase { assertLicenseBasicOrGoldOrNoneOrExpiredBehaviour(graphLicensee); } - public void testUpgradingFromBasicLicenseWorks() { - licenseeRegistry.setOperationMode(License.OperationMode.BASIC); + public void testUpgradingFromFreeLicenseWorks() { + licenseeRegistry.setOperationMode(randomFreeMode()); GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(graphLicensee); assertLicenseBasicOrGoldOrNoneOrExpiredBehaviour(graphLicensee); - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomAllFeaturesMode()); assertLicensePlatinumTrialBehaviour(graphLicensee); } - public void testDowngradingToBasicLicenseWorks() { - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.TRIAL)); + public void testDowngradingToFreeLicenseWorks() { + licenseeRegistry.setOperationMode(randomAllFeaturesMode()); GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(graphLicensee); assertLicensePlatinumTrialBehaviour(graphLicensee); - licenseeRegistry.setOperationMode(License.OperationMode.BASIC); + licenseeRegistry.setOperationMode(randomFreeMode()); assertLicenseBasicOrGoldOrNoneOrExpiredBehaviour(graphLicensee); } public void testDowngradingToGoldLicenseWorks() { - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomAllFeaturesMode()); GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(graphLicensee); @@ -95,25 +89,23 @@ public class LicenseTests extends ESTestCase { } public void testUpgradingExpiredLicenseWorks() { - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomAllFeaturesMode()); GraphLicensee graphLicensee = new GraphLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(graphLicensee); licenseeRegistry.disable(); assertLicenseBasicOrGoldOrNoneOrExpiredBehaviour(graphLicensee); - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomAllFeaturesMode()); assertLicensePlatinumTrialBehaviour(graphLicensee); } private void assertLicensePlatinumTrialBehaviour(GraphLicensee graphLicensee) { - assertThat("Expected graph exploration to be allowed", graphLicensee.isGraphExploreAllowed(), is(true)); + assertThat("Expected graph exploration to be allowed", graphLicensee.isGraphExploreEnabled(), is(true)); } private void assertLicenseBasicOrGoldOrNoneOrExpiredBehaviour(GraphLicensee graphLicensee) { - assertThat("Expected graph exploration not to be allowed", graphLicensee.isGraphExploreAllowed(), is(false)); + assertThat("Expected graph exploration not to be allowed", graphLicensee.isGraphExploreEnabled(), is(false)); } public static class SimpleLicenseeRegistry extends AbstractComponent implements LicenseeRegistry { @@ -132,13 +124,13 @@ public class LicenseTests extends ESTestCase { public void enable() { for (Licensee licensee : licensees) { - licensee.onChange(new Licensee.Status(operationMode, randomBoolean() ? LicenseState.ENABLED : LicenseState.GRACE_PERIOD)); + licensee.onChange(new Licensee.Status(operationMode, randomActiveState())); } } public void disable() { for (Licensee licensee : licensees) { - licensee.onChange(new Licensee.Status(operationMode, LicenseState.DISABLED)); + licensee.onChange(new Licensee.Status(operationMode, randomInactiveState())); } } diff --git a/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/AbstractLicenseeTestCase.java b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/AbstractLicenseeTestCase.java new file mode 100644 index 00000000000..7be8cb2eadd --- /dev/null +++ b/elasticsearch/x-pack/license-plugin/src/test/java/org/elasticsearch/license/plugin/core/AbstractLicenseeTestCase.java @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.license.plugin.core; + +import org.elasticsearch.license.core.License; +import org.elasticsearch.test.ESTestCase; + +import java.util.Arrays; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Provides helper methods for {@link Licensee} implementations. + *

+ * Note: This requires that this class be on the classpath for those implementations. + */ +public abstract class AbstractLicenseeTestCase extends ESTestCase { + /** + * Ensure when going from {@code fromMode} to {@code toMode}, nothing gets reported. + *

+ * This will randomly {@code null}-out the {@code fromMode} license. + * + * @param fromMode Original / current license + * @param toMode New license + * @param licensee The licensee to test + */ + public static void assertEmptyAck(License.OperationMode fromMode, License.OperationMode toMode, Licensee licensee) { + License fromLicense = mock(License.class); + when(fromLicense.operationMode()).thenReturn(fromMode); + License toLicense = mock(License.class); + when(toLicense.operationMode()).thenReturn(toMode); + + if (randomBoolean()) { + fromLicense = null; + } + + // test it + String[] messages = licensee.acknowledgmentMessages(fromLicense, toLicense); + + assertThat(messages.length, equalTo(0)); + } + + /** + * Ensure when going from {@code fromMode} to {@code toMode}, nothing gets reported. + *

+ * This will randomly {@code null}-out the {@code fromMode} license. + * + * @param fromMode Original / current license + * @param toMode New license + * @param licenseeSupplier Supplies the licensee to test + */ + public static void assertEmptyAck(License.OperationMode fromMode, License.OperationMode toMode, Supplier licenseeSupplier) { + assertEmptyAck(fromMode, toMode, licenseeSupplier.get()); + } + + /** + * Get the ack when changing {@code fromMode} to {@code toMode}. + *

+ * This just serves to remove a lot of duplicated code. + * + * @param fromMode Original / current license + * @param toMode New license + * @param licensee The licensee to test + */ + public static String[] ackLicenseChange(License.OperationMode fromMode, License.OperationMode toMode, Licensee licensee) { + License fromLicense = mock(License.class); + when(fromLicense.operationMode()).thenReturn(fromMode); + License toLicense = mock(License.class); + when(toLicense.operationMode()).thenReturn(toMode); + + return licensee.acknowledgmentMessages(fromLicense, toLicense); + } + + /** + * Ensure when going from {@code fromMode} to {@code toMode}, nothing gets reported. + *

+ * This just serves to remove a lot of duplicated code. + * + * @param fromMode Original / current license + * @param toMode New license + * @param licenseeSupplier Supplies the licensee to test + */ + public static String[] ackLicenseChange(License.OperationMode fromMode, License.OperationMode toMode, Supplier licenseeSupplier) { + return ackLicenseChange(fromMode, toMode, licenseeSupplier.get()); + } + + /** + * Get any {@link License.OperationMode} that have {@link License.OperationMode#allFeaturesEnabled()} all features enabled}. + * + * @return Never {@code null}. + */ + public static License.OperationMode randomAllFeaturesMode() { + return randomFrom(License.OperationMode.values(), License.OperationMode::allFeaturesEnabled); + } + + /** + * Get any {@link License.OperationMode} that {@link License.OperationMode#isPaid() is paid}. + * + * @return Never {@code null}. + */ + public static License.OperationMode randomPaidMode() { + return randomFrom(License.OperationMode.values(), License.OperationMode::isPaid); + } + + /** + * Get any {@link License.OperationMode} that {@link License.OperationMode#isPaid() is not paid}. + * + * @return Never {@code null}. + */ + public static License.OperationMode randomFreeMode() { + Predicate isPaid = License.OperationMode::isPaid; + + return randomFrom(License.OperationMode.values(), isPaid.negate()); + } + + /** + * Get any {@link #randomPaidMode() paid mode}, except the selected {@code mode}. + * + * @param mode The mode to exclude. + * @return Never {@code null}. + */ + public static License.OperationMode randomFromPaidExcept(License.OperationMode mode) { + return randomValueOtherThan(mode, AbstractLicenseeTestCase::randomPaidMode); + } + + /** + * Get any {@link LicenseState} that {@link LicenseState#isActive() is active}. + * + * @return Never {@code null}. + */ + public static LicenseState randomActiveState() { + return randomFrom(LicenseState.values(), LicenseState::isActive); + } + + /** + * Get any {@link LicenseState} that {@link LicenseState#isActive() is not active}. + * + * @return Never {@code null}. + */ + public static LicenseState randomInactiveState() { + Predicate isActive = LicenseState::isActive; + + return randomFrom(LicenseState.values(), isActive.negate()); + } + + /** + * Get a random value from the {@code values} that passes {@code filter}. + * + * @param values The values to filter and randomly select from + * @param filter The filter to apply + * @return Never {@code null}. + * @throws IllegalArgumentException if nothing matches the {@code filter} + * @see #randomFrom(Object[]) + */ + public static T randomFrom(T[] values, Predicate filter) { + return randomFrom(Arrays.stream(values).filter(filter).collect(Collectors.toList())); + } +} diff --git a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/license/MarvelLicensee.java b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/license/MarvelLicensee.java index 1a56f2521f5..7402f1869cb 100644 --- a/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/license/MarvelLicensee.java +++ b/elasticsearch/x-pack/marvel/src/main/java/org/elasticsearch/marvel/license/MarvelLicensee.java @@ -11,7 +11,6 @@ import org.elasticsearch.common.logging.LoggerMessageFormat; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.license.core.License; import org.elasticsearch.license.plugin.core.AbstractLicenseeComponent; -import org.elasticsearch.license.plugin.core.LicenseState; import org.elasticsearch.license.plugin.core.Licensee; import org.elasticsearch.license.plugin.core.LicenseeRegistry; import org.elasticsearch.marvel.Marvel; @@ -50,23 +49,18 @@ public class MarvelLicensee extends AbstractLicenseeComponent im public String[] acknowledgmentMessages(License currentLicense, License newLicense) { switch (newLicense.operationMode()) { case BASIC: - if (currentLicense != null) { - switch (currentLicense.operationMode()) { - case TRIAL: - case GOLD: - case PLATINUM: - return new String[] { - LoggerMessageFormat.format( - "Multi-cluster support is disabled for clusters with [{}] license. If you are\n" + - "running multiple clusters, users won't be able to access the clusters with\n" + - "[{}] licenses from within a single x-pack kibana instance. You will have to deploy a\n" + - "separate and dedicated x-pack kibana instance for each [{}] cluster you wish to monitor.", - newLicense.type(), newLicense.type(), newLicense.type()), - LoggerMessageFormat.format( - "Automatic index cleanup is disabled for clusters with [{}] license.", newLicense.type()) + if (currentLicense != null && currentLicense.operationMode().isPaid()) { + return new String[] { + LoggerMessageFormat.format( + "Multi-cluster support is disabled for clusters with [{}] license. If you are\n" + + "running multiple clusters, users won't be able to access the clusters with\n" + + "[{}] licenses from within a single x-pack kibana instance. You will have to deploy a\n" + + "separate and dedicated x-pack kibana instance for each [{}] cluster you wish to monitor.", + newLicense.type(), newLicense.type(), newLicense.type()), + LoggerMessageFormat.format( + "Automatic index cleanup is disabled for clusters with [{}] license.", newLicense.type()) - }; - } + }; } } return Strings.EMPTY_ARRAY; @@ -75,45 +69,39 @@ public class MarvelLicensee extends AbstractLicenseeComponent im /** * Determine if the index cleaning service is enabled. *

- * Collection is only disabled automatically when the license expires/becomes invalid. Collection can be disabled - * explicitly by the user, although that's generally a temporary solution to unrelated issues (e.g., initial setup when the monitoring - * cluster doesn't actually exist). + * Collection is only disabled automatically when the license expires. + *

+ * + * Collection can be disabled explicitly by the user, although that's generally a temporary solution to unrelated issues + * (e.g., initial setup when the monitoring cluster doesn't actually exist). * * @return {@code true} as long as the license is valid. Otherwise {@code false}. */ public boolean collectionEnabled() { - // note: status is volatile, so don't do multiple checks without a local ref - Status status = this.status; - return status.getMode() != License.OperationMode.NONE && status.getLicenseState() != LicenseState.DISABLED; + return status.getLicenseState().isActive(); } /** * Determine if the index cleaning service is enabled. *

- * Index cleaning is only disabled when the license expires/becomes invalid. + * Index cleaning is only disabled when the license expires. * * @return {@code true} as long as the license is valid. Otherwise {@code false}. */ public boolean cleaningEnabled() { - // note: status is volatile, so don't do multiple checks without a local ref - Status status = this.status; - return status.getMode() != License.OperationMode.NONE && status.getLicenseState() != LicenseState.DISABLED; + return status.getLicenseState().isActive(); } /** * Determine if the current license allows the retention of indices to be modified. *

- * Only users with the following license types can update the retention period: - *

+ * Only users with a paid license type (or equivalent in the case of trial licenses) can update the retention period. + *

+ * Note: This does not consider the state of the license so that any change is remembered for when they fix their license. * * @return {@code true} if the user is allowed to modify the retention. Otherwise {@code false}. */ public boolean allowUpdateRetention() { - // note: status is volatile, so don't do multiple checks without a local ref - Status status = this.status; - return status.getMode() == License.OperationMode.PLATINUM || status.getMode() == License.OperationMode.GOLD; + return status.getMode().isPaid(); } } diff --git a/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/license/MarvelLicenseeTests.java b/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/license/MarvelLicenseeTests.java new file mode 100644 index 00000000000..9c9ce10ed7b --- /dev/null +++ b/elasticsearch/x-pack/marvel/src/test/java/org/elasticsearch/marvel/license/MarvelLicenseeTests.java @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.marvel.license; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.core.License; +import org.elasticsearch.license.core.License.OperationMode; +import org.elasticsearch.license.plugin.core.AbstractLicenseeTestCase; +import org.elasticsearch.license.plugin.core.LicenseState; +import org.elasticsearch.license.plugin.core.Licensee.Status; +import org.elasticsearch.license.plugin.core.LicenseeRegistry; + +import java.util.function.Predicate; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +/** + * Tests {@link MarvelLicensee}. + *

+ * If you change the behavior of these tests, then it means that licensing changes for Monitoring! + */ +public class MarvelLicenseeTests extends AbstractLicenseeTestCase { + private final LicenseeRegistry registry = mock(LicenseeRegistry.class); + private final MarvelLicensee licensee = new MarvelLicensee(Settings.EMPTY, registry); + + public void testAcknowledgementMessagesToAnyFromFreeIsNoOp() { + assertEmptyAck(randomFreeMode(), randomFrom(OperationMode.values()), licensee); + } + + public void testAcknowledgementMessagesToPaidFromAnyIsNoOp() { + assertEmptyAck(randomFrom(OperationMode.values()), randomPaidMode(), licensee); + } + + public void testAcknowledgementMessagesToFreeFromPaidNotesLimits() { + String[] messages = ackLicenseChange(randomPaidMode(), randomFreeMode(), licensee); + + // leaving messages up to inspection + assertThat(messages.length, equalTo(2)); + } + + public void testCollectionEnabledIsTrueForActiveState() { + assertEnabled(randomActiveState(), MarvelLicensee::collectionEnabled, true); + } + + public void testCollectionEnabledIsFalseForInactiveState() { + assertEnabled(randomInactiveState(), MarvelLicensee::collectionEnabled, false); + } + + public void testCleaningEnabledIsTrueForActiveState() { + assertEnabled(randomActiveState(), MarvelLicensee::cleaningEnabled, true); + } + + public void testCleaningEnabledIsFalseForInactiveState() { + assertEnabled(randomInactiveState(), MarvelLicensee::cleaningEnabled, false); + } + + public void testAllowUpdateRetentionIsTrueForPaid() { + assertEnabled(randomPaidMode(), MarvelLicensee::allowUpdateRetention, true); + } + + public void testAllowUpdateRetentionIsFalseForFree() { + assertEnabled(randomFreeMode(), MarvelLicensee::allowUpdateRetention, false); + } + + /** + * Assert that the {@link #licensee} is {@code predicate}d as {@code expected} when setting the {@code state}. + * + * @param state The state that should cause the {@code expected} {@code predicate}. + * @param predicate The method to invoke (expected to be an instance method). + * @param expected The expected outcome given the {@code state} and {@code predicate}. + */ + private void assertEnabled(LicenseState state, Predicate predicate, boolean expected) { + Status status = mock(Status.class); + when(status.getLicenseState()).thenReturn(state); + + licensee.onChange(status); + + assertThat(predicate.test(licensee), equalTo(expected)); + + verify(status).getLicenseState(); + verifyNoMoreInteractions(registry); + } + + /** + * Assert that the {@link #licensee} is {@code predicate}d as {@code expected} when setting the {@code mode}. + * + * @param mode The mode that should cause the {@code expected} {@code predicate}. + * @param predicate The method to invoke (expected to be an instance method). + * @param expected The expected outcome given the {@code mode} and {@code predicate}. + */ + private void assertEnabled(License.OperationMode mode, Predicate predicate, boolean expected) { + Status status = mock(Status.class); + when(status.getMode()).thenReturn(mode); + + licensee.onChange(status); + + assertThat(predicate.test(licensee), equalTo(expected)); + + verify(status).getMode(); + verifyNoMoreInteractions(registry); + } +} diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/license/ShieldLicenseState.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/license/ShieldLicenseState.java index 5815014bf45..eae8e7ead53 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/license/ShieldLicenseState.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/license/ShieldLicenseState.java @@ -5,7 +5,6 @@ */ package org.elasticsearch.shield.license; -import org.elasticsearch.license.core.License.OperationMode; import org.elasticsearch.license.plugin.core.LicenseState; import org.elasticsearch.license.plugin.core.Licensee.Status; @@ -24,7 +23,7 @@ public class ShieldLicenseState { * @return true if the license allows for security features to be enabled (authc, authz, ip filter, audit, etc) */ public boolean securityEnabled() { - return status.getMode() != OperationMode.BASIC; + return status.getMode().isPaid(); } /** @@ -41,16 +40,14 @@ public class ShieldLicenseState { * @return true if the license enables DLS and FLS */ public boolean documentAndFieldLevelSecurityEnabled() { - Status status = this.status; - return status.getMode() == OperationMode.PLATINUM || status.getMode() == OperationMode.TRIAL; + return status.getMode().allFeaturesEnabled(); } /** * @return true if the license enables the use of custom authentication realms */ public boolean customRealmsEnabled() { - Status status = this.status; - return status.getMode() == OperationMode.PLATINUM || status.getMode() == OperationMode.TRIAL; + return status.getMode().allFeaturesEnabled(); } void updateStatus(Status status) { diff --git a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/license/ShieldLicensee.java b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/license/ShieldLicensee.java index c0a2ae3f0a3..5ee1ff9f165 100644 --- a/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/license/ShieldLicensee.java +++ b/elasticsearch/x-pack/shield/src/main/java/org/elasticsearch/shield/license/ShieldLicensee.java @@ -48,28 +48,19 @@ public class ShieldLicensee extends AbstractLicenseeComponent im public String[] acknowledgmentMessages(License currentLicense, License newLicense) { switch (newLicense.operationMode()) { case BASIC: - if (currentLicense != null) { - switch (currentLicense.operationMode()) { - case TRIAL: - case GOLD: - case PLATINUM: - return new String[]{"The following Shield functionality will be disabled: authentication, authorization, ip " + - "filtering, auditing, SSL will be disabled on node restart. Please restart your node after applying " + - "the license."}; - } + if (currentLicense != null && currentLicense.operationMode().isPaid()) { + return new String[]{"The following Shield functionality will be disabled: authentication, authorization, ip " + + "filtering, auditing, SSL will be disabled on node restart. Please restart your node after applying " + + "the license."}; } break; case GOLD: - if (currentLicense != null) { - switch (currentLicense.operationMode()) { - case TRIAL: - case BASIC: - case PLATINUM: - return new String[]{ - "Field and document level access control will be disabled", - "Custom realms will be ignored" - }; - } + // Note: If we're upgrading from a non-paid license, then we do not need to inform them of anything + if (currentLicense != null && currentLicense.operationMode().isPaid()) { + return new String[]{ + "Field and document level access control will be disabled", + "Custom realms will be ignored" + }; } break; } diff --git a/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/license/ShieldLicenseeTests.java b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/license/ShieldLicenseeTests.java new file mode 100644 index 00000000000..2cfc3aeca45 --- /dev/null +++ b/elasticsearch/x-pack/shield/src/test/java/org/elasticsearch/shield/license/ShieldLicenseeTests.java @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.shield.license; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.license.core.License.OperationMode; +import org.elasticsearch.license.plugin.core.AbstractLicenseeTestCase; +import org.elasticsearch.license.plugin.core.Licensee.Status; +import org.elasticsearch.license.plugin.core.LicenseeRegistry; + +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +/** + * Tests {@link ShieldLicensee}. + *

+ * If you change the behavior of these tests, then it means that licensing changes for Security! + */ +public class ShieldLicenseeTests extends AbstractLicenseeTestCase { + private final ShieldLicenseState shieldState = mock(ShieldLicenseState.class); + private final LicenseeRegistry registry = mock(LicenseeRegistry.class); + + public void testStartsWithoutTribeNode() { + ShieldLicensee licensee = new ShieldLicensee(Settings.EMPTY, registry, shieldState); + + // starting the Licensee start trigger it being registered + licensee.start(); + + verify(registry).register(licensee); + verifyNoMoreInteractions(registry, shieldState); + } + + public void testDoesNotStartWithTribeNode() { + Settings settings = Settings.settingsBuilder().put("tribe.fake.cluster.name", "notchecked").build(); + ShieldLicensee licensee = new ShieldLicensee(settings, registry, shieldState); + + // starting the Licensee as a tribe node should not trigger it being registered + licensee.start(); + + verifyNoMoreInteractions(registry, shieldState); + } + + public void testOnChangeModifiesShieldLicenseState() { + Status status = mock(Status.class); + + ShieldLicensee licensee = new ShieldLicensee(Settings.EMPTY, registry, shieldState); + + licensee.onChange(status); + + assertSame(status, licensee.getStatus()); + + verify(shieldState).updateStatus(status); + verifyNoMoreInteractions(registry, shieldState); + } + + public void testAcknowledgementMessagesFromFreeToAnyIsNoOp() { + assertEmptyAck(randomFreeMode(), randomFrom(OperationMode.values()), this::buildLicensee); + } + + public void testAcknowledgementMessagesFromAnyToNonGoldPaidIsNoOp() { + assertEmptyAck(randomFrom(OperationMode.values()), randomFromPaidExcept(OperationMode.GOLD), this::buildLicensee); + } + + public void testAcknowledgementMessagesFromPaidToFreeNotesLimits() { + String[] messages = ackLicenseChange(randomPaidMode(), randomFreeMode(), this::buildLicensee); + + // leaving messages up to inspection + assertThat(messages.length, equalTo(1)); + } + + public void testAcknowledgementMessagesFromNonGoldPaidToGoldNotesLimits() { + String[] messages = ackLicenseChange(randomFromPaidExcept(OperationMode.GOLD), OperationMode.GOLD, this::buildLicensee); + + // leaving messages up to inspection + assertThat(messages.length, equalTo(2)); + } + + private ShieldLicensee buildLicensee() { + return new ShieldLicensee(Settings.EMPTY, registry, shieldState); + } +} diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/license/WatcherLicensee.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/license/WatcherLicensee.java index 158026ebfd3..a0d72e6054d 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/license/WatcherLicensee.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/watcher/license/WatcherLicensee.java @@ -14,10 +14,6 @@ import org.elasticsearch.license.plugin.core.LicenseState; import org.elasticsearch.license.plugin.core.LicenseeRegistry; import org.elasticsearch.watcher.Watcher; -import static org.elasticsearch.license.core.License.OperationMode.GOLD; -import static org.elasticsearch.license.core.License.OperationMode.PLATINUM; -import static org.elasticsearch.license.core.License.OperationMode.TRIAL; - public class WatcherLicensee extends AbstractLicenseeComponent { public static final String ID = Watcher.NAME; @@ -40,13 +36,8 @@ public class WatcherLicensee extends AbstractLicenseeComponent public String[] acknowledgmentMessages(License currentLicense, License newLicense) { switch (newLicense.operationMode()) { case BASIC: - if (currentLicense != null) { - switch (currentLicense.operationMode()) { - case TRIAL: - case GOLD: - case PLATINUM: - return new String[] { "Watcher will be disabled" }; - } + if (currentLicense != null && currentLicense.operationMode().isPaid()) { + return new String[] { "Watcher will be disabled" }; } break; } @@ -66,9 +57,9 @@ public class WatcherLicensee extends AbstractLicenseeComponent } public boolean isWatcherTransportActionAllowed() { + // status is volatile, so a local variable is used for a consistent view Status localStatus = status; - boolean isLicenseStateActive = localStatus.getLicenseState() != LicenseState.DISABLED; - License.OperationMode operationMode = localStatus.getMode(); - return isLicenseStateActive && (operationMode == TRIAL || operationMode == GOLD || operationMode == PLATINUM); + + return localStatus.getLicenseState().isActive() && localStatus.getMode().isPaid(); } } diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/license/LicenseTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/license/LicenseTests.java index f916462a2bf..cddb77515a1 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/license/LicenseTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/watcher/license/LicenseTests.java @@ -8,23 +8,21 @@ package org.elasticsearch.watcher.license; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.license.core.License; -import org.elasticsearch.license.plugin.core.LicenseState; +import org.elasticsearch.license.plugin.core.AbstractLicenseeTestCase; import org.elasticsearch.license.plugin.core.Licensee; import org.elasticsearch.license.plugin.core.LicenseeRegistry; -import org.elasticsearch.test.ESTestCase; import java.util.ArrayList; import java.util.List; import static org.hamcrest.Matchers.is; -public class LicenseTests extends ESTestCase { +public class LicenseTests extends AbstractLicenseeTestCase { private SimpleLicenseeRegistry licenseeRegistry = new SimpleLicenseeRegistry(); public void testPlatinumGoldTrialLicenseCanDoEverything() throws Exception { - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.GOLD, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomPaidMode()); WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(watcherLicensee); @@ -32,7 +30,7 @@ public class LicenseTests extends ESTestCase { } public void testBasicLicenseIsDisabled() throws Exception { - licenseeRegistry.setOperationMode(License.OperationMode.BASIC); + licenseeRegistry.setOperationMode(randomFreeMode()); WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(watcherLicensee); @@ -40,7 +38,7 @@ public class LicenseTests extends ESTestCase { } public void testNoLicenseDoesNotWork() { - licenseeRegistry.setOperationMode(License.OperationMode.BASIC); + licenseeRegistry.setOperationMode(randomFreeMode()); WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(watcherLicensee); licenseeRegistry.disable(); @@ -49,8 +47,7 @@ public class LicenseTests extends ESTestCase { } public void testExpiredPlatinumGoldTrialLicenseIsRestricted() throws Exception { - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.GOLD, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomPaidMode()); WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(watcherLicensee); licenseeRegistry.disable(); @@ -59,40 +56,36 @@ public class LicenseTests extends ESTestCase { } public void testUpgradingFromBasicLicenseWorks() { - licenseeRegistry.setOperationMode(License.OperationMode.BASIC); + licenseeRegistry.setOperationMode(randomFreeMode()); WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(watcherLicensee); assertLicenseBasicOrNoneOrExpiredBehaviour(watcherLicensee); - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.GOLD, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomPaidMode()); assertLicenseGoldPlatinumTrialBehaviour(watcherLicensee); } public void testDowngradingToBasicLicenseWorks() { - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.GOLD, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomPaidMode()); WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(watcherLicensee); assertLicenseGoldPlatinumTrialBehaviour(watcherLicensee); - licenseeRegistry.setOperationMode(License.OperationMode.BASIC); + licenseeRegistry.setOperationMode(randomFreeMode()); assertLicenseBasicOrNoneOrExpiredBehaviour(watcherLicensee); } public void testUpgradingExpiredLicenseWorks() { - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.GOLD, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomPaidMode()); WatcherLicensee watcherLicensee = new WatcherLicensee(Settings.EMPTY, licenseeRegistry); licenseeRegistry.register(watcherLicensee); licenseeRegistry.disable(); assertLicenseBasicOrNoneOrExpiredBehaviour(watcherLicensee); - licenseeRegistry.setOperationMode( - randomFrom(License.OperationMode.PLATINUM, License.OperationMode.GOLD, License.OperationMode.TRIAL)); + licenseeRegistry.setOperationMode(randomPaidMode()); assertLicenseGoldPlatinumTrialBehaviour(watcherLicensee); } @@ -126,13 +119,13 @@ public class LicenseTests extends ESTestCase { public void enable() { for (Licensee licensee : licensees) { - licensee.onChange(new Licensee.Status(operationMode, randomBoolean() ? LicenseState.ENABLED : LicenseState.GRACE_PERIOD)); + licensee.onChange(new Licensee.Status(operationMode, randomActiveState())); } } public void disable() { for (Licensee licensee : licensees) { - licensee.onChange(new Licensee.Status(operationMode, LicenseState.DISABLED)); + licensee.onChange(new Licensee.Status(operationMode, randomInactiveState())); } }