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