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.ipc; 019 020import static org.junit.Assert.*; 021 022import java.io.File; 023import java.io.FileOutputStream; 024import java.io.IOException; 025import java.nio.ByteBuffer; 026import java.nio.channels.FileChannel; 027import org.apache.hadoop.hbase.HBaseClassTestRule; 028import org.apache.hadoop.hbase.testclassification.RPCTests; 029import org.apache.hadoop.hbase.testclassification.SmallTests; 030import org.apache.hadoop.hbase.util.Bytes; 031import org.junit.After; 032import org.junit.Before; 033import org.junit.ClassRule; 034import org.junit.Test; 035import org.junit.experimental.categories.Category; 036import org.mockito.Mockito; 037 038import org.apache.hbase.thirdparty.com.google.common.base.Charsets; 039import org.apache.hbase.thirdparty.com.google.common.io.Files; 040 041@Category({RPCTests.class, SmallTests.class}) 042public class TestBufferChain { 043 044 @ClassRule 045 public static final HBaseClassTestRule CLASS_RULE = 046 HBaseClassTestRule.forClass(TestBufferChain.class); 047 048 private File tmpFile; 049 050 private static final byte[][] HELLO_WORLD_CHUNKS = new byte[][] { 051 "hello".getBytes(Charsets.UTF_8), 052 " ".getBytes(Charsets.UTF_8), 053 "world".getBytes(Charsets.UTF_8) 054 }; 055 056 @Before 057 public void setup() throws IOException { 058 tmpFile = File.createTempFile("TestBufferChain", "txt"); 059 } 060 061 @After 062 public void teardown() { 063 tmpFile.delete(); 064 } 065 066 @Test 067 public void testGetBackBytesWePutIn() { 068 ByteBuffer[] bufs = wrapArrays(HELLO_WORLD_CHUNKS); 069 BufferChain chain = new BufferChain(bufs); 070 assertTrue(Bytes.equals(Bytes.toBytes("hello world"), chain.getBytes())); 071 } 072 073 @Test 074 public void testChainChunkBiggerThanWholeArray() throws IOException { 075 ByteBuffer[] bufs = wrapArrays(HELLO_WORLD_CHUNKS); 076 BufferChain chain = new BufferChain(bufs); 077 writeAndVerify(chain, "hello world", 8192); 078 assertNoRemaining(bufs); 079 } 080 081 @Test 082 public void testChainChunkBiggerThanSomeArrays() throws IOException { 083 ByteBuffer[] bufs = wrapArrays(HELLO_WORLD_CHUNKS); 084 BufferChain chain = new BufferChain(bufs); 085 writeAndVerify(chain, "hello world", 3); 086 assertNoRemaining(bufs); 087 } 088 089 @Test 090 public void testLimitOffset() throws IOException { 091 ByteBuffer[] bufs = new ByteBuffer[] { 092 stringBuf("XXXhelloYYY", 3, 5), 093 stringBuf(" ", 0, 1), 094 stringBuf("XXXXworldY", 4, 5) }; 095 BufferChain chain = new BufferChain(bufs); 096 writeAndVerify(chain , "hello world", 3); 097 assertNoRemaining(bufs); 098 } 099 100 @Test 101 public void testWithSpy() throws IOException { 102 ByteBuffer[] bufs = new ByteBuffer[] { 103 stringBuf("XXXhelloYYY", 3, 5), 104 stringBuf(" ", 0, 1), 105 stringBuf("XXXXworldY", 4, 5) }; 106 BufferChain chain = new BufferChain(bufs); 107 FileOutputStream fos = new FileOutputStream(tmpFile); 108 FileChannel ch = Mockito.spy(fos.getChannel()); 109 try { 110 chain.write(ch, 2); 111 assertEquals("he", Files.toString(tmpFile, Charsets.UTF_8)); 112 chain.write(ch, 2); 113 assertEquals("hell", Files.toString(tmpFile, Charsets.UTF_8)); 114 chain.write(ch, 3); 115 assertEquals("hello w", Files.toString(tmpFile, Charsets.UTF_8)); 116 chain.write(ch, 8); 117 assertEquals("hello world", Files.toString(tmpFile, Charsets.UTF_8)); 118 } finally { 119 ch.close(); 120 fos.close(); 121 } 122 } 123 124 private ByteBuffer stringBuf(String string, int position, int length) { 125 ByteBuffer buf = ByteBuffer.wrap(string.getBytes(Charsets.UTF_8)); 126 buf.position(position); 127 buf.limit(position + length); 128 assertTrue(buf.hasRemaining()); 129 return buf; 130 } 131 132 private void assertNoRemaining(ByteBuffer[] bufs) { 133 for (ByteBuffer buf : bufs) { 134 assertFalse(buf.hasRemaining()); 135 } 136 } 137 138 private ByteBuffer[] wrapArrays(byte[][] arrays) { 139 ByteBuffer[] ret = new ByteBuffer[arrays.length]; 140 for (int i = 0; i < arrays.length; i++) { 141 ret[i] = ByteBuffer.wrap(arrays[i]); 142 } 143 return ret; 144 } 145 146 private void writeAndVerify(BufferChain chain, String string, int chunkSize) 147 throws IOException { 148 FileOutputStream fos = new FileOutputStream(tmpFile); 149 FileChannel ch = fos.getChannel(); 150 try { 151 long remaining = string.length(); 152 while (chain.hasRemaining()) { 153 long n = chain.write(ch, chunkSize); 154 assertTrue(n == chunkSize || n == remaining); 155 remaining -= n; 156 } 157 assertEquals(0, remaining); 158 } finally { 159 fos.close(); 160 } 161 assertFalse(chain.hasRemaining()); 162 assertEquals(string, Files.toString(tmpFile, Charsets.UTF_8)); 163 } 164}