- Fix test concurrency bugs

- Minor test fixes
- LicensesService documentation

Original commit: elastic/x-pack-elasticsearch@ab98ba8a2d
This commit is contained in:
Areek Zillur 2014-11-04 22:54:27 -05:00
parent 93944f27f2
commit 3aec0fd1f0
5 changed files with 139 additions and 132 deletions

View File

@ -46,15 +46,19 @@ import java.util.concurrent.atomic.AtomicReference;
import static org.elasticsearch.license.core.ESLicenses.reduceAndMap; import static org.elasticsearch.license.core.ESLicenses.reduceAndMap;
/** /**
* Service responsible for managing {@link org.elasticsearch.license.plugin.core.LicensesMetaData} * Service responsible for managing {@link LicensesMetaData}
* Interfaces through which this is exposed are: * Interfaces through which this is exposed are:
* - LicensesManagerService - responsible for managing signed and one-time-trial licenses * - LicensesManagerService - responsible for managing signed and one-time-trial licenses
* - LicensesClientService - responsible for feature registration and notification to consumer plugin(s) * - LicensesClientService - responsible for feature registration and notification to consumer plugin(s)
*
* <p/> * <p/>
* Registration Scheme: * Registration Scheme:
* <p/>
* A consumer plugin (feature) is registered with {@link LicensesClientService#register(String, TrialLicenseOptions, LicensesClientService.Listener)} * A consumer plugin (feature) is registered with {@link LicensesClientService#register(String, TrialLicenseOptions, LicensesClientService.Listener)}
* This method can be called at any time during the life-cycle of the consumer plugin. * This method can be called at any time during the life-cycle of the consumer plugin.
* * If the feature can not be registered immediately, it is queued up and registered on the first clusterChanged event with
* no {@link GatewayService#STATE_NOT_RECOVERED_BLOCK} block
* Upon successful registration, the feature(s) are notified appropriately using the notification scheme
* *
* <p/> * <p/>
* Notification Scheme: * Notification Scheme:
@ -69,7 +73,7 @@ import static org.elasticsearch.license.core.ESLicenses.reduceAndMap;
* <p/> * <p/>
* The {@link LicensingClientNotificationJob} calls {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} to schedule * The {@link LicensingClientNotificationJob} calls {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} to schedule
* another delayed {@link LicensingClientNotificationJob} as stated above. It is a no-op in case of a global block on * another delayed {@link LicensingClientNotificationJob} as stated above. It is a no-op in case of a global block on
* {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK} * {@link GatewayService#STATE_NOT_RECOVERED_BLOCK}
* <p/> * <p/>
* Upon successful registration of a new feature: * Upon successful registration of a new feature:
* - {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} is called * - {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} is called
@ -78,8 +82,8 @@ import static org.elasticsearch.license.core.ESLicenses.reduceAndMap;
* - {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} is called if: * - {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} is called if:
* - new trial/signed license(s) are found in the cluster state meta data * - new trial/signed license(s) are found in the cluster state meta data
* - if new feature(s) are added to the registeredListener * - if new feature(s) are added to the registeredListener
* - if the previous cluster state had a global block on {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK} * - if the previous cluster state had a global block on {@link GatewayService#STATE_NOT_RECOVERED_BLOCK}
* - no-op in case of global block on {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK} * - no-op in case of global block on {@link GatewayService#STATE_NOT_RECOVERED_BLOCK}
*/ */
@Singleton @Singleton
public class LicensesService extends AbstractLifecycleComponent<LicensesService> implements ClusterStateListener, LicensesManagerService, LicensesClientService { public class LicensesService extends AbstractLifecycleComponent<LicensesService> implements ClusterStateListener, LicensesManagerService, LicensesClientService {
@ -380,10 +384,10 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
} }
/** /**
* When there is no global block on {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK}: * When there is no global block on {@link GatewayService#STATE_NOT_RECOVERED_BLOCK}:
* - tries to register any {@link #pendingListeners} by calling {@link #registeredListeners} * - tries to register any {@link #pendingListeners} by calling {@link #registeredListeners}
* - if any {@link #pendingListeners} are registered successfully or if previous cluster state had a block on * - if any {@link #pendingListeners} are registered successfully or if previous cluster state had a block on
* {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK}, calls * {@link GatewayService#STATE_NOT_RECOVERED_BLOCK}, calls
* {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)} * {@link #notifyFeaturesAndScheduleNotification(LicensesMetaData)}
* - else calls {@link #notifyFeaturesAndScheduleNotificationIfNeeded(LicensesMetaData)} * - else calls {@link #notifyFeaturesAndScheduleNotificationIfNeeded(LicensesMetaData)}
*/ */
@ -435,6 +439,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
return; return;
} }
notifyFeaturesAndScheduleNotification(currentLicensesMetaData); notifyFeaturesAndScheduleNotification(currentLicensesMetaData);
logLicenseMetaDataStats("Setting last observed metaData", currentLicensesMetaData);
lastObservedLicensesState.set(currentLicensesMetaData); lastObservedLicensesState.set(currentLicensesMetaData);
} }
@ -493,7 +498,6 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logLicenseMetaDataStats("Setting last observed metaData", currentLicensesMetaData);
if (nextScheduleFrequency == -1l) { if (nextScheduleFrequency == -1l) {
logger.debug("no need to schedule next notification"); logger.debug("no need to schedule next notification");
} else { } else {
@ -506,10 +510,22 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
} }
private void logLicenseMetaDataStats(String prefix, LicensesMetaData licensesMetaData) { private void logLicenseMetaDataStats(String prefix, LicensesMetaData licensesMetaData) {
if (logger.isDebugEnabled()) {
if (licensesMetaData != null) { if (licensesMetaData != null) {
logger.debug(prefix + " LicensesMetaData: signedLicenses: " + licensesMetaData.getSignatures().size() + " trialLicenses: " + licensesMetaData.getEncodedTrialLicenses().size()); StringBuilder signedFeatures = new StringBuilder();
for (ESLicense license : licenseManager.fromSignatures(licensesMetaData.getSignatures())) {
signedFeatures.append(license.feature());
signedFeatures.append(", ");
}
StringBuilder trialFeatures = new StringBuilder();
for (ESLicense license : TrialLicenseUtils.fromEncodedTrialLicenses(licensesMetaData.getEncodedTrialLicenses())) {
trialFeatures.append(license.feature());
trialFeatures.append(", ");
}
logger.debug(prefix + " LicensesMetaData: signedLicenses: [" + signedFeatures.toString() + "] trialLicenses: [" + trialFeatures.toString() + "]");
} else { } else {
logger.debug(prefix + " LicensesMetaData: signedLicenses: 0 trialLicenses: 0"); logger.debug(prefix + " LicensesMetaData: signedLicenses: [] trialLicenses: []");
}
} }
} }
@ -537,7 +553,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
* *
* @param listenerHolder of the feature to register * @param listenerHolder of the feature to register
* @return true if registration has been completed, false otherwise (if masterNode is not available & trail license spec is provided) * @return true if registration has been completed, false otherwise (if masterNode is not available & trail license spec is provided)
* or if there is a global block on {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK} * or if there is a global block on {@link GatewayService#STATE_NOT_RECOVERED_BLOCK}
*/ */
private boolean registerListener(final ListenerHolder listenerHolder) { private boolean registerListener(final ListenerHolder listenerHolder) {
logger.debug("Registering listener for " + listenerHolder.feature); logger.debug("Registering listener for " + listenerHolder.feature);
@ -644,7 +660,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
/** /**
* Job for notifying on expired license(s) to registered feature(s) * Job for notifying on expired license(s) to registered feature(s)
* In case of a global block on {@link org.elasticsearch.gateway.GatewayService#STATE_NOT_RECOVERED_BLOCK}, * In case of a global block on {@link GatewayService#STATE_NOT_RECOVERED_BLOCK},
* the notification is not run, instead the feature(s) would be notified on the next * the notification is not run, instead the feature(s) would be notified on the next
* {@link #clusterChanged(org.elasticsearch.cluster.ClusterChangedEvent)} with no global block * {@link #clusterChanged(org.elasticsearch.cluster.ClusterChangedEvent)} with no global block
*/ */
@ -717,12 +733,14 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
private void enableFeatureIfNeeded() { private void enableFeatureIfNeeded() {
if (enabled.compareAndSet(false, true)) { if (enabled.compareAndSet(false, true)) {
logger.debug("feature: " + feature + " calling onEnabled");
listener.onEnabled(); listener.onEnabled();
} }
} }
private void disableFeatureIfNeeded() { private void disableFeatureIfNeeded() {
if (enabled.compareAndSet(true, false)) { if (enabled.compareAndSet(true, false)) {
logger.debug("feature: " + feature + " calling onDisabled");
listener.onDisabled(); listener.onDisabled();
} }
} }
@ -733,7 +751,7 @@ public class LicensesService extends AbstractLifecycleComponent<LicensesService>
} }
/** /**
* Thin wrapper to work with {@link org.elasticsearch.license.plugin.core.LicensesMetaData} * Thin wrapper to work with {@link LicensesMetaData}
* Never mutates the wrapped metaData * Never mutates the wrapped metaData
*/ */
private static class LicensesWrapper { private static class LicensesWrapper {

View File

@ -11,16 +11,20 @@ import org.elasticsearch.cluster.ProcessedClusterStateUpdateTask;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.base.Predicate; import org.elasticsearch.common.base.Predicate;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.ESLicense; import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.licensor.ESLicenseSigner; import org.elasticsearch.license.licensor.ESLicenseSigner;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationPluginService; import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.consumer.TestPluginServiceBase; import org.elasticsearch.license.plugin.consumer.TestPluginServiceBase;
import org.elasticsearch.license.plugin.core.LicensesManagerService; import org.elasticsearch.license.plugin.core.LicensesManagerService;
import org.elasticsearch.license.plugin.core.LicensesMetaData; import org.elasticsearch.license.plugin.core.LicensesMetaData;
import org.elasticsearch.license.plugin.core.LicensesStatus;
import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.InternalTestCluster; import org.elasticsearch.test.InternalTestCluster;
@ -92,6 +96,14 @@ public abstract class AbstractLicensesIntegrationTests extends ElasticsearchInte
return signer.sign(licenseSpec); return signer.sign(licenseSpec);
} }
protected void putLicense(String feature, TimeValue expiryDuration) throws Exception {
ESLicense license1 = generateSignedLicense(feature, expiryDuration);
final PutLicenseResponse putLicenseResponse = new PutLicenseRequestBuilder(client().admin().cluster()).setLicense(Lists.newArrayList(license1)).get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
}
protected void assertLicenseManagerEnabledFeatureFor(final String feature) throws InterruptedException { protected void assertLicenseManagerEnabledFeatureFor(final String feature) throws InterruptedException {
assertLicenseManagerStatusFor(feature, true); assertLicenseManagerStatusFor(feature, true);
} }
@ -101,7 +113,7 @@ public abstract class AbstractLicensesIntegrationTests extends ElasticsearchInte
} }
protected void assertLicenseManagerStatusFor(final String feature, final boolean expectedEnabled) throws InterruptedException { protected void assertLicenseManagerStatusFor(final String feature, final boolean expectedEnabled) throws InterruptedException {
assertThat(awaitBusy(new Predicate<Object>() { assertThat("LicenseManager for feature " + feature + " should have enabled status of " + expectedEnabled, awaitBusy(new Predicate<Object>() {
@Override @Override
public boolean apply(Object o) { public boolean apply(Object o) {
for (LicensesManagerService managerService : licensesManagerServices()) { for (LicensesManagerService managerService : licensesManagerServices()) {
@ -133,17 +145,17 @@ public abstract class AbstractLicensesIntegrationTests extends ElasticsearchInte
protected void assertLazyConsumerPluginNotification(final boolean expectedEnabled, int timeoutInSec) throws InterruptedException { protected void assertLazyConsumerPluginNotification(final boolean expectedEnabled, int timeoutInSec) throws InterruptedException {
final List<TestPluginServiceBase> consumerPluginServices = consumerLazyPluginServices(); final List<TestPluginServiceBase> consumerPluginServices = consumerLazyPluginServices();
assertThat("At least one instance has to be present", consumerPluginServices.size(), greaterThan(0)); assertThat("At least one instance has to be present", consumerPluginServices.size(), greaterThan(0));
assertConsumerPluginNotification(consumerPluginServices, expectedEnabled, timeoutInSec); assertConsumerPluginNotification("LazyConsumer should have license status of: " + expectedEnabled, consumerPluginServices, expectedEnabled, timeoutInSec);
} }
protected void assertEagerConsumerPluginNotification(final boolean expectedEnabled, int timeoutInSec) throws InterruptedException { protected void assertEagerConsumerPluginNotification(final boolean expectedEnabled, int timeoutInSec) throws InterruptedException {
final List<TestPluginServiceBase> consumerPluginServices = consumerEagerPluginServices(); final List<TestPluginServiceBase> consumerPluginServices = consumerEagerPluginServices();
assertThat("At least one instance has to be present", consumerPluginServices.size(), greaterThan(0)); assertThat("At least one instance has to be present", consumerPluginServices.size(), greaterThan(0));
assertConsumerPluginNotification(consumerPluginServices, expectedEnabled, timeoutInSec); assertConsumerPluginNotification("EagerConsumer should have license status of: " + expectedEnabled, consumerPluginServices, expectedEnabled, timeoutInSec);
} }
private void assertConsumerPluginNotification(final Iterable<TestPluginServiceBase> consumerPluginServices, final boolean expectedEnabled, int timeoutInSec) throws InterruptedException { private void assertConsumerPluginNotification(String msg, final Iterable<TestPluginServiceBase> consumerPluginServices, final boolean expectedEnabled, int timeoutInSec) throws InterruptedException {
assertThat(awaitBusy(new Predicate<Object>() { assertThat(msg, awaitBusy(new Predicate<Object>() {
@Override @Override
public boolean apply(Object o) { public boolean apply(Object o) {
for (TestPluginServiceBase pluginService : consumerPluginServices) { for (TestPluginServiceBase pluginService : consumerPluginServices) {

View File

@ -6,19 +6,14 @@
package org.elasticsearch.license.plugin; package org.elasticsearch.license.plugin;
import org.elasticsearch.common.base.Predicate; import org.elasticsearch.common.base.Predicate;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationConsumerPlugin; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationConsumerPlugin;
import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationConsumerPlugin; import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationConsumerPlugin;
import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationPluginService; import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.core.LicensesStatus;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
@ -31,7 +26,7 @@ public class LicensesPluginIntegrationTests extends AbstractLicensesIntegrationT
private final boolean useEagerLicenseRegistrationPlugin = randomBoolean(); private final boolean useEagerLicenseRegistrationPlugin = randomBoolean();
private final int trialLicenseDurationInSeconds = 2; private final int trialLicenseDurationInSeconds = 5;
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {
return ImmutableSettings.settingsBuilder() return ImmutableSettings.settingsBuilder()
@ -69,10 +64,7 @@ public class LicensesPluginIntegrationTests extends AbstractLicensesIntegrationT
assertLicenseManagerDisabledFeatureFor(getCurrentFeatureName()); assertLicenseManagerDisabledFeatureFor(getCurrentFeatureName());
logger.info(" --> put signed license"); logger.info(" --> put signed license");
ESLicense license = generateSignedLicense(getCurrentFeatureName(), TimeValue.timeValueSeconds(trialLicenseDurationInSeconds)); putLicense(getCurrentFeatureName(), TimeValue.timeValueSeconds(trialLicenseDurationInSeconds));
final PutLicenseResponse putLicenseResponse = new PutLicenseRequestBuilder(client().admin().cluster()).setLicense(Lists.newArrayList(license)).get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
logger.info(" --> check signed license enabled notification"); logger.info(" --> check signed license enabled notification");
// consumer plugin should notify onEnabled on all data nodes (signed license) // consumer plugin should notify onEnabled on all data nodes (signed license)
@ -111,10 +103,7 @@ public class LicensesPluginIntegrationTests extends AbstractLicensesIntegrationT
assertConsumerPluginEnabledNotification(1); assertConsumerPluginEnabledNotification(1);
logger.info(" --> put signed license while trial license is in effect"); logger.info(" --> put signed license while trial license is in effect");
ESLicense license = generateSignedLicense(getCurrentFeatureName(), TimeValue.timeValueSeconds(trialLicenseDurationInSeconds * 2)); putLicense(getCurrentFeatureName(), TimeValue.timeValueSeconds(trialLicenseDurationInSeconds * 2));
final PutLicenseResponse putLicenseResponse = new PutLicenseRequestBuilder(client().admin().cluster()).setLicense(Lists.newArrayList(license)).get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
logger.info(" --> check signed license enabled notification"); logger.info(" --> check signed license enabled notification");
// consumer plugin should notify onEnabled on all data nodes (signed license) // consumer plugin should notify onEnabled on all data nodes (signed license)

View File

@ -5,38 +5,30 @@
*/ */
package org.elasticsearch.license.plugin; package org.elasticsearch.license.plugin;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.license.core.ESLicense;
import org.elasticsearch.license.plugin.action.put.PutLicenseRequestBuilder;
import org.elasticsearch.license.plugin.action.put.PutLicenseResponse;
import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationConsumerPlugin; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationConsumerPlugin;
import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService; import org.elasticsearch.license.plugin.consumer.EagerLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationConsumerPlugin; import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationConsumerPlugin;
import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationPluginService; import org.elasticsearch.license.plugin.consumer.LazyLicenseRegistrationPluginService;
import org.elasticsearch.license.plugin.core.LicensesStatus;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope; import static org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST; import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
import static org.hamcrest.CoreMatchers.equalTo;
@ClusterScope(scope = TEST, numDataNodes = 0, numClientNodes = 0) @ClusterScope(scope = TEST, numDataNodes = 0, numClientNodes = 0)
public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegrationTests { public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegrationTests {
private final int trialLicenseDurationInSeconds = 2;
private final String FEATURE_NAME_1 = EagerLicenseRegistrationPluginService.FEATURE_NAME; private final String FEATURE_NAME_1 = EagerLicenseRegistrationPluginService.FEATURE_NAME;
private final String FEATURE_NAME_2 = LazyLicenseRegistrationPluginService.FEATURE_NAME; private final String FEATURE_NAME_2 = LazyLicenseRegistrationPluginService.FEATURE_NAME;
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {
return ImmutableSettings.settingsBuilder() return ImmutableSettings.settingsBuilder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(EagerLicenseRegistrationConsumerPlugin.NAME + ".trial_license_duration_in_seconds", trialLicenseDurationInSeconds) .put(EagerLicenseRegistrationConsumerPlugin.NAME + ".trial_license_duration_in_seconds", 2)
.put(LazyLicenseRegistrationConsumerPlugin.NAME + ".trial_license_duration_in_seconds", trialLicenseDurationInSeconds) .put(LazyLicenseRegistrationConsumerPlugin.NAME + ".trial_license_duration_in_seconds", 2)
.putArray("plugin.types", LicensePlugin.class.getName(), EagerLicenseRegistrationConsumerPlugin.class.getName(), LazyLicenseRegistrationConsumerPlugin.class.getName()) .putArray("plugin.types", LicensePlugin.class.getName(), EagerLicenseRegistrationConsumerPlugin.class.getName(), LazyLicenseRegistrationConsumerPlugin.class.getName())
.build(); .build();
} }
@ -59,10 +51,10 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
@Test @Test
public void testWithNoTrialLicense() throws Exception { public void testWithNoTrialLicense() throws Exception {
int nNodes = randomIntBetween(2, 10); int nNodes = randomIntBetween(2, 10);
String[] nodes = startNodesWithConsumerPlugins(nNodes, -1, -1); startNodesWithConsumerPlugins(nNodes, -1, -1);
assertEagerConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2); assertEagerConsumerPluginDisableNotification(1);
assertLazyConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2); assertLazyConsumerPluginDisableNotification(1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
} }
@ -71,7 +63,7 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
public void testOneTrialAndNonTrialConsumer() throws Exception { public void testOneTrialAndNonTrialConsumer() throws Exception {
int nNodes = randomIntBetween(2, 10); int nNodes = randomIntBetween(2, 10);
int consumer2TrialLicenseDuration = 2; int consumer2TrialLicenseDuration = 2;
String[] nodes = startNodesWithConsumerPlugins(nNodes, -1, consumer2TrialLicenseDuration); startNodesWithConsumerPlugins(nNodes, -1, consumer2TrialLicenseDuration);
logger.info(" --> trial license generated for " + FEATURE_NAME_2 + " no trial license for " + FEATURE_NAME_1); logger.info(" --> trial license generated for " + FEATURE_NAME_2 + " no trial license for " + FEATURE_NAME_1);
// managerService should report feature to be enabled on all data nodes // managerService should report feature to be enabled on all data nodes
@ -82,16 +74,11 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
assertLazyConsumerPluginEnableNotification(1); assertLazyConsumerPluginEnableNotification(1);
logger.info(" --> put signed license for " + FEATURE_NAME_1); logger.info(" --> put signed license for " + FEATURE_NAME_1);
ESLicense license1 = generateSignedLicense(FEATURE_NAME_1, TimeValue.timeValueSeconds(consumer2TrialLicenseDuration)); putLicense(FEATURE_NAME_1, TimeValue.timeValueSeconds(consumer2TrialLicenseDuration));
final PutLicenseResponse putLicenseResponse = new PutLicenseRequestBuilder(client().admin().cluster()).setLicense(Lists.newArrayList(license1)).get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
logger.info(" --> check that both " + FEATURE_NAME_1 + " and " + FEATURE_NAME_2 + " are enabled"); logger.info(" --> check that both " + FEATURE_NAME_1 + " and " + FEATURE_NAME_2 + " are enabled");
assertEagerConsumerPluginEnableNotification(1); assertEagerConsumerPluginEnableNotification(1);
assertLazyConsumerPluginEnableNotification(1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2);
logger.info(" --> check signed license expiry notification"); logger.info(" --> check signed license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired signed license) // consumer plugin should notify onDisabled on all data nodes (expired signed license)
@ -105,7 +92,10 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
public void testMultipleConsumerPlugins() throws Exception { public void testMultipleConsumerPlugins() throws Exception {
int nNodes = randomIntBetween(2, 10); int nNodes = randomIntBetween(2, 10);
String[] nodes = startNodesWithConsumerPlugins(nNodes, trialLicenseDurationInSeconds, trialLicenseDurationInSeconds); int consumer1TrialLicenseExpiry = 2;
int consumer2TrialLicenseExpiry = 2;
startNodesWithConsumerPlugins(nNodes, consumer1TrialLicenseExpiry, consumer2TrialLicenseExpiry);
logger.info(" --> trial license generated"); logger.info(" --> trial license generated");
// managerService should report feature to be enabled on all data nodes // managerService should report feature to be enabled on all data nodes
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1);
@ -116,14 +106,14 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
logger.info(" --> check trial license expiry notification"); logger.info(" --> check trial license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired trial license) // consumer plugin should notify onDisabled on all data nodes (expired trial license)
assertEagerConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2); assertEagerConsumerPluginDisableNotification(consumer1TrialLicenseExpiry * 2);
assertLazyConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2); assertLazyConsumerPluginDisableNotification(consumer2TrialLicenseExpiry * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
logger.info(" --> put signed license"); logger.info(" --> put signed license");
putLicense(FEATURE_NAME_1, TimeValue.timeValueSeconds(trialLicenseDurationInSeconds)); putLicense(FEATURE_NAME_1, TimeValue.timeValueSeconds(consumer1TrialLicenseExpiry));
putLicense(FEATURE_NAME_2, TimeValue.timeValueSeconds(trialLicenseDurationInSeconds)); putLicense(FEATURE_NAME_2, TimeValue.timeValueSeconds(consumer2TrialLicenseExpiry));
logger.info(" --> check signed license enabled notification"); logger.info(" --> check signed license enabled notification");
// consumer plugin should notify onEnabled on all data nodes (signed license) // consumer plugin should notify onEnabled on all data nodes (signed license)
@ -134,8 +124,8 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
logger.info(" --> check signed license expiry notification"); logger.info(" --> check signed license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired signed license) // consumer plugin should notify onDisabled on all data nodes (expired signed license)
assertEagerConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2); assertEagerConsumerPluginDisableNotification(consumer1TrialLicenseExpiry * 2);
assertLazyConsumerPluginDisableNotification(trialLicenseDurationInSeconds * 2); assertLazyConsumerPluginDisableNotification(consumer2TrialLicenseExpiry * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
} }
@ -143,27 +133,27 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
@Test @Test
public void testRandomFeatureLicensesActions() throws Exception { public void testRandomFeatureLicensesActions() throws Exception {
int nNodes = randomIntBetween(2, 10); int nNodes = randomIntBetween(2, 10);
int trialLicenseDuration1 = rarely() ? -1 : randomIntBetween(1, 2); int trialLicenseDuration1 = rarely() ? -1 : randomIntBetween(2, 3);
int trialLicenseDuration2 = rarely() ? -1 : randomIntBetween(1, 2); int trialLicenseDuration2 = rarely() ? -1 : randomIntBetween(2, 3);
String[] nodes = startNodesWithConsumerPlugins(nNodes, trialLicenseDuration1, trialLicenseDuration2); startNodesWithConsumerPlugins(nNodes, trialLicenseDuration1, trialLicenseDuration2);
if (trialLicenseDuration1 != -1) { if (trialLicenseDuration1 != -1) {
assertEagerConsumerPluginEnableNotification(1); assertEagerConsumerPluginEnableNotification(trialLicenseDuration1);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_1);
} else { } else {
assertEagerConsumerPluginDisableNotification(1); assertEagerConsumerPluginDisableNotification(3 * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
putLicense(FEATURE_NAME_1, TimeValue.timeValueMillis(300 * 2)); putLicense(FEATURE_NAME_1, TimeValue.timeValueMillis(500 * 2));
} }
if (trialLicenseDuration2 != -1) { if (trialLicenseDuration2 != -1) {
assertLazyConsumerPluginEnableNotification(1); assertLazyConsumerPluginEnableNotification(trialLicenseDuration2);
assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerEnabledFeatureFor(FEATURE_NAME_2);
} else { } else {
assertLazyConsumerPluginDisableNotification(1); assertLazyConsumerPluginDisableNotification(3 * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
putLicense(FEATURE_NAME_2, TimeValue.timeValueMillis(300 * 2)); putLicense(FEATURE_NAME_2, TimeValue.timeValueMillis(500 * 2));
} }
logger.info(" --> check license enabled notification"); logger.info(" --> check license enabled notification");
@ -174,25 +164,16 @@ public class LicensesPluginsIntegrationTests extends AbstractLicensesIntegration
logger.info(" --> check license expiry notification"); logger.info(" --> check license expiry notification");
// consumer plugin should notify onDisabled on all data nodes (expired signed license) // consumer plugin should notify onDisabled on all data nodes (expired signed license)
assertEagerConsumerPluginDisableNotification(2 * 2); assertEagerConsumerPluginDisableNotification(3 * 2);
assertLazyConsumerPluginDisableNotification(2 * 2); assertLazyConsumerPluginDisableNotification(3 * 2);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_1);
assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2); assertLicenseManagerDisabledFeatureFor(FEATURE_NAME_2);
} }
private String[] startNodesWithConsumerPlugins(int nNodes, int consumer1TrialLicenseDuration, int consumer2TrialLicenseDuration) { private void startNodesWithConsumerPlugins(int nNodes, int consumer1TrialLicenseDuration, int consumer2TrialLicenseDuration) {
String[] nodes = new String[nNodes];
for (int i = 0; i < nNodes; i++) { for (int i = 0; i < nNodes; i++) {
nodes[i] = internalCluster().startNode(nodeSettingsWithConsumerPlugin(consumer1TrialLicenseDuration, consumer2TrialLicenseDuration)); internalCluster().startNode(nodeSettingsWithConsumerPlugin(consumer1TrialLicenseDuration, consumer2TrialLicenseDuration));
} }
return nodes;
}
private void putLicense(String feature, TimeValue expiryDuration) throws Exception {
ESLicense license1 = generateSignedLicense(feature, expiryDuration);
final PutLicenseResponse putLicenseResponse = new PutLicenseRequestBuilder(client().admin().cluster()).setLicense(Lists.newArrayList(license1)).get();
assertThat(putLicenseResponse.isAcknowledged(), equalTo(true));
assertThat(putLicenseResponse.status(), equalTo(LicensesStatus.VALID));
} }
} }

View File

@ -109,8 +109,9 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
final TimeValue expiryDuration = TimeValue.timeValueSeconds(2); final TimeValue expiryDuration = TimeValue.timeValueSeconds(2);
actions.add(registerWithTrialLicense(clientService, clientListener, "feature1", expiryDuration)); String feature1 = "feature1";
actions.add(assertExpiryAction("trial", expiryDuration)); actions.add(registerWithTrialLicense(clientService, clientListener, feature1, expiryDuration));
actions.add(assertExpiryAction(feature1, "trial", expiryDuration));
assertClientListenerNotificationCount(clientListener, actions); assertClientListenerNotificationCount(clientListener, actions);
} }
@ -126,14 +127,16 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
List<Action> secondClientActions = new ArrayList<>(); List<Action> secondClientActions = new ArrayList<>();
final TimeValue firstExpiryDuration = TimeValue.timeValueSeconds(2); final TimeValue firstExpiryDuration = TimeValue.timeValueSeconds(2);
firstClientActions.add(registerWithoutTrialLicense(licensesService, clientListener1, "feature1")); String feature1 = "feature1";
firstClientActions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, "feature1", firstExpiryDuration)); firstClientActions.add(registerWithoutTrialLicense(licensesService, clientListener1, feature1));
firstClientActions.add(assertExpiryAction("signed", firstExpiryDuration)); firstClientActions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, feature1, firstExpiryDuration));
firstClientActions.add(assertExpiryAction(feature1, "signed", firstExpiryDuration));
final TimeValue secondExpiryDuration = TimeValue.timeValueSeconds(1); final TimeValue secondExpiryDuration = TimeValue.timeValueSeconds(1);
secondClientActions.add(registerWithoutTrialLicense(licensesService, clientListener2, "feature2")); String feature2 = "feature2";
secondClientActions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, "feature2", secondExpiryDuration)); secondClientActions.add(registerWithoutTrialLicense(licensesService, clientListener2, feature2));
secondClientActions.add(assertExpiryAction("signed", secondExpiryDuration)); secondClientActions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, feature2, secondExpiryDuration));
secondClientActions.add(assertExpiryAction(feature2, "signed", secondExpiryDuration));
if (randomBoolean()) { if (randomBoolean()) {
assertClientListenerNotificationCount(clientListener1, firstClientActions); assertClientListenerNotificationCount(clientListener1, firstClientActions);
@ -156,13 +159,15 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
List<Action> secondClientActions = new ArrayList<>(); List<Action> secondClientActions = new ArrayList<>();
final TimeValue firstExpiryDuration = TimeValue.timeValueSeconds(2); final TimeValue firstExpiryDuration = TimeValue.timeValueSeconds(2);
firstClientActions.add(registerWithoutTrialLicense(licensesService, clientListener1, "feature1")); String feature1 = "feature1";
firstClientActions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, "feature1", firstExpiryDuration)); firstClientActions.add(registerWithoutTrialLicense(licensesService, clientListener1, feature1));
firstClientActions.add(assertExpiryAction("signed", firstExpiryDuration)); firstClientActions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, feature1, firstExpiryDuration));
firstClientActions.add(assertExpiryAction(feature1, "signed", firstExpiryDuration));
final TimeValue secondExpiryDuration = TimeValue.timeValueSeconds(1); final TimeValue secondExpiryDuration = TimeValue.timeValueSeconds(1);
secondClientActions.add(registerWithTrialLicense(licensesService, clientListener2, "feature2", secondExpiryDuration)); String feature2 = "feature2";
secondClientActions.add(assertExpiryAction("trial", secondExpiryDuration)); secondClientActions.add(registerWithTrialLicense(licensesService, clientListener2, feature2, secondExpiryDuration));
secondClientActions.add(assertExpiryAction(feature2, "trial", secondExpiryDuration));
if (randomBoolean()) { if (randomBoolean()) {
assertClientListenerNotificationCount(clientListener1, firstClientActions); assertClientListenerNotificationCount(clientListener1, firstClientActions);
@ -184,12 +189,14 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
List<Action> secondClientActions = new ArrayList<>(); List<Action> secondClientActions = new ArrayList<>();
TimeValue firstExpiryDuration = TimeValue.timeValueSeconds(1); TimeValue firstExpiryDuration = TimeValue.timeValueSeconds(1);
firstClientActions.add(registerWithTrialLicense(licensesService, clientListener1, "feature1", firstExpiryDuration)); String feature1 = "feature1";
firstClientActions.add(assertExpiryAction("trial", firstExpiryDuration)); firstClientActions.add(registerWithTrialLicense(licensesService, clientListener1, feature1, firstExpiryDuration));
firstClientActions.add(assertExpiryAction(feature1, "trial", firstExpiryDuration));
TimeValue secondExpiryDuration = TimeValue.timeValueSeconds(2); TimeValue secondExpiryDuration = TimeValue.timeValueSeconds(2);
secondClientActions.add(registerWithTrialLicense(licensesService, clientListener2, "feature2", secondExpiryDuration)); String feature2 = "feature2";
secondClientActions.add(assertExpiryAction("trial", secondExpiryDuration)); secondClientActions.add(registerWithTrialLicense(licensesService, clientListener2, feature2, secondExpiryDuration));
secondClientActions.add(assertExpiryAction(feature2, "trial", secondExpiryDuration));
if (randomBoolean()) { if (randomBoolean()) {
assertClientListenerNotificationCount(clientListener1, firstClientActions); assertClientListenerNotificationCount(clientListener1, firstClientActions);
@ -218,8 +225,9 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
TimeValue expiryDuration = TimeValue.timeValueSeconds(2); TimeValue expiryDuration = TimeValue.timeValueSeconds(2);
actions.add(registerWithTrialLicense(clientService, clientListener, "feature1", expiryDuration)); String feature = "feature1";
actions.add(assertExpiryAction("trial", expiryDuration)); actions.add(registerWithTrialLicense(clientService, clientListener, feature, expiryDuration));
actions.add(assertExpiryAction(feature, "trial", expiryDuration));
assertClientListenerNotificationCount(clientListener, actions); assertClientListenerNotificationCount(clientListener, actions);
} }
@ -231,19 +239,19 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
Map<TestTrackingClientListener, List<Action>> clientListenersWithActions = new HashMap<>(); Map<TestTrackingClientListener, List<Action>> clientListenersWithActions = new HashMap<>();
TimeValue expiryDuration = TimeValue.timeValueSeconds(0); TimeValue expiryDuration = TimeValue.timeValueSeconds(0);
for (int i = 0; i < randomIntBetween(10, 20); i++) { for (int i = 0; i < randomIntBetween(5, 10); i++) {
final TestTrackingClientListener clientListener = new TestTrackingClientListener(); final TestTrackingClientListener clientListener = new TestTrackingClientListener();
String feature = randomRealisticUnicodeOfCodepointLengthBetween(2, 10); String feature = "feature_" + String.valueOf(i);
expiryDuration = TimeValue.timeValueMillis(randomIntBetween(1, 5) * 100l + expiryDuration.millis()); expiryDuration = TimeValue.timeValueMillis(randomIntBetween(1, 3) * 1000l + expiryDuration.millis());
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
if (randomBoolean()) { if (randomBoolean()) {
actions.add(registerWithTrialLicense(licensesService, clientListener, feature, expiryDuration)); actions.add(registerWithTrialLicense(licensesService, clientListener, feature, expiryDuration));
actions.add(assertExpiryAction("trial", expiryDuration)); actions.add(assertExpiryAction(feature, "trial", expiryDuration));
} else { } else {
actions.add(registerWithoutTrialLicense(licensesService, clientListener, feature)); actions.add(registerWithoutTrialLicense(licensesService, clientListener, feature));
actions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, feature, expiryDuration)); actions.add(generateAndPutSignedLicenseAction(masterLicensesManagerService, feature, expiryDuration));
actions.add(assertExpiryAction("signed", expiryDuration)); actions.add(assertExpiryAction(feature, "signed", expiryDuration));
} }
clientListenersWithActions.put(clientListener, actions); clientListenersWithActions.put(clientListener, actions);
} }
@ -274,8 +282,9 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
} }
}); });
try { try {
assertThat(latch.await(100, TimeUnit.MILLISECONDS), equalTo(true)); latch.await();
} catch (InterruptedException e) { } catch (InterruptedException e) {
fail(e.getMessage());
} }
assertThat(success.get(), equalTo(true)); assertThat(success.get(), equalTo(true));
} }
@ -320,51 +329,49 @@ public class LicensesServiceTests extends AbstractLicensesIntegrationTests {
}, 0, 1, "should trigger onEnable for " + feature + " once [trial license]"); }, 0, 1, "should trigger onEnable for " + feature + " once [trial license]");
} }
private Action assertExpiryAction(String licenseType, TimeValue expiryDuration) { private Action assertExpiryAction(String feature, String licenseType, TimeValue expiryDuration) {
return new Action(new Runnable() { return new Action(new Runnable() {
@Override @Override
public void run() {} public void run() {}
}, 1, 0, TimeValue.timeValueMillis(expiryDuration.getMillis() * 2), }, 1, 0, TimeValue.timeValueMillis(expiryDuration.getMillis() * 2),
"should trigger onDisable once [" + licenseType + " license expiry]"); "should trigger onDisable for " + feature + " once [" + licenseType + " license expiry]");
} }
private void assertClientListenerNotificationCount(final TestTrackingClientListener clientListener, List<Action> actions) throws Exception { private void assertClientListenerNotificationCount(final TestTrackingClientListener clientListener, List<Action> actions) throws Exception {
assertThat(clientListener.onDisabledCount.get(), equalTo(0));
assertThat(clientListener.onEnabledCount.get(), equalTo(0));
for (final Action action : actions) { for (final Action action : actions) {
final AtomicBoolean actionPerformed = new AtomicBoolean(false); final CountDownLatch enableLatch = new CountDownLatch(action.expectedEnabledCount);
assertThat(action.msg, awaitBusy(new Predicate<Object>() { final CountDownLatch disableLatch = new CountDownLatch(action.expectedDisabledCount);
AtomicInteger previousOnEnabledCount = new AtomicInteger(0);
AtomicInteger previousOnDisabledCount = new AtomicInteger(0);
@Override clientListener.latch(enableLatch, disableLatch);
public boolean apply(Object o) {
if (actionPerformed.compareAndSet(false, true)) {
previousOnEnabledCount.set(clientListener.onEnabledCount.get());
previousOnDisabledCount.set(clientListener.onDisabledCount.get());
action.run(); action.run();
if (action.expectedEnabledCount > 0) {
assertThat(action.msg, enableLatch.await(action.timeout.getMillis() * 2, TimeUnit.MILLISECONDS), equalTo(true));
} else if (action.expectedDisabledCount > 0) {
assertThat(action.msg, disableLatch.await(action.timeout.getMillis() * 2, TimeUnit.MILLISECONDS), equalTo(true));
} }
return ((clientListener.onEnabledCount.get() - previousOnEnabledCount.get()) == action.expectedEnabledCount
&& (clientListener.onDisabledCount.get() - previousOnDisabledCount.get()) == action.expectedDisabledCount);
}
}, action.timeout.getMillis(), TimeUnit.MILLISECONDS), equalTo(true));
} }
} }
private class TestTrackingClientListener implements LicensesClientService.Listener { private class TestTrackingClientListener implements LicensesClientService.Listener {
AtomicInteger onEnabledCount = new AtomicInteger(0); CountDownLatch enableLatch;
AtomicInteger onDisabledCount = new AtomicInteger(0); CountDownLatch disableLatch;
public synchronized void latch(CountDownLatch enableLatch, CountDownLatch disableLatch) {
this.enableLatch = enableLatch;
this.disableLatch = disableLatch;
}
@Override @Override
public void onEnabled() { public void onEnabled() {
onEnabledCount.incrementAndGet(); this.enableLatch.countDown();
} }
@Override @Override
public void onDisabled() { public void onDisabled() {
onDisabledCount.incrementAndGet(); this.disableLatch.countDown();
} }
} }