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()
057        .add(baseConf);
058    assertEquals("1", compoundConf.get("A"));
059    assertEquals(2, compoundConf.getInt("B", 0));
060    assertEquals(3, compoundConf.getInt("C", 0));
061    assertEquals(0, compoundConf.getInt("D", 0));
062
063    assertEquals(CompoundConfiguration.class, compoundConf
064        .getClassByName(CompoundConfiguration.class.getName()));
065    try {
066      compoundConf.getClassByName("bad_class_name");
067      fail("Trying to load bad_class_name should throw an exception");
068    } catch (ClassNotFoundException e) {
069      // win!
070    }
071  }
072
073  @Test
074  public void testPut() {
075    CompoundConfiguration compoundConf = new CompoundConfiguration()
076      .add(baseConf);
077    assertEquals("1", compoundConf.get("A"));
078    assertEquals(2, compoundConf.getInt("B", 0));
079    assertEquals(3, compoundConf.getInt("C", 0));
080    assertEquals(0, compoundConf.getInt("D", 0));
081
082    compoundConf.set("A", "1337");
083    compoundConf.set("string", "stringvalue");
084    assertEquals(1337, compoundConf.getInt("A", 0));
085    assertEquals("stringvalue", compoundConf.get("string"));
086
087    // we didn't modify the base conf
088    assertEquals("1", baseConf.get("A"));
089    assertNull(baseConf.get("string"));
090
091    // adding to the base shows up in the compound
092    baseConf.set("setInParent", "fromParent");
093    assertEquals("fromParent", compoundConf.get("setInParent"));
094  }
095
096  @Test
097  public void testWithConfig() {
098    Configuration conf = new Configuration();
099    conf.set("B", "2b");
100    conf.set("C", "33");
101    conf.set("D", "4");
102
103    CompoundConfiguration compoundConf = new CompoundConfiguration()
104        .add(baseConf)
105        .add(conf);
106    assertEquals("1", compoundConf.get("A"));
107    assertEquals("2b", compoundConf.get("B"));
108    assertEquals(33, compoundConf.getInt("C", 0));
109    assertEquals("4", compoundConf.get("D"));
110    assertEquals(4, compoundConf.getInt("D", 0));
111    assertNull(compoundConf.get("E"));
112    assertEquals(6, compoundConf.getInt("F", 6));
113
114    int cnt = 0;
115    for (Map.Entry<String,String> entry : compoundConf) {
116      cnt++;
117      if (entry.getKey().equals("B")) {
118        assertEquals("2b", entry.getValue());
119      } else if (entry.getKey().equals("G")) {
120        assertNull(entry.getValue());
121      }
122    }
123    // verify that entries from ImmutableConfigMap's are merged in the iterator's view
124    assertEquals(baseConfSize + 1, cnt);
125  }
126
127  private Bytes strToIb(String s) {
128    return new Bytes(Bytes.toBytes(s));
129  }
130
131  @Test
132  public void testWithIbwMap() {
133    Map<Bytes, Bytes> map = new HashMap<>();
134    map.put(strToIb("B"), strToIb("2b"));
135    map.put(strToIb("C"), strToIb("33"));
136    map.put(strToIb("D"), strToIb("4"));
137    // unlike config, note that IBW Maps can accept null values
138    map.put(strToIb("G"), null);
139
140    CompoundConfiguration compoundConf = new CompoundConfiguration()
141      .add(baseConf)
142      .addBytesMap(map);
143    assertEquals("1", compoundConf.get("A"));
144    assertEquals("2b", compoundConf.get("B"));
145    assertEquals(33, compoundConf.getInt("C", 0));
146    assertEquals("4", compoundConf.get("D"));
147    assertEquals(4, compoundConf.getInt("D", 0));
148    assertNull(compoundConf.get("E"));
149    assertEquals(6, compoundConf.getInt("F", 6));
150    assertNull(compoundConf.get("G"));
151
152    int cnt = 0;
153    for (Map.Entry<String,String> entry : compoundConf) {
154      cnt++;
155      if (entry.getKey().equals("B")) {
156        assertEquals("2b", entry.getValue());
157      } else if (entry.getKey().equals("G")) {
158        assertNull(entry.getValue());
159      }
160    }
161    // verify that entries from ImmutableConfigMap's are merged in the iterator's view
162    assertEquals(baseConfSize + 2, cnt);
163
164    // Verify that adding map after compound configuration is modified overrides properly
165    CompoundConfiguration conf2 = new CompoundConfiguration();
166    conf2.set("X", "modification");
167    conf2.set("D", "not4");
168    assertEquals("modification", conf2.get("X"));
169    assertEquals("not4", conf2.get("D"));
170    conf2.addBytesMap(map);
171    assertEquals("4", conf2.get("D")); // map overrides
172  }
173
174  @Test
175  public void testWithStringMap() {
176    Map<String, String> map = new HashMap<>();
177    map.put("B", "2b");
178    map.put("C", "33");
179    map.put("D", "4");
180    // unlike config, note that IBW Maps can accept null values
181    map.put("G", null);
182
183    CompoundConfiguration compoundConf = new CompoundConfiguration().addStringMap(map);
184    assertEquals("2b", compoundConf.get("B"));
185    assertEquals(33, compoundConf.getInt("C", 0));
186    assertEquals("4", compoundConf.get("D"));
187    assertEquals(4, compoundConf.getInt("D", 0));
188    assertNull(compoundConf.get("E"));
189    assertEquals(6, compoundConf.getInt("F", 6));
190    assertNull(compoundConf.get("G"));
191
192    int cnt = 0;
193    for (Map.Entry<String,String> entry : compoundConf) {
194      cnt++;
195      if (entry.getKey().equals("B")) {
196        assertEquals("2b", entry.getValue());
197      } else if (entry.getKey().equals("G")) {
198        assertNull(entry.getValue());
199      }
200    }
201    // verify that entries from ImmutableConfigMap's are merged in the iterator's view
202    assertEquals(4, cnt);
203
204    // Verify that adding map after compound configuration is modified overrides properly
205    CompoundConfiguration conf2 = new CompoundConfiguration();
206    conf2.set("X", "modification");
207    conf2.set("D", "not4");
208    assertEquals("modification", conf2.get("X"));
209    assertEquals("not4", conf2.get("D"));
210    conf2.addStringMap(map);
211    assertEquals("4", conf2.get("D")); // map overrides
212  }
213
214  @Test
215  public void testLaterConfigsOverrideEarlier() {
216    Map<String, String> map1 = new HashMap<>();
217    map1.put("A", "2");
218    map1.put("D", "5");
219    Map<String, String> map2 = new HashMap<>();
220    String newValueForA = "3", newValueForB = "4";
221    map2.put("A", newValueForA);
222    map2.put("B", newValueForB);
223
224    CompoundConfiguration compoundConf = new CompoundConfiguration()
225      .addStringMap(map1).add(baseConf);
226    assertEquals("1", compoundConf.get("A"));
227    assertEquals("5", compoundConf.get("D"));
228    compoundConf.addStringMap(map2);
229    assertEquals(newValueForA, compoundConf.get("A"));
230    assertEquals(newValueForB, compoundConf.get("B"));
231    assertEquals("5", compoundConf.get("D"));
232
233    int cnt = 0;
234    for (Map.Entry<String,String> entry : compoundConf) {
235      cnt++;
236      if (entry.getKey().equals("A")) {
237        assertEquals(newValueForA, entry.getValue());
238      } else if (entry.getKey().equals("B")) {
239        assertEquals(newValueForB, entry.getValue());
240      }
241    }
242    // verify that entries from ImmutableConfigMap's are merged in the iterator's view
243    assertEquals(baseConfSize + 1, cnt);
244  }
245}