Skip to content

Commit

Permalink
node-name needs to be truncated because the byte array is not base64
Browse files Browse the repository at this point in the history
Add unit test, stress test commented and updated the JavaDoc
  • Loading branch information
marcosgopen committed May 20, 2024
1 parent eb49de2 commit ed0d407
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 2 deletions.
11 changes: 11 additions & 0 deletions extensions/narayana-jta/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@
<groupId>org.jboss.narayana.jts</groupId>
<artifactId>narayana-jts-integration</artifactId>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -59,7 +60,15 @@ private static void shortenNodeName(TransactionManagerConfiguration transactions
HASH_ALGORITHM_FOR_SHORTENING);
final byte[] nodeNameAsBytes = originalNodeName.getBytes();
MessageDigest messageDigest224 = MessageDigest.getInstance(HASH_ALGORITHM_FOR_SHORTENING);
transactions.nodeName = new String(messageDigest224.digest(nodeNameAsBytes), StandardCharsets.UTF_8);
byte[] hashedByteArray = messageDigest224.digest(nodeNameAsBytes);

//Encode the byte array in Base64
//encoding the array might result in a longer array
byte[] base64Result = Base64.getEncoder().encode(hashedByteArray);
//truncate the array
byte[] slice = Arrays.copyOfRange(base64Result, 0, 28);

transactions.nodeName = new String(slice, StandardCharsets.UTF_8);
log.warnf("New node name is \"%s\"", transactions.nodeName);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public final class TransactionManagerConfiguration {
* Whether the node name should be shortened if necessary.
* The node name must not exceed a length of 28 bytes. If this property is set to {@code true}, and the node name exceeds 28
* bytes, the node name is shortened by calculating the <a href="https://en.wikipedia.org/wiki/SHA-2">SHA-224</a> hash,
* which has a length of 28 bytes.
* which has a length of 28 bytes, encoded to Base64 format and then shorten to 28 bytes.
*
* @see #nodeName
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.quarkus.narayana.jta.runtime;

import static org.junit.jupiter.api.Assertions.assertFalse;

import java.nio.charset.StandardCharsets;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.UUID;

import org.junit.jupiter.api.Test;

public class NarayanaJtaRecorderTest {

@Test
void testByteLength() {
TransactionManagerConfiguration transactions = new TransactionManagerConfiguration();
transactions.shortenNodeNameIfNecessary = true;
// create nodeNames larger than 28 bytes
for (int i = 1; i < 100; i++) {
String originalNodeName = UUID.randomUUID().toString();
NarayanaJtaRecorder r = new NarayanaJtaRecorder();
transactions.nodeName = originalNodeName;
r.setNodeName(transactions);
int numberOfBytes = transactions.nodeName.getBytes(StandardCharsets.UTF_8).length;
assertFalse(numberOfBytes > 28,
"node name bytes still exceeded 28 bytes limit, number of bytes is " + numberOfBytes);
}
for (int i = 1; i < 1000; i++) {
byte[] data = new byte[i];
NarayanaJtaRecorder r = new NarayanaJtaRecorder();
transactions.nodeName = new String(data);
r.setNodeName(transactions);
int numberOfBytes = transactions.nodeName.getBytes(StandardCharsets.UTF_8).length;
assertFalse(numberOfBytes > 28,
"node name bytes still exceeded 28 bytes limit, number of bytes is " + numberOfBytes);
}
}

//commented because it is a stress test
// @Test
void testCollision() {
SortedSet<String> set = new TreeSet<>();
TransactionManagerConfiguration transactions = new TransactionManagerConfiguration();
transactions.shortenNodeNameIfNecessary = true;
// create a nodeName larger than 28 bytes
for (int i = 1; i < 1000000; i++) {
String originalNodeName = UUID.randomUUID().toString();
NarayanaJtaRecorder r = new NarayanaJtaRecorder();
transactions.nodeName = originalNodeName;
r.setNodeName(transactions);
assertFalse(set.contains(transactions.nodeName), "Collision of IDs for " + transactions.nodeName);
set.add(transactions.nodeName);
}
}

}

0 comments on commit ed0d407

Please sign in to comment.