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