Skip to content

The protobuf-java version introduced by the Java Agent conflicts with the protobuf-java version used in AgentTestRunner, causing the test cases to fail. #13912

@YaoYingLong

Description

@YaoYingLong

Describe the bug

When integrating hbase-client versions 1.0.0 to 1.7.2, the hbase-client depends on protobuf-java version 2.x. However, the getExportedSpans method in AgentTestRunner uses protobuf-java for deserialization, but it relies on protobuf-java version 3.x. This leads to a conflict between the LiteralByteString class from version 2.x and the GeneratedMessageV3 class from version 3.x.

Steps to reproduce

Add the dependency testImplementation("org.apache.hbase:hbase-client:1.4.0"), and then execute the following code:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class HbaseClient140Test {

private static final Integer MASTER_PORT = 16000;
private static final Integer REGION_SERVER_PORT = 16020;

private static final String NAMESPACE = "ot_test";
private static final byte[] COLUMN_FAMILY = Bytes.toBytes("cf");
private static final TableName TABLE_NAME = TableName.valueOf("ot_test:eleven_test_table");
private static final TableName META = TableName.valueOf("hbase:meta");

private static final String DB_SYSTEM = "HBase";
private static final String SCAN = "Scan";
private static final String MUTATE = "Mutate";
private static final String GET = "Get";
private static final String MULTI = "Multi";

private static final String HOSTNAME = getHostName();

@RegisterExtension
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();

private static final GenericContainer<?> hbaseContainer =
new GenericContainer<>(DockerImageName.parse("harisekhon/hbase:2.0"))
.withCreateContainerCmdModifier(
cmd -> {
cmd.getHostConfig()
.withPortBindings(
new PortBinding(Ports.Binding.bindPort(2181), new ExposedPort(2181)),
new PortBinding(Ports.Binding.bindPort(16000), new ExposedPort(16000)),
new PortBinding(Ports.Binding.bindPort(16010), new ExposedPort(16010)),
new PortBinding(Ports.Binding.bindPort(16020), new ExposedPort(16020)),
new PortBinding(Ports.Binding.bindPort(16030), new ExposedPort(16030)),
new PortBinding(Ports.Binding.bindPort(16201), new ExposedPort(16201)),
new PortBinding(Ports.Binding.bindPort(16301), new ExposedPort(16301)));
})
.withExposedPorts(2181, 16000, 16010, 16020, 16030, 16201, 16301)
.withCreateContainerCmdModifier(cmd -> cmd.withHostName(HOSTNAME))
.waitingFor(Wait.forListeningPort())
.waitingFor(Wait.forLogMessage(".Master has completed initialization.\n", 1));

private static Connection connection;

private static String getHostName() {
InetAddress localHost = null;
try {
localHost = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
return null;
}
return localHost.getHostName();
}

@BeforeAll
static void setupSpec() {
hbaseContainer.start();

String host = hbaseContainer.getHost();
Configuration config = HBaseConfiguration.create();
config.set("hbase.zookeeper.quorum", host);
config.set("hbase.zookeeper.property.clientPort", "2181");
Exception error = null;
try {
  connection = ConnectionFactory.createConnection(config);
} catch (IOException e) {
  error = e;
}
assertNull(error);

}

@afterall
static void cleanupSpec() {
hbaseContainer.stop();
try {
connection.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

@beforeeach
void setup() {
testing.clearData();
}

@test
@order(1)
public void createNameBaseTest() {
Exception error = null;
boolean namespaceCreateStatus;
try {
Admin admin = connection.getAdmin();
NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(NAMESPACE).build();
admin.createNamespace(namespaceDescriptor);
namespaceCreateStatus = true;
admin.close();
} catch (IOException e) {
namespaceCreateStatus = false;
error = e;
}
assertNull(error);
assertTrue(namespaceCreateStatus);
}

@test
@order(2)
public void listNamespaceTest() throws InterruptedException {
Exception error = null;
boolean namespaceExists = false;
try {
Admin admin = connection.getAdmin();
for (NamespaceDescriptor ns : admin.listNamespaceDescriptors()) {
if (ns.getName().equals(NAMESPACE)) {
namespaceExists = true;
}
}
admin.close();
} catch (IOException e) {
error = e;
}
assertNull(error);
assertTrue(namespaceExists);
testing.waitAndAssertTraces(
traceAssertConsumer(null, "IsMasterRunning", MASTER_PORT, false),
traceAssertConsumer(null, "ListNamespaceDescriptors", MASTER_PORT, false));
}

private static Consumer traceAssertConsumer(
TableName table, String operation, int port, boolean hasTable) {
List assertions = new ArrayList<>();
assertions.add(equalTo(SemanticAttributes.DB_SYSTEM, DB_SYSTEM));
assertions.add(equalTo(SemanticAttributes.DB_OPERATION, operation));
if (hasTable) {
assertions.add(equalTo(SemanticAttributes.DB_NAME, table.getNameAsString()));
}
assertions.add(equalTo(SemanticAttributes.NET_PEER_NAME, HOSTNAME));
assertions.add(equalTo(SemanticAttributes.NET_PEER_PORT, port));
assertions.add(satisfies(SemanticAttributes.DB_USER, AbstractAssert::isNotNull));
String spanName = operation + (hasTable ? " " + table.getNameAsString() : "");
return trace ->
trace.hasSpansSatisfyingExactly(
span ->
span.hasName(spanName)
.hasKind(SpanKind.CLIENT)
.hasAttributesSatisfyingExactly(assertions));
}
}

Expected behavior

Expected the test class to execute successfully.

Actual behavior

Using protobuf-java:2.5.0 will result in a java.lang.NoClassDefFoundError: com/google/protobuf/GeneratedMessageV3 exception, while using the default 3.x version will result in a java.lang.NoClassDefFoundError: com/google/protobuf/LiteralByteString.

Javaagent or library instrumentation version

Integrated HBase version 1.4.0 myself, but haven't submitted the PR yet.

Environment

JDK:
OS:

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds author feedbackWaiting for additional feedback from the authorneeds triageNew issue that requires triagestale

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions