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