1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.hdfs.server.namenode; 19 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 import static org.mockito.Mockito.mock; 25 26 import java.io.IOException; 27 import java.net.URI; 28 import java.util.Collection; 29 30 import org.apache.hadoop.conf.Configuration; 31 import org.apache.hadoop.hdfs.DFSConfigKeys; 32 import org.apache.hadoop.hdfs.MiniDFSCluster; 33 import org.apache.hadoop.hdfs.server.common.Storage; 34 import org.apache.hadoop.hdfs.server.common.StorageInfo; 35 import org.apache.hadoop.hdfs.server.protocol.NamespaceInfo; 36 import org.junit.Test; 37 38 public class TestGenericJournalConf { 39 private static final String DUMMY_URI = "dummy://test"; 40 41 /** 42 * Test that an exception is thrown if a journal class doesn't exist 43 * in the configuration 44 */ 45 @Test(expected=IllegalArgumentException.class) testNotConfigured()46 public void testNotConfigured() throws Exception { 47 MiniDFSCluster cluster = null; 48 Configuration conf = new Configuration(); 49 50 conf.set(DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_KEY, 51 "dummy://test"); 52 try { 53 cluster = new MiniDFSCluster.Builder(conf).numDataNodes(0).build(); 54 cluster.waitActive(); 55 } finally { 56 if (cluster != null) { 57 cluster.shutdown(); 58 } 59 } 60 } 61 62 /** 63 * Test that an exception is thrown if a journal class doesn't 64 * exist in the classloader. 65 */ 66 @Test(expected=IllegalArgumentException.class) testClassDoesntExist()67 public void testClassDoesntExist() throws Exception { 68 MiniDFSCluster cluster = null; 69 Configuration conf = new Configuration(); 70 71 conf.set(DFSConfigKeys.DFS_NAMENODE_EDITS_PLUGIN_PREFIX + ".dummy", 72 "org.apache.hadoop.nonexistent"); 73 conf.set(DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_KEY, 74 "dummy://test"); 75 76 try { 77 cluster = new MiniDFSCluster.Builder(conf).numDataNodes(0).build(); 78 cluster.waitActive(); 79 } finally { 80 if (cluster != null) { 81 cluster.shutdown(); 82 } 83 } 84 } 85 86 /** 87 * Test that a implementation of JournalManager without a 88 * (Configuration,URI) constructor throws an exception 89 */ 90 @Test testBadConstructor()91 public void testBadConstructor() throws Exception { 92 MiniDFSCluster cluster = null; 93 Configuration conf = new Configuration(); 94 95 conf.set(DFSConfigKeys.DFS_NAMENODE_EDITS_PLUGIN_PREFIX + ".dummy", 96 BadConstructorJournalManager.class.getName()); 97 conf.set(DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_KEY, 98 "dummy://test"); 99 try { 100 cluster = new MiniDFSCluster.Builder(conf).numDataNodes(0).build(); 101 cluster.waitActive(); 102 fail("Should have failed before this point"); 103 } catch (IllegalArgumentException iae) { 104 if (!iae.getMessage().contains("Unable to construct journal")) { 105 fail("Should have failed with unable to construct exception"); 106 } 107 } finally { 108 if (cluster != null) { 109 cluster.shutdown(); 110 } 111 } 112 } 113 114 /** 115 * Test that a dummy implementation of JournalManager can 116 * be initialized on startup 117 */ 118 @Test testDummyJournalManager()119 public void testDummyJournalManager() throws Exception { 120 MiniDFSCluster cluster = null; 121 Configuration conf = new Configuration(); 122 123 conf.set(DFSConfigKeys.DFS_NAMENODE_EDITS_PLUGIN_PREFIX + ".dummy", 124 DummyJournalManager.class.getName()); 125 conf.set(DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_KEY, DUMMY_URI); 126 conf.setInt(DFSConfigKeys.DFS_NAMENODE_CHECKED_VOLUMES_MINIMUM_KEY, 0); 127 try { 128 cluster = new MiniDFSCluster.Builder(conf).numDataNodes(0).build(); 129 cluster.waitActive(); 130 131 assertTrue(DummyJournalManager.shouldPromptCalled); 132 assertTrue(DummyJournalManager.formatCalled); 133 assertNotNull(DummyJournalManager.conf); 134 assertEquals(new URI(DUMMY_URI), DummyJournalManager.uri); 135 assertNotNull(DummyJournalManager.nsInfo); 136 assertEquals(DummyJournalManager.nsInfo.getClusterID(), 137 cluster.getNameNode().getNamesystem().getClusterId()); 138 } finally { 139 if (cluster != null) { 140 cluster.shutdown(); 141 } 142 } 143 } 144 145 public static class DummyJournalManager implements JournalManager { 146 static Configuration conf = null; 147 static URI uri = null; 148 static NamespaceInfo nsInfo = null; 149 static boolean formatCalled = false; 150 static boolean shouldPromptCalled = false; 151 DummyJournalManager(Configuration conf, URI u, NamespaceInfo nsInfo)152 public DummyJournalManager(Configuration conf, URI u, 153 NamespaceInfo nsInfo) { 154 // Set static vars so the test case can verify them. 155 DummyJournalManager.conf = conf; 156 DummyJournalManager.uri = u; 157 DummyJournalManager.nsInfo = nsInfo; 158 } 159 160 @Override format(NamespaceInfo nsInfo)161 public void format(NamespaceInfo nsInfo) throws IOException { 162 formatCalled = true; 163 } 164 165 @Override startLogSegment(long txId, int layoutVersion)166 public EditLogOutputStream startLogSegment(long txId, int layoutVersion) 167 throws IOException { 168 return mock(EditLogOutputStream.class); 169 } 170 171 @Override finalizeLogSegment(long firstTxId, long lastTxId)172 public void finalizeLogSegment(long firstTxId, long lastTxId) 173 throws IOException { 174 // noop 175 } 176 177 @Override selectInputStreams(Collection<EditLogInputStream> streams, long fromTxnId, boolean inProgressOk)178 public void selectInputStreams(Collection<EditLogInputStream> streams, 179 long fromTxnId, boolean inProgressOk) { 180 } 181 182 @Override setOutputBufferCapacity(int size)183 public void setOutputBufferCapacity(int size) {} 184 185 @Override purgeLogsOlderThan(long minTxIdToKeep)186 public void purgeLogsOlderThan(long minTxIdToKeep) 187 throws IOException {} 188 189 @Override recoverUnfinalizedSegments()190 public void recoverUnfinalizedSegments() throws IOException {} 191 192 @Override close()193 public void close() throws IOException {} 194 195 @Override hasSomeData()196 public boolean hasSomeData() throws IOException { 197 shouldPromptCalled = true; 198 return false; 199 } 200 201 @Override doPreUpgrade()202 public void doPreUpgrade() throws IOException {} 203 204 @Override doUpgrade(Storage storage)205 public void doUpgrade(Storage storage) throws IOException {} 206 207 @Override doFinalize()208 public void doFinalize() throws IOException {} 209 210 @Override canRollBack(StorageInfo storage, StorageInfo prevStorage, int targetLayoutVersion)211 public boolean canRollBack(StorageInfo storage, StorageInfo prevStorage, int targetLayoutVersion) 212 throws IOException { 213 return false; 214 } 215 216 @Override doRollback()217 public void doRollback() throws IOException {} 218 219 @Override discardSegments(long startTxId)220 public void discardSegments(long startTxId) throws IOException {} 221 222 @Override getJournalCTime()223 public long getJournalCTime() throws IOException { 224 return -1; 225 } 226 } 227 228 public static class BadConstructorJournalManager extends DummyJournalManager { BadConstructorJournalManager()229 public BadConstructorJournalManager() { 230 super(null, null, null); 231 } 232 233 @Override doPreUpgrade()234 public void doPreUpgrade() throws IOException {} 235 236 @Override doUpgrade(Storage storage)237 public void doUpgrade(Storage storage) throws IOException {} 238 239 @Override doFinalize()240 public void doFinalize() throws IOException {} 241 242 @Override canRollBack(StorageInfo storage, StorageInfo prevStorage, int targetLayoutVersion)243 public boolean canRollBack(StorageInfo storage, StorageInfo prevStorage, int targetLayoutVersion) 244 throws IOException { 245 return false; 246 } 247 248 @Override doRollback()249 public void doRollback() throws IOException {} 250 251 @Override getJournalCTime()252 public long getJournalCTime() throws IOException { 253 return -1; 254 } 255 } 256 } 257