/** * 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.hadoop.net; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.CommonConfigurationKeys; import org.junit.Assert; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Test the static mapping class. * Because the map is actually static, this map needs to be reset for every test */ public class TestStaticMapping extends Assert { private static final Log LOG = LogFactory.getLog(TestStaticMapping.class); /** * Reset the map then create a new instance of the {@link StaticMapping} * class with a null configuration * @return a new instance */ private StaticMapping newInstance() { StaticMapping.resetMap(); return new StaticMapping(); } /** * Reset the map then create a new instance of the {@link StaticMapping} * class with the topology script in the configuration set to * the parameter * @param script a (never executed) script, can be null * @return a new instance */ private StaticMapping newInstance(String script) { StaticMapping mapping = newInstance(); mapping.setConf(createConf(script)); return mapping; } /** * Create a configuration with a specific topology script * @param script a (never executed) script, can be null * @return a configuration */ private Configuration createConf(String script) { Configuration conf = new Configuration(); if (script != null) { conf.set(CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY, script); } else { conf.unset(CommonConfigurationKeys.NET_TOPOLOGY_SCRIPT_FILE_NAME_KEY); } return conf; } private void assertSingleSwitch(DNSToSwitchMapping mapping) { assertEquals("Expected a single switch mapping " + mapping, true, AbstractDNSToSwitchMapping.isMappingSingleSwitch(mapping)); } private void assertMultiSwitch(DNSToSwitchMapping mapping) { assertEquals("Expected a multi switch mapping " + mapping, false, AbstractDNSToSwitchMapping.isMappingSingleSwitch(mapping)); } protected void assertMapSize(AbstractDNSToSwitchMapping switchMapping, int expectedSize) { assertEquals( "Expected two entries in the map " + switchMapping.dumpTopology(), expectedSize, switchMapping.getSwitchMap().size()); } private List<String> createQueryList() { List<String> l1 = new ArrayList<String>(2); l1.add("n1"); l1.add("unknown"); return l1; } @Test public void testStaticIsSingleSwitchOnNullScript() throws Throwable { StaticMapping mapping = newInstance(null); mapping.setConf(createConf(null)); assertSingleSwitch(mapping); } @Test public void testStaticIsMultiSwitchOnScript() throws Throwable { StaticMapping mapping = newInstance("ls"); assertMultiSwitch(mapping); } @Test public void testAddResolveNodes() throws Throwable { StaticMapping mapping = newInstance(); StaticMapping.addNodeToRack("n1", "/r1"); List<String> queryList = createQueryList(); List<String> resolved = mapping.resolve(queryList); assertEquals(2, resolved.size()); assertEquals("/r1", resolved.get(0)); assertEquals(NetworkTopology.DEFAULT_RACK, resolved.get(1)); // get the switch map and examine it Map<String, String> switchMap = mapping.getSwitchMap(); String topology = mapping.dumpTopology(); LOG.info(topology); assertEquals(topology, 1, switchMap.size()); assertEquals(topology, "/r1", switchMap.get("n1")); } /** * Verify that a configuration string builds a topology */ @Test public void testReadNodesFromConfig() throws Throwable { StaticMapping mapping = newInstance(); Configuration conf = new Configuration(); conf.set(StaticMapping.KEY_HADOOP_CONFIGURED_NODE_MAPPING, "n1=/r1,n2=/r2"); mapping.setConf(conf); //even though we have inserted elements into the list, because //it is driven by the script key in the configuration, it still //thinks that it is single rack assertSingleSwitch(mapping); List<String> l1 = new ArrayList<String>(3); l1.add("n1"); l1.add("unknown"); l1.add("n2"); List<String> resolved = mapping.resolve(l1); assertEquals(3, resolved.size()); assertEquals("/r1", resolved.get(0)); assertEquals(NetworkTopology.DEFAULT_RACK, resolved.get(1)); assertEquals("/r2", resolved.get(2)); Map<String, String> switchMap = mapping.getSwitchMap(); String topology = mapping.dumpTopology(); LOG.info(topology); assertEquals(topology, 2, switchMap.size()); assertEquals(topology, "/r1", switchMap.get("n1")); assertNull(topology, switchMap.get("unknown")); } /** * Verify that if the inner mapping is single-switch, so is the cached one * @throws Throwable on any problem */ @Test public void testCachingRelaysSingleSwitchQueries() throws Throwable { //create a single switch map StaticMapping staticMapping = newInstance(null); assertSingleSwitch(staticMapping); CachedDNSToSwitchMapping cachedMap = new CachedDNSToSwitchMapping(staticMapping); LOG.info("Mapping: " + cachedMap + "\n" + cachedMap.dumpTopology()); assertSingleSwitch(cachedMap); } /** * Verify that if the inner mapping is multi-switch, so is the cached one * @throws Throwable on any problem */ @Test public void testCachingRelaysMultiSwitchQueries() throws Throwable { StaticMapping staticMapping = newInstance("top"); assertMultiSwitch(staticMapping); CachedDNSToSwitchMapping cachedMap = new CachedDNSToSwitchMapping(staticMapping); LOG.info("Mapping: " + cachedMap + "\n" + cachedMap.dumpTopology()); assertMultiSwitch(cachedMap); } /** * This test verifies that resultion queries get relayed to the inner rack * @throws Throwable on any problem */ @Test public void testCachingRelaysResolveQueries() throws Throwable { StaticMapping mapping = newInstance(); mapping.setConf(createConf("top")); StaticMapping staticMapping = mapping; CachedDNSToSwitchMapping cachedMap = new CachedDNSToSwitchMapping(staticMapping); assertMapSize(cachedMap, 0); //add a node to the static map StaticMapping.addNodeToRack("n1", "/r1"); //verify it is there assertMapSize(staticMapping, 1); //verify that the cache hasn't picked it up yet assertMapSize(cachedMap, 0); //now relay the query cachedMap.resolve(createQueryList()); //and verify the cache is no longer empty assertMapSize(cachedMap, 2); } /** * This test verifies that resultion queries get relayed to the inner rack * @throws Throwable on any problem */ @Test public void testCachingCachesNegativeEntries() throws Throwable { StaticMapping staticMapping = newInstance(); CachedDNSToSwitchMapping cachedMap = new CachedDNSToSwitchMapping(staticMapping); assertMapSize(cachedMap, 0); assertMapSize(staticMapping, 0); List<String> resolved = cachedMap.resolve(createQueryList()); //and verify the cache is no longer empty while the static map is assertMapSize(staticMapping, 0); assertMapSize(cachedMap, 2); } }