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.client.replication;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertTrue;
023import static org.junit.Assert.fail;
024
025import java.util.Collection;
026import java.util.HashMap;
027import java.util.Map;
028import java.util.UUID;
029import org.apache.hadoop.hbase.HBaseClassTestRule;
030import org.apache.hadoop.hbase.HColumnDescriptor;
031import org.apache.hadoop.hbase.HConstants;
032import org.apache.hadoop.hbase.HTableDescriptor;
033import org.apache.hadoop.hbase.TableName;
034import org.apache.hadoop.hbase.TableNotFoundException;
035import org.apache.hadoop.hbase.client.Admin;
036import org.apache.hadoop.hbase.client.Connection;
037import org.apache.hadoop.hbase.client.ConnectionFactory;
038import org.apache.hadoop.hbase.replication.BaseReplicationEndpoint;
039import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
040import org.apache.hadoop.hbase.replication.TestReplicationBase;
041import org.apache.hadoop.hbase.testclassification.ClientTests;
042import org.apache.hadoop.hbase.testclassification.MediumTests;
043import org.junit.AfterClass;
044import org.junit.BeforeClass;
045import org.junit.ClassRule;
046import org.junit.Rule;
047import org.junit.Test;
048import org.junit.experimental.categories.Category;
049import org.junit.rules.TestName;
050
051/**
052 * Unit testing of ReplicationAdmin with clusters
053 */
054@Category({ MediumTests.class, ClientTests.class })
055public class TestReplicationAdminWithClusters extends TestReplicationBase {
056
057  @ClassRule
058  public static final HBaseClassTestRule CLASS_RULE =
059      HBaseClassTestRule.forClass(TestReplicationAdminWithClusters.class);
060
061  static Connection connection1;
062  static Connection connection2;
063  static Admin admin1;
064  static Admin admin2;
065  static ReplicationAdmin adminExt;
066
067  @Rule
068  public TestName name = new TestName();
069
070  @BeforeClass
071  public static void setUpBeforeClass() throws Exception {
072    TestReplicationBase.setUpBeforeClass();
073    connection1 = ConnectionFactory.createConnection(conf1);
074    connection2 = ConnectionFactory.createConnection(conf2);
075    admin1 = connection1.getAdmin();
076    admin2 = connection2.getAdmin();
077    adminExt = new ReplicationAdmin(conf1);
078  }
079
080  @AfterClass
081  public static void tearDownAfterClass() throws Exception {
082    admin1.close();
083    admin2.close();
084    adminExt.close();
085    connection1.close();
086    connection2.close();
087    TestReplicationBase.tearDownAfterClass();
088  }
089
090  @Test
091  public void disableNotFullReplication() throws Exception {
092    HTableDescriptor table = new HTableDescriptor(admin2.getTableDescriptor(tableName));
093    HColumnDescriptor f = new HColumnDescriptor("notReplicatedFamily");
094    table.addFamily(f);
095    admin1.disableTable(tableName);
096    admin1.modifyTable(tableName, table);
097    admin1.enableTable(tableName);
098
099    admin1.disableTableReplication(tableName);
100    table = admin1.getTableDescriptor(tableName);
101    for (HColumnDescriptor fam : table.getColumnFamilies()) {
102      assertEquals(HConstants.REPLICATION_SCOPE_LOCAL, fam.getScope());
103    }
104
105    admin1.deleteColumnFamily(table.getTableName(), f.getName());
106  }
107
108  @Test
109  public void testEnableReplicationWhenSlaveClusterDoesntHaveTable() throws Exception {
110    admin1.disableTableReplication(tableName);
111    admin2.disableTable(tableName);
112    admin2.deleteTable(tableName);
113    assertFalse(admin2.tableExists(tableName));
114    admin1.enableTableReplication(tableName);
115    assertTrue(admin2.tableExists(tableName));
116  }
117
118  @Test
119  public void testEnableReplicationWhenReplicationNotEnabled() throws Exception {
120    HTableDescriptor table = new HTableDescriptor(admin1.getTableDescriptor(tableName));
121    for (HColumnDescriptor fam : table.getColumnFamilies()) {
122      fam.setScope(HConstants.REPLICATION_SCOPE_LOCAL);
123    }
124    admin1.disableTable(tableName);
125    admin1.modifyTable(tableName, table);
126    admin1.enableTable(tableName);
127
128    admin2.disableTable(tableName);
129    admin2.modifyTable(tableName, table);
130    admin2.enableTable(tableName);
131
132    admin1.enableTableReplication(tableName);
133    table = admin1.getTableDescriptor(tableName);
134    for (HColumnDescriptor fam : table.getColumnFamilies()) {
135      assertEquals(HConstants.REPLICATION_SCOPE_GLOBAL, fam.getScope());
136    }
137  }
138
139  @Test
140  public void testEnableReplicationWhenTableDescriptorIsNotSameInClusters() throws Exception {
141    HTableDescriptor table = new HTableDescriptor(admin2.getTableDescriptor(tableName));
142    HColumnDescriptor f = new HColumnDescriptor("newFamily");
143    table.addFamily(f);
144    admin2.disableTable(tableName);
145    admin2.modifyTable(tableName, table);
146    admin2.enableTable(tableName);
147
148    try {
149      admin1.enableTableReplication(tableName);
150      fail("Exception should be thrown if table descriptors in the clusters are not same.");
151    } catch (RuntimeException ignored) {
152
153    }
154    admin1.disableTable(tableName);
155    admin1.modifyTable(tableName, table);
156    admin1.enableTable(tableName);
157    admin1.enableTableReplication(tableName);
158    table = admin1.getTableDescriptor(tableName);
159    for (HColumnDescriptor fam : table.getColumnFamilies()) {
160      assertEquals(HConstants.REPLICATION_SCOPE_GLOBAL, fam.getScope());
161    }
162
163    admin1.deleteColumnFamily(tableName, f.getName());
164    admin2.deleteColumnFamily(tableName, f.getName());
165  }
166
167  @Test
168  public void testDisableAndEnableReplication() throws Exception {
169    admin1.disableTableReplication(tableName);
170    HTableDescriptor table = admin1.getTableDescriptor(tableName);
171    for (HColumnDescriptor fam : table.getColumnFamilies()) {
172      assertEquals(HConstants.REPLICATION_SCOPE_LOCAL, fam.getScope());
173    }
174    admin1.enableTableReplication(tableName);
175    table = admin1.getTableDescriptor(tableName);
176    for (HColumnDescriptor fam : table.getColumnFamilies()) {
177      assertEquals(HConstants.REPLICATION_SCOPE_GLOBAL, fam.getScope());
178    }
179  }
180
181  @Test(expected = TableNotFoundException.class)
182  public void testDisableReplicationForNonExistingTable() throws Exception {
183    admin1.disableTableReplication(TableName.valueOf(name.getMethodName()));
184  }
185
186  @Test(expected = TableNotFoundException.class)
187  public void testEnableReplicationForNonExistingTable() throws Exception {
188    admin1.enableTableReplication(TableName.valueOf(name.getMethodName()));
189  }
190
191  @Test(expected = IllegalArgumentException.class)
192  public void testDisableReplicationWhenTableNameAsNull() throws Exception {
193    admin1.disableTableReplication(null);
194  }
195
196  @Test(expected = IllegalArgumentException.class)
197  public void testEnableReplicationWhenTableNameAsNull() throws Exception {
198    admin1.enableTableReplication(null);
199  }
200
201  /*
202   * Test enable table replication should create table only in user explicit specified table-cfs.
203   * HBASE-14717
204   */
205  @Test
206  public void testEnableReplicationForExplicitSetTableCfs() throws Exception {
207    final TableName tableName = TableName.valueOf(name.getMethodName());
208    String peerId = "2";
209    if (admin2.isTableAvailable(TestReplicationBase.tableName)) {
210      admin2.disableTable(TestReplicationBase.tableName);
211      admin2.deleteTable(TestReplicationBase.tableName);
212    }
213    assertFalse("Table should not exists in the peer cluster",
214      admin2.isTableAvailable(TestReplicationBase.tableName));
215
216    // update peer config
217    ReplicationPeerConfig rpc = admin1.getReplicationPeerConfig(peerId);
218    rpc.setReplicateAllUserTables(false);
219    admin1.updateReplicationPeerConfig(peerId, rpc);
220
221    Map<TableName, ? extends Collection<String>> tableCfs = new HashMap<>();
222    tableCfs.put(tableName, null);
223    try {
224      adminExt.setPeerTableCFs(peerId, tableCfs);
225      admin1.enableTableReplication(TestReplicationBase.tableName);
226      assertFalse("Table should not be created if user has set table cfs explicitly for the "
227          + "peer and this is not part of that collection",
228        admin2.isTableAvailable(TestReplicationBase.tableName));
229
230      tableCfs.put(TestReplicationBase.tableName, null);
231      adminExt.setPeerTableCFs(peerId, tableCfs);
232      admin1.enableTableReplication(TestReplicationBase.tableName);
233      assertTrue(
234        "Table should be created if user has explicitly added table into table cfs collection",
235        admin2.isTableAvailable(TestReplicationBase.tableName));
236    } finally {
237      adminExt.removePeerTableCFs(peerId, adminExt.getPeerTableCFs(peerId));
238      admin1.disableTableReplication(TestReplicationBase.tableName);
239
240      rpc = admin1.getReplicationPeerConfig(peerId);
241      rpc.setReplicateAllUserTables(true);
242      admin1.updateReplicationPeerConfig(peerId, rpc);
243    }
244  }
245
246  @Test
247  public void testReplicationPeerConfigUpdateCallback() throws Exception {
248    String peerId = "1";
249    ReplicationPeerConfig rpc = new ReplicationPeerConfig();
250    rpc.setClusterKey(utility2.getClusterKey());
251    rpc.setReplicationEndpointImpl(TestUpdatableReplicationEndpoint.class.getName());
252    rpc.getConfiguration().put("key1", "value1");
253
254    admin1.addReplicationPeer(peerId, rpc);
255
256    rpc.getConfiguration().put("key1", "value2");
257    admin.updatePeerConfig(peerId, rpc);
258    if (!TestUpdatableReplicationEndpoint.hasCalledBack()) {
259      synchronized (TestUpdatableReplicationEndpoint.class) {
260        TestUpdatableReplicationEndpoint.class.wait(2000L);
261      }
262    }
263
264    assertEquals(true, TestUpdatableReplicationEndpoint.hasCalledBack());
265
266    admin.removePeer(peerId);
267  }
268
269  public static class TestUpdatableReplicationEndpoint extends BaseReplicationEndpoint {
270    private static boolean calledBack = false;
271    public static boolean hasCalledBack(){
272      return calledBack;
273    }
274    @Override
275    public synchronized void peerConfigUpdated(ReplicationPeerConfig rpc){
276      calledBack = true;
277      notifyAll();
278    }
279
280    @Override
281    public void start() {
282      startAsync();
283    }
284
285    @Override
286    public void stop() {
287      stopAsync();
288    }
289
290    @Override
291    protected void doStart() {
292      notifyStarted();
293    }
294
295    @Override
296    protected void doStop() {
297      notifyStopped();
298    }
299
300    @Override
301    public UUID getPeerUUID() {
302      return utility1.getRandomUUID();
303    }
304
305    @Override
306    public boolean replicate(ReplicateContext replicateContext) {
307      return false;
308    }
309  }
310}