/* * 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.internal.processors.igfs; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.FileSystemConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper; import org.apache.ignite.igfs.IgfsIpcEndpointConfiguration; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.processors.cache.GridCacheDefaultAffinityKeyMapper; import org.apache.ignite.internal.util.typedef.G; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; import static org.apache.ignite.igfs.IgfsMode.DUAL_ASYNC; import static org.apache.ignite.igfs.IgfsMode.DUAL_SYNC; import static org.apache.ignite.igfs.IgfsMode.PROXY; /** * Tests for node validation logic in {@link IgfsProcessor}. * <p> * Tests starting with "testLocal" are checking * {@link IgfsUtils#validateLocalIgfsConfigurations(org.apache.ignite.configuration.IgniteConfiguration)}. * <p> * Tests starting with "testRemote" are checking {@link IgfsProcessor#checkIgfsOnRemoteNode(org.apache.ignite.cluster.ClusterNode)}. */ public class IgfsProcessorValidationSelfTest extends IgfsCommonAbstractTest { /** IP finder. */ private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); /** Grid #1 config. */ private IgniteConfiguration g1Cfg; /** First IGFS config in grid #1. */ private FileSystemConfiguration g1IgfsCfg1 = new FileSystemConfiguration(); /** Second IGFS config in grid#1. */ private FileSystemConfiguration g1IgfsCfg2 = new FileSystemConfiguration(); /** {@inheritDoc} */ @Override protected void beforeTest() throws Exception { g1Cfg = getConfiguration("g1"); } /** {@inheritDoc} */ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); TcpDiscoverySpi discoSpi = new TcpDiscoverySpi(); discoSpi.setIpFinder(IP_FINDER); cfg.setDiscoverySpi(discoSpi); g1IgfsCfg1.setName("g1IgfsCfg1"); g1IgfsCfg2.setName("g1IgfsCfg2"); cfg.setFileSystemConfiguration(g1IgfsCfg1, g1IgfsCfg2); cfg.setLocalHost("127.0.0.1"); return cfg; } /** {@inheritDoc} */ @Override protected void afterTest() throws Exception { stopAllGrids(); } /** * Returns a new array that contains the concatenated contents of two arrays. * * @param first the first array of elements to concatenate. * @param second the second array of elements to concatenate. * @param cls Class of elements. * @return Concatenated array. */ private <T> T[] concat(T[] first, T[] second, Class<?> cls) { Collection<T> res = new ArrayList<>(); res.addAll(Arrays.asList(first)); res.addAll(Arrays.asList(second)); return res.toArray((T[]) Array.newInstance(cls, res.size())); } /** * @throws Exception If failed. */ public void testLocalIfAffinityMapperIsWrongClass() throws Exception { for (FileSystemConfiguration igfsCfg : g1Cfg.getFileSystemConfiguration()) { igfsCfg.setDataCacheConfiguration(dataCache(1024)); igfsCfg.setMetaCacheConfiguration(metaCache()); igfsCfg.getMetaCacheConfiguration().setAffinityMapper(new GridCacheDefaultAffinityKeyMapper()); igfsCfg.getDataCacheConfiguration().setAffinityMapper(new GridCacheDefaultAffinityKeyMapper()); } checkGridStartFails(g1Cfg, "Invalid IGFS data cache configuration (key affinity mapper class should be", true); } /** * @throws Exception If failed. */ public void testLocalIfIgfsConfigsHaveDuplicatedNames() throws Exception { String igfsCfgName = "igfs-cfg"; g1IgfsCfg1.setName(igfsCfgName); g1IgfsCfg2.setName(igfsCfgName); checkGridStartFails(g1Cfg, "Duplicate IGFS name found (check configuration and assign unique name", true); } /** * @throws Exception If failed. */ public void testLocalIfQueryIndexingEnabledForDataCache() throws Exception { g1IgfsCfg1.setDataCacheConfiguration(dataCache(1024)); g1IgfsCfg1.getDataCacheConfiguration().setIndexedTypes(Integer.class, String.class); checkGridStartFails(g1Cfg, "IGFS data cache cannot start with enabled query indexing", true); } /** * @throws Exception If failed. */ public void testLocalIfQueryIndexingEnabledForMetaCache() throws Exception { g1IgfsCfg1.setMetaCacheConfiguration(metaCache()); g1IgfsCfg1.getMetaCacheConfiguration().setIndexedTypes(Integer.class, String.class); checkGridStartFails(g1Cfg, "IGFS metadata cache cannot start with enabled query indexing", true); } /** * @throws Exception If failed. */ @SuppressWarnings("NullableProblems") public void testLocalNullIgfsNameIsNotSupported() throws Exception { try { g1IgfsCfg1.setName(null); fail("IGFS name cannot be null"); } catch (IllegalArgumentException e) { // No-op. } ArrayList<FileSystemConfiguration> fsCfgs = new ArrayList<>(Arrays.asList(g1Cfg.getFileSystemConfiguration())); fsCfgs.add(new FileSystemConfiguration()); // IGFS doesn't have default name (name == null). g1Cfg.setFileSystemConfiguration(fsCfgs.toArray(new FileSystemConfiguration[fsCfgs.size()])); checkGridStartFails(g1Cfg, "IGFS name cannot be null", true); } /** * @throws Exception If failed. */ public void testLocalIfNonPrimaryModeAndHadoopFileSystemUriIsNull() throws Exception { g1IgfsCfg2.setDefaultMode(PROXY); checkGridStartFails(g1Cfg, "secondaryFileSystem cannot be null when mode is not PRIMARY", true); } /** * @throws Exception If failed. */ public void testRemoteIfDataBlockSizeDiffers() throws Exception { IgniteConfiguration g2Cfg = getConfiguration("g2"); FileSystemConfiguration g2IgfsCfg1 = new FileSystemConfiguration(g1IgfsCfg1); g2IgfsCfg1.setBlockSize(g2IgfsCfg1.getBlockSize() + 100); g2Cfg.setFileSystemConfiguration(g2IgfsCfg1, g1IgfsCfg2); G.start(g1Cfg); checkGridStartFails(g2Cfg, "Data block size should be the same on all nodes in grid for IGFS", false); } /** * @throws Exception If failed. */ public void testRemoteIfAffinityMapperGroupSizeDiffers() throws Exception { IgniteConfiguration g2Cfg = getConfiguration("g2"); G.start(g1Cfg); for (FileSystemConfiguration igfsCfg : g2Cfg.getFileSystemConfiguration()) igfsCfg.setDataCacheConfiguration(dataCache(1000)); checkGridStartFails(g2Cfg, "Affinity mapper group size should be the same on all nodes in grid for IGFS", false); } /** * @throws Exception If failed. */ public void testRemoteIfDefaultModeDiffers() throws Exception { IgniteConfiguration g2Cfg = getConfiguration("g2"); FileSystemConfiguration g2IgfsCfg1 = new FileSystemConfiguration(g1IgfsCfg1); FileSystemConfiguration g2IgfsCfg2 = new FileSystemConfiguration(g1IgfsCfg2); g1IgfsCfg1.setDefaultMode(DUAL_ASYNC); g1IgfsCfg2.setDefaultMode(DUAL_ASYNC); g2IgfsCfg1.setDefaultMode(DUAL_SYNC); g2IgfsCfg2.setDefaultMode(DUAL_SYNC); g2Cfg.setFileSystemConfiguration(g2IgfsCfg1, g2IgfsCfg2); G.start(g1Cfg); checkGridStartFails(g2Cfg, "Default mode should be the same on all nodes in grid for IGFS", false); } /** * @throws Exception If failed. */ public void testRemoteIfPathModeDiffers() throws Exception { IgniteConfiguration g2Cfg = getConfiguration("g2"); FileSystemConfiguration g2IgfsCfg1 = new FileSystemConfiguration(g1IgfsCfg1); FileSystemConfiguration g2IgfsCfg2 = new FileSystemConfiguration(g1IgfsCfg2); g2IgfsCfg1.setPathModes(Collections.singletonMap("/somePath", DUAL_SYNC)); g2IgfsCfg2.setPathModes(Collections.singletonMap("/somePath", DUAL_SYNC)); g2Cfg.setFileSystemConfiguration(g2IgfsCfg1, g2IgfsCfg2); G.start(g1Cfg); checkGridStartFails(g2Cfg, "Path modes should be the same on all nodes in grid for IGFS", false); } /** * @throws Exception If failed. */ public void testZeroEndpointTcpPort() throws Exception { checkInvalidPort(0); } /** * @throws Exception If failed. */ public void testNegativeEndpointTcpPort() throws Exception { checkInvalidPort(-1); } /** * @throws Exception If failed. */ public void testTooBigEndpointTcpPort() throws Exception { checkInvalidPort(65536); } /** * @throws Exception If failed. */ public void testPreConfiguredCache() throws Exception { FileSystemConfiguration igfsCfg1 = new FileSystemConfiguration(g1IgfsCfg1); igfsCfg1.setName("igfs"); g1Cfg.setFileSystemConfiguration(igfsCfg1); CacheConfiguration ccfgData = dataCache(1024); ccfgData.setRebalanceTimeout(10001); CacheConfiguration ccfgMeta = metaCache(); ccfgMeta.setRebalanceTimeout(10002); igfsCfg1.setDataCacheConfiguration(ccfgData); igfsCfg1.setMetaCacheConfiguration(ccfgMeta); IgniteEx g = (IgniteEx)G.start(g1Cfg); assertEquals(10001, g.cachex(g.igfsx("igfs").configuration().getDataCacheConfiguration().getName()) .configuration().getRebalanceTimeout()); assertEquals(10002, g.cachex(g.igfsx("igfs").configuration().getMetaCacheConfiguration().getName()) .configuration().getRebalanceTimeout()); } /** * Check invalid port handling. * * @param port Port. * @throws Exception If failed. */ private void checkInvalidPort(int port) throws Exception { final String failMsg = "IGFS endpoint TCP port is out of range"; final String igfsCfgName = "igfs-cfg"; final IgfsIpcEndpointConfiguration igfsEndpointCfg = new IgfsIpcEndpointConfiguration(); igfsEndpointCfg.setPort(port); g1IgfsCfg1.setName(igfsCfgName); g1IgfsCfg1.setIpcEndpointConfiguration(igfsEndpointCfg); checkGridStartFails(g1Cfg, failMsg, true); } /** * @throws Exception If failed. */ public void testInvalidEndpointThreadCount() throws Exception { final String failMsg = "IGFS endpoint thread count must be positive"; final String igfsCfgName = "igfs-cfg"; final IgfsIpcEndpointConfiguration igfsEndpointCfg = new IgfsIpcEndpointConfiguration(); igfsEndpointCfg.setThreadCount(0); g1IgfsCfg1.setName(igfsCfgName); g1IgfsCfg1.setIpcEndpointConfiguration(igfsEndpointCfg); checkGridStartFails(g1Cfg, failMsg, true); } /** * Checks that the given grid configuration will lead to {@link IgniteCheckedException} upon grid startup. * * @param cfg Grid configuration to check. * @param excMsgSnippet Root cause (assertion) exception message snippet. * @param testLoc {@code True} if checking is done for "testLocal" tests. */ private void checkGridStartFails(IgniteConfiguration cfg, CharSequence excMsgSnippet, boolean testLoc) { assertNotNull(cfg); assertNotNull(excMsgSnippet); try { G.start(cfg); fail("No exception has been thrown."); } catch (IgniteException e) { if (testLoc) { if (e.getMessage().contains(excMsgSnippet) || ("Failed to start processor: GridProcessorAdapter []".equals(e.getMessage()) && (e.getCause().getMessage().contains(excMsgSnippet) || e.getCause().getCause().getMessage().contains(excMsgSnippet)))) return; // Expected exception. } else if (e.getMessage().contains(excMsgSnippet)) return; // Expected exception. error("Caught unexpected exception.", e); fail(); } } /** * @param grpSize Group size to use in {@link org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper}. * @return 2 preconfigured data cache. */ private CacheConfiguration dataCache(int grpSize) { CacheConfiguration dataCache = defaultCacheConfiguration(); dataCache.setAffinityMapper(new IgfsGroupDataBlocksKeyMapper(grpSize)); dataCache.setAtomicityMode(TRANSACTIONAL); return dataCache; } /** * @return preconfigured meta cache. */ private CacheConfiguration metaCache() { CacheConfiguration metaCache = defaultCacheConfiguration(); metaCache.setAtomicityMode(TRANSACTIONAL); return metaCache; } }