blob: ad0655b8f1654b3940e79504823e5103e32c2890 [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.lang.reflect.Field;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteJdbcThinDriver;
import org.apache.ignite.Ignition;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
import org.apache.ignite.cache.query.ContinuousQuery;
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.cache.query.ScanQuery;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.configuration.DataRegionConfiguration;
import org.apache.ignite.configuration.DataStorageConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.configuration.SqlConfiguration;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.internal.binary.mutabletest.GridBinaryTestClasses.TestObjectAllTypes;
import org.apache.ignite.internal.binary.mutabletest.GridBinaryTestClasses.TestObjectEnum;
import org.apache.ignite.internal.commandline.CommandList;
import org.apache.ignite.internal.commandline.systemview.SystemViewCommandArg;
import org.apache.ignite.internal.metric.SystemViewSelfTest.TestPredicate;
import org.apache.ignite.internal.metric.SystemViewSelfTest.TestRunnable;
import org.apache.ignite.internal.metric.SystemViewSelfTest.TestTransformer;
import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
import org.apache.ignite.internal.processors.cache.metric.SqlViewExporterSpiTest.TestAffinityFunction;
import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
import org.apache.ignite.internal.processors.metastorage.DistributedMetaStorage;
import org.apache.ignite.internal.processors.service.DummyService;
import org.apache.ignite.internal.util.StripedExecutor;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.internal.visor.systemview.VisorSystemViewTask;
import org.apache.ignite.services.ServiceConfiguration;
import org.apache.ignite.spi.systemview.view.SystemView;
import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker.AttributeVisitor;
import org.apache.ignite.testframework.GridTestUtils;
import org.apache.ignite.transactions.Transaction;
import org.junit.Test;
import static java.lang.Integer.MAX_VALUE;
import static java.util.Arrays.asList;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.regex.Pattern.quote;
import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
import static org.apache.ignite.cluster.ClusterState.ACTIVE;
import static org.apache.ignite.cluster.ClusterState.INACTIVE;
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.SYSTEM_VIEW;
import static org.apache.ignite.internal.commandline.systemview.SystemViewCommand.COLUMN_SEPARATOR;
import static org.apache.ignite.internal.commandline.systemview.SystemViewCommandArg.NODE_ID;
import static org.apache.ignite.internal.managers.systemview.GridSystemViewManager.STREAM_POOL_QUEUE_VIEW;
import static org.apache.ignite.internal.managers.systemview.GridSystemViewManager.SYS_POOL_QUEUE_VIEW;
import static org.apache.ignite.internal.managers.systemview.ScanQuerySystemView.SCAN_QRY_SYS_VIEW;
import static org.apache.ignite.internal.metric.SystemViewSelfTest.TEST_PREDICATE;
import static org.apache.ignite.internal.metric.SystemViewSelfTest.TEST_TRANSFORMER;
import static org.apache.ignite.internal.processors.cache.ClusterCachesInfo.CACHES_VIEW;
import static org.apache.ignite.internal.processors.cache.ClusterCachesInfo.CACHE_GRPS_VIEW;
import static org.apache.ignite.internal.processors.cache.GridCacheProcessor.CACHE_GRP_PAGE_LIST_VIEW;
import static org.apache.ignite.internal.processors.cache.GridCacheProcessor.PART_STATES_VIEW;
import static org.apache.ignite.internal.processors.cache.GridCacheUtils.cacheGroupId;
import static org.apache.ignite.internal.processors.cache.GridCacheUtils.cacheId;
import static org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl.BINARY_METADATA_VIEW;
import static org.apache.ignite.internal.processors.cache.index.AbstractSchemaSelfTest.queryProcessor;
import static org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager.METASTORE_VIEW;
import static org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager.DATA_REGION_PAGE_LIST_VIEW;
import static org.apache.ignite.internal.processors.cache.transactions.IgniteTxManager.TXS_MON_LIST;
import static org.apache.ignite.internal.processors.continuous.GridContinuousProcessor.CQ_SYS_VIEW;
import static org.apache.ignite.internal.processors.metastorage.persistence.DistributedMetaStorageImpl.DISTRIBUTED_METASTORE_VIEW;
import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.toSqlName;
import static org.apache.ignite.internal.processors.odbc.ClientListenerProcessor.CLI_CONN_VIEW;
import static org.apache.ignite.internal.processors.query.QueryUtils.DFLT_SCHEMA;
import static org.apache.ignite.internal.processors.query.QueryUtils.SCHEMA_SYS;
import static org.apache.ignite.internal.processors.query.h2.SchemaManager.SQL_SCHEMA_VIEW;
import static org.apache.ignite.internal.processors.query.h2.SchemaManager.SQL_TBLS_VIEW;
import static org.apache.ignite.internal.processors.query.h2.SchemaManager.SQL_TBL_COLS_VIEW;
import static org.apache.ignite.internal.processors.query.h2.SchemaManager.SQL_VIEWS_VIEW;
import static org.apache.ignite.internal.processors.query.h2.SchemaManager.SQL_VIEW_COLS_VIEW;
import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.SVCS_VIEW;
import static org.apache.ignite.internal.processors.task.GridTaskProcessor.TASKS_VIEW;
import static org.apache.ignite.internal.util.IgniteUtils.toStringSafe;
import static org.apache.ignite.testframework.GridTestUtils.assertContains;
import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
/** Tests output of {@link CommandList#SYSTEM_VIEW} command. */
public class SystemViewCommandTest extends GridCommandHandlerClusterByClassAbstractTest {
/** Command line argument for printing content of a system view. */
private static final String CMD_SYS_VIEW = SYSTEM_VIEW.text();
/** Latch that is used to unblock all compute jobs. */
private static final CountDownLatch COMPUTE_JOB_UNBLOCK_LATCH = new CountDownLatch(1);
/** Latch that indicates number of compute jobs to be blocked.*/
private static final CountDownLatch COMPUTE_JOB_BLOCK_LATCH = new CountDownLatch(5);
/** Name of the test data region. */
private static final String DATA_REGION_NAME = "in-memory";
/** Test node with 0 index. */
private IgniteEx ignite0;
/** Test node with 1 index. */
private IgniteEx ignite1;
/** {@inheritDoc} */
@Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
cfg.setDataStorageConfiguration(new DataStorageConfiguration()
.setDataRegionConfigurations(new DataRegionConfiguration()
.setName(DATA_REGION_NAME)
.setMaxSize(100L * 1024 * 1024))
.setDefaultDataRegionConfiguration(new DataRegionConfiguration()
.setPersistenceEnabled(true)));
return cfg;
}
/** {@inheritDoc} */
@Override protected void beforeTest() throws Exception {
super.beforeTest();
injectTestSystemOut();
autoConfirmation = false;
ignite0 = ignite(0);
ignite1 = ignite(1);
}
/** Tests command error output in case of mandatory system view name is omitted. */
@Test
public void testSystemViewNameMissedFailure() {
assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_SYS_VIEW),
"The name of the system view for which its content should be printed is expected.");
}
/** Tests command error output in case value of {@link SystemViewCommandArg#NODE_ID} argument is omitted. */
@Test
public void testNodeIdMissedFailure() {
assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_SYS_VIEW, SVCS_VIEW, NODE_ID.argName()),
"ID of the node from which system view content should be obtained is expected.");
}
/** Tests command error output in case value of {@link SystemViewCommandArg#NODE_ID} argument is invalid.*/
@Test
public void testInvalidNodeIdFailure() {
assertContains(log,
executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_SYS_VIEW, SVCS_VIEW, 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 system view names are specified. */
@Test
public void testMultipleSystemViewNamesFailure() {
assertContains(log,
executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_SYS_VIEW, SVCS_VIEW, CACHE_GRP_PAGE_LIST_VIEW),
"Multiple system view names are not supported.");
}
/**
* Tests command error output in case {@link SystemViewCommandArg#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_SYS_VIEW, "--node-id", incorrectNodeId, CACHES_VIEW),
"Failed to perform operation.\nNode with id=" + incorrectNodeId + " not found");
}
/** Tests command output in case nonexistent system view names is specified. */
@Test
public void testNonExistentSystemView() {
assertContains(log, executeCommand(EXIT_CODE_OK, CMD_SYS_VIEW, "non_existent_system_view"),
"No system view with specified name was found [name=non_existent_system_view]");
}
/** */
@Test
public void testCachesView() {
Set<String> cacheNames = new HashSet<>(asList("cache-1", "cache-2"));
cacheNames.forEach(cacheName -> ignite0.createCache(cacheName));
List<List<String>> cachesView = systemView(ignite0, CACHES_VIEW);
assertEquals(ignite0.context().cache().cacheDescriptors().size(), cachesView.size());
cachesView.forEach(row -> cacheNames.remove(row.get(0)));
assertTrue(cacheNames.isEmpty());
}
/** */
@Test
public void testCacheGroupsView() {
Set<String> grpNames = new HashSet<>(asList("grp-1", "grp-2"));
for (String grpName : grpNames)
ignite0.createCache(new CacheConfiguration<>("cache-" + grpName).setGroupName(grpName));
List<List<String>> cacheGrpsView = systemView(ignite0, CACHE_GRPS_VIEW);
assertEquals(ignite0.context().cache().cacheGroupDescriptors().size(), cacheGrpsView.size());
cacheGrpsView.forEach(row -> grpNames.remove(row.get(0)));
assertTrue(grpNames.toString(), grpNames.isEmpty());
}
/** */
@Test
public void testComputeBroadcast() throws Exception {
long tasksCnt = COMPUTE_JOB_BLOCK_LATCH.getCount();
try {
for (int i = 0; i < tasksCnt; i++) {
ignite0.compute().broadcastAsync(() -> {
try {
COMPUTE_JOB_BLOCK_LATCH.countDown();
COMPUTE_JOB_UNBLOCK_LATCH.await();
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
}
COMPUTE_JOB_BLOCK_LATCH.await();
List<List<String>> tasksView = systemView(ignite0, TASKS_VIEW).stream()
.filter(row -> !VisorSystemViewTask.class.getName().equals(row.get(3)))
.collect(Collectors.toList());
assertEquals(tasksCnt, tasksView.size());
tasksView.forEach(row -> {
assertEquals("false", row.get(10)); //internal
assertEquals("null", row.get(6)); // affinityCacheName
assertEquals("-1", row.get(5)); // affinityPartitionId
assertTrue(row.get(4).startsWith(getClass().getName())); // taskClassName
assertTrue(row.get(3).startsWith(getClass().getName())); // taskName
assertEquals(ignite0.localNode().id().toString(), row.get(2)); // taskNodeId
assertEquals("0", row.get(12)); // userVersion
});
}
finally {
COMPUTE_JOB_UNBLOCK_LATCH.countDown();
}
}
/** */
@Test
public void testServices() {
ServiceConfiguration srvcCfg = new ServiceConfiguration();
srvcCfg.setName("service");
srvcCfg.setMaxPerNodeCount(1);
srvcCfg.setService(new DummyService());
ignite0.services().deploy(srvcCfg);
List<List<String>> srvsView = systemView(ignite0, SVCS_VIEW);
assertEquals(1, srvsView.size());
List<String> sysView = srvsView.get(0);
assertEquals(srvcCfg.getName(), sysView.get(1)); // name
assertEquals(DummyService.class.getName(), sysView.get(2)); // serviceClass
assertEquals(Integer.toString(srvcCfg.getMaxPerNodeCount()), sysView.get(6)); // maxPerNodeCount
}
/** */
@Test
public void testClientsConnections() throws Exception {
String host = ignite0.configuration().getClientConnectorConfiguration().getHost();
if (host == null)
host = ignite0.configuration().getLocalHost();
int port = ignite0.configuration().getClientConnectorConfiguration().getPort();
try (
IgniteClient ignored1 = Ignition.startClient(new ClientConfiguration().setAddresses(host + ":" + port));
Connection ignored2 = new IgniteJdbcThinDriver().connect("jdbc:ignite:thin://" + host, new Properties())
) {
assertEquals(2, systemView(ignite0, CLI_CONN_VIEW).size());
}
}
/** */
@Test
public void testTransactions() throws Exception {
IgniteCache<Integer, Integer> cache = ignite0.createCache(
new CacheConfiguration<Integer, Integer>("test-cache").setAtomicityMode(TRANSACTIONAL));
assertTrue(systemView(ignite0, TXS_MON_LIST).isEmpty());
CountDownLatch txBlockLatch = new CountDownLatch(10);
CountDownLatch txUnblockLatch = new CountDownLatch(1);
try {
AtomicInteger cntr = new AtomicInteger();
GridTestUtils.runMultiThreadedAsync(() -> {
try (
Transaction ignored = ignite0.transactions().withLabel("test")
.txStart(PESSIMISTIC, REPEATABLE_READ)
) {
cache.put(cntr.incrementAndGet(), cntr.incrementAndGet());
cache.put(cntr.incrementAndGet(), cntr.incrementAndGet());
txBlockLatch.countDown();
txUnblockLatch.await();
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, 5, "sys-view-cmd-tx-test-1");
GridTestUtils.runMultiThreadedAsync(() -> {
try (Transaction ignored = ignite0.transactions().txStart(OPTIMISTIC, SERIALIZABLE)) {
cache.put(cntr.incrementAndGet(), cntr.incrementAndGet());
cache.put(cntr.incrementAndGet(), cntr.incrementAndGet());
txBlockLatch.countDown();
txUnblockLatch.await();
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, 5, "sys-view-cmd-tx-test-2");
txBlockLatch.await(getTestTimeout(), MILLISECONDS);
List<List<String>> txsView = systemView(ignite0, TXS_MON_LIST);
assertEquals(10, txsView.size());
}
finally {
txUnblockLatch.countDown();
}
assertTrue(waitForCondition(() -> systemView(ignite0, TXS_MON_LIST).isEmpty(), getTestTimeout()));
}
/** */
@Test
public void testSchemas() throws Exception {
try (
IgniteEx g = startGrid(getConfiguration(getTestIgniteInstanceName(3))
.setSqlConfiguration(new SqlConfiguration().setSqlSchemas("MY_SCHEMA", "ANOTHER_SCHEMA")))
) {
Set<String> schemaNames = new HashSet<>();
HashSet<String> expSchemas = new HashSet<>(asList("MY_SCHEMA", "ANOTHER_SCHEMA", "SYS", "PUBLIC"));
List<List<String>> sqlSchemaView = systemView(g, SQL_SCHEMA_VIEW);
sqlSchemaView.forEach(row -> schemaNames.add(row.get(0))); // name
assertEquals(schemaNames, expSchemas);
}
}
/** */
@Test
public void testViews() {
Set<String> expViewNames = new HashSet<>(asList(
"METRICS",
"VIEWS",
"SERVICES",
"CACHE_GROUPS",
"CACHES",
"TASKS",
"JOBS",
"SQL_QUERIES_HISTORY",
"NODES",
"SCHEMAS",
"NODE_METRICS",
"BASELINE_NODES",
"BASELINE_NODE_ATTRIBUTES",
"INDEXES",
"LOCAL_CACHE_GROUPS_IO",
"SQL_QUERIES",
"SCAN_QUERIES",
"NODE_ATTRIBUTES",
"TABLES",
"CLIENT_CONNECTIONS",
"TABLE_COLUMNS",
"VIEW_COLUMNS",
"TRANSACTIONS",
"CONTINUOUS_QUERIES",
"STRIPED_THREADPOOL_QUEUE",
"DATASTREAM_THREADPOOL_QUEUE",
"DATA_REGION_PAGE_LISTS",
"CACHE_GROUP_PAGE_LISTS",
"PARTITION_STATES",
"BINARY_METADATA",
"METASTORAGE",
"DISTRIBUTED_METASTORAGE",
"STATISTICS_CONFIGURATION",
"STATISTICS_PARTITION_DATA",
"STATISTICS_LOCAL_DATA"
));
Set<String> viewNames = new HashSet<>();
List<List<String>> sqlViewsView = systemView(ignite0, SQL_VIEWS_VIEW);
sqlViewsView.forEach(row -> viewNames.add(row.get(0))); // name
assertEquals(expViewNames, viewNames);
}
/** */
@Test
public void testTable() {
assertTrue(systemView(ignite0, SQL_TBLS_VIEW).isEmpty());
executeSql(ignite0, "CREATE TABLE T1(ID LONG PRIMARY KEY, NAME VARCHAR)");
List<List<String>> sqlTablesView = systemView(ignite0, SQL_TBLS_VIEW);
assertEquals(1, sqlTablesView.size());
List<String> row = sqlTablesView.get(0);
assertEquals(Integer.toString(cacheId("SQL_PUBLIC_T1")), row.get(0)); // CACHE_GROUP_ID
assertEquals("SQL_PUBLIC_T1", row.get(1)); // CACHE_GROUP_NAME
assertEquals(Integer.toString(cacheId("SQL_PUBLIC_T1")), row.get(2)); // CACHE_ID
assertEquals("SQL_PUBLIC_T1", row.get(3)); // CACHE_NAME
assertEquals(DFLT_SCHEMA, row.get(4)); // SCHEMA_NAME
assertEquals("T1", row.get(5)); // TABLE_NAME
assertEquals("null", row.get(6)); // AFFINITY_KEY_COLUMN
assertEquals("ID", row.get(7)); // KEY_ALIAS
assertEquals("null", row.get(8)); // VALUE_ALIAS
assertEquals("java.lang.Long", row.get(9)); // KEY_TYPE_NAME
assertFalse("null".equals(row.get(10))); // VALUE_TYPE_NAME
executeSql(ignite0, "CREATE TABLE T2(ID LONG PRIMARY KEY, NAME VARCHAR)");
assertEquals(2, systemView(ignite0, SQL_TBLS_VIEW).size());
executeSql(ignite0, "DROP TABLE T1");
executeSql(ignite0, "DROP TABLE T2");
assertTrue(systemView(ignite0, SQL_TBLS_VIEW).isEmpty());
}
/** */
@Test
public void testTableColumns() {
assertTrue(systemView(ignite0, SQL_TBL_COLS_VIEW).isEmpty());
executeSql(ignite0, "CREATE TABLE T1(ID LONG PRIMARY KEY, NAME VARCHAR(40))");
Set<?> actCols = systemView(ignite0, SQL_TBL_COLS_VIEW).stream()
.map(row -> row.get(0)) // columnName
.collect(Collectors.toSet());
assertEquals(new HashSet<>(asList("ID", "NAME", "_KEY", "_VAL")), actCols);
executeSql(ignite0, "CREATE TABLE T2(ID LONG PRIMARY KEY, NAME VARCHAR(50))");
Set<List<String>> expSqlTableColumnsView = new HashSet<>(asList(
asList("ID", "T1", "PUBLIC", "false", "false", "null", "true", "true", "-1", "-1", Long.class.getName()),
asList("NAME", "T1", "PUBLIC", "false", "false", "null", "true", "false", "40", "-1", String.class.getName()),
asList("_KEY", "T1", "PUBLIC", "true", "false", "null", "false", "true", "-1", "-1", "null"),
asList("_VAL", "T1", "PUBLIC", "false", "false", "null", "true", "false", "-1", "-1", "null"),
asList("ID", "T2", "PUBLIC", "false", "false", "null", "true", "true", "-1", "-1", Long.class.getName()),
asList("NAME", "T2", "PUBLIC", "false", "false", "null", "true", "false", "50", "-1", String.class.getName()),
asList("_KEY", "T2", "PUBLIC", "true", "false", "null", "false", "true", "-1", "-1", "null"),
asList("_VAL", "T2", "PUBLIC", "false", "false", "null", "true", "false", "-1", "-1", "null")
));
Set<List<String>> sqlTableColumnsView = new HashSet<>(systemView(ignite0, SQL_TBL_COLS_VIEW));
assertEquals(expSqlTableColumnsView, sqlTableColumnsView);
executeSql(ignite0, "DROP TABLE T1");
executeSql(ignite0, "DROP TABLE T2");
assertTrue(systemView(ignite0, SQL_TBL_COLS_VIEW).isEmpty());
}
/** */
@Test
public void testViewColumns() {
Set<List<String>> expsqlViewColumnsView = new HashSet<>(asList(
asList("CONNECTION_ID", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", "19", "0", Long.class.getName()),
asList("LOCAL_ADDRESS", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", Integer.toString(MAX_VALUE), "0",
String.class.getName()),
asList("REMOTE_ADDRESS", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", Integer.toString(MAX_VALUE), "0",
String.class.getName()),
asList("TYPE", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", Integer.toString(MAX_VALUE), "0",
String.class.getName()),
asList("USER", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", Integer.toString(MAX_VALUE), "0",
String.class.getName()),
asList("VERSION", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", Integer.toString(MAX_VALUE), "0",
String.class.getName())
));
Set<List<String>> sqlViewColumnsView = systemView(ignite0, SQL_VIEW_COLS_VIEW).stream()
.filter(row -> "CLIENT_CONNECTIONS".equals(row.get(1))) // viewName
.collect(Collectors.toSet());
assertEquals(expsqlViewColumnsView, sqlViewColumnsView);
}
/** */
@Test
public void testContinuousQuery() throws Exception {
IgniteCache<Integer, Integer> cache = ignite0.createCache("test-cache");
assertTrue(systemView(ignite0, CQ_SYS_VIEW).isEmpty());
assertTrue(systemView(ignite1, CQ_SYS_VIEW).isEmpty());
try (QueryCursor<?> ignored = cache.query(new ContinuousQuery<>()
.setInitialQuery(new ScanQuery<>())
.setPageSize(100)
.setTimeInterval(1000)
.setLocalListener(evts -> {
// No-op.
})
.setRemoteFilterFactory(() -> evt -> true)
)) {
for (int i = 0; i < 100; i++)
cache.put(i, i);
checkContinuouQueryView(ignite0, true);
checkContinuouQueryView(ignite1, false);
}
assertTrue(systemView(ignite0, CQ_SYS_VIEW).isEmpty());
assertTrue(waitForCondition(() -> systemView(ignite1, CQ_SYS_VIEW).isEmpty(), getTestTimeout()));
}
/** */
private void checkContinuouQueryView(IgniteEx node, boolean loc) {
List<List<String>> cqSysView = systemView(node, CQ_SYS_VIEW);
assertEquals(1, cqSysView.size());
List<String> row = cqSysView.get(0);
assertEquals("test-cache", row.get(0)); //cacheName
assertEquals("100", row.get(7)); // bufferSize
assertEquals("1000", row.get(9)); // interval
assertEquals(ignite0.localNode().id().toString(), row.get(14)); // nodeId
if (loc)
assertTrue(row.get(1).startsWith(getClass().getName())); // localListener
else
assertEquals("null", row.get(1)); // localListener
assertTrue(row.get(2).startsWith(getClass().getName())); // remoteFilter
assertEquals("null", row.get(4)); // localTransformedListener
assertEquals("null", row.get(3)); // remoteTransformer
}
/** */
@Test
public void testLocalScanQuery() throws Exception {
IgniteCache<Integer, Integer> cache1 = ignite0.createCache(
new CacheConfiguration<Integer, Integer>("cache1").setGroupName("group1"));
int part = ignite0.affinity("cache1").primaryPartitions(ignite0.localNode())[0];
List<Integer> partKeys = partitionKeys(cache1, part, 11, 0);
partKeys.forEach(key -> cache1.put(key, key));
assertTrue(systemView(ignite0, SCAN_QRY_SYS_VIEW).isEmpty());
try (
QueryCursor<Integer> qryRes1 = cache1.query(
new ScanQuery<Integer, Integer>()
.setFilter(new TestPredicate())
.setLocal(true)
.setPartition(part)
.setPageSize(10),
new TestTransformer())
) {
assertTrue(qryRes1.iterator().hasNext());
assertTrue(waitForCondition(() -> !systemView(ignite0, SCAN_QRY_SYS_VIEW).isEmpty(), getTestTimeout()));
List<String> view = systemView(ignite0, SCAN_QRY_SYS_VIEW).get(0);
assertEquals(ignite0.localNode().id().toString(), view.get(0)); // originNodeId
assertEquals("0", view.get(1)); // queryId
assertEquals("cache1", view.get(2)); // cacheName
assertEquals(Integer.toString(cacheId("cache1")), view.get(3)); // cacheId
assertEquals(Integer.toString(cacheGroupId("cache1", "group1")), view.get(4)); // cacheGroupId
assertEquals("group1", view.get(5)); // cacheGroupName
assertTrue(Long.parseLong(view.get(6)) <= System.currentTimeMillis()); // startTime
assertTrue(Long.parseLong(view.get(7)) >= 0); // duration
assertFalse(Boolean.parseBoolean(view.get(8))); // canceled
assertEquals(TEST_PREDICATE, view.get(9)); // filter
assertTrue(Boolean.parseBoolean(view.get(11))); // local
assertEquals(part, Integer.parseInt(view.get(13))); // partition
assertEquals(toStringSafe(ignite0.context().discovery().topologyVersionEx()), view.get(16)); // topology
assertEquals(TEST_TRANSFORMER, view.get(17)); // transformer
assertFalse(Boolean.parseBoolean(view.get(10))); // keepBinary
assertEquals("null", view.get(14)); // subjectId
assertEquals("null", view.get(15)); // taskName
}
assertTrue(waitForCondition(() -> systemView(ignite0, SCAN_QRY_SYS_VIEW).isEmpty(), getTestTimeout()));
}
/** */
@Test
public void testScanQuery() throws Exception {
try (
IgniteEx client1 = startClientGrid("client-1");
IgniteEx client2 = startClientGrid("client-2")
) {
IgniteCache<Integer, Integer> cache1 = client1.createCache(
new CacheConfiguration<Integer, Integer>("cache1").setGroupName("group1"));
IgniteCache<Integer, Integer> cache2 = client2.createCache("cache2");
for (int i = 0; i < 100; i++) {
cache1.put(i, i);
cache2.put(i, i);
}
assertTrue(systemView(ignite0, SCAN_QRY_SYS_VIEW).isEmpty());
assertTrue(systemView(ignite1, SCAN_QRY_SYS_VIEW).isEmpty());
try (
QueryCursor<Integer> qryRes1 = cache1.query(
new ScanQuery<Integer, Integer>()
.setFilter(new TestPredicate())
.setPageSize(10),
new TestTransformer());
QueryCursor<?> qryRes2 = cache2.withKeepBinary().query(new ScanQuery<>().setPageSize(20))
) {
assertTrue(qryRes1.iterator().hasNext());
assertTrue(qryRes2.iterator().hasNext());
checkScanQueryView(client1, client2, ignite0);
checkScanQueryView(client1, client2, ignite1);
}
assertTrue(waitForCondition(() ->
systemView(ignite0, SCAN_QRY_SYS_VIEW).isEmpty() && systemView(ignite1, SCAN_QRY_SYS_VIEW).isEmpty(),
getTestTimeout()));
}
}
/** */
private void checkScanQueryView(IgniteEx client1, IgniteEx client2, IgniteEx node) throws Exception {
assertTrue(waitForCondition(() -> systemView(ignite0, SCAN_QRY_SYS_VIEW).size() > 1, getTestTimeout()));
Consumer<List<String>> cache1checker = view -> {
assertEquals(client1.localNode().id().toString(), view.get(0));
assertTrue(Long.parseLong(view.get(1)) != 0);
assertEquals("cache1", view.get(2));
assertEquals(Integer.toString(cacheId("cache1")), view.get(3));
assertEquals(Integer.toString(cacheGroupId("cache1", "group1")), view.get(4));
assertEquals("group1", view.get(5));
assertTrue(Long.parseLong(view.get(6)) <= System.currentTimeMillis());
assertTrue(Long.parseLong(view.get(7)) >= 0);
assertFalse(Boolean.parseBoolean(view.get(8)));
assertEquals(TEST_PREDICATE, view.get(9));
assertFalse(Boolean.parseBoolean(view.get(11)));
assertEquals("-1", view.get(13));
assertEquals(toStringSafe(client1.context().discovery().topologyVersionEx()), view.get(16));
assertEquals(TEST_TRANSFORMER, view.get(17));
assertFalse(Boolean.parseBoolean(view.get(10)));
assertEquals("null", view.get(14));
assertEquals("null", view.get(15));
assertEquals("10", view.get(12));
};
Consumer<List<String>> cache2checker = view -> {
assertEquals(client2.localNode().id().toString(), view.get(0));
assertTrue(Long.parseLong(view.get(1)) != 0);
assertEquals("cache2", view.get(2));
assertEquals(Integer.toString(cacheId("cache2")), view.get(3));
assertEquals(Integer.toString(cacheGroupId("cache2", null)), view.get(4));
assertEquals("cache2", view.get(5));
assertTrue(Long.parseLong(view.get(6)) <= System.currentTimeMillis());
assertTrue(Long.parseLong(view.get(7)) >= 0);
assertFalse(Boolean.parseBoolean(view.get(8)));
assertEquals("null", view.get(9));
assertFalse(Boolean.parseBoolean(view.get(11)));
assertEquals("-1", view.get(13));
assertEquals(toStringSafe(client2.context().discovery().topologyVersionEx()), view.get(16));
assertEquals("null", view.get(17));
assertTrue(Boolean.parseBoolean(view.get(10)));
assertEquals("null", view.get(14));
assertEquals("null", view.get(15));
assertEquals("20", view.get(12));
};
boolean found1 = false;
boolean found2 = false;
for (List<String> row : systemView(node, SCAN_QRY_SYS_VIEW)) {
if ("cache2".equals(row.get(2))) {
cache2checker.accept(row);
found1 = true;
}
else {
cache1checker.accept(row);
found2 = true;
}
}
assertTrue(found1 && found2);
}
/** */
@Test
public void testStripedExecutor() throws Exception {
checkStripeExecutorView(ignite0.context().pools().getStripedExecutorService(),
SYS_POOL_QUEUE_VIEW,
"sys");
}
/** */
@Test
public void testStreamerExecutor() throws Exception {
checkStripeExecutorView(ignite0.context().pools().getDataStreamerExecutorService(),
STREAM_POOL_QUEUE_VIEW,
"data-streamer");
}
/**
* Checks striped executor system view.
*
* @param execSvc Striped executor.
* @param view System view name.
* @param poolName Executor name.
*/
private void checkStripeExecutorView(StripedExecutor execSvc, String view, String poolName) throws Exception {
CountDownLatch latch = new CountDownLatch(1);
execSvc.execute(0, new TestRunnable(latch, 0));
execSvc.execute(0, new TestRunnable(latch, 1));
execSvc.execute(1, new TestRunnable(latch, 2));
execSvc.execute(1, new TestRunnable(latch, 3));
try {
assertTrue(waitForCondition(() -> systemView(ignite0, view).size() == 2, getTestTimeout()));
List<List<String>> stripedQueue = systemView(ignite0, view);
List<String> row0 = stripedQueue.get(0);
assertEquals("0", row0.get(0));
assertEquals(TestRunnable.class.getSimpleName() + '1', row0.get(1));
assertEquals(poolName + "-stripe-0", row0.get(2));
assertEquals(TestRunnable.class.getName(), row0.get(3));
List<String> row1 = stripedQueue.get(1);
assertEquals("1", row1.get(0));
assertEquals(TestRunnable.class.getSimpleName() + '3', row1.get(1));
assertEquals(poolName + "-stripe-1", row1.get(2));
assertEquals(TestRunnable.class.getName(), row1.get(3));
}
finally {
latch.countDown();
}
}
/** */
@Test
public void testPagesList() throws Exception {
String cacheName = "cacheFL";
IgniteCache<Integer, byte[]> cache = ignite0.getOrCreateCache(new CacheConfiguration<Integer, byte[]>()
.setName(cacheName)
.setAffinity(new RendezvousAffinityFunction()
.setPartitions(1)));
GridCacheDatabaseSharedManager dbMgr = (GridCacheDatabaseSharedManager)ignite0.context().cache().context()
.database();
int pageSize = dbMgr.pageSize();
try {
dbMgr.enableCheckpoints(false).get();
int key = 0;
// Fill up different free-list buckets.
for (int j = 0; j < pageSize / 2; j++)
cache.put(key++, new byte[j + 1]);
// Put some pages to one bucket to overflow pages cache.
for (int j = 0; j < 1000; j++)
cache.put(key++, new byte[pageSize / 2]);
List<List<String>> cacheGrpView = systemView(ignite0, CACHE_GRP_PAGE_LIST_VIEW);
List<List<String>> dataRegionView = systemView(ignite0, DATA_REGION_PAGE_LIST_VIEW);
String cacheId = Integer.toString(cacheId(cacheName));
// Test filtering by 3 columns.
assertFalse(cacheGrpView.stream().noneMatch(row ->
cacheId.equals(row.get(0)) &&
"0".equals(row.get(1)) &&
"0".equals(row.get(3))));
// Test filtering with invalid cache group id.
assertTrue(cacheGrpView.stream().noneMatch(row -> "-1".equals(row.get(0))));
// Test filtering with invalid partition id.
assertTrue(cacheGrpView.stream().noneMatch(row -> "-1".equals(row.get(1))));
// Test filtering with invalid bucket number.
assertTrue(cacheGrpView.stream().noneMatch(row -> "-1".equals(row.get(3))));
assertFalse(cacheGrpView.stream().noneMatch(row ->
Integer.parseInt(row.get(4)) > 0 && cacheId.equals(row.get(0))));
assertFalse(cacheGrpView.stream().noneMatch(row ->
Integer.parseInt(row.get(5)) > 0 && cacheId.equals(row.get(0))));
assertFalse(cacheGrpView.stream().noneMatch(row ->
Integer.parseInt(row.get(6)) > 0 && cacheId.equals(row.get(0))));
assertFalse(dataRegionView.stream().noneMatch(row -> row.get(0).startsWith(DATA_REGION_NAME)));
assertTrue(dataRegionView.stream().noneMatch(row ->
row.get(0).startsWith(DATA_REGION_NAME) && Integer.parseInt(row.get(4)) > 0));
}
finally {
dbMgr.enableCheckpoints(true).get();
}
ignite0.cluster().state(INACTIVE);
ignite0.cluster().state(ACTIVE);
IgniteCache<Integer, Integer> cacheInMemory = ignite0.getOrCreateCache(
new CacheConfiguration<Integer, Integer>()
.setName("cacheFLInMemory")
.setDataRegionName(DATA_REGION_NAME));
cacheInMemory.put(0, 0);
// After activation/deactivation new view for data region pages lists should be created, check that new view
// correctly reflects changes in free-lists.
assertTrue(systemView(ignite0, DATA_REGION_PAGE_LIST_VIEW).stream().noneMatch(row ->
row.get(0).startsWith(DATA_REGION_NAME) && Integer.parseInt(row.get(4)) > 0));
}
/** */
@Test
public void testPartitionStates() throws Exception {
String nodeName0 = getTestIgniteInstanceName(0);
String nodeName1 = getTestIgniteInstanceName(1);
String nodeName2 = getTestIgniteInstanceName(2);
IgniteCache<Integer, Integer> cache1 = ignite0.createCache(new CacheConfiguration<Integer, Integer>()
.setName("cache1")
.setCacheMode(CacheMode.PARTITIONED)
.setAffinity(new TestAffinityFunction(new String[][] {{nodeName0, nodeName1}, {nodeName1, nodeName2},
{nodeName2, nodeName0}})));
IgniteCache<Integer, Integer> cache2 = ignite0.createCache(new CacheConfiguration<Integer, Integer>()
.setName("cache2")
.setCacheMode(CacheMode.PARTITIONED)
.setAffinity(new TestAffinityFunction(new String[][] {{nodeName0, nodeName1, nodeName2}, {nodeName1}})));
for (int i = 0; i < 100; i++) {
cache1.put(i, i);
cache2.put(i, i);
}
try (IgniteEx ignite2 = startGrid(nodeName2)) {
ignite2.rebalanceEnabled(false);
ignite0.cluster().setBaselineTopology(ignite0.cluster().topologyVersion());
String nodeId0 = ignite0.cluster().localNode().id().toString();
String nodeId1 = ignite(1).cluster().localNode().id().toString();
String nodeId2 = ignite2.cluster().localNode().id().toString();
String cacheGrpId1 = Integer.toString(ignite0.cachex("cache1").context().groupId());
String cacheGrpId2 = Integer.toString(ignite0.cachex("cache2").context().groupId());
String owningState = GridDhtPartitionState.OWNING.name();
String movingState = GridDhtPartitionState.MOVING.name();
for (int i = 0; i < 3; i++) {
List<List<String>> partStatesView = systemView(ignite(i), PART_STATES_VIEW);
// Check partitions for cache1.
checkPartitionStatesView(partStatesView, owningState, true, cacheGrpId1, nodeId0, 0);
checkPartitionStatesView(partStatesView, owningState, false, cacheGrpId1, nodeId1, 0);
checkPartitionStatesView(partStatesView, owningState, true, cacheGrpId1, nodeId1, 1);
checkPartitionStatesView(partStatesView, movingState, false, cacheGrpId1, nodeId2, 1);
checkPartitionStatesView(partStatesView, owningState, true, cacheGrpId1, nodeId0, 2);
checkPartitionStatesView(partStatesView, movingState, false, cacheGrpId1, nodeId2, 2);
checkPartitionStatesView(partStatesView, owningState, true, cacheGrpId2, nodeId0, 0);
checkPartitionStatesView(partStatesView, owningState, false, cacheGrpId2, nodeId1, 0);
checkPartitionStatesView(partStatesView, movingState, false, cacheGrpId2, nodeId2, 0);
checkPartitionStatesView(partStatesView, owningState, true, cacheGrpId2, nodeId1, 1);
}
AffinityTopologyVersion topVer = ignite0.context().discovery().topologyVersionEx();
ignite2.rebalanceEnabled(true);
// Wait until rebalance complete.
assertTrue(waitForCondition(() ->
ignite0.context().discovery().topologyVersionEx().compareTo(topVer) > 0, getTestTimeout()));
for (int i = 0; i < 3; i++) {
List<List<String>> rows = systemView(ignite(i), PART_STATES_VIEW);
assertEquals(10, rows.stream().filter(row ->
(cacheGrpId1.equals(row.get(0)) || cacheGrpId2.equals(row.get(0))) && owningState.equals(row.get(3))).count());
assertTrue(rows.stream().noneMatch(row ->
(cacheGrpId1.equals(row.get(0)) || cacheGrpId2.equals(row.get(0))) && movingState.equals(row.get(3))));
}
// Check that assignment is now changed to ideal.
for (int i = 0; i < 3; i++) {
List<List<String>> rows = systemView(ignite(i), PART_STATES_VIEW);
checkPartitionStatesView(rows, owningState, false, cacheGrpId1, nodeId0, 2);
checkPartitionStatesView(rows, owningState, true, cacheGrpId1, nodeId2, 2);
}
}
finally {
ignite0.cluster().setBaselineTopology(ignite0.cluster().topologyVersion());
}
}
/**
* Checks that partitions stated view contains row with specified parameters.
*
* @param partStatesView Partition states view rows.
* @param state Partition state.
* @param isPrimary Primary falg.
* @param cacheGrpId Cache group id.
* @param nodeId Node id.
* @param partitionId partition id.
*/
private void checkPartitionStatesView(
List<List<String>> partStatesView,
String state,
boolean isPrimary,
String cacheGrpId,
String nodeId,
int partitionId
) {
assertEquals(1, partStatesView.stream().filter(row ->
cacheGrpId.equals(row.get(0)) &&
nodeId.equals(row.get(1)) &&
Integer.toString(partitionId).equals(row.get(2)) &&
state.equals(row.get(3)) &&
Boolean.toString(isPrimary).equals(row.get(4))
).count());
}
/** */
@Test
public void testBinaryMeta() {
IgniteCache<Integer, TestObjectAllTypes> c1 = ignite0.createCache("test-cache");
IgniteCache<Integer, TestObjectEnum> c2 = ignite0.createCache("test-enum-cache");
executeSql(ignite0, "CREATE TABLE T1(ID LONG PRIMARY KEY, NAME VARCHAR(40), ACCOUNT BIGINT)");
executeSql(ignite0, "INSERT INTO T1(ID, NAME, ACCOUNT) VALUES(1, 'test', 1)");
c1.put(1, new TestObjectAllTypes());
c2.put(1, TestObjectEnum.A);
List<List<String>> binaryMetaView = systemView(ignite0, BINARY_METADATA_VIEW);
assertEquals(3, binaryMetaView.size());
for (List<String> row : binaryMetaView) {
if (Objects.equals(TestObjectEnum.class.getName(), row.get(1))) {
assertTrue(Boolean.parseBoolean(row.get(6)));
assertEquals("0", row.get(3));
}
else if (Objects.equals(TestObjectAllTypes.class.getName(), row.get(1))) {
assertFalse(Boolean.parseBoolean(row.get(6)));
Field[] fields = TestObjectAllTypes.class.getDeclaredFields();
assertEquals(Integer.toString(fields.length), row.get(3));
for (Field field : fields)
assertTrue(row.get(4).contains(field.getName()));
}
else {
assertFalse(Boolean.parseBoolean(row.get(6)));
assertEquals("2", row.get(3));
assertTrue(row.get(4).contains("NAME"));
assertTrue(row.get(4).contains("ACCOUNT"));
}
}
}
/** */
@Test
public void testMetastorage() throws Exception {
IgniteCacheDatabaseSharedManager db = ignite0.context().cache().context().database();
String name = "test-key";
String val = "test-value";
db.checkpointReadLock();
try {
db.metaStorage().write(name, val);
}
finally {
db.checkpointReadUnlock();
}
assertEquals(1, systemView(ignite0, METASTORE_VIEW).stream()
.filter(row -> name.equals(row.get(0)) && val.equals(row.get(1)))
.count());
}
/** */
@Test
public void testDistributedMetastorage() throws Exception {
DistributedMetaStorage dms = ignite0.context().distributedMetastorage();
String name = "test-distributed-key";
String val = "test-distributed-value";
dms.write(name, val);
assertEquals(1, systemView(ignite0, DISTRIBUTED_METASTORE_VIEW).stream()
.filter(row -> name.equals(row.get(0)) && val.equals(row.get(1)))
.count());
assertTrue(waitForCondition(() -> systemView(ignite1, DISTRIBUTED_METASTORE_VIEW).stream()
.filter(row -> name.equals(row.get(0)) && val.equals(row.get(1)))
.count() == 1,
getTestTimeout()));
}
/**
* Execute query on given node.
*
* @param node Node.
* @param sql Statement.
*/
private List<List<?>> executeSql(Ignite node, String sql, Object... args) {
SqlFieldsQuery qry = new SqlFieldsQuery(sql)
.setArgs(args)
.setSchema("PUBLIC");
return queryProcessor(node).querySqlFields(qry, true).getAll();
}
/**
* Gets system view content via control utility from specified node. Here we also check if attributes names
* returned by the command match the real ones. And that both "SQL" and "Java" command names styles are supported.
*
* @param node The node to obtain system view from.
* @param sysViewName Name of the system view which content is required.
* @return Content of the requested system view.
*/
private List<List<String>> systemView(IgniteEx node, String sysViewName) {
List<String> attrNames = new ArrayList<>();
SystemView<?> sysView = node.context().systemView().view(sysViewName);
sysView.walker().visitAll(new AttributeVisitor() {
@Override public <T> void accept(int idx, String name, Class<T> clazz) {
attrNames.add(name);
}
});
String nodeId = node.context().discovery().localNode().id().toString();
List<List<String>> rows = parseSystemViewCommandOutput(
executeCommand(EXIT_CODE_OK, CMD_SYS_VIEW, toSqlName(sysViewName), NODE_ID.argName(), nodeId));
assertEquals(attrNames, rows.get(0));
rows = parseSystemViewCommandOutput(
executeCommand(EXIT_CODE_OK, CMD_SYS_VIEW, toSqlName(sysViewName).toLowerCase(), NODE_ID.argName(), nodeId));
assertEquals(attrNames, rows.get(0));
rows = parseSystemViewCommandOutput(
executeCommand(EXIT_CODE_OK, CMD_SYS_VIEW, sysViewName, NODE_ID.argName(), nodeId));
assertEquals(attrNames, rows.remove(0));
int attrsCnt = sysView.walker().count();
rows.forEach(row -> assertEquals(attrsCnt, row.size()));
return rows;
}
/**
* Obtains system view values for each row from command output.
*
* @param out Command output to parse.
* @return System view values.
*/
private List<List<String>> parseSystemViewCommandOutput(String out) {
String outStart = "--------------------------------------------------------------------------------";
String outEnd = "Command [" + SYSTEM_VIEW.toCommandName() + "] finished with code: " + EXIT_CODE_OK;
List<String> rows = Arrays.asList(out.substring(
out.indexOf(outStart) + outStart.length() + 1,
out.indexOf(outEnd) - 1
).split(U.nl()));
return rows.stream().map(row ->
Arrays.stream(row.split(quote(COLUMN_SEPARATOR)))
.map(String::trim)
.filter(str -> !str.isEmpty())
.collect(Collectors.toList()))
.collect(Collectors.toList());
}
/**
* 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();
}
}