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;
019
020import static org.junit.jupiter.api.Assertions.assertArrayEquals;
021import static org.junit.jupiter.api.Assertions.assertEquals;
022import static org.junit.jupiter.api.Assertions.assertSame;
023import static org.junit.jupiter.api.Assertions.assertThrows;
024
025import java.nio.ByteBuffer;
026import java.util.HashMap;
027import java.util.Map;
028import org.apache.hadoop.conf.Configuration;
029import org.apache.hadoop.hbase.testclassification.MiscTests;
030import org.apache.hadoop.hbase.testclassification.SmallTests;
031import org.apache.hadoop.hbase.util.Bytes;
032import org.junit.jupiter.api.Tag;
033import org.junit.jupiter.api.Test;
034
035/**
036 * Tests for various kinds of TableNames.
037 */
038@Tag(MiscTests.TAG)
039@Tag(SmallTests.TAG)
040public class TestTableName {
041
042  private static String[] emptyNames = { "", " " };
043  private static String[] invalidNamespace = { ":a", "%:a" };
044  private static String[] legalTableNames = { "foo", "with-dash_under.dot", "_under_start_ok",
045    "with-dash.with_underscore", "02-01-2012.my_table_01-02", "xyz._mytable_", "9_9_0.table_02",
046    "dot1.dot2.table", "new.-mytable", "with-dash.with.dot", "legal..t2", "legal..legal.t2",
047    "trailingdots..", "trailing.dots...", "ns:mytable", "ns:_mytable_", "ns:my_table_01-02" };
048  private static String[] illegalTableNames = { ".dot_start_illegal", "-dash_start_illegal",
049    "spaces not ok", "-dash-.start_illegal", "new.table with space", "01 .table", "ns:-illegaldash",
050    "new:.illegaldot", "new:illegalcolon1:", "new:illegalcolon1:2" };
051
052  static class Names {
053    String ns;
054    byte[] nsb;
055    String tn;
056    byte[] tnb;
057    String nn;
058    byte[] nnb;
059
060    Names(String ns, String tn) {
061      this.ns = ns;
062      nsb = Bytes.toBytes(ns);
063      this.tn = tn;
064      tnb = Bytes.toBytes(tn);
065      nn = this.ns + ":" + this.tn;
066      nnb = Bytes.toBytes(nn);
067    }
068
069    @Override
070    public boolean equals(Object o) {
071      if (this == o) {
072        return true;
073      }
074      if (!(o instanceof Names)) {
075        return false;
076      }
077      Names names = (Names) o;
078      if (!ns.equals(names.ns)) {
079        return false;
080      }
081      if (!tn.equals(names.tn)) {
082        return false;
083      }
084      return true;
085    }
086
087    @Override
088    public int hashCode() {
089      int result = ns.hashCode();
090      result = 31 * result + tn.hashCode();
091      return result;
092    }
093  }
094
095  private static Names[] names = new Names[] { new Names("n1", "n1"), new Names("n2", "n2"),
096    new Names("table1", "table1"), new Names("table2", "table2"), new Names("table2", "table1"),
097    new Names("table1", "table2"), new Names("n1", "table1"), new Names("n1", "table1"),
098    new Names("n2", "table2"), new Names("n2", "table2") };
099
100  @Test
101  public void testInvalidNamespace() {
102    for (String tn : invalidNamespace) {
103      assertThrows(IllegalArgumentException.class,
104        () -> TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn)));
105    }
106  }
107
108  @Test
109  public void testEmptyNamespaceName() {
110    for (String nn : emptyNames) {
111      assertThrows(IllegalArgumentException.class,
112        () -> TableName.isLegalNamespaceName(Bytes.toBytes(nn)));
113    }
114  }
115
116  @Test
117  public void testEmptyTableName() {
118    for (String tn : emptyNames) {
119      assertThrows(IllegalArgumentException.class,
120        () -> TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn)));
121    }
122  }
123
124  @Test
125  public void testLegalHTableNames() {
126    for (String tn : legalTableNames) {
127      TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn));
128    }
129  }
130
131  @Test
132  public void testIllegalHTableNames() {
133    for (String tn : illegalTableNames) {
134      assertThrows(IllegalArgumentException.class,
135        () -> TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn)));
136    }
137  }
138
139  @Test
140  public void testValueOf() {
141    Map<String, TableName> inCache = new HashMap<>();
142    // fill cache
143    for (Names name : names) {
144      inCache.put(name.nn, TableName.valueOf(name.ns, name.tn));
145    }
146    for (Names name : names) {
147      assertSame(inCache.get(name.nn), validateNames(TableName.valueOf(name.ns, name.tn), name));
148      assertSame(inCache.get(name.nn), validateNames(TableName.valueOf(name.nsb, name.tnb), name));
149      assertSame(inCache.get(name.nn), validateNames(TableName.valueOf(name.nn), name));
150      assertSame(inCache.get(name.nn), validateNames(TableName.valueOf(name.nnb), name));
151      assertSame(inCache.get(name.nn), validateNames(
152        TableName.valueOf(ByteBuffer.wrap(name.nsb), ByteBuffer.wrap(name.tnb)), name));
153    }
154  }
155
156  private TableName validateNames(TableName expected, Names names) {
157    assertEquals(expected.getNameAsString(), names.nn);
158    assertArrayEquals(expected.getName(), names.nnb);
159    assertEquals(expected.getQualifierAsString(), names.tn);
160    assertArrayEquals(expected.getQualifier(), names.tnb);
161    assertEquals(expected.getNamespaceAsString(), names.ns);
162    assertArrayEquals(expected.getNamespace(), names.nsb);
163    return expected;
164  }
165
166  @Test
167  public void testValidMetaTableSuffix() {
168    String[] validSuffixes = { "REPL1", "123", "123abc" };
169    for (String suffix : validSuffixes) {
170      Configuration conf = HBaseConfiguration.create();
171      conf.set(HConstants.HBASE_META_TABLE_SUFFIX, suffix);
172      TableName metaTableName = TableName.initializeHbaseMetaTableName(conf);
173      assertEquals("hbase:meta_" + suffix, metaTableName.getNameAsString());
174    }
175  }
176
177  @Test
178  public void testInvalidMetaTableSuffix() {
179    String[] invalidSuffixes = { "test_1", "test-1", "test.1", "test 1", "_test", "-test", ".test",
180      "has!special", "has:colon", " " };
181    for (String suffix : invalidSuffixes) {
182      Configuration conf = HBaseConfiguration.create();
183      conf.set(HConstants.HBASE_META_TABLE_SUFFIX, suffix);
184      assertThrows(IllegalArgumentException.class,
185        () -> TableName.initializeHbaseMetaTableName(conf),
186        "Expected IllegalArgumentException for suffix: " + suffix);
187    }
188  }
189}