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.client; 019 020import static org.apache.hadoop.hbase.client.trace.hamcrest.AttributesMatchers.containsEntry; 021import static org.apache.hadoop.hbase.client.trace.hamcrest.AttributesMatchers.containsEntryWithStringValuesOf; 022import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasAttributes; 023import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasEnded; 024import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasKind; 025import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasName; 026import static org.apache.hadoop.hbase.client.trace.hamcrest.SpanDataMatchers.hasStatusWithCode; 027import static org.apache.hadoop.hbase.client.trace.hamcrest.TraceTestUtil.buildConnectionAttributesMatcher; 028import static org.apache.hadoop.hbase.client.trace.hamcrest.TraceTestUtil.buildTableAttributesMatcher; 029import static org.hamcrest.MatcherAssert.assertThat; 030import static org.hamcrest.Matchers.allOf; 031import static org.hamcrest.Matchers.containsInAnyOrder; 032import static org.hamcrest.Matchers.hasItem; 033 034import io.opentelemetry.api.trace.SpanKind; 035import io.opentelemetry.api.trace.StatusCode; 036import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule; 037import io.opentelemetry.sdk.trace.data.SpanData; 038import java.io.IOException; 039import java.util.Arrays; 040import java.util.concurrent.CompletableFuture; 041import java.util.concurrent.TimeUnit; 042import org.apache.hadoop.conf.Configuration; 043import org.apache.hadoop.hbase.HBaseClassTestRule; 044import org.apache.hadoop.hbase.HBaseConfiguration; 045import org.apache.hadoop.hbase.HConstants; 046import org.apache.hadoop.hbase.HRegionLocation; 047import org.apache.hadoop.hbase.MatcherPredicate; 048import org.apache.hadoop.hbase.RegionLocations; 049import org.apache.hadoop.hbase.ServerName; 050import org.apache.hadoop.hbase.TableName; 051import org.apache.hadoop.hbase.Waiter; 052import org.apache.hadoop.hbase.security.UserProvider; 053import org.apache.hadoop.hbase.testclassification.ClientTests; 054import org.apache.hadoop.hbase.testclassification.MediumTests; 055import org.hamcrest.Matcher; 056import org.junit.After; 057import org.junit.Before; 058import org.junit.ClassRule; 059import org.junit.Rule; 060import org.junit.Test; 061import org.junit.experimental.categories.Category; 062import org.slf4j.Logger; 063import org.slf4j.LoggerFactory; 064 065import org.apache.hbase.thirdparty.com.google.common.io.Closeables; 066 067@Category({ ClientTests.class, MediumTests.class }) 068public class TestAsyncRegionLocatorTracing { 069 private static final Logger LOG = LoggerFactory.getLogger(TestAsyncRegionLocatorTracing.class); 070 071 @ClassRule 072 public static final HBaseClassTestRule CLASS_RULE = 073 HBaseClassTestRule.forClass(TestAsyncRegionLocatorTracing.class); 074 075 private static final Configuration CONF = HBaseConfiguration.create(); 076 077 private AsyncConnectionImpl conn; 078 079 private RegionLocations locs; 080 081 @Rule 082 public OpenTelemetryRule traceRule = OpenTelemetryRule.create(); 083 084 @Before 085 public void setUp() throws IOException { 086 RegionInfo metaRegionInfo = RegionInfoBuilder.newBuilder(TableName.META_TABLE_NAME).build(); 087 locs = new RegionLocations( 088 new HRegionLocation(metaRegionInfo, 089 ServerName.valueOf("127.0.0.1", 12345, System.currentTimeMillis())), 090 new HRegionLocation(RegionReplicaUtil.getRegionInfoForReplica(metaRegionInfo, 1), 091 ServerName.valueOf("127.0.0.2", 12345, System.currentTimeMillis())), 092 new HRegionLocation(RegionReplicaUtil.getRegionInfoForReplica(metaRegionInfo, 2), 093 ServerName.valueOf("127.0.0.3", 12345, System.currentTimeMillis()))); 094 conn = new AsyncConnectionImpl(CONF, new DoNothingConnectionRegistry(CONF) { 095 096 @Override 097 public CompletableFuture<RegionLocations> getMetaRegionLocations() { 098 return CompletableFuture.completedFuture(locs); 099 } 100 }, "test", UserProvider.instantiate(CONF).getCurrent()); 101 } 102 103 @After 104 public void tearDown() throws IOException { 105 Closeables.close(conn, true); 106 } 107 108 private SpanData waitSpan(String name) { 109 return waitSpan(hasName(name)); 110 } 111 112 private SpanData waitSpan(Matcher<SpanData> matcher) { 113 Matcher<SpanData> spanLocator = allOf(matcher, hasEnded()); 114 try { 115 Waiter.waitFor(CONF, 1000, new MatcherPredicate<>("waiting for span", 116 () -> traceRule.getSpans(), hasItem(spanLocator))); 117 } catch (AssertionError e) { 118 LOG.error("AssertionError while waiting for matching span. Span reservoir contains: {}", 119 traceRule.getSpans()); 120 throw e; 121 } 122 return traceRule.getSpans().stream().filter(spanLocator::matches).findFirst() 123 .orElseThrow(AssertionError::new); 124 } 125 126 @Test 127 public void testClearCache() { 128 conn.getLocator().clearCache(); 129 SpanData span = waitSpan("AsyncRegionLocator.clearCache"); 130 assertThat(span, allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL), 131 buildConnectionAttributesMatcher(conn))); 132 } 133 134 @Test 135 public void testClearCacheServerName() { 136 ServerName sn = ServerName.valueOf("127.0.0.1", 12345, System.currentTimeMillis()); 137 conn.getLocator().clearCache(sn); 138 SpanData span = waitSpan("AsyncRegionLocator.clearCache"); 139 assertThat(span, 140 allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL), 141 buildConnectionAttributesMatcher(conn), 142 hasAttributes(containsEntry("db.hbase.server.name", sn.getServerName())))); 143 } 144 145 @Test 146 public void testClearCacheTableName() { 147 conn.getLocator().clearCache(TableName.META_TABLE_NAME); 148 SpanData span = waitSpan("AsyncRegionLocator.clearCache"); 149 assertThat(span, 150 allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL), 151 buildConnectionAttributesMatcher(conn), 152 buildTableAttributesMatcher(TableName.META_TABLE_NAME))); 153 } 154 155 @Test 156 public void testGetRegionLocation() { 157 conn.getLocator().getRegionLocation(TableName.META_TABLE_NAME, HConstants.EMPTY_START_ROW, 158 RegionLocateType.CURRENT, TimeUnit.SECONDS.toNanos(1)).join(); 159 SpanData span = waitSpan("AsyncRegionLocator.getRegionLocation"); 160 assertThat(span, 161 allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL), 162 buildConnectionAttributesMatcher(conn), 163 buildTableAttributesMatcher(TableName.META_TABLE_NAME), 164 hasAttributes(containsEntryWithStringValuesOf("db.hbase.regions", 165 locs.getDefaultRegionLocation().getRegion().getRegionNameAsString())))); 166 } 167 168 @Test 169 public void testGetRegionLocations() { 170 conn.getLocator().getRegionLocations(TableName.META_TABLE_NAME, HConstants.EMPTY_START_ROW, 171 RegionLocateType.CURRENT, false, TimeUnit.SECONDS.toNanos(1)).join(); 172 SpanData span = waitSpan("AsyncRegionLocator.getRegionLocations"); 173 String[] expectedRegions = 174 Arrays.stream(locs.getRegionLocations()).map(HRegionLocation::getRegion) 175 .map(RegionInfo::getRegionNameAsString).toArray(String[]::new); 176 assertThat(span, allOf(hasStatusWithCode(StatusCode.OK), hasKind(SpanKind.INTERNAL), 177 buildConnectionAttributesMatcher(conn), 178 buildTableAttributesMatcher(TableName.META_TABLE_NAME), hasAttributes( 179 containsEntryWithStringValuesOf("db.hbase.regions", containsInAnyOrder(expectedRegions))))); 180 } 181}