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.regionserver.compactions; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertThrows; 022 023import java.text.SimpleDateFormat; 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.hbase.ExtendedCell; 026import org.apache.hadoop.hbase.PrivateCellUtil; 027import org.apache.hadoop.hbase.testclassification.RegionServerTests; 028import org.apache.hadoop.hbase.testclassification.SmallTests; 029import org.apache.hadoop.hbase.util.Bytes; 030import org.junit.jupiter.api.AfterEach; 031import org.junit.jupiter.api.BeforeEach; 032import org.junit.jupiter.api.Tag; 033import org.junit.jupiter.api.Test; 034 035@Tag(RegionServerTests.TAG) 036@Tag(SmallTests.TAG) 037public class TestRowKeyDateTieringValueProvider { 038 039 private RowKeyDateTieringValueProvider provider; 040 private Configuration conf; 041 042 @BeforeEach 043 public void setUp() { 044 conf = new Configuration(); 045 provider = new RowKeyDateTieringValueProvider(); 046 } 047 048 @AfterEach 049 public void tearDown() { 050 provider = null; 051 conf = null; 052 } 053 054 @Test 055 public void testInitWithValidConfig() throws Exception { 056 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "(\\d{4}-\\d{2}-\\d{2})"); 057 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyy-MM-dd"); 058 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "1"); 059 provider.init(conf); 060 assertEquals(provider.getRowKeyPattern().pattern(), "(\\d{4}-\\d{2}-\\d{2})"); 061 assertEquals(provider.getDateFormat().toPattern(), "yyyy-MM-dd"); 062 assertEquals(Integer.valueOf(1), provider.getRowKeyRegexExtractGroup()); 063 } 064 065 @Test 066 public void testInitWithMissingRegexPattern() throws Exception { 067 assertThrows(IllegalArgumentException.class, () -> { 068 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyy-MM-dd"); 069 provider.init(conf); 070 }); 071 } 072 073 @Test 074 public void testInitWithMissingDateFormat() throws Exception { 075 assertThrows(IllegalArgumentException.class, () -> { 076 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "(\\d{4}-\\d{2}-\\d{2})"); 077 provider.init(conf); 078 }); 079 } 080 081 @Test 082 public void testInitWithInvalidDateFormat() throws Exception { 083 assertThrows(IllegalArgumentException.class, () -> { 084 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "(\\d{4}-\\d{2}-\\d{2})"); 085 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "invalid-format"); 086 provider.init(conf); 087 }); 088 } 089 090 @Test 091 public void testInitWithInvalidExtractGroup() throws Exception { 092 assertThrows(IllegalArgumentException.class, () -> { 093 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "(\\d{4}-\\d{2}-\\d{2})"); 094 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyy-MM-dd"); 095 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "-1"); 096 provider.init(conf); 097 }); 098 } 099 100 @Test 101 public void testInitWithExtractGroupExceedingPatternGroups() throws Exception { 102 assertThrows(IllegalArgumentException.class, () -> { 103 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "(\\d{4}-\\d{2}-\\d{2})"); 104 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyy-MM-dd"); 105 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "2"); // Only 1 group in 106 // pattern 107 provider.init(conf); 108 }); 109 } 110 111 @Test 112 public void testGetTieringValue() throws Exception { 113 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "_(\\d{4}-\\d{2}-\\d{2})_"); 114 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyy-MM-dd"); 115 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "1"); 116 provider.init(conf); 117 118 String dateStr = "2023-10-15"; 119 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 120 long expectedTimestamp = sdf.parse(dateStr).getTime(); 121 122 String rowKeyStr = "order_" + dateStr + "_details"; 123 byte[] rowKey = Bytes.toBytes(rowKeyStr); 124 ExtendedCell cell = PrivateCellUtil.createFirstOnRow(rowKey); 125 long actualTimestamp = provider.getTieringValue(cell); 126 127 assertEquals(expectedTimestamp, actualTimestamp); 128 } 129 130 @Test 131 public void testGetTieringValueWithNonMatchingRowKey() throws Exception { 132 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "_(\\d{4}-\\d{2}-\\d{2})_"); 133 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyy-MM-dd"); 134 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "1"); 135 provider.init(conf); 136 137 String rowKeyStr = "order_details_no_date"; 138 byte[] rowKey = Bytes.toBytes(rowKeyStr); 139 ExtendedCell cell = PrivateCellUtil.createFirstOnRow(rowKey); 140 long actualTimestamp = provider.getTieringValue(cell); 141 142 assertEquals(Long.MAX_VALUE, actualTimestamp); 143 } 144 145 @Test 146 public void testGetTieringValueWithInvalidDateInRowKey() throws Exception { 147 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "_(\\d{14})_"); 148 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyyMMddHHmmss"); 149 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "1"); 150 provider.init(conf); 151 152 // Invalid Month (14) 153 String rowKeyStr = "order_20151412124556_date"; 154 byte[] rowKey = Bytes.toBytes(rowKeyStr); 155 ExtendedCell cell = PrivateCellUtil.createFirstOnRow(rowKey); 156 long actualTimestamp = provider.getTieringValue(cell); 157 158 assertEquals(Long.MAX_VALUE, actualTimestamp); 159 } 160 161 @Test 162 public void testGetTieringValueWithNonUTF8RowKey() throws Exception { 163 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "_(\\d{8})_"); 164 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyyMMdd"); 165 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "1"); 166 provider.init(conf); 167 168 // Row key with non-UTF-8 bytes (invalid UTF-8 sequence) 169 byte[] rowKey = 170 new byte[] { 0x6F, 0x72, 0x64, 0x65, 0x72, 0x5F, (byte) 0xFF, (byte) 0xFE, 0x5F }; 171 ExtendedCell cell = PrivateCellUtil.createFirstOnRow(rowKey); 172 long timestamp = provider.getTieringValue(cell); 173 174 assertEquals(Long.MAX_VALUE, timestamp); 175 } 176 177 @Test 178 public void testGetTieringValueWithoutInitialization() { 179 assertThrows(IllegalStateException.class, () -> { 180 String rowKeyStr = "order_9999999999999999_date"; 181 byte[] rowKey = Bytes.toBytes(rowKeyStr); 182 ExtendedCell cell = PrivateCellUtil.createFirstOnRow(rowKey); 183 provider.getTieringValue(cell); 184 }); 185 } 186}