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;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertThrows;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import java.io.IOException;
025import java.util.Arrays;
026import java.util.ConcurrentModificationException;
027import org.apache.hadoop.hbase.Cell;
028import org.apache.hadoop.hbase.CellScanner;
029import org.apache.hadoop.hbase.CellUtil;
030import org.apache.hadoop.hbase.KeyValue;
031import org.apache.hadoop.hbase.testclassification.ClientTests;
032import org.apache.hadoop.hbase.testclassification.SmallTests;
033import org.apache.hadoop.hbase.util.Bytes;
034import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
035import org.junit.jupiter.api.Tag;
036import org.junit.jupiter.api.Test;
037
038/**
039 * Test that I can Iterate Client Actions that hold Cells (Get does not have Cells).
040 */
041@Tag(SmallTests.TAG)
042@Tag(ClientTests.TAG)
043public class TestPutDeleteEtcCellIteration {
044
045  private static final byte[] ROW = new byte[] { 'r' };
046  private static final long TIMESTAMP = EnvironmentEdgeManager.currentTime();
047  private static final int COUNT = 10;
048
049  @Test
050  public void testPutIteration() throws IOException {
051    Put p = new Put(ROW);
052    for (int i = 0; i < COUNT; i++) {
053      byte[] bytes = Bytes.toBytes(i);
054      p.addColumn(bytes, bytes, TIMESTAMP, bytes);
055    }
056    int index = 0;
057    for (CellScanner cellScanner = p.cellScanner(); cellScanner.advance();) {
058      Cell cell = cellScanner.current();
059      byte[] bytes = Bytes.toBytes(index++);
060      assertEquals(new KeyValue(ROW, bytes, bytes, TIMESTAMP, bytes), cell);
061    }
062    assertEquals(COUNT, index);
063  }
064
065  @Test
066  public void testPutConcurrentModificationOnIteration() throws IOException {
067    Put p = new Put(ROW);
068    for (int i = 0; i < COUNT; i++) {
069      byte[] bytes = Bytes.toBytes(i);
070      p.addColumn(bytes, bytes, TIMESTAMP, bytes);
071    }
072    assertThrows(ConcurrentModificationException.class, () -> {
073      int index = 0;
074      for (CellScanner cellScanner = p.cellScanner(); cellScanner.advance();) {
075        Cell cell = cellScanner.current();
076        byte[] bytes = Bytes.toBytes(index++);
077        // When we hit the trigger, try inserting a new KV; should trigger exception
078        p.addColumn(bytes, bytes, TIMESTAMP, bytes);
079        assertEquals(new KeyValue(ROW, bytes, bytes, TIMESTAMP, bytes), cell);
080      }
081    });
082  }
083
084  @Test
085  public void testDeleteIteration() throws IOException {
086    Delete d = new Delete(ROW);
087    for (int i = 0; i < COUNT; i++) {
088      byte[] bytes = Bytes.toBytes(i);
089      d.addColumn(bytes, bytes, TIMESTAMP);
090    }
091    int index = 0;
092    for (CellScanner cellScanner = d.cellScanner(); cellScanner.advance();) {
093      Cell cell = cellScanner.current();
094      byte[] bytes = Bytes.toBytes(index++);
095      assertEquals(new KeyValue(ROW, bytes, bytes, TIMESTAMP, KeyValue.Type.Delete), cell);
096    }
097    assertEquals(COUNT, index);
098  }
099
100  @Test
101  public void testAppendIteration() throws IOException {
102    Append a = new Append(ROW);
103    for (int i = 0; i < COUNT; i++) {
104      byte[] bytes = Bytes.toBytes(i);
105      a.addColumn(bytes, bytes, bytes);
106    }
107    int index = 0;
108    for (CellScanner cellScanner = a.cellScanner(); cellScanner.advance();) {
109      Cell cell = cellScanner.current();
110      byte[] bytes = Bytes.toBytes(index++);
111      KeyValue kv = (KeyValue) cell;
112      assertTrue(Bytes.equals(CellUtil.cloneFamily(kv), bytes));
113      assertTrue(Bytes.equals(CellUtil.cloneValue(kv), bytes));
114    }
115    assertEquals(COUNT, index);
116  }
117
118  @Test
119  public void testIncrementIteration() throws IOException {
120    Increment increment = new Increment(ROW);
121    for (int i = 0; i < COUNT; i++) {
122      byte[] bytes = Bytes.toBytes(i);
123      increment.addColumn(bytes, bytes, i);
124    }
125    int index = 0;
126    for (CellScanner cellScanner = increment.cellScanner(); cellScanner.advance();) {
127      Cell cell = cellScanner.current();
128      int value = index;
129      byte[] bytes = Bytes.toBytes(index++);
130      KeyValue kv = (KeyValue) cell;
131      assertTrue(Bytes.equals(CellUtil.cloneFamily(kv), bytes));
132      long a = Bytes.toLong(CellUtil.cloneValue(kv));
133      assertEquals(value, a);
134    }
135    assertEquals(COUNT, index);
136  }
137
138  @Test
139  public void testResultIteration() throws IOException {
140    Cell[] cells = new Cell[COUNT];
141    for (int i = 0; i < COUNT; i++) {
142      byte[] bytes = Bytes.toBytes(i);
143      cells[i] = new KeyValue(ROW, bytes, bytes, TIMESTAMP, bytes);
144    }
145    Result r = Result.create(Arrays.asList(cells));
146    int index = 0;
147    for (CellScanner cellScanner = r.cellScanner(); cellScanner.advance();) {
148      Cell cell = cellScanner.current();
149      byte[] bytes = Bytes.toBytes(index++);
150      assertEquals(new KeyValue(ROW, bytes, bytes, TIMESTAMP, bytes), cell);
151    }
152    assertEquals(COUNT, index);
153  }
154}