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