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.util; 019 020import static org.hamcrest.MatcherAssert.assertThat; 021import static org.hamcrest.Matchers.startsWith; 022import static org.junit.jupiter.api.Assertions.assertEquals; 023import static org.junit.jupiter.api.Assertions.assertNull; 024import static org.junit.jupiter.api.Assertions.assertThrows; 025 026import java.io.IOException; 027import org.apache.hadoop.fs.FSDataInputStream; 028import org.apache.hadoop.fs.FSDataOutputStream; 029import org.apache.hadoop.fs.FileSystem; 030import org.apache.hadoop.fs.Path; 031import org.apache.hadoop.hbase.HBaseCommonTestingUtil; 032import org.apache.hadoop.hbase.testclassification.MiscTests; 033import org.apache.hadoop.hbase.testclassification.SmallTests; 034import org.junit.jupiter.api.AfterAll; 035import org.junit.jupiter.api.BeforeAll; 036import org.junit.jupiter.api.BeforeEach; 037import org.junit.jupiter.api.Tag; 038import org.junit.jupiter.api.Test; 039import org.junit.jupiter.api.TestInfo; 040 041import org.apache.hbase.thirdparty.com.google.common.io.ByteStreams; 042 043@Tag(MiscTests.TAG) 044@Tag(SmallTests.TAG) 045public class TestRotateFile { 046 047 private static HBaseCommonTestingUtil UTIL = new HBaseCommonTestingUtil(); 048 049 private static FileSystem FS; 050 051 private Path dir; 052 053 private RotateFile rotateFile; 054 055 @BeforeAll 056 public static void setUpBeforeClass() throws IOException { 057 FS = FileSystem.get(UTIL.getConfiguration()); 058 } 059 060 @AfterAll 061 public static void tearDownAfterClass() { 062 UTIL.cleanupTestDir(); 063 } 064 065 @BeforeEach 066 public void setUp(TestInfo testInfo) throws IOException { 067 String methodName = testInfo.getTestMethod().get().getName(); 068 dir = UTIL.getDataTestDir(methodName); 069 if (!FS.mkdirs(dir)) { 070 throw new IOException("Can not create dir " + dir); 071 } 072 rotateFile = new RotateFile(FS, dir, methodName, 1024); 073 assertNull(rotateFile.read()); 074 } 075 076 @Test 077 public void testSimpleReadWrite() throws IOException { 078 for (int i = 0; i < 10; i++) { 079 rotateFile.write(Bytes.toBytes(i)); 080 assertEquals(i, Bytes.toInt(rotateFile.read())); 081 } 082 rotateFile.delete(); 083 assertNull(rotateFile.read()); 084 } 085 086 @Test 087 public void testCompareTimestamp() throws IOException { 088 long now = EnvironmentEdgeManager.currentTime(); 089 rotateFile.write(Bytes.toBytes(10)); 090 Path file = FS.listStatus(dir)[0].getPath(); 091 rotateFile.write(Bytes.toBytes(100)); 092 093 // put a fake file with a less timestamp there 094 RotateFile.write(FS, file, now - 1, Bytes.toBytes(10)); 095 assertEquals(100, Bytes.toInt(rotateFile.read())); 096 097 // put a fake file with a greater timestamp there 098 RotateFile.write(FS, file, EnvironmentEdgeManager.currentTime() + 100, Bytes.toBytes(10)); 099 assertEquals(10, Bytes.toInt(rotateFile.read())); 100 } 101 102 @Test 103 public void testMaxFileSize() throws IOException { 104 assertThrows(IOException.class, () -> rotateFile.write(new byte[1025])); 105 // put a file greater than max file size 106 rotateFile.write(Bytes.toBytes(10)); 107 Path file = FS.listStatus(dir)[0].getPath(); 108 RotateFile.write(FS, file, EnvironmentEdgeManager.currentTime(), new byte[1025]); 109 assertThrows(IOException.class, () -> rotateFile.read()); 110 } 111 112 @Test 113 public void testNotEnoughData() throws IOException { 114 rotateFile.write(Bytes.toBytes(10)); 115 assertEquals(10, Bytes.toInt(rotateFile.read())); 116 // remove the last byte 117 Path file = FS.listStatus(dir)[0].getPath(); 118 byte[] data; 119 try (FSDataInputStream in = FS.open(file)) { 120 data = ByteStreams.toByteArray(in); 121 } 122 try (FSDataOutputStream out = FS.create(file, true)) { 123 out.write(data, 0, data.length - 1); 124 } 125 // should hit EOF so read nothing 126 assertNull(rotateFile.read()); 127 } 128 129 @Test 130 public void testChecksumMismatch() throws IOException { 131 rotateFile.write(Bytes.toBytes(10)); 132 assertEquals(10, Bytes.toInt(rotateFile.read())); 133 // mess up one byte 134 Path file = FS.listStatus(dir)[0].getPath(); 135 byte[] data; 136 try (FSDataInputStream in = FS.open(file)) { 137 data = ByteStreams.toByteArray(in); 138 } 139 data[4]++; 140 try (FSDataOutputStream out = FS.create(file, true)) { 141 out.write(data, 0, data.length); 142 } 143 // should get checksum mismatch 144 IOException error = assertThrows(IOException.class, () -> rotateFile.read()); 145 assertThat(error.getMessage(), startsWith("Checksum mismatch")); 146 } 147}