1   /*
2    * Copyright 2011 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  
21  package org.apache.hadoop.hbase.coprocessor;
22  
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.HBaseTestingUtility;
29  import org.apache.hadoop.hbase.HConstants;
30  import org.apache.hadoop.hbase.MediumTests;
31  import org.apache.hadoop.hbase.MiniHBaseCluster;
32  import org.apache.hadoop.hbase.client.Delete;
33  import org.apache.hadoop.hbase.client.Get;
34  import org.apache.hadoop.hbase.client.HTable;
35  import org.apache.hadoop.hbase.client.Mutation;
36  import org.apache.hadoop.hbase.client.Put;
37  import org.apache.hadoop.hbase.client.Result;
38  import org.apache.hadoop.hbase.util.Bytes;
39  import org.junit.After;
40  import org.junit.AfterClass;
41  import org.junit.Assert;
42  import org.junit.Before;
43  import org.junit.BeforeClass;
44  import org.junit.Test;
45  import org.junit.experimental.categories.Category;
46  
47  /**
48   * A test class to cover multi row mutations protocol
49   */
50  @Category(MediumTests.class)
51  public class TestMultiRowMutationProtocol {
52  
53    private static final byte[] TEST_TABLE = Bytes.toBytes("TestTable");
54    private static final byte[] TEST_FAMILY = Bytes.toBytes("TestFamily");
55    private static final byte[] INVALID_FAMILY = Bytes.toBytes("InvalidFamily");
56    private static final byte[] TEST_QUALIFIER = Bytes.toBytes("TestQualifier");
57    private static byte[] ROW = Bytes.toBytes("testRow");
58    
59    private static final int ROWSIZE = 20;
60    private static final int rowSeperator1 = 5;
61    private static final int rowSeperator2 = 12;
62    private static byte[][] ROWS = makeN(ROW, ROWSIZE);
63  
64    private static HBaseTestingUtility util = new HBaseTestingUtility();
65    private static MiniHBaseCluster cluster = null;
66    
67    private HTable table = null;
68    
69    @BeforeClass
70    public static void setupBeforeClass() throws Exception {
71      // set configure to indicate which cp should be loaded
72      Configuration conf = util.getConfiguration();
73      conf.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
74        "org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint");
75  
76      util.startMiniCluster(2);
77      cluster = util.getMiniHBaseCluster();
78  
79      HTable table = util.createTable(TEST_TABLE, TEST_FAMILY);
80      util.createMultiRegions(util.getConfiguration(), table, TEST_FAMILY,
81                              new byte[][] { HConstants.EMPTY_BYTE_ARRAY,
82                                  ROWS[rowSeperator1], ROWS[rowSeperator2] });
83  
84      for (int i = 0; i < ROWSIZE; i++) {
85        Put put = new Put(ROWS[i]);
86        put.setWriteToWAL(false);
87        put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(i));
88        table.put(put);
89      }
90  
91      // sleep here is an ugly hack to allow region transitions to finish
92      long timeout = System.currentTimeMillis() + (15 * 1000);
93      while ((System.currentTimeMillis() < timeout) &&
94        (table.getRegionsInfo().size() != 3)) {
95        Thread.sleep(250);
96      }
97      table.close();
98    }
99  
100   @AfterClass
101   public static void tearDownAfterClass() throws Exception {
102     util.shutdownMiniCluster();
103   }
104   
105   @Before
106   public void setup() throws IOException {
107     table = new HTable(util.getConfiguration(), TEST_TABLE);
108     for (int i = 0; i < ROWSIZE; i++) {
109       Put put = new Put(ROWS[i]);
110       put.setWriteToWAL(false);
111       put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(i));
112       table.put(put);
113     }
114   }
115   
116   @After
117   public void tearDown() throws IOException {
118     table.close();
119   }
120   
121   @Test
122   public void testMultiRowMutations() throws IOException {
123     List<Mutation> mutations = new ArrayList<Mutation>();
124 
125     Put put = new Put(ROWS[1]);
126     put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(2 * 1));
127     mutations.add(put);
128     Delete del = new Delete(ROWS[3]);
129     del.deleteColumns(TEST_FAMILY, TEST_QUALIFIER);
130     mutations.add(del);
131     
132     MultiRowMutationProtocol p =
133         table.coprocessorProxy(MultiRowMutationProtocol.class, mutations.get(0).getRow());
134     try {
135       p.mutateRows(mutations);
136     } catch (IOException e) {
137       Assert.assertTrue(false);
138     }
139     
140     Get get = new Get(ROWS[1]);
141     get.addColumn(TEST_FAMILY, TEST_QUALIFIER);
142     Result result = table.get(get);
143     Assert.assertEquals(2, Bytes.toInt(result.getValue(TEST_FAMILY, TEST_QUALIFIER)));
144     
145     
146     get = new Get(ROWS[3]);
147     get.addColumn(TEST_FAMILY, TEST_QUALIFIER);
148     result = table.get(get);
149     Assert.assertNull(result.getValue(TEST_FAMILY, TEST_QUALIFIER));
150   }
151   
152   @Test
153   public void testMultiRowMutationsAcrossRegions() throws IOException {
154     List<Mutation> mutations = new ArrayList<Mutation>();
155 
156     Put put = new Put(ROWS[1]);
157     put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(2 * 1));
158     mutations.add(put);
159     Delete del = new Delete(ROWS[7]);
160     del.deleteColumns(TEST_FAMILY, TEST_QUALIFIER);
161     mutations.add(del);
162     
163     MultiRowMutationProtocol p =
164         table.coprocessorProxy(MultiRowMutationProtocol.class, mutations.get(0).getRow());
165     try {
166       p.mutateRows(mutations);
167       Assert.assertTrue(false);
168     } catch (IOException e) {
169     }
170   }
171   
172   @Test
173   public void testInvalidFamiliy() throws IOException {
174     List<Mutation> invalids = new ArrayList<Mutation>();
175     Put put = new Put(ROWS[1]);
176     put.add(INVALID_FAMILY, TEST_QUALIFIER, Bytes.toBytes(2 * 1));
177     invalids.add(put);
178     
179     MultiRowMutationProtocol p =
180         table.coprocessorProxy(MultiRowMutationProtocol.class, ROWS[1]);
181     try {
182       p.mutateRows(invalids);
183       Assert.assertTrue(false);
184     } catch (IOException e) {
185     }
186     
187     List<Mutation> valids = new ArrayList<Mutation>();
188     put = new Put(ROWS[1]);
189     put.add(TEST_FAMILY, TEST_QUALIFIER, Bytes.toBytes(2 * 1));
190     valids.add(put);
191     try {
192       p.mutateRows(valids);
193     } catch (IOException e) {
194       Assert.assertTrue(false);
195     }
196   }
197 
198   /**
199    * an infrastructure method to prepare rows for the testtable.
200    * @param base
201    * @param n
202    * @return
203    */
204   private static byte[][] makeN(byte[] base, int n) {
205     byte[][] ret = new byte[n][];
206     for (int i = 0; i < n; i++) {
207       ret[i] = Bytes.add(base, Bytes.toBytes(i));
208     }
209     return ret;
210   }
211 }