diff --git a/CHANGELOG.md b/CHANGELOG.md index 727c137e..d21013cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,17 @@ Version template: --> # Alfred Telemetry Changelog +## [0.6.0] - 2021-06-30 + +### Added +* Alfresco 7 support [#107] + +### Fixed +* Prometheus scraping: max number of requests reached during Alfresco startup [#104] + +[#107]: https://github.com/xenit-eu/alfred-telemetry/pull/107 +[#104]: https://github.com/xenit-eu/alfred-telemetry/pull/104 + ## [0.5.2] - 2021-05-19 ### Added diff --git a/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/binder/solr/SolrMetricsBeanPostProcessor.java b/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/binder/solr/SolrMetricsBeanPostProcessor.java index 6d964d13..a8b4c9cb 100644 --- a/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/binder/solr/SolrMetricsBeanPostProcessor.java +++ b/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/binder/solr/SolrMetricsBeanPostProcessor.java @@ -1,9 +1,10 @@ package eu.xenit.alfred.telemetry.binder.solr; -import eu.xenit.alfred.telemetry.binder.solr.sharding.SolrShardingMetrics; import eu.xenit.alfred.telemetry.binder.solr.sharding.SolrShardingMetricsFactory; +import eu.xenit.alfred.telemetry.binder.solr.tracking.SolrTrackingMetrics; import io.micrometer.core.instrument.MeterRegistry; import java.util.Properties; +import org.alfresco.service.transaction.TransactionService; import org.quartz.Scheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,6 +21,10 @@ public class SolrMetricsBeanPostProcessor implements BeanDefinitionRegistryPostP private static final Logger LOGGER = LoggerFactory.getLogger(SolrMetricsBeanPostProcessor.class); + public static final String SEARCH_TRACKING_COMPONENT_BEAN_ID_BEFORE_7 = "search.solrTrackingComponent"; + public static final String SEARCH_TRACKING_COMPONENT_BEAN_ID_AFTER_7 = "search.trackingComponent"; + public static final String SOLR_TRACKING_METRICS_ENABLED_PROPERTY = "alfred.telemetry.binder.solr.tracking.enabled"; + public static final String SOLR_TRACKING_METRICS_BEAN_ID = "eu.xenit.alfred.telemetry.binder.solr.tracking.SolrTrackingMetrics"; public static final String SOLR_SHARDING_REGISTRY_BEAN_ID = "search.SolrShardRegistry"; public static final String SOLR_SHARDING_METRICS_BEAN_ID = "eu.xenit.alfred.telemetry.binder.solr.sharding.SolrShardingMetrics"; public static final String SOLR_SHARDING_METRICS_CRON_PROPERTY = "alfred.telemetry.binder.solr.sharding.cronexpression"; @@ -30,15 +35,50 @@ public class SolrMetricsBeanPostProcessor implements BeanDefinitionRegistryPostP private final Properties globalProperties; private MeterRegistry meterRegistry; + private TransactionService transactionService; - public SolrMetricsBeanPostProcessor(Properties globalProperties, MeterRegistry meterRegistry, Scheduler scheduler) { + public SolrMetricsBeanPostProcessor(Properties globalProperties, MeterRegistry meterRegistry, Scheduler scheduler, TransactionService transactionService) { this.globalProperties = globalProperties; this.meterRegistry = meterRegistry; this.scheduler = scheduler; + this.transactionService = transactionService; } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { + createTrackingMetricsBean(beanDefinitionRegistry); + createShardingMetricsBean(beanDefinitionRegistry); + } + + private void createTrackingMetricsBean(BeanDefinitionRegistry beanDefinitionRegistry) { + if (!Boolean.parseBoolean(globalProperties.getProperty(SOLR_TRACKING_METRICS_ENABLED_PROPERTY))) { + LOGGER.info("Solr tracking metrics are not enabled, skipping."); + return; + } + + BeanDefinition solrTrackingComponentBean; + try { + //Fetching bean for Alfresco <7 + solrTrackingComponentBean = beanDefinitionRegistry.getBeanDefinition( + SEARCH_TRACKING_COMPONENT_BEAN_ID_BEFORE_7); + } catch (NoSuchBeanDefinitionException e) { + LOGGER.info(String.format("%s not found, trying %s", SEARCH_TRACKING_COMPONENT_BEAN_ID_BEFORE_7, + SEARCH_TRACKING_COMPONENT_BEAN_ID_AFTER_7)); + solrTrackingComponentBean = beanDefinitionRegistry.getBeanDefinition( + SEARCH_TRACKING_COMPONENT_BEAN_ID_AFTER_7); + } + GenericBeanDefinition solrTrackingMetricsBean = new GenericBeanDefinition(); + solrTrackingMetricsBean.setBeanClass(SolrTrackingMetrics.class); + ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues(); + constructorArgumentValues.addGenericArgumentValue(solrTrackingComponentBean); + constructorArgumentValues.addGenericArgumentValue(transactionService); + constructorArgumentValues.addGenericArgumentValue(meterRegistry); + solrTrackingMetricsBean.setConstructorArgumentValues(constructorArgumentValues); + beanDefinitionRegistry.registerBeanDefinition(SOLR_TRACKING_METRICS_BEAN_ID, solrTrackingMetricsBean); + LOGGER.info("Registered SolrTrackingMetrics bean"); + } + + private void createShardingMetricsBean(BeanDefinitionRegistry beanDefinitionRegistry) { if (!Boolean.parseBoolean(globalProperties.getProperty(SOLR_SHARDING_METRICS_ENABLED_PROPERTY))) { LOGGER.info("Solr sharding metrics are not enabled, skipping."); return; diff --git a/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/binder/solr/tracking/SolrTrackingMetrics.java b/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/binder/solr/tracking/SolrTrackingMetrics.java index 65bbc4f4..900ab71d 100644 --- a/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/binder/solr/tracking/SolrTrackingMetrics.java +++ b/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/binder/solr/tracking/SolrTrackingMetrics.java @@ -3,7 +3,7 @@ import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.MeterRegistry; import java.util.function.ToDoubleFunction; -import org.alfresco.repo.solr.SOLRTrackingComponent; +import org.alfresco.repo.solr.SOLRTrackingComponentImpl; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.service.transaction.TransactionService; import org.slf4j.Logger; @@ -16,31 +16,28 @@ public class SolrTrackingMetrics { public static final String SOLR_METRICS_PREFIX = "solr.tracking"; private TransactionService transactionService; - private SOLRTrackingComponent solrTrackingComponent; + private SOLRTrackingComponentImpl solrTrackingComponent; private MeterRegistry registry; - public SolrTrackingMetrics(SOLRTrackingComponent solrTrackingComponent, TransactionService transactionService, - MeterRegistry registry, boolean enabled) { + public SolrTrackingMetrics(SOLRTrackingComponentImpl solrTrackingComponent, TransactionService transactionService, + MeterRegistry registry) { this.solrTrackingComponent = solrTrackingComponent; this.transactionService = transactionService; this.registry = registry; - if (enabled) { - registerMetrics(); - } } private void registerMetrics() { LOGGER.info("Registering Solr metrics"); - registerSolrTrackingMetric("maxTxnId", SOLRTrackingComponent::getMaxTxnId, "number"); - registerSolrTrackingMetric("maxTxnCommitTime", SOLRTrackingComponent::getMaxTxnCommitTime, "timestamp"); - registerSolrTrackingMetric("maxChangeSetId", SOLRTrackingComponent::getMaxChangeSetId, "number"); - registerSolrTrackingMetric("maxChangeSetCommitTime", SOLRTrackingComponent::getMaxChangeSetCommitTime, + registerSolrTrackingMetric("maxTxnId", SOLRTrackingComponentImpl::getMaxTxnId, "number"); + registerSolrTrackingMetric("maxTxnCommitTime", SOLRTrackingComponentImpl::getMaxTxnCommitTime, "timestamp"); + registerSolrTrackingMetric("maxChangeSetId", SOLRTrackingComponentImpl::getMaxChangeSetId, "number"); + registerSolrTrackingMetric("maxChangeSetCommitTime", SOLRTrackingComponentImpl::getMaxChangeSetCommitTime, "timestamp"); } - private void registerSolrTrackingMetric(String name, ToDoubleFunction function, + private void registerSolrTrackingMetric(String name, ToDoubleFunction function, String baseUnit) { - ToDoubleFunction wrappedFunction = solrTrackingComponent1 -> { + ToDoubleFunction wrappedFunction = solrTrackingComponent1 -> { RetryingTransactionHelper retryingTransactionHelper = transactionService.getRetryingTransactionHelper(); return retryingTransactionHelper .doInTransaction(() -> function.applyAsDouble(solrTrackingComponent1), true); diff --git a/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/registry/prometheus/PrometheusConfig.java b/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/registry/prometheus/PrometheusConfig.java index 1e95e0d6..123c79e7 100644 --- a/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/registry/prometheus/PrometheusConfig.java +++ b/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/registry/prometheus/PrometheusConfig.java @@ -5,6 +5,7 @@ public class PrometheusConfig extends AbstractRegistryConfig { private int maxRequests; + private int suppressMaxRequestsFailuresDuringUptimeMinutes; public int getMaxRequests() { return maxRequests; @@ -13,4 +14,12 @@ public int getMaxRequests() { public void setMaxRequests(int maxRequests) { this.maxRequests = maxRequests; } + + public int getSuppressMaxRequestsFailuresDuringUptimeMinutes() { + return suppressMaxRequestsFailuresDuringUptimeMinutes; + } + + public void setSuppressMaxRequestsFailuresDuringUptimeMinutes(int suppressMaxRequestsFailuresDuringUptimeMinutes) { + this.suppressMaxRequestsFailuresDuringUptimeMinutes = suppressMaxRequestsFailuresDuringUptimeMinutes; + } } diff --git a/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/webscripts/PrometheusWebScript.java b/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/webscripts/PrometheusWebScript.java index daa22b8e..8e09b1db 100644 --- a/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/webscripts/PrometheusWebScript.java +++ b/alfred-telemetry-platform/src/main/java/eu/xenit/alfred/telemetry/webscripts/PrometheusWebScript.java @@ -4,62 +4,105 @@ import eu.xenit.alfred.telemetry.util.PrometheusRegistryUtil; import io.micrometer.core.instrument.MeterRegistry; import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.charset.StandardCharsets; import java.util.concurrent.Semaphore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.extensions.webscripts.AbstractWebScript; -import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptResponse; +import org.springframework.http.HttpStatus; import org.springframework.util.ClassUtils; public class PrometheusWebScript extends AbstractWebScript { + private static final Logger logger = LoggerFactory.getLogger(PrometheusWebScript.class); + private final int maxRequests; + private final int suppressMaxRequestsFailuresDuringUptimeMinutes; + private final RuntimeMXBean runtimeMXBean; private final Semaphore semaphore; private final MeterRegistry meterRegistry; public PrometheusWebScript(MeterRegistry meterRegistry, PrometheusConfig prometheusConfig) { + this(meterRegistry, ManagementFactory.getRuntimeMXBean(), prometheusConfig); + } + + public PrometheusWebScript(MeterRegistry meterRegistry, RuntimeMXBean runtimeMXBean, + PrometheusConfig prometheusConfig) { this.meterRegistry = meterRegistry; this.maxRequests = prometheusConfig.getMaxRequests(); + this.suppressMaxRequestsFailuresDuringUptimeMinutes = prometheusConfig + .getSuppressMaxRequestsFailuresDuringUptimeMinutes(); + this.runtimeMXBean = runtimeMXBean; this.semaphore = new Semaphore(maxRequests); } - private static boolean prometheusAvailableOnClasspath() { - return ClassUtils.isPresent("io.micrometer.prometheus.PrometheusMeterRegistry", - PrometheusWebScript.class.getClassLoader()); - } - @Override - public void execute(WebScriptRequest webScriptRequest, WebScriptResponse webScriptResponse) throws IOException { + public void execute(WebScriptRequest request, WebScriptResponse response) throws IOException { if (!prometheusAvailableOnClasspath()) { - throw new WebScriptException(404, "micrometer-prometheus-registry not available on the classpath"); + setStatusCodeAndWriteResponse(response, HttpStatus.NOT_FOUND, + "micrometer-prometheus-registry not available on the classpath"); + return; } if (!PrometheusRegistryUtil.isOrContainsPrometheusRegistry(meterRegistry)) { - throw new WebScriptException(404, "The global MeterRegistry doesn't contain a PrometheusMeterRegistry"); + setStatusCodeAndWriteResponse(response, HttpStatus.NOT_FOUND, + "The global MeterRegistry doesn't contain a PrometheusMeterRegistry"); + return; } if (!semaphore.tryAcquire()) { - throw new WebScriptException(503, "Max number of active requests (" + maxRequests + ") reached"); + final String message = "Max number of active requests (" + maxRequests + ") reached"; + logMaxRequestsViolation(message); + setStatusCodeAndWriteResponse(response, HttpStatus.SERVICE_UNAVAILABLE, message); + return; } try { - executeInternal(webScriptResponse); + executeInternal(response); } finally { semaphore.release(); } } + private static boolean prometheusAvailableOnClasspath() { + return ClassUtils.isPresent("io.micrometer.prometheus.PrometheusMeterRegistry", + PrometheusWebScript.class.getClassLoader()); + } + private void executeInternal(WebScriptResponse response) throws IOException { - response.setStatus(200); - writeTextToResponse(PrometheusRegistryUtil.extractPrometheusScrapeData(meterRegistry), response); + setStatusCodeAndWriteResponse(response, HttpStatus.OK, + PrometheusRegistryUtil.extractPrometheusScrapeData(meterRegistry)); + } + + private void setStatusCodeAndWriteResponse(WebScriptResponse response, HttpStatus status, String message) + throws IOException { + response.setStatus(status.value()); + writeResponse(response, message); } - private void writeTextToResponse(final String text, final WebScriptResponse response) throws IOException { + private void writeResponse(final WebScriptResponse response, final String text) throws IOException { response.setContentType("text/plain"); response.setContentEncoding("UTF-8"); - response.setHeader("length", String.valueOf(text.getBytes().length)); - response.getOutputStream().write(text.getBytes()); + byte[] bytes = text.getBytes(StandardCharsets.UTF_8); + response.setHeader("length", String.valueOf(bytes.length)); + response.getOutputStream().write(bytes); + } + + private void logMaxRequestsViolation(String message) { + if (uptimeAtLeast(suppressMaxRequestsFailuresDuringUptimeMinutes)) { + logger.error(message); + } else { + logger.debug(message); + } + } + + private boolean uptimeAtLeast(int minutes) { + return runtimeMXBean.getUptime() > (1000L * 60 * minutes); } } diff --git a/alfred-telemetry-platform/src/main/resources/alfresco/module/alfred-telemetry-platform/alfresco-global.properties b/alfred-telemetry-platform/src/main/resources/alfresco/module/alfred-telemetry-platform/alfresco-global.properties index fb9e2bf8..0c3cf20d 100644 --- a/alfred-telemetry-platform/src/main/resources/alfresco/module/alfred-telemetry-platform/alfresco-global.properties +++ b/alfred-telemetry-platform/src/main/resources/alfresco/module/alfred-telemetry-platform/alfresco-global.properties @@ -16,6 +16,7 @@ alfred.telemetry.export.jmx.enabled=true ## Micrometer Prometheus registry configuration alfred.telemetry.export.prometheus.enabled=true alfred.telemetry.export.prometheus.max-requests=1 +alfred.telemetry.export.prometheus.suppress-max-request-failures-during-uptime-minutes=5 #### Alfresco integration configuration #### diff --git a/alfred-telemetry-platform/src/main/resources/alfresco/module/alfred-telemetry-platform/context/registry-context.xml b/alfred-telemetry-platform/src/main/resources/alfresco/module/alfred-telemetry-platform/context/registry-context.xml index 29de549b..862421ce 100644 --- a/alfred-telemetry-platform/src/main/resources/alfresco/module/alfred-telemetry-platform/context/registry-context.xml +++ b/alfred-telemetry-platform/src/main/resources/alfresco/module/alfred-telemetry-platform/context/registry-context.xml @@ -61,6 +61,8 @@ class="eu.xenit.alfred.telemetry.registry.prometheus.PrometheusConfig"> + - - - - - - \ No newline at end of file diff --git a/alfred-telemetry-platform/src/test/java/eu/xenit/alfred/telemetry/binder/solr/SolrMetricsBeanPostProcessorTest.java b/alfred-telemetry-platform/src/test/java/eu/xenit/alfred/telemetry/binder/solr/SolrMetricsBeanPostProcessorTest.java new file mode 100644 index 00000000..748633d5 --- /dev/null +++ b/alfred-telemetry-platform/src/test/java/eu/xenit/alfred/telemetry/binder/solr/SolrMetricsBeanPostProcessorTest.java @@ -0,0 +1,64 @@ +package eu.xenit.alfred.telemetry.binder.solr; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.micrometer.core.instrument.MeterRegistry; +import java.util.Properties; +import org.alfresco.service.transaction.TransactionService; +import org.junit.jupiter.api.Test; +import org.quartz.Scheduler; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; + +class SolrMetricsBeanPostProcessorTest { + + @Test + public void testAllBeansCreated() { + SolrMetricsBeanPostProcessor solrMetricsBeanPostProcessor = getSolrMetricsBeanPostProcessor(true, true); + BeanDefinitionRegistry beanDefinitionRegistry = mock(BeanDefinitionRegistry.class); + solrMetricsBeanPostProcessor.postProcessBeanDefinitionRegistry(beanDefinitionRegistry); + verify(beanDefinitionRegistry) + .registerBeanDefinition(eq(SolrMetricsBeanPostProcessor.SOLR_TRACKING_METRICS_BEAN_ID), any()); + verify(beanDefinitionRegistry) + .registerBeanDefinition(eq(SolrMetricsBeanPostProcessor.SOLR_SHARDING_METRICS_BEAN_ID), any()); + } + + private SolrMetricsBeanPostProcessor getSolrMetricsBeanPostProcessor(boolean tracking, boolean sharding) { + Properties properties = new Properties(); + properties.setProperty(SolrMetricsBeanPostProcessor.SOLR_TRACKING_METRICS_ENABLED_PROPERTY, + Boolean.toString(tracking)); + properties.setProperty(SolrMetricsBeanPostProcessor.SOLR_SHARDING_METRICS_ENABLED_PROPERTY, + Boolean.toString(sharding)); + SolrMetricsBeanPostProcessor solrMetricsBeanPostProcessor = new SolrMetricsBeanPostProcessor(properties, + mock(MeterRegistry.class), mock(Scheduler.class), mock(TransactionService.class)); + return solrMetricsBeanPostProcessor; + } + + @Test + public void noBeansCreated() { + BeanDefinitionRegistry beanDefinitionRegistry = mock(BeanDefinitionRegistry.class); + getSolrMetricsBeanPostProcessor(false, false).postProcessBeanDefinitionRegistry(beanDefinitionRegistry); + verify(beanDefinitionRegistry, never()) + .registerBeanDefinition(eq(SolrMetricsBeanPostProcessor.SOLR_TRACKING_METRICS_BEAN_ID), any()); + verify(beanDefinitionRegistry, never()) + .registerBeanDefinition(eq(SolrMetricsBeanPostProcessor.SOLR_SHARDING_METRICS_BEAN_ID), any()); + } + + @Test + public void checkAlfresco7BeanCreated() { + BeanDefinitionRegistry beanDefinitionRegistry = mock(BeanDefinitionRegistry.class); + when(beanDefinitionRegistry + .getBeanDefinition(eq(SolrMetricsBeanPostProcessor.SEARCH_TRACKING_COMPONENT_BEAN_ID_BEFORE_7))) + .thenThrow( + NoSuchBeanDefinitionException.class); + getSolrMetricsBeanPostProcessor(true, false).postProcessBeanDefinitionRegistry(beanDefinitionRegistry); + verify(beanDefinitionRegistry) + .registerBeanDefinition(eq(SolrMetricsBeanPostProcessor.SOLR_TRACKING_METRICS_BEAN_ID), any()); + } + +} \ No newline at end of file diff --git a/alfred-telemetry-platform/src/test/java/eu/xenit/alfred/telemetry/webscripts/PrometheusWebScriptTest.java b/alfred-telemetry-platform/src/test/java/eu/xenit/alfred/telemetry/webscripts/PrometheusWebScriptTest.java index 015f70dc..5d5ffea8 100644 --- a/alfred-telemetry-platform/src/test/java/eu/xenit/alfred/telemetry/webscripts/PrometheusWebScriptTest.java +++ b/alfred-telemetry-platform/src/test/java/eu/xenit/alfred/telemetry/webscripts/PrometheusWebScriptTest.java @@ -4,7 +4,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -16,12 +15,12 @@ import java.io.UncheckedIOException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.extensions.webscripts.WebScriptException; import org.springframework.extensions.webscripts.WebScriptRequest; import org.springframework.extensions.webscripts.WebScriptResponse; @@ -33,30 +32,40 @@ class PrometheusWebScriptTest { @Mock private PrometheusMeterRegistry registry; + @Mock + private WebScriptRequest mockedRequest; + @Mock + private WebScriptResponse mockedResponse; + private ByteArrayOutputStream responseOutputStream; + + @BeforeEach + void setup() throws IOException { + responseOutputStream = new ByteArrayOutputStream(); + when(mockedResponse.getOutputStream()).thenReturn(responseOutputStream); + } + @Test void execute() throws IOException { PrometheusWebScript webScript = initWebScript(1); when(registry.scrape()).thenReturn(TEST_SCRAPE_TEXT); - WebScriptRequest request = mock(WebScriptRequest.class); - WebScriptResponse response = mock(WebScriptResponse.class); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - when(response.getOutputStream()).thenReturn(out); - - webScript.execute(request, response); - verify(response).setStatus(200); - assertThat(out.toString("UTF-8"), is(equalTo(TEST_SCRAPE_TEXT))); + webScript.execute(mockedRequest, mockedResponse); + verify(mockedResponse).setStatus(200); + assertThat(responseOutputStream.toString("UTF-8"), is(equalTo(TEST_SCRAPE_TEXT))); } @Test - void execute_maxRequestsReached() { + void execute_maxRequestsReached() throws IOException { PrometheusWebScript webScript = initWebScript(1); + AtomicBoolean firstThreadIsBlocked = new AtomicBoolean(false); when(registry.scrape()).thenAnswer(answer -> { + firstThreadIsBlocked.set(true); await().forever().until(() -> false); return TEST_SCRAPE_TEXT; }); + // Trigger a first response on a separate thread Runnable firstHttpRequest = () -> { WebScriptRequest request = mock(WebScriptRequest.class); WebScriptResponse response = mock(WebScriptResponse.class); @@ -67,26 +76,22 @@ void execute_maxRequestsReached() { } }; - Runnable secondHttpRequest = () -> { - WebScriptRequest request = mock(WebScriptRequest.class); - WebScriptResponse response = mock(WebScriptResponse.class); - WebScriptException e = assertThrows(WebScriptException.class, () -> webScript.execute(request, response)); - assertThat(e.getStatus(), is(equalTo(503))); - }; - - ExecutorService executorService = Executors.newFixedThreadPool(2); + ExecutorService executorService = Executors.newFixedThreadPool(1); executorService.submit(firstHttpRequest); - Future future = executorService.submit(secondHttpRequest); - await().until(future::isDone); + await().untilAtomic(firstThreadIsBlocked, is(true)); + + webScript.execute(mockedRequest, mockedResponse); + verify(mockedResponse).setStatus(503); + executorService.shutdownNow(); + } private PrometheusWebScript initWebScript(int maxRequests) { PrometheusConfig config = new PrometheusConfig(); config.setMaxRequests(maxRequests); return new PrometheusWebScript(registry, config); - } } \ No newline at end of file diff --git a/build.gradle b/build.gradle index c0786c2c..7072f4f0 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ def copyPropertyValueIfExists(sourcePropertyName, targetPropertyName) { allprojects { group = 'eu.xenit.alfred.telemetry' - version = '0.5.2' + version = '0.6.0' boolean isRelease = ci.branch?.startsWith("release") if (!isRelease) { diff --git a/integration-tests/alfresco-community-70/overload.gradle b/integration-tests/alfresco-community-70/overload.gradle new file mode 100644 index 00000000..b23f4634 --- /dev/null +++ b/integration-tests/alfresco-community-70/overload.gradle @@ -0,0 +1,8 @@ +ext { + alfrescoBaseWarBom = 'org.alfresco:acs-community-packaging:7.0.0' + alfrescoBaseWar = 'org.alfresco:content-services-community@war' + + alfrescoBaseImage = 'docker.io/xenit/alfresco-repository-community:7.0.0' + + solrFlavor = 'solr6' +} \ No newline at end of file diff --git a/integration-tests/alfresco-enterprise-70/overload.gradle b/integration-tests/alfresco-enterprise-70/overload.gradle new file mode 100644 index 00000000..d5cc6eea --- /dev/null +++ b/integration-tests/alfresco-enterprise-70/overload.gradle @@ -0,0 +1,8 @@ +ext { + alfrescoBaseWarBom = 'org.alfresco:acs-packaging:7.0.0' + alfrescoBaseWar = 'org.alfresco:content-services@war' + + alfrescoBaseImage = 'hub.xenit.eu/alfresco-enterprise/alfresco-repository-enterprise:7.0.0' + + solrFlavor = 'solr6' +} \ No newline at end of file diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle index aceec061..d6ed0ac2 100644 --- a/integration-tests/build.gradle +++ b/integration-tests/build.gradle @@ -74,6 +74,9 @@ subprojects { alfrescoSM "io.micrometer:micrometer-registry-jmx:${micrometerVersion}" alfrescoSM "io.micrometer:micrometer-registry-prometheus:${micrometerVersion}" + if (project.hasProperty("alfrescoBaseWarBom")) { + baseAlfrescoWar platform("${alfrescoBaseWarBom}") + } baseAlfrescoWar "${alfrescoBaseWar}" } diff --git a/settings.gradle b/settings.gradle index 63af8bc3..3e9766bb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,7 +11,7 @@ include ':alfred-telemetry-solr' include ':integration-tests' -def integrationTestVersions = ["52", "60", "61", "62"]; +def integrationTestVersions = ["52", "60", "61", "62", "70"]; if (hasProperty("enterprise")) { integrationTestVersions.each {version -> include ":integration-tests:alfresco-enterprise-${version}"