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.conf; 019 020import static org.junit.Assert.assertFalse; 021import static org.junit.Assert.assertTrue; 022 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.HBaseClassTestRule; 025import org.apache.hadoop.hbase.testclassification.ClientTests; 026import org.apache.hadoop.hbase.testclassification.SmallTests; 027import org.junit.ClassRule; 028import org.junit.Test; 029import org.junit.experimental.categories.Category; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033@Category({ SmallTests.class, ClientTests.class }) 034public class TestConfigurationManager { 035 036 @ClassRule 037 public static final HBaseClassTestRule CLASS_RULE = 038 HBaseClassTestRule.forClass(TestConfigurationManager.class); 039 040 private static final Logger LOG = LoggerFactory.getLogger(TestConfigurationManager.class); 041 042 static class DummyConfigurationObserver implements ConfigurationObserver { 043 private boolean notifiedOnChange = false; 044 private final ConfigurationManager cm; 045 046 public DummyConfigurationObserver(ConfigurationManager cm) { 047 this.cm = cm; 048 register(); 049 } 050 051 @Override 052 public void onConfigurationChange(Configuration conf) { 053 notifiedOnChange = true; 054 } 055 056 // Was the observer notified on Configuration change? 057 public boolean wasNotifiedOnChange() { 058 return notifiedOnChange; 059 } 060 061 public void resetNotifiedOnChange() { 062 notifiedOnChange = false; 063 } 064 065 public void register() { 066 cm.registerObserver(this); 067 } 068 069 public void deregister() { 070 cm.deregisterObserver(this); 071 } 072 } 073 074 /** 075 * Test if observers get notified by the <code>ConfigurationManager</code> when the Configuration 076 * is reloaded. 077 */ 078 @Test 079 public void testCheckIfObserversNotified() { 080 Configuration conf = new Configuration(); 081 ConfigurationManager cm = new ConfigurationManager(); 082 DummyConfigurationObserver d1 = new DummyConfigurationObserver(cm); 083 084 // Check if we get notified. 085 cm.notifyAllObservers(conf); 086 assertTrue(d1.wasNotifiedOnChange()); 087 d1.resetNotifiedOnChange(); 088 089 // Now check if we get notified on change with more than one observers. 090 DummyConfigurationObserver d2 = new DummyConfigurationObserver(cm); 091 cm.notifyAllObservers(conf); 092 assertTrue(d1.wasNotifiedOnChange()); 093 d1.resetNotifiedOnChange(); 094 assertTrue(d2.wasNotifiedOnChange()); 095 d2.resetNotifiedOnChange(); 096 097 // Now try deregistering an observer and verify that it was not notified 098 d2.deregister(); 099 cm.notifyAllObservers(conf); 100 assertTrue(d1.wasNotifiedOnChange()); 101 d1.resetNotifiedOnChange(); 102 assertFalse(d2.wasNotifiedOnChange()); 103 } 104 105 // Register an observer that will go out of scope immediately, allowing 106 // us to test that out of scope observers are deregistered. 107 private void registerLocalObserver(ConfigurationManager cm) { 108 new DummyConfigurationObserver(cm); 109 } 110 111 /** 112 * Test if out-of-scope observers are deregistered on GC. 113 */ 114 @Test 115 public void testDeregisterOnOutOfScope() { 116 Configuration conf = new Configuration(); 117 ConfigurationManager cm = new ConfigurationManager(); 118 119 boolean outOfScopeObserversDeregistered = false; 120 121 // On my machine, I was able to cause a GC after around 5 iterations. 122 // If we do not cause a GC in 100k iterations, which is very unlikely, 123 // there might be something wrong with the GC. 124 for (int i = 0; i < 100000; i++) { 125 registerLocalObserver(cm); 126 cm.notifyAllObservers(conf); 127 128 // 'Suggest' the system to do a GC. We should be able to cause GC 129 // atleast once in the 2000 iterations. 130 System.gc(); 131 132 // If GC indeed happened, all the observers (which are all out of scope), 133 // should have been deregistered. 134 if (cm.getNumObservers() <= i) { 135 outOfScopeObserversDeregistered = true; 136 break; 137 } 138 } 139 if (!outOfScopeObserversDeregistered) { 140 LOG.warn("Observers were not GC-ed! Something seems to be wrong."); 141 } 142 assertTrue(outOfScopeObserversDeregistered); 143 } 144}