001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNull;
022import static org.junit.Assert.fail;
023
024import java.util.HashMap;
025import java.util.Map;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.testclassification.MiscTests;
028import org.apache.hadoop.hbase.testclassification.SmallTests;
029import org.apache.hadoop.hbase.util.Bytes;
030import org.junit.Before;
031import org.junit.ClassRule;
032import org.junit.Test;
033import org.junit.experimental.categories.Category;
034
035@Category({ MiscTests.class, SmallTests.class })
036public class TestCompoundConfiguration {
037
038  @ClassRule
039  public static final HBaseClassTestRule CLASS_RULE =
040    HBaseClassTestRule.forClass(TestCompoundConfiguration.class);
041
042  private Configuration baseConf;
043  private int baseConfSize;
044
045  @Before
046  public void setUp() throws Exception {
047    baseConf = new Configuration();
048    baseConf.set("A", "1");
049    baseConf.setInt("B", 2);
050    baseConf.set("C", "3");
051    baseConfSize = baseConf.size();
052  }
053
054  @Test
055  public void testBasicFunctionality() throws ClassNotFoundException {
056    CompoundConfiguration compoundConf = new CompoundConfiguration().add(baseConf);
057    assertEquals("1", compoundConf.get("A"));
058    assertEquals(2, compoundConf.getInt("B", 0));
059    assertEquals(3, compoundConf.getInt("C", 0));
060    assertEquals(0, compoundConf.getInt("D", 0));
061
062    assertEquals(CompoundConfiguration.class,
063      compoundConf.getClassByName(CompoundConfiguration.class.getName()));
064    try {
065      compoundConf.getClassByName("bad_class_name");
066      fail("Trying to load bad_class_name should throw an exception");
067    } catch (ClassNotFoundException e) {
068      // win!
069    }
070  }
071
072  @Test
073  public void testPut() {
074    CompoundConfiguration compoundConf = new CompoundConfiguration().add(baseConf);
075    assertEquals("1", compoundConf.get("A"));
076    assertEquals(2, compoundConf.getInt("B", 0));
077    assertEquals(3, compoundConf.getInt("C", 0));
078    assertEquals(0, compoundConf.getInt("D", 0));
079
080    compoundConf.set("A", "1337");
081    compoundConf.set("string", "stringvalue");
082    assertEquals(1337, compoundConf.getInt("A", 0));
083    assertEquals("stringvalue", compoundConf.get("string"));
084
085    // we didn't modify the base conf
086    assertEquals("1", baseConf.get("A"));
087    assertNull(baseConf.get("string"));
088
089    // adding to the base shows up in the compound
090    baseConf.set("setInParent", "fromParent");
091    assertEquals("fromParent", compoundConf.get("setInParent"));
092  }
093
094  @Test
095  public void testWithConfig() {
096    Configuration conf = new Configuration();
097    conf.set("B", "2b");
098    conf.set("C", "33");
099    conf.set("D", "4");
100
101    CompoundConfiguration compoundConf = new CompoundConfiguration().add(baseConf).add(conf);
102    assertEquals("1", compoundConf.get("A"));
103    assertEquals("2b", compoundConf.get("B"));
104    assertEquals(33, compoundConf.getInt("C", 0));
105    assertEquals("4", compoundConf.get("D"));
106    assertEquals(4, compoundConf.getInt("D", 0));
107    assertNull(compoundConf.get("E"));
108    assertEquals(6, compoundConf.getInt("F", 6));
109
110    int cnt = 0;
111    for (Map.Entry<String, String> entry : compoundConf) {
112      cnt++;
113      if (entry.getKey().equals("B")) {
114        assertEquals("2b", entry.getValue());
115      } else if (entry.getKey().equals("G")) {
116        assertNull(entry.getValue());
117      }
118    }
119    // verify that entries from ImmutableConfigMap's are merged in the iterator's view
120    assertEquals(baseConfSize + 1, cnt);
121  }
122
123  private Bytes strToIb(String s) {
124    return new Bytes(Bytes.toBytes(s));
125  }
126
127  @Test
128  public void testWithIbwMap() {
129    Map<Bytes, Bytes> map = new HashMap<>();
130    map.put(strToIb("B"), strToIb("2b"));
131    map.put(strToIb("C"), strToIb("33"));
132    map.put(strToIb("D"), strToIb("4"));
133    // unlike config, note that IBW Maps can accept null values
134    map.put(strToIb("G"), null);
135
136    CompoundConfiguration compoundConf = new CompoundConfiguration().add(baseConf).addBytesMap(map);
137    assertEquals("1", compoundConf.get("A"));
138    assertEquals("2b", compoundConf.get("B"));
139    assertEquals(33, compoundConf.getInt("C", 0));
140    assertEquals("4", compoundConf.get("D"));
141    assertEquals(4, compoundConf.getInt("D", 0));
142    assertNull(compoundConf.get("E"));
143    assertEquals(6, compoundConf.getInt("F", 6));
144    assertNull(compoundConf.get("G"));
145
146    int cnt = 0;
147    for (Map.Entry<String, String> entry : compoundConf) {
148      cnt++;
149      if (entry.getKey().equals("B")) {
150        assertEquals("2b", entry.getValue());
151      } else if (entry.getKey().equals("G")) {
152        assertNull(entry.getValue());
153      }
154    }
155    // verify that entries from ImmutableConfigMap's are merged in the iterator's view
156    assertEquals(baseConfSize + 2, cnt);
157
158    // Verify that adding map after compound configuration is modified overrides properly
159    CompoundConfiguration conf2 = new CompoundConfiguration();
160    conf2.set("X", "modification");
161    conf2.set("D", "not4");
162    assertEquals("modification", conf2.get("X"));
163    assertEquals("not4", conf2.get("D"));
164    conf2.addBytesMap(map);
165    assertEquals("4", conf2.get("D")); // map overrides
166  }
167
168  @Test
169  public void testWithStringMap() {
170    Map<String, String> map = new HashMap<>();
171    map.put("B", "2b");
172    map.put("C", "33");
173    map.put("D", "4");
174    // unlike config, note that IBW Maps can accept null values
175    map.put("G", null);
176
177    CompoundConfiguration compoundConf = new CompoundConfiguration().addStringMap(map);
178    assertEquals("2b", compoundConf.get("B"));
179    assertEquals(33, compoundConf.getInt("C", 0));
180    assertEquals("4", compoundConf.get("D"));
181    assertEquals(4, compoundConf.getInt("D", 0));
182    assertNull(compoundConf.get("E"));
183    assertEquals(6, compoundConf.getInt("F", 6));
184    assertNull(compoundConf.get("G"));
185
186    int cnt = 0;
187    for (Map.Entry<String, String> entry : compoundConf) {
188      cnt++;
189      if (entry.getKey().equals("B")) {
190        assertEquals("2b", entry.getValue());
191      } else if (entry.getKey().equals("G")) {
192        assertNull(entry.getValue());
193      }
194    }
195    // verify that entries from ImmutableConfigMap's are merged in the iterator's view
196    assertEquals(4, cnt);
197
198    // Verify that adding map after compound configuration is modified overrides properly
199    CompoundConfiguration conf2 = new CompoundConfiguration();
200    conf2.set("X", "modification");
201    conf2.set("D", "not4");
202    assertEquals("modification", conf2.get("X"));
203    assertEquals("not4", conf2.get("D"));
204    conf2.addStringMap(map);
205    assertEquals("4", conf2.get("D")); // map overrides
206  }
207
208  @Test
209  public void testLaterConfigsOverrideEarlier() {
210    Map<String, String> map1 = new HashMap<>();
211    map1.put("A", "2");
212    map1.put("D", "5");
213    Map<String, String> map2 = new HashMap<>();
214    String newValueForA = "3", newValueForB = "4";
215    map2.put("A", newValueForA);
216    map2.put("B", newValueForB);
217
218    CompoundConfiguration compoundConf =
219      new CompoundConfiguration().addStringMap(map1).add(baseConf);
220    assertEquals("1", compoundConf.get("A"));
221    assertEquals("5", compoundConf.get("D"));
222    compoundConf.addStringMap(map2);
223    assertEquals(newValueForA, compoundConf.get("A"));
224    assertEquals(newValueForB, compoundConf.get("B"));
225    assertEquals("5", compoundConf.get("D"));
226
227    int cnt = 0;
228    for (Map.Entry<String, String> entry : compoundConf) {
229      cnt++;
230      if (entry.getKey().equals("A")) {
231        assertEquals(newValueForA, entry.getValue());
232      } else if (entry.getKey().equals("B")) {
233        assertEquals(newValueForB, entry.getValue());
234      }
235    }
236    // verify that entries from ImmutableConfigMap's are merged in the iterator's view
237    assertEquals(baseConfSize + 1, cnt);
238  }
239}