| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.hcatalog.hbase.snapshot; |
| |
| import java.io.IOException; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| import org.apache.commons.lang.builder.ToStringBuilder; |
| import org.apache.commons.lang.builder.ToStringStyle; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; |
| import org.apache.hcatalog.hbase.SkeletonHBaseTest; |
| import org.junit.Assert; |
| import org.junit.Test; |
| |
| public class TestRevisionManagerEndpoint extends SkeletonHBaseTest { |
| |
| static { |
| // test case specific mini cluster settings |
| testConf = new Configuration(false); |
| testConf.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, |
| "org.apache.hcatalog.hbase.snapshot.RevisionManagerEndpoint", |
| "org.apache.hadoop.hbase.coprocessor.GenericEndpoint"); |
| testConf.set(RMConstants.REVISION_MGR_ENDPOINT_IMPL_CLASS, MockRM.class.getName()); |
| } |
| |
| /** |
| * Mock implementation to test the protocol/serialization |
| */ |
| public static class MockRM implements RevisionManager { |
| |
| private static class Invocation { |
| Invocation(String methodName, Object ret, Object... args) { |
| this.methodName = methodName; |
| this.args = args; |
| this.ret = ret; |
| } |
| |
| String methodName; |
| Object[] args; |
| Object ret; |
| |
| private static boolean equals(Object obj1, Object obj2) { |
| if (obj1 == obj2) return true; |
| if (obj1 == null || obj2 == null) return false; |
| if (obj1 instanceof Transaction || obj1 instanceof TableSnapshot) { |
| return obj1.toString().equals(obj2.toString()); |
| } |
| return obj1.equals(obj2); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| Invocation other = (Invocation) obj; |
| if (this == other) return true; |
| if (other == null) return false; |
| if (this.args != other.args) { |
| if (this.args == null || other.args == null) return false; |
| if (this.args.length != other.args.length) return false; |
| for (int i = 0; i < args.length; i++) { |
| if (!equals(this.args[i], other.args[i])) return false; |
| } |
| } |
| return equals(this.ret, other.ret); |
| } |
| |
| @Override |
| public String toString() { |
| return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE). |
| append("method", this.methodName). |
| append("args", this.args). |
| append("returns", this.ret). |
| toString(); |
| } |
| } |
| |
| final static String DEFAULT_INSTANCE = "default"; |
| final static Map<String, MockRM> INSTANCES = new ConcurrentHashMap<String, MockRM>(); |
| Invocation lastCall; |
| boolean isOpen = false; |
| |
| private <T extends Object> T recordCall(T result, Object... args) { |
| StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); |
| lastCall = new Invocation(stackTrace[2].getMethodName(), result, args); |
| return result; |
| } |
| |
| @Override |
| public void initialize(Configuration conf) { |
| if (!INSTANCES.containsKey(DEFAULT_INSTANCE)) |
| INSTANCES.put(DEFAULT_INSTANCE, this); |
| } |
| |
| @Override |
| public void open() throws IOException { |
| isOpen = true; |
| } |
| |
| @Override |
| public void close() throws IOException { |
| isOpen = false; |
| } |
| |
| @Override |
| public void createTable(String table, List<String> columnFamilies) throws IOException { |
| } |
| |
| @Override |
| public void dropTable(String table) throws IOException { |
| } |
| |
| @Override |
| public Transaction beginWriteTransaction(String table, |
| List<String> families) throws IOException { |
| return recordCall(null, table, families); |
| } |
| |
| @Override |
| public Transaction beginWriteTransaction(String table, |
| List<String> families, long keepAlive) throws IOException { |
| return recordCall(null, table, families, keepAlive); |
| } |
| |
| @Override |
| public void commitWriteTransaction(Transaction transaction) |
| throws IOException { |
| } |
| |
| @Override |
| public void abortWriteTransaction(Transaction transaction) |
| throws IOException { |
| } |
| |
| @Override |
| public List<FamilyRevision> getAbortedWriteTransactions(String table, |
| String columnFamily) throws IOException { |
| return null; |
| } |
| |
| @Override |
| public TableSnapshot createSnapshot(String tableName) |
| throws IOException { |
| return null; |
| } |
| |
| @Override |
| public TableSnapshot createSnapshot(String tableName, long revision) |
| throws IOException { |
| TableSnapshot ret = new TableSnapshot(tableName, new HashMap<String, Long>(), revision); |
| return recordCall(ret, tableName, revision); |
| } |
| |
| @Override |
| public void keepAlive(Transaction transaction) throws IOException { |
| recordCall(null, transaction); |
| } |
| } |
| |
| @Test |
| public void testRevisionManagerProtocol() throws Throwable { |
| |
| Configuration conf = getHbaseConf(); |
| RevisionManager rm = RevisionManagerFactory.getOpenedRevisionManager( |
| RevisionManagerEndpointClient.class.getName(), conf); |
| |
| MockRM mockImpl = MockRM.INSTANCES.get(MockRM.DEFAULT_INSTANCE); |
| Assert.assertNotNull(mockImpl); |
| Assert.assertTrue(mockImpl.isOpen); |
| |
| Transaction t = new Transaction("t1", Arrays.asList("f1", "f2"), 0, 0); |
| MockRM.Invocation call = new MockRM.Invocation("keepAlive", null, t); |
| rm.keepAlive(t); |
| Assert.assertEquals(call.methodName, call, mockImpl.lastCall); |
| |
| t = new Transaction("t2", Arrays.asList("f21", "f22"), 0, 0); |
| call = new MockRM.Invocation("beginWriteTransaction", null, t.getTableName(), t.getColumnFamilies()); |
| call.ret = rm.beginWriteTransaction(t.getTableName(), t.getColumnFamilies()); |
| Assert.assertEquals(call.methodName, call, mockImpl.lastCall); |
| |
| call = new MockRM.Invocation("createSnapshot", null, "t3", 1L); |
| call.ret = rm.createSnapshot("t3", 1); |
| Assert.assertEquals(call.methodName, call, mockImpl.lastCall); |
| |
| } |
| |
| } |