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("(\\d{4}-\\d{2}-\\d{2})", provider.getRowKeyPattern().pattern()); 061 assertEquals("yyyy-MM-dd", provider.getDateFormat().toPattern()); 062 assertEquals(Integer.valueOf(1), provider.getRowKeyRegexExtractGroup()); 063 } 064 065 @Test 066 public void testInitWithMissingRegexPattern() { 067 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyy-MM-dd"); 068 assertThrows(IllegalArgumentException.class, () -> provider.init(conf)); 069 } 070 071 @Test 072 public void testInitWithMissingDateFormat() { 073 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "(\\d{4}-\\d{2}-\\d{2})"); 074 assertThrows(IllegalArgumentException.class, () -> provider.init(conf)); 075 } 076 077 @Test 078 public void testInitWithInvalidDateFormat() { 079 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "(\\d{4}-\\d{2}-\\d{2})"); 080 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "invalid-format"); 081 assertThrows(IllegalArgumentException.class, () -> provider.init(conf)); 082 } 083 084 @Test 085 public void testInitWithInvalidExtractGroup() { 086 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "(\\d{4}-\\d{2}-\\d{2})"); 087 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyy-MM-dd"); 088 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "-1"); 089 assertThrows(IllegalArgumentException.class, () -> provider.init(conf)); 090 } 091 092 @Test 093 public void testInitWithExtractGroupExceedingPatternGroups() { 094 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "(\\d{4}-\\d{2}-\\d{2})"); 095 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyy-MM-dd"); 096 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "2"); // Only 1 group in 097 // pattern 098 assertThrows(IllegalArgumentException.class, () -> provider.init(conf)); 099 } 100 101 @Test 102 public void testGetTieringValue() throws Exception { 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, "1"); 106 provider.init(conf); 107 108 String dateStr = "2023-10-15"; 109 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 110 long expectedTimestamp = sdf.parse(dateStr).getTime(); 111 112 String rowKeyStr = "order_" + dateStr + "_details"; 113 byte[] rowKey = Bytes.toBytes(rowKeyStr); 114 ExtendedCell cell = PrivateCellUtil.createFirstOnRow(rowKey); 115 long actualTimestamp = provider.getTieringValue(cell); 116 117 assertEquals(expectedTimestamp, actualTimestamp); 118 } 119 120 @Test 121 public void testGetTieringValueWithNonMatchingRowKey() throws Exception { 122 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "_(\\d{4}-\\d{2}-\\d{2})_"); 123 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyy-MM-dd"); 124 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "1"); 125 provider.init(conf); 126 127 String rowKeyStr = "order_details_no_date"; 128 byte[] rowKey = Bytes.toBytes(rowKeyStr); 129 ExtendedCell cell = PrivateCellUtil.createFirstOnRow(rowKey); 130 long actualTimestamp = provider.getTieringValue(cell); 131 132 assertEquals(Long.MAX_VALUE, actualTimestamp); 133 } 134 135 @Test 136 public void testGetTieringValueWithInvalidDateInRowKey() throws Exception { 137 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "_(\\d{14})_"); 138 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyyMMddHHmmss"); 139 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "1"); 140 provider.init(conf); 141 142 // Invalid Month (14) 143 String rowKeyStr = "order_20151412124556_date"; 144 byte[] rowKey = Bytes.toBytes(rowKeyStr); 145 ExtendedCell cell = PrivateCellUtil.createFirstOnRow(rowKey); 146 long actualTimestamp = provider.getTieringValue(cell); 147 148 assertEquals(Long.MAX_VALUE, actualTimestamp); 149 } 150 151 @Test 152 public void testGetTieringValueWithNonUTF8RowKey() throws Exception { 153 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_PATTERN, "_(\\d{8})_"); 154 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_FORMAT, "yyyyMMdd"); 155 conf.set(RowKeyDateTieringValueProvider.TIERING_KEY_DATE_GROUP, "1"); 156 provider.init(conf); 157 158 // Row key with non-UTF-8 bytes (invalid UTF-8 sequence) 159 byte[] rowKey = 160 new byte[] { 0x6F, 0x72, 0x64, 0x65, 0x72, 0x5F, (byte) 0xFF, (byte) 0xFE, 0x5F }; 161 ExtendedCell cell = PrivateCellUtil.createFirstOnRow(rowKey); 162 long timestamp = provider.getTieringValue(cell); 163 164 assertEquals(Long.MAX_VALUE, timestamp); 165 } 166 167 @Test 168 public void testGetTieringValueWithoutInitialization() { 169 String rowKeyStr = "order_9999999999999999_date"; 170 byte[] rowKey = Bytes.toBytes(rowKeyStr); 171 ExtendedCell cell = PrivateCellUtil.createFirstOnRow(rowKey); 172 assertThrows(IllegalStateException.class, () -> provider.getTieringValue(cell)); 173 } 174}