blob: beffa3e00ea072f0cf12cd370fe8fd7577faaad7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ignite.util;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.internal.commandline.CommandList;
import org.apache.ignite.internal.commandline.metric.MetricCommandArg;
import org.apache.ignite.internal.processors.metric.MetricRegistry;
import org.apache.ignite.internal.processors.metric.impl.HistogramMetricImpl;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.junit.Test;
import static java.util.regex.Pattern.quote;
import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_INVALID_ARGUMENTS;
import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
import static org.apache.ignite.internal.commandline.CommandList.METRIC;
import static org.apache.ignite.internal.commandline.metric.MetricCommandArg.NODE_ID;
import static org.apache.ignite.internal.commandline.systemview.SystemViewCommand.COLUMN_SEPARATOR;
import static org.apache.ignite.internal.processors.metric.GridMetricManager.IGNITE_METRICS;
import static org.apache.ignite.internal.processors.metric.GridMetricManager.SYS_METRICS;
import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.SEPARATOR;
import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.metricName;
import static org.apache.ignite.testframework.GridTestUtils.assertContains;
/** Tests output of {@link CommandList#METRIC} command. */
public class MetricCommandTest extends GridCommandHandlerClusterByClassAbstractTest {
/** Command line argument for printing metric values. */
private static final String CMD_METRIC = METRIC.text();
/** Test node with 0 index. */
private IgniteEx ignite0;
/** {@inheritDoc} */
@Override protected void beforeTest() throws Exception {
super.beforeTest();
injectTestSystemOut();
autoConfirmation = false;
ignite0 = ignite(0);
}
/** Tests command error output in case of mandatory metric name is omitted. */
@Test
public void testMetricNameMissedFailure() {
assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC),
"The name of a metric(metric registry) is expected.");
}
/** Tests command error output in case value of {@link MetricCommandArg#NODE_ID} argument is omitted. */
@Test
public void testNodeIdMissedFailure() {
assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, SYS_METRICS, NODE_ID.argName()),
"ID of the node from which metric values should be obtained is expected.");
}
/** Tests command error output in case value of {@link MetricCommandArg#NODE_ID} argument is invalid.*/
@Test
public void testInvalidNodeIdFailure() {
assertContains(log,
executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, SYS_METRICS, NODE_ID.argName(), "invalid_node_id"),
"Failed to parse " + NODE_ID.argName() +
" command argument. String representation of \"java.util.UUID\" is exepected." +
" For example: 123e4567-e89b-42d3-a456-556642440000"
);
}
/** Tests command error output in case multiple metric names are specified. */
@Test
public void testMultipleMetricNamesFailure() {
assertContains(log,
executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, IGNITE_METRICS, SYS_METRICS),
"Multiple metric(metric registry) names are not supported.");
}
/** Tests command error output in case {@link MetricCommandArg#NODE_ID} argument value refers to nonexistent node. */
@Test
public void testNonExistentNodeIdFailure() {
String incorrectNodeId = UUID.randomUUID().toString();
assertContains(log,
executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_METRIC, "--node-id", incorrectNodeId, IGNITE_METRICS),
"Failed to perform operation.\nNode with id=" + incorrectNodeId + " not found");
}
/** Tests command output in case nonexistent metric name is specified. */
@Test
public void testNonExistentMetric() {
assertContains(log, executeCommand(EXIT_CODE_OK, CMD_METRIC, IGNITE_METRICS + SEPARATOR),
"No metric with specified name was found [name=" + IGNITE_METRICS + SEPARATOR + ']');
assertContains(log, executeCommand(EXIT_CODE_OK, CMD_METRIC, "nonexistent.metric"),
"No metric with specified name was found [name=nonexistent.metric]");
}
/** */
@Test
public void testHistogramMetrics() {
String mregName = "histogram-registry";
MetricRegistry mreg = ignite0.context().metric().registry(mregName);
long[] bounds = new long[] {50, 500};
HistogramMetricImpl histogram = mreg.histogram("histogram", bounds, null);
histogram.value(10);
histogram.value(51);
histogram.value(60);
histogram.value(600);
histogram.value(600);
histogram.value(600);
histogram = mreg.histogram("histogram_with_underscore", bounds, null);
histogram.value(10);
histogram.value(51);
histogram.value(60);
histogram.value(600);
histogram.value(600);
histogram.value(600);
assertEquals("1", metric(ignite0, metricName(mregName, "histogram_0_50")));
assertEquals("2", metric(ignite0, metricName(mregName, "histogram_50_500")));
assertEquals("3", metric(ignite0, metricName(mregName, "histogram_500_inf")));
assertEquals("[1, 2, 3]", metric(ignite0, metricName(mregName, "histogram")));
assertEquals("1", metric(ignite0, metricName(mregName, "histogram_with_underscore_0_50")));
assertEquals("2", metric(ignite0, metricName(mregName, "histogram_with_underscore_50_500")));
assertEquals("3", metric(ignite0, metricName(mregName, "histogram_with_underscore_500_inf")));
assertEquals("[1, 2, 3]", metric(ignite0, metricName(mregName, "histogram_with_underscore")));
}
/** */
@Test
public void testNodeIdArgument() {
String mregName = "boolean-metric-registry";
MetricRegistry mreg = ignite0.context().metric().registry(mregName);
mreg.booleanMetric("boolean-metric", "");
mreg = ignite(1).context().metric().registry(mregName);
mreg.booleanMetric("boolean-metric", "").value(true);
assertEquals("false", metric(ignite0, metricName(mregName, "boolean-metric")));
assertEquals("true", metric(ignite(1), metricName(mregName, "boolean-metric")));
}
/** */
@Test
public void testRegistryMetrics() {
String mregName = "test-metric-registry";
MetricRegistry mreg = ignite0.context().metric().registry(mregName);
mreg.booleanMetric("boolean-metric", "");
mreg.longMetric("long-metric", "").increment();
mreg.intMetric("int-metric", "").increment();
mreg.doubleMetric("double-metric", "");
mreg.hitRateMetric("hitrate-metric", "", getTestTimeout(), 2);
mreg.histogram("histogram", new long[] {50, 100}, null).value(10);
mreg.hitRateMetric("hitrate-metric", "", getTestTimeout(), 2);
mreg.objectMetric("object-metric", Object.class, "").value(new Object() {
@Override public String toString() {
return "test-object";
}
});
Map<String, String> metrics = metrics(ignite0, mregName);
assertEquals("0.0", metrics.get(metricName(mregName, "double-metric")));
assertEquals("false", metrics.get(metricName(mregName, "boolean-metric")));
assertEquals("1", metrics.get(metricName(mregName, "long-metric")));
assertEquals("1", metrics.get(metricName(mregName, "int-metric")));
assertEquals("test-object", metrics.get(metricName(mregName, "object-metric")));
assertEquals("[1, 0, 0]", metrics.get(metricName(mregName, "histogram")));
assertEquals("0", metric(ignite0, metricName(mregName, "hitrate-metric")));
}
/** */
@Test
public void testBooleanMetrics() {
String mregName = "boolean-metric-registry";
MetricRegistry mreg = ignite0.context().metric().registry(mregName);
mreg.booleanMetric("boolean-metric", "");
assertEquals("false", metric(ignite0, metricName(mregName, "boolean-metric")));
mreg.register("boolean-gauge", () -> true, "");
assertEquals("true", metric(ignite0, metricName(mregName, "boolean-gauge")));
}
/** */
@Test
public void testLongMetrics() {
String mregName = "long-metric-registry";
MetricRegistry mreg = ignite0.context().metric().registry(mregName);
mreg.longMetric("long-metric", "").add(Long.MAX_VALUE);
assertEquals(Long.toString(Long.MAX_VALUE), metric(ignite0, metricName(mregName, "long-metric")));
mreg.register("long-gauge", () -> 0L, "");
assertEquals("0", metric(ignite0, metricName(mregName, "long-gauge")));
}
/** */
@Test
public void testIntegerMetrics() {
String mregName = "int-metric-registry";
MetricRegistry mreg = ignite0.context().metric().registry(mregName);
mreg.intMetric("int-metric", "").add(Integer.MAX_VALUE);
assertEquals(Integer.toString(Integer.MAX_VALUE), metric(ignite0, metricName(mregName, "int-metric")));
mreg.register("int-gauge", () -> 0, "");
assertEquals("0", metric(ignite0, metricName(mregName, "int-gauge")));
}
/** */
@Test
public void testDoubleMetrics() {
String mregName = "int-double-registry";
MetricRegistry mreg = ignite0.context().metric().registry(mregName);
mreg.doubleMetric("double-metric", "").add(111.222);
assertEquals("111.222", metric(ignite0, metricName(mregName, "double-metric")));
mreg.register("double-gauge", () -> 0D, "");
assertEquals("0.0", metric(ignite0, metricName(mregName, "double-gauge")));
}
/** */
@Test
public void testObjectMetrics() {
String mregName = "object-registry";
MetricRegistry mreg = ignite0.context().metric().registry(mregName);
Object metricVal = new Object() {
@Override public String toString() {
return "test-object";
}
};
mreg.objectMetric("object-metric", Object.class, "").value(metricVal);
assertEquals("test-object", metric(ignite0, metricName(mregName, "object-metric")));
mreg.register("object-gauge", () -> metricVal, Object.class, "");
assertEquals("test-object", metric(ignite0, metricName(mregName, "object-gauge")));
}
/** */
@Test
public void testHitrateMetrics() {
String mregName = "hitrate-registry";
MetricRegistry mreg = ignite0.context().metric().registry(mregName);
mreg.hitRateMetric("hitrate-metric", "", getTestTimeout(), 2).add(Integer.MAX_VALUE);
assertEquals(Integer.toString(Integer.MAX_VALUE), metric(ignite0, metricName(mregName, "hitrate-metric")));
}
/**
* Gets metric values via command-line utility.
*
* @param node Node to obtain metric values from.
* @param name Name of a particular metric or metric registry.
* @return String representation of metric values.
*/
private Map<String, String> metrics(IgniteEx node, String name) {
String nodeId = node.context().discovery().localNode().id().toString();
String out = executeCommand(EXIT_CODE_OK, CMD_METRIC, name, NODE_ID.argName(), nodeId);
Map<String, String> res = parseMetricCommandOutput(out);
assertEquals("value", res.remove("metric"));
return res;
}
/**
* Gets single metric value via command-line utility.
*
* @param node Node to obtain metric from.
* @param name Name of the metric.
* @return String representation of metric value.
*/
private String metric(IgniteEx node, String name) {
Map<String, String> metrics = metrics(node, name);
assertEquals(1, metrics.size());
return metrics.get(name);
}
/**
* Obtains metric values from command output.
*
* @param out Command output to parse.
* @return Metric values.
*/
private Map<String, String> parseMetricCommandOutput(String out) {
String outStart = "--------------------------------------------------------------------------------";
String outEnd = "Command [" + METRIC.toCommandName() + "] finished with code: " + EXIT_CODE_OK;
String[] rows = out.substring(
out.indexOf(outStart) + outStart.length() + 1,
out.indexOf(outEnd) - 1
).split(U.nl());
Map<String, String> res = new HashMap<>();
for (String row : rows) {
Iterator<String> iter = Arrays.stream(row.split(quote(COLUMN_SEPARATOR)))
.map(String::trim)
.filter(str -> !str.isEmpty())
.iterator();
res.put(iter.next(), iter.next());
}
return res;
}
/**
* Executes command and checks its exit code.
*
* @param expExitCode Expected exit code.
* @param args Command lines arguments.
* @return Result of command execution.
*/
private String executeCommand(int expExitCode, String... args) {
int res = execute(args);
assertEquals(expExitCode, res);
return testOut.toString();
}
}