1   /*
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.coprocessor;
21  
22  import static org.junit.Assert.assertArrayEquals;
23  import static org.junit.Assert.assertEquals;
24  
25  import java.io.IOException;
26  import java.util.Map;
27  
28  import org.apache.hadoop.conf.Configuration;
29  import org.apache.hadoop.hbase.HBaseTestingUtility;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.MiniHBaseCluster;
32  import org.apache.hadoop.hbase.client.HTable;
33  import org.apache.hadoop.hbase.client.Put;
34  import org.apache.hadoop.hbase.client.Scan;
35  import org.apache.hadoop.hbase.client.coprocessor.Batch;
36  import org.apache.hadoop.hbase.util.Bytes;
37  import org.apache.hadoop.io.Text;
38  import org.junit.AfterClass;
39  import org.junit.BeforeClass;
40  import org.junit.Test;
41  
42  /**
43   * TestEndpoint: test cases to verify coprocessor Endpoint
44   */
45  public class TestCoprocessorEndpoint {
46  
47    private static final byte[] TEST_TABLE = Bytes.toBytes("TestTable");
48    private static final byte[] TEST_FAMILY = Bytes.toBytes("TestFamily");
49    private static final byte[] TEST_QUALIFIER = Bytes.toBytes("TestQualifier");
50    private static byte[] ROW = Bytes.toBytes("testRow");
51  
52    private static final int ROWSIZE = 20;
53    private static final int rowSeperator1 = 5;
54    private static final int rowSeperator2 = 12;
55    private static byte[][] ROWS = makeN(ROW, ROWSIZE);
56  
57    private static HBaseTestingUtility util = new HBaseTestingUtility();
58    private static MiniHBaseCluster cluster = null;
59  
60    @BeforeClass
61    public static void setupBeforeClass() throws Exception {
62      // set configure to indicate which cp should be loaded
63      Configuration conf = util.getConfiguration();
64      conf.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
65          "org.apache.hadoop.hbase.coprocessor.ColumnAggregationEndpoint",
66          "org.apache.hadoop.hbase.coprocessor.GenericEndpoint");
67  
68      util.startMiniCluster(2);
69      cluster = util.getMiniHBaseCluster();
70  
71      HTable table = util.createTable(TEST_TABLE, TEST_FAMILY);
72      util.createMultiRegions(util.getConfiguration(), table, TEST_FAMILY,
73                              new byte[][] { HConstants.EMPTY_BYTE_ARRAY,
74                                  ROWS[rowSeperator1], ROWS[rowSeperator2] });
75  
76      for (int i = 0; i < ROWSIZE; i++) {
77        Put put = new Put(ROWS[i]);
78        put.setWriteToWAL(false);
79        put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(i));
80        table.put(put);
81      }
82  
83      // sleep here is an ugly hack to allow region transitions to finish
84      long timeout = System.currentTimeMillis() + (15 * 1000);
85      while ((System.currentTimeMillis() < timeout) &&
86        (table.getRegionsInfo().size() != 2)) {
87        Thread.sleep(250);
88      }
89    }
90  
91    @AfterClass
92    public static void tearDownAfterClass() throws Exception {
93      util.shutdownMiniCluster();
94    }
95  
96    @Test
97    public void testGeneric() throws Throwable {
98      HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
99      GenericProtocol protocol = table.coprocessorProxy(GenericProtocol.class,
100                                                       Bytes.toBytes("testRow"));
101     String workResult1 = protocol.doWork("foo");
102     assertEquals("foo", workResult1);
103     byte[] workResult2 = protocol.doWork(new byte[]{1});
104     assertArrayEquals(new byte[]{1}, workResult2);
105     byte workResult3 = protocol.doWork((byte)1);
106     assertEquals((byte)1, workResult3);
107     char workResult4 = protocol.doWork('c');
108     assertEquals('c', workResult4);
109     boolean workResult5 = protocol.doWork(true);
110     assertEquals(true, workResult5);
111     short workResult6 = protocol.doWork((short)1);
112     assertEquals((short)1, workResult6);
113     int workResult7 = protocol.doWork(5);
114     assertEquals(5, workResult7);
115     long workResult8 = protocol.doWork(5l);
116     assertEquals(5l, workResult8);
117     double workResult9 = protocol.doWork(6d);
118     assertEquals(6d, workResult9, 0.01);
119     float workResult10 = protocol.doWork(6f);
120     assertEquals(6f, workResult10, 0.01);
121     Text workResult11 = protocol.doWork(new Text("foo"));
122     assertEquals(new Text("foo"), workResult11);
123   }
124 
125   @Test
126   public void testAggregation() throws Throwable {
127     HTable table = new HTable(util.getConfiguration(), TEST_TABLE);
128     Scan scan;
129     Map<byte[], Long> results;
130 
131     // scan: for all regions
132     results = table
133         .coprocessorExec(ColumnAggregationProtocol.class,
134                          ROWS[rowSeperator1 - 1], ROWS[rowSeperator2 + 1],
135                          new Batch.Call<ColumnAggregationProtocol, Long>() {
136                            public Long call(ColumnAggregationProtocol instance)
137                                throws IOException {
138                              return instance.sum(TEST_FAMILY, TEST_QUALIFIER);
139                            }
140                          });
141     int sumResult = 0;
142     int expectedResult = 0;
143     for (Map.Entry<byte[], Long> e : results.entrySet()) {
144       sumResult += e.getValue();
145     }
146     for (int i = 0; i < ROWSIZE; i++) {
147       expectedResult += i;
148     }
149     assertEquals("Invalid result", sumResult, expectedResult);
150 
151     results.clear();
152 
153     // scan: for region 2 and region 3
154     results = table
155         .coprocessorExec(ColumnAggregationProtocol.class,
156                          ROWS[rowSeperator1 + 1], ROWS[rowSeperator2 + 1],
157                          new Batch.Call<ColumnAggregationProtocol, Long>() {
158                            public Long call(ColumnAggregationProtocol instance)
159                                throws IOException {
160                              return instance.sum(TEST_FAMILY, TEST_QUALIFIER);
161                            }
162                          });
163     sumResult = 0;
164     expectedResult = 0;
165     for (Map.Entry<byte[], Long> e : results.entrySet()) {
166       sumResult += e.getValue();
167     }
168     for (int i = rowSeperator1; i < ROWSIZE; i++) {
169       expectedResult += i;
170     }
171     assertEquals("Invalid result", sumResult, expectedResult);
172   }
173 
174   private static byte[][] makeN(byte[] base, int n) {
175     byte[][] ret = new byte[n][];
176     for (int i = 0; i < n; i++) {
177       ret[i] = Bytes.add(base, Bytes.toBytes(String.format("%02d", i)));
178     }
179     return ret;
180   }
181 }