/*
* 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.ranger.authorization.hbase;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.hadoop.hbase.Cell;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class ColumnIteratorTest {
@Test
public void test_firewalling() {
// passing null collection
ColumnIterator iterator = new ColumnIterator(null);
Assert.assertFalse(iterator.hasNext());
}
@SuppressWarnings("unchecked")
@Test
public void test_setOfBytes() {
/*
* It is pointless to test the functionality of base iterator! What we want to Assert.assert is that ColumnIterator delegates to the real iterators appropriately.
*/
Iterator<byte[]> iterator = mock(Iterator.class);
// We want to make sure ColumnIterator will return exactly what the real iterator gives it. Let's us doctor mock iteracor to return items in a particular order.
final String[] values = new String[] {"a", "b", "c"};
when(iterator.next()).thenAnswer(new Answer<byte[]>() {
// return all the items of the values array in order as byte[]. After which return null.
int index = 0;
@Override
public byte[] answer(InvocationOnMock invocation) throws Throwable {
if (index < values.length) {
return values[index++].getBytes(); // we need post increment
} else {
return null;
}
}
});
// We want hasNext() to return false after as many times as values were stuffed into it.
when(iterator.hasNext()).thenAnswer(new Answer<Boolean>() {
int i = 0;
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
return i++ < values.length; // we want post increment
}
});
// let's stuff this iterator into the collection that we would pass to the ColumnIterator
Set<byte[]> collection = mock(Set.class);
when(collection.iterator()).thenReturn(iterator);
ColumnIterator columnIterator = new ColumnIterator(collection);
int i = 0;
while (columnIterator.hasNext()) {
String value = columnIterator.next();
Assert.assertEquals(values[i++], value);
}
// We should get back exactly as many items as were in the real iterator, no more no less
Assert.assertEquals(3, i);
// this should be called only once!
verify(collection, times(1)).iterator();
// verify next() was called on the iterator exactly 3 times
verify(iterator, times(3)).next();
}
@SuppressWarnings("unchecked")
@Test
public void test_ListOfCell() {
/*
* We are not interested in validating the behavior of the real iterator. Instead just the behavior specific to the column iterator.
*/
final String[] qualifiers = new String[] {"a", "b", "c"};
Iterator<Cell> iterator = mock(Iterator.class);
// Have the iterator return true as many times as the size of keys array
when(iterator.hasNext()).thenAnswer(new Answer<Boolean>() {
int i = 0;
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
return i++ < qualifiers.length;
}
});
// have the iterator return a Cell composed of the key and value arrays
when(iterator.next()).thenAnswer(new Answer<Cell>() {
int i = 0;
@Override
public Cell answer(InvocationOnMock invocation)
throws Throwable {
Cell cell = mock(Cell.class);
when(cell.getQualifierOffset()).thenReturn(0);
when(cell.getQualifierLength()).thenReturn(1);
when(cell.getQualifierArray()).thenReturn(qualifiers[i++].getBytes());
return cell;
}
});
// stuff it into the collection
List<Cell> list = mock(List.class);
when(list.iterator()).thenReturn(iterator);
// now let's check the behavior
ColumnIterator columnIterator = new ColumnIterator(list);
int i = 0;
while (columnIterator.hasNext()) {
String value = columnIterator.next();
Assert.assertEquals(qualifiers[i++], value);
}
// We should get back exactly as many items as were in the real iterator, no more no less
Assert.assertEquals(3, i);
// this should be called only once!
verify(list, times(1)).iterator();
// verify next() was called on the iterator exactly 3 times
verify(iterator, times(3)).next();
}
}