1   /**
2    * Copyright 2009 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;
21  
22  
23  import static org.junit.Assert.*;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.ByteArrayOutputStream;
27  import java.io.DataInputStream;
28  import java.io.DataOutputStream;
29  import java.io.IOException;
30  import java.util.ArrayList;
31  import java.util.HashSet;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.NavigableSet;
35  import java.util.Set;
36  import java.util.TreeMap;
37  
38  import org.apache.hadoop.hbase.HServerLoad092.RegionLoad;
39  import org.apache.hadoop.hbase.client.Delete;
40  import org.apache.hadoop.hbase.client.Get;
41  import org.apache.hadoop.hbase.client.Put;
42  import org.apache.hadoop.hbase.client.Result;
43  import org.apache.hadoop.hbase.client.RowLock;
44  import org.apache.hadoop.hbase.client.Scan;
45  import org.apache.hadoop.hbase.filter.BinaryComparator;
46  import org.apache.hadoop.hbase.filter.Filter;
47  import org.apache.hadoop.hbase.filter.PrefixFilter;
48  import org.apache.hadoop.hbase.filter.RowFilter;
49  import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
50  import org.apache.hadoop.hbase.io.HbaseMapWritable;
51  import org.apache.hadoop.hbase.io.TimeRange;
52  import org.apache.hadoop.hbase.util.Bytes;
53  import org.apache.hadoop.hbase.util.Writables;
54  import org.apache.hadoop.io.DataInputBuffer;
55  import org.junit.Test;
56  import org.junit.experimental.categories.Category;
57  
58  /**
59   * Test HBase Writables serializations
60   */
61  @Category(SmallTests.class)
62  public class TestSerialization {
63    @Test
64    public void testHServerLoadVersioning() throws IOException {
65      Set<String> cps = new HashSet<String>(0);
66      Map<byte [], RegionLoad> regions = new TreeMap<byte [], RegionLoad>(Bytes.BYTES_COMPARATOR);
67      regions.put(HConstants.META_TABLE_NAME,
68        new HServerLoad092.RegionLoad(HConstants.META_TABLE_NAME, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cps));
69      HServerLoad092 hsl092 = new HServerLoad092(0, 0, 0, 0, regions, cps);
70      byte [] hsl092bytes = Writables.getBytes(hsl092);
71      HServerLoad hsl = (HServerLoad)Writables.getWritable(hsl092bytes, new HServerLoad());
72      // TO BE CONTINUED
73    }
74  
75    @Test public void testCompareFilter() throws Exception {
76      Filter f = new RowFilter(CompareOp.EQUAL,
77        new BinaryComparator(Bytes.toBytes("testRowOne-2")));
78      byte [] bytes = Writables.getBytes(f);
79      Filter ff = (Filter)Writables.getWritable(bytes, new RowFilter());
80      assertNotNull(ff);
81    }
82  
83    @Test public void testKeyValue() throws Exception {
84      final String name = "testKeyValue";
85      byte [] row = Bytes.toBytes(name);
86      byte [] family = Bytes.toBytes(name);
87      byte [] qualifier = Bytes.toBytes(name);
88      KeyValue original = new KeyValue(row, family, qualifier);
89      byte [] bytes = Writables.getBytes(original);
90      KeyValue newone = (KeyValue)Writables.getWritable(bytes, new KeyValue());
91      assertTrue(KeyValue.COMPARATOR.compare(original, newone) == 0);
92    }
93  
94    @Test public void testCreateKeyValueInvalidNegativeLength() {
95  
96      KeyValue kv_0 = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"),       // 51 bytes
97                                   Bytes.toBytes("myQualifier"), 12345L, Bytes.toBytes("my12345"));
98  
99      KeyValue kv_1 = new KeyValue(Bytes.toBytes("myRow"), Bytes.toBytes("myCF"),       // 49 bytes
100                                  Bytes.toBytes("myQualifier"), 12345L, Bytes.toBytes("my123"));
101 
102     KeyValue kv_i = new KeyValue();
103 
104     ByteArrayOutputStream baos = new ByteArrayOutputStream();
105     DataOutputStream dos = new DataOutputStream(baos);
106 
107     long l = 0;
108     try {
109       kv_0.write(dos);
110       l  = dos.size();
111       kv_1.write(dos);
112       l += dos.size();
113       assertEquals(151L, l);
114     } catch (IOException e) {
115       fail("Unexpected IOException" + e.getMessage());
116     }
117 
118     ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
119     DataInputStream dis = new DataInputStream(bais);
120 
121     try {
122       kv_i.readFields(dis);
123       assertTrue(kv_0.equals(kv_1));
124     } catch (Exception e) {
125       fail("Unexpected Exception" + e.getMessage());
126     }
127 
128     // length -1
129     try {
130       // even if we have a good kv now in dis we will just pass length with -1 for simplicity
131       kv_i.readFields(-1, dis);
132       fail("Expected corrupt stream");
133     } catch (Exception e) {
134       assertEquals("Failed read -1 bytes, stream corrupt?", e.getMessage());
135     }
136 
137   }
138 
139   @SuppressWarnings("unchecked")
140   @Test public void testHbaseMapWritable() throws Exception {
141     HbaseMapWritable<byte [], byte []> hmw =
142       new HbaseMapWritable<byte[], byte[]>();
143     hmw.put("key".getBytes(), "value".getBytes());
144     byte [] bytes = Writables.getBytes(hmw);
145     hmw = (HbaseMapWritable<byte[], byte[]>)
146       Writables.getWritable(bytes, new HbaseMapWritable<byte [], byte []>());
147     assertTrue(hmw.size() == 1);
148     assertTrue(Bytes.equals("value".getBytes(), hmw.get("key".getBytes())));
149   }
150 
151 
152   @Test public void testTableDescriptor() throws Exception {
153     final String name = "testTableDescriptor";
154     HTableDescriptor htd = createTableDescriptor(name);
155     byte [] mb = Writables.getBytes(htd);
156     HTableDescriptor deserializedHtd =
157       (HTableDescriptor)Writables.getWritable(mb, new HTableDescriptor());
158     assertEquals(htd.getNameAsString(), deserializedHtd.getNameAsString());
159   }
160 
161   /**
162    * Test RegionInfo serialization
163    * @throws Exception
164    */
165   @Test public void testRegionInfo() throws Exception {
166     HRegionInfo hri = createRandomRegion("testRegionInfo");
167     byte [] hrib = Writables.getBytes(hri);
168     HRegionInfo deserializedHri =
169       (HRegionInfo)Writables.getWritable(hrib, new HRegionInfo());
170     assertEquals(hri.getEncodedName(), deserializedHri.getEncodedName());
171     //assertEquals(hri.getTableDesc().getFamilies().size(),
172     //  deserializedHri.getTableDesc().getFamilies().size());
173   }
174 
175   @Test public void testRegionInfos() throws Exception {
176     HRegionInfo hri = createRandomRegion("testRegionInfos");
177     byte [] hrib = Writables.getBytes(hri);
178     byte [] triple = new byte [3 * hrib.length];
179     System.arraycopy(hrib, 0, triple, 0, hrib.length);
180     System.arraycopy(hrib, 0, triple, hrib.length, hrib.length);
181     System.arraycopy(hrib, 0, triple, hrib.length * 2, hrib.length);
182     List<HRegionInfo> regions = Writables.getHRegionInfos(triple, 0, triple.length);
183     assertTrue(regions.size() == 3);
184     assertTrue(regions.get(0).equals(regions.get(1)));
185     assertTrue(regions.get(0).equals(regions.get(2)));
186   }
187 
188   private HRegionInfo createRandomRegion(final String name) {
189     HTableDescriptor htd = new HTableDescriptor(name);
190     String [] families = new String [] {"info", "anchor"};
191     for (int i = 0; i < families.length; i++) {
192       htd.addFamily(new HColumnDescriptor(families[i]));
193     }
194     return new HRegionInfo(htd.getName(), HConstants.EMPTY_START_ROW,
195       HConstants.EMPTY_END_ROW);
196   }
197 
198   @Test public void testPut() throws Exception{
199     byte[] row = "row".getBytes();
200     byte[] fam = "fam".getBytes();
201     byte[] qf1 = "qf1".getBytes();
202     byte[] qf2 = "qf2".getBytes();
203     byte[] qf3 = "qf3".getBytes();
204     byte[] qf4 = "qf4".getBytes();
205     byte[] qf5 = "qf5".getBytes();
206     byte[] qf6 = "qf6".getBytes();
207     byte[] qf7 = "qf7".getBytes();
208     byte[] qf8 = "qf8".getBytes();
209 
210     long ts = System.currentTimeMillis();
211     byte[] val = "val".getBytes();
212 
213     Put put = new Put(row);
214     put.setWriteToWAL(false);
215     put.add(fam, qf1, ts, val);
216     put.add(fam, qf2, ts, val);
217     put.add(fam, qf3, ts, val);
218     put.add(fam, qf4, ts, val);
219     put.add(fam, qf5, ts, val);
220     put.add(fam, qf6, ts, val);
221     put.add(fam, qf7, ts, val);
222     put.add(fam, qf8, ts, val);
223 
224     byte[] sb = Writables.getBytes(put);
225     Put desPut = (Put)Writables.getWritable(sb, new Put());
226 
227     //Timing test
228 //    long start = System.nanoTime();
229 //    desPut = (Put)Writables.getWritable(sb, new Put());
230 //    long stop = System.nanoTime();
231 //    System.out.println("timer " +(stop-start));
232 
233     assertTrue(Bytes.equals(put.getRow(), desPut.getRow()));
234     List<KeyValue> list = null;
235     List<KeyValue> desList = null;
236     for(Map.Entry<byte[], List<KeyValue>> entry : put.getFamilyMap().entrySet()){
237       assertTrue(desPut.getFamilyMap().containsKey(entry.getKey()));
238       list = entry.getValue();
239       desList = desPut.getFamilyMap().get(entry.getKey());
240       for(int i=0; i<list.size(); i++){
241         assertTrue(list.get(i).equals(desList.get(i)));
242       }
243     }
244   }
245 
246 
247   @Test public void testPut2() throws Exception{
248     byte[] row = "testAbort,,1243116656250".getBytes();
249     byte[] fam = "historian".getBytes();
250     byte[] qf1 = "creation".getBytes();
251 
252     long ts = 9223372036854775807L;
253     byte[] val = "dont-care".getBytes();
254 
255     Put put = new Put(row);
256     put.add(fam, qf1, ts, val);
257 
258     byte[] sb = Writables.getBytes(put);
259     Put desPut = (Put)Writables.getWritable(sb, new Put());
260 
261     assertTrue(Bytes.equals(put.getRow(), desPut.getRow()));
262     List<KeyValue> list = null;
263     List<KeyValue> desList = null;
264     for(Map.Entry<byte[], List<KeyValue>> entry : put.getFamilyMap().entrySet()){
265       assertTrue(desPut.getFamilyMap().containsKey(entry.getKey()));
266       list = entry.getValue();
267       desList = desPut.getFamilyMap().get(entry.getKey());
268       for(int i=0; i<list.size(); i++){
269         assertTrue(list.get(i).equals(desList.get(i)));
270       }
271     }
272   }
273 
274 
275   @Test public void testDelete() throws Exception{
276     byte[] row = "row".getBytes();
277     byte[] fam = "fam".getBytes();
278     byte[] qf1 = "qf1".getBytes();
279 
280     long ts = System.currentTimeMillis();
281 
282     Delete delete = new Delete(row);
283     delete.deleteColumn(fam, qf1, ts);
284 
285     byte[] sb = Writables.getBytes(delete);
286     Delete desDelete = (Delete)Writables.getWritable(sb, new Delete());
287 
288     assertTrue(Bytes.equals(delete.getRow(), desDelete.getRow()));
289     List<KeyValue> list = null;
290     List<KeyValue> desList = null;
291     for(Map.Entry<byte[], List<KeyValue>> entry :
292         delete.getFamilyMap().entrySet()){
293       assertTrue(desDelete.getFamilyMap().containsKey(entry.getKey()));
294       list = entry.getValue();
295       desList = desDelete.getFamilyMap().get(entry.getKey());
296       for(int i=0; i<list.size(); i++){
297         assertTrue(list.get(i).equals(desList.get(i)));
298       }
299     }
300   }
301 
302   @Test public void testGet() throws Exception{
303     byte[] row = "row".getBytes();
304     byte[] fam = "fam".getBytes();
305     byte[] qf1 = "qf1".getBytes();
306 
307     long ts = System.currentTimeMillis();
308     int maxVersions = 2;
309     long lockid = 5;
310     RowLock rowLock = new RowLock(lockid);
311 
312     Get get = new Get(row, rowLock);
313     get.addColumn(fam, qf1);
314     get.setTimeRange(ts, ts+1);
315     get.setMaxVersions(maxVersions);
316 
317     byte[] sb = Writables.getBytes(get);
318     Get desGet = (Get)Writables.getWritable(sb, new Get());
319 
320     assertTrue(Bytes.equals(get.getRow(), desGet.getRow()));
321     Set<byte[]> set = null;
322     Set<byte[]> desSet = null;
323 
324     for(Map.Entry<byte[], NavigableSet<byte[]>> entry :
325         get.getFamilyMap().entrySet()){
326       assertTrue(desGet.getFamilyMap().containsKey(entry.getKey()));
327       set = entry.getValue();
328       desSet = desGet.getFamilyMap().get(entry.getKey());
329       for(byte [] qualifier : set){
330         assertTrue(desSet.contains(qualifier));
331       }
332     }
333 
334     assertEquals(get.getLockId(), desGet.getLockId());
335     assertEquals(get.getMaxVersions(), desGet.getMaxVersions());
336     TimeRange tr = get.getTimeRange();
337     TimeRange desTr = desGet.getTimeRange();
338     assertEquals(tr.getMax(), desTr.getMax());
339     assertEquals(tr.getMin(), desTr.getMin());
340   }
341 
342 
343   @Test public void testScan() throws Exception {
344 
345     byte[] startRow = "startRow".getBytes();
346     byte[] stopRow  = "stopRow".getBytes();
347     byte[] fam = "fam".getBytes();
348     byte[] qf1 = "qf1".getBytes();
349 
350     long ts = System.currentTimeMillis();
351     int maxVersions = 2;
352 
353     Scan scan = new Scan(startRow, stopRow);
354     scan.addColumn(fam, qf1);
355     scan.setTimeRange(ts, ts+1);
356     scan.setMaxVersions(maxVersions);
357 
358     byte[] sb = Writables.getBytes(scan);
359     Scan desScan = (Scan)Writables.getWritable(sb, new Scan());
360 
361     assertTrue(Bytes.equals(scan.getStartRow(), desScan.getStartRow()));
362     assertTrue(Bytes.equals(scan.getStopRow(), desScan.getStopRow()));
363     assertEquals(scan.getCacheBlocks(), desScan.getCacheBlocks());
364     Set<byte[]> set = null;
365     Set<byte[]> desSet = null;
366 
367     for(Map.Entry<byte[], NavigableSet<byte[]>> entry :
368         scan.getFamilyMap().entrySet()){
369       assertTrue(desScan.getFamilyMap().containsKey(entry.getKey()));
370       set = entry.getValue();
371       desSet = desScan.getFamilyMap().get(entry.getKey());
372       for(byte[] column : set){
373         assertTrue(desSet.contains(column));
374       }
375 
376       // Test filters are serialized properly.
377       scan = new Scan(startRow);
378       final String name = "testScan";
379       byte [] prefix = Bytes.toBytes(name);
380       scan.setFilter(new PrefixFilter(prefix));
381       sb = Writables.getBytes(scan);
382       desScan = (Scan)Writables.getWritable(sb, new Scan());
383       Filter f = desScan.getFilter();
384       assertTrue(f instanceof PrefixFilter);
385     }
386 
387     assertEquals(scan.getMaxVersions(), desScan.getMaxVersions());
388     TimeRange tr = scan.getTimeRange();
389     TimeRange desTr = desScan.getTimeRange();
390     assertEquals(tr.getMax(), desTr.getMax());
391     assertEquals(tr.getMin(), desTr.getMin());
392   }
393 
394   @Test public void testResultEmpty() throws Exception {
395     List<KeyValue> keys = new ArrayList<KeyValue>();
396     Result r = new Result(keys);
397     assertTrue(r.isEmpty());
398     byte [] rb = Writables.getBytes(r);
399     Result deserializedR = (Result)Writables.getWritable(rb, new Result());
400     assertTrue(deserializedR.isEmpty());
401   }
402 
403 
404   @Test public void testResult() throws Exception {
405     byte [] rowA = Bytes.toBytes("rowA");
406     byte [] famA = Bytes.toBytes("famA");
407     byte [] qfA = Bytes.toBytes("qfA");
408     byte [] valueA = Bytes.toBytes("valueA");
409 
410     byte [] rowB = Bytes.toBytes("rowB");
411     byte [] famB = Bytes.toBytes("famB");
412     byte [] qfB = Bytes.toBytes("qfB");
413     byte [] valueB = Bytes.toBytes("valueB");
414 
415     KeyValue kvA = new KeyValue(rowA, famA, qfA, valueA);
416     KeyValue kvB = new KeyValue(rowB, famB, qfB, valueB);
417 
418     Result result = new Result(new KeyValue[]{kvA, kvB});
419 
420     byte [] rb = Writables.getBytes(result);
421     Result deResult = (Result)Writables.getWritable(rb, new Result());
422 
423     assertTrue("results are not equivalent, first key mismatch",
424         result.raw()[0].equals(deResult.raw()[0]));
425 
426     assertTrue("results are not equivalent, second key mismatch",
427         result.raw()[1].equals(deResult.raw()[1]));
428 
429     // Test empty Result
430     Result r = new Result();
431     byte [] b = Writables.getBytes(r);
432     Result deserialized = (Result)Writables.getWritable(b, new Result());
433     assertEquals(r.size(), deserialized.size());
434   }
435 
436   @Test public void testResultDynamicBuild() throws Exception {
437     byte [] rowA = Bytes.toBytes("rowA");
438     byte [] famA = Bytes.toBytes("famA");
439     byte [] qfA = Bytes.toBytes("qfA");
440     byte [] valueA = Bytes.toBytes("valueA");
441 
442     byte [] rowB = Bytes.toBytes("rowB");
443     byte [] famB = Bytes.toBytes("famB");
444     byte [] qfB = Bytes.toBytes("qfB");
445     byte [] valueB = Bytes.toBytes("valueB");
446 
447     KeyValue kvA = new KeyValue(rowA, famA, qfA, valueA);
448     KeyValue kvB = new KeyValue(rowB, famB, qfB, valueB);
449 
450     Result result = new Result(new KeyValue[]{kvA, kvB});
451 
452     byte [] rb = Writables.getBytes(result);
453 
454 
455     // Call getRow() first
456     Result deResult = (Result)Writables.getWritable(rb, new Result());
457     byte [] row = deResult.getRow();
458     assertTrue(Bytes.equals(row, rowA));
459 
460     // Call sorted() first
461     deResult = (Result)Writables.getWritable(rb, new Result());
462     assertTrue("results are not equivalent, first key mismatch",
463         result.raw()[0].equals(deResult.raw()[0]));
464     assertTrue("results are not equivalent, second key mismatch",
465         result.raw()[1].equals(deResult.raw()[1]));
466 
467     // Call raw() first
468     deResult = (Result)Writables.getWritable(rb, new Result());
469     assertTrue("results are not equivalent, first key mismatch",
470         result.raw()[0].equals(deResult.raw()[0]));
471     assertTrue("results are not equivalent, second key mismatch",
472         result.raw()[1].equals(deResult.raw()[1]));
473 
474 
475   }
476 
477   @Test public void testResultArray() throws Exception {
478     byte [] rowA = Bytes.toBytes("rowA");
479     byte [] famA = Bytes.toBytes("famA");
480     byte [] qfA = Bytes.toBytes("qfA");
481     byte [] valueA = Bytes.toBytes("valueA");
482 
483     byte [] rowB = Bytes.toBytes("rowB");
484     byte [] famB = Bytes.toBytes("famB");
485     byte [] qfB = Bytes.toBytes("qfB");
486     byte [] valueB = Bytes.toBytes("valueB");
487 
488     KeyValue kvA = new KeyValue(rowA, famA, qfA, valueA);
489     KeyValue kvB = new KeyValue(rowB, famB, qfB, valueB);
490 
491 
492     Result result1 = new Result(new KeyValue[]{kvA, kvB});
493     Result result2 = new Result(new KeyValue[]{kvB});
494     Result result3 = new Result(new KeyValue[]{kvB});
495 
496     Result [] results = new Result [] {result1, result2, result3};
497 
498     ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
499     DataOutputStream out = new DataOutputStream(byteStream);
500     Result.writeArray(out, results);
501 
502     byte [] rb = byteStream.toByteArray();
503 
504     DataInputBuffer in = new DataInputBuffer();
505     in.reset(rb, 0, rb.length);
506 
507     Result [] deResults = Result.readArray(in);
508 
509     assertTrue(results.length == deResults.length);
510 
511     for(int i=0;i<results.length;i++) {
512       KeyValue [] keysA = results[i].raw();
513       KeyValue [] keysB = deResults[i].raw();
514       assertTrue(keysA.length == keysB.length);
515       for(int j=0;j<keysA.length;j++) {
516         assertTrue("Expected equivalent keys but found:\n" +
517             "KeyA : " + keysA[j].toString() + "\n" +
518             "KeyB : " + keysB[j].toString() + "\n" +
519             keysA.length + " total keys, " + i + "th so far"
520             ,keysA[j].equals(keysB[j]));
521       }
522     }
523 
524   }
525 
526   @Test public void testResultArrayEmpty() throws Exception {
527     List<KeyValue> keys = new ArrayList<KeyValue>();
528     Result r = new Result(keys);
529     Result [] results = new Result [] {r};
530 
531     ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
532     DataOutputStream out = new DataOutputStream(byteStream);
533 
534     Result.writeArray(out, results);
535 
536     results = null;
537 
538     byteStream = new ByteArrayOutputStream();
539     out = new DataOutputStream(byteStream);
540     Result.writeArray(out, results);
541 
542     byte [] rb = byteStream.toByteArray();
543 
544     DataInputBuffer in = new DataInputBuffer();
545     in.reset(rb, 0, rb.length);
546 
547     Result [] deResults = Result.readArray(in);
548 
549     assertTrue(deResults.length == 0);
550 
551     results = new Result[0];
552 
553     byteStream = new ByteArrayOutputStream();
554     out = new DataOutputStream(byteStream);
555     Result.writeArray(out, results);
556 
557     rb = byteStream.toByteArray();
558 
559     in = new DataInputBuffer();
560     in.reset(rb, 0, rb.length);
561 
562     deResults = Result.readArray(in);
563 
564     assertTrue(deResults.length == 0);
565 
566   }
567 
568   @Test public void testTimeRange() throws Exception{
569     TimeRange tr = new TimeRange(0,5);
570     byte [] mb = Writables.getBytes(tr);
571     TimeRange deserializedTr =
572       (TimeRange)Writables.getWritable(mb, new TimeRange());
573 
574     assertEquals(tr.getMax(), deserializedTr.getMax());
575     assertEquals(tr.getMin(), deserializedTr.getMin());
576 
577   }
578 
579   @Test public void testKeyValue2() throws Exception {
580     final String name = "testKeyValue2";
581     byte[] row = name.getBytes();
582     byte[] fam = "fam".getBytes();
583     byte[] qf = "qf".getBytes();
584     long ts = System.currentTimeMillis();
585     byte[] val = "val".getBytes();
586 
587     KeyValue kv = new KeyValue(row, fam, qf, ts, val);
588 
589     byte [] mb = Writables.getBytes(kv);
590     KeyValue deserializedKv =
591       (KeyValue)Writables.getWritable(mb, new KeyValue());
592     assertTrue(Bytes.equals(kv.getBuffer(), deserializedKv.getBuffer()));
593     assertEquals(kv.getOffset(), deserializedKv.getOffset());
594     assertEquals(kv.getLength(), deserializedKv.getLength());
595   }
596 
597   protected static final int MAXVERSIONS = 3;
598   protected final static byte [] fam1 = Bytes.toBytes("colfamily1");
599   protected final static byte [] fam2 = Bytes.toBytes("colfamily2");
600   protected final static byte [] fam3 = Bytes.toBytes("colfamily3");
601   protected static final byte [][] COLUMNS = {fam1, fam2, fam3};
602 
603   /**
604    * Create a table of name <code>name</code> with {@link COLUMNS} for
605    * families.
606    * @param name Name to give table.
607    * @return Column descriptor.
608    */
609   protected HTableDescriptor createTableDescriptor(final String name) {
610     return createTableDescriptor(name, MAXVERSIONS);
611   }
612 
613   /**
614    * Create a table of name <code>name</code> with {@link COLUMNS} for
615    * families.
616    * @param name Name to give table.
617    * @param versions How many versions to allow per column.
618    * @return Column descriptor.
619    */
620   protected HTableDescriptor createTableDescriptor(final String name,
621       final int versions) {
622     HTableDescriptor htd = new HTableDescriptor(name);
623     htd.addFamily(new HColumnDescriptor(fam1)
624         .setMaxVersions(versions)
625         .setBlockCacheEnabled(false)
626     );
627     htd.addFamily(new HColumnDescriptor(fam2)
628         .setMaxVersions(versions)
629         .setBlockCacheEnabled(false)
630     );
631     htd.addFamily(new HColumnDescriptor(fam3)
632         .setMaxVersions(versions)
633         .setBlockCacheEnabled(false)
634     );
635     return htd;
636   }
637 
638   @org.junit.Rule
639   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
640     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
641 }
642