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.io.hfile;
019
020import static org.junit.Assert.*;
021import static org.mockito.Mockito.*;
022
023import java.io.IOException;
024import org.apache.hadoop.fs.FSDataInputStream;
025import org.apache.hadoop.hbase.HBaseClassTestRule;
026import org.apache.hadoop.hbase.testclassification.IOTests;
027import org.apache.hadoop.hbase.testclassification.SmallTests;
028import org.junit.ClassRule;
029import org.junit.Rule;
030import org.junit.Test;
031import org.junit.experimental.categories.Category;
032import org.junit.rules.ExpectedException;
033
034/**
035 * Unit test suite covering HFileBlock positional read logic.
036 */
037@Category({IOTests.class, SmallTests.class})
038public class TestHFileBlockPositionalRead {
039
040  @ClassRule
041  public static final HBaseClassTestRule CLASS_RULE =
042      HBaseClassTestRule.forClass(TestHFileBlockPositionalRead.class);
043
044  @Rule
045  public ExpectedException exception = ExpectedException.none();
046
047  @Test
048  public void testPositionalReadNoExtra() throws IOException {
049    long position = 0;
050    int bufOffset = 0;
051    int necessaryLen = 10;
052    int extraLen = 0;
053    int totalLen = necessaryLen + extraLen;
054    byte[] buf = new byte[totalLen];
055    FSDataInputStream in = mock(FSDataInputStream.class);
056    when(in.read(position, buf, bufOffset, totalLen)).thenReturn(totalLen);
057    boolean ret = HFileBlock.positionalReadWithExtra(in, position, buf,
058        bufOffset, necessaryLen, extraLen);
059    assertFalse("Expect false return when no extra bytes requested", ret);
060    verify(in).read(position, buf, bufOffset, totalLen);
061    verifyNoMoreInteractions(in);
062  }
063
064  @Test
065  public void testPositionalReadShortReadOfNecessaryBytes() throws IOException {
066    long position = 0;
067    int bufOffset = 0;
068    int necessaryLen = 10;
069    int extraLen = 0;
070    int totalLen = necessaryLen + extraLen;
071    byte[] buf = new byte[totalLen];
072    FSDataInputStream in = mock(FSDataInputStream.class);
073    when(in.read(position, buf, bufOffset, totalLen)).thenReturn(5);
074    when(in.read(5, buf, 5, 5)).thenReturn(5);
075    boolean ret = HFileBlock.positionalReadWithExtra(in, position, buf,
076        bufOffset, necessaryLen, extraLen);
077    assertFalse("Expect false return when no extra bytes requested", ret);
078    verify(in).read(position, buf, bufOffset, totalLen);
079    verify(in).read(5, buf, 5, 5);
080    verifyNoMoreInteractions(in);
081  }
082
083  @Test
084  public void testPositionalReadExtraSucceeded() throws IOException {
085    long position = 0;
086    int bufOffset = 0;
087    int necessaryLen = 10;
088    int extraLen = 5;
089    int totalLen = necessaryLen + extraLen;
090    byte[] buf = new byte[totalLen];
091    FSDataInputStream in = mock(FSDataInputStream.class);
092    when(in.read(position, buf, bufOffset, totalLen)).thenReturn(totalLen);
093    boolean ret = HFileBlock.positionalReadWithExtra(in, position, buf,
094        bufOffset, necessaryLen, extraLen);
095    assertTrue("Expect true return when reading extra bytes succeeds", ret);
096    verify(in).read(position, buf, bufOffset, totalLen);
097    verifyNoMoreInteractions(in);
098  }
099
100  @Test
101  public void testPositionalReadExtraFailed() throws IOException {
102    long position = 0;
103    int bufOffset = 0;
104    int necessaryLen = 10;
105    int extraLen = 5;
106    int totalLen = necessaryLen + extraLen;
107    byte[] buf = new byte[totalLen];
108    FSDataInputStream in = mock(FSDataInputStream.class);
109    when(in.read(position, buf, bufOffset, totalLen)).thenReturn(necessaryLen);
110    boolean ret = HFileBlock.positionalReadWithExtra(in, position, buf,
111        bufOffset, necessaryLen, extraLen);
112    assertFalse("Expect false return when reading extra bytes fails", ret);
113    verify(in).read(position, buf, bufOffset, totalLen);
114    verifyNoMoreInteractions(in);
115  }
116
117  @Test
118  public void testPositionalReadShortReadCompletesNecessaryAndExtraBytes()
119      throws IOException {
120    long position = 0;
121    int bufOffset = 0;
122    int necessaryLen = 10;
123    int extraLen = 5;
124    int totalLen = necessaryLen + extraLen;
125    byte[] buf = new byte[totalLen];
126    FSDataInputStream in = mock(FSDataInputStream.class);
127    when(in.read(position, buf, bufOffset, totalLen)).thenReturn(5);
128    when(in.read(5, buf, 5, 10)).thenReturn(10);
129    boolean ret = HFileBlock.positionalReadWithExtra(in, position, buf,
130        bufOffset, necessaryLen, extraLen);
131    assertTrue("Expect true return when reading extra bytes succeeds", ret);
132    verify(in).read(position, buf, bufOffset, totalLen);
133    verify(in).read(5, buf, 5, 10);
134    verifyNoMoreInteractions(in);
135  }
136
137  @Test
138  public void testPositionalReadPrematureEOF() throws IOException {
139    long position = 0;
140    int bufOffset = 0;
141    int necessaryLen = 10;
142    int extraLen = 0;
143    int totalLen = necessaryLen + extraLen;
144    byte[] buf = new byte[totalLen];
145    FSDataInputStream in = mock(FSDataInputStream.class);
146    when(in.read(position, buf, bufOffset, totalLen)).thenReturn(9);
147    when(in.read(position, buf, bufOffset, totalLen)).thenReturn(-1);
148    exception.expect(IOException.class);
149    exception.expectMessage("EOF");
150    HFileBlock.positionalReadWithExtra(in, position, buf, bufOffset,
151        necessaryLen, extraLen);
152  }
153}