13 septembrie 2025

Jupiter Parameterized Test

import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

public class ServerStreamingInputValidationTest extends AbstractTest {

@ParameterizedTest
@MethodSource("testData")
void testBlockingInputValidation(WithdrawRequest request, Status.Code code) {
var ex = Assertions.assertThrows(StatusRuntimeException.class, () -> this.blockingStub.withdraw(request).hasNext());
Assertions.assertEquals(code, ex.getStatus().getCode());
}

@ParameterizedTest
@MethodSource("testData")
void testAsyncInputValidation(WithdrawRequest request, Status.Code code) {
var observer = new ResponseObserver<Money>();
this.asyncStub.withdraw(request, observer);
observer.await();

Assertions.assertTrue(observer.getItems().isEmpty());
Assertions.assertNotNull(observer.getThrowable());
Assertions.assertEquals(code, ((StatusRuntimeException) observer.getThrowable()).getStatus().getCode());
}

private Stream<Arguments> testData() {
return Stream.of(
// input, expectation
Arguments.of(WithdrawRequest.newBuilder().setAccountNumber(11).setAmount(10).build(), Status.Code.INVALID_ARGUMENT),
Arguments.of(WithdrawRequest.newBuilder().setAccountNumber(1).setAmount(17).build(), Status.Code.INVALID_ARGUMENT),
Arguments.of(WithdrawRequest.newBuilder().setAccountNumber(1).setAmount(120).build(), Status.Code.FAILED_PRECONDITION)
);
}
}

07 august 2025

Kill process in Windows & Linux

Windows:

> netstat -ano | findstr :8080

> taskkill PID <pid> /F


Linux:

> sudo lsof -i 8080

> sudo kill -9 <pid>

02 august 2025

Proto vs Json performance test

 


public class PerformanceTest {
private static final Logger LOGGER = LoggerFactory.getLogger(PerformanceTest.class);
private static final ObjectMapper MAPPER = new ObjectMapper();

public static void main(String[] args) throws Exception {
var protoPerson = Person.newBuilder()
.setLastName(
"T")
.setAge(
32)
.setEmail(
"t@email.com")
.setEmployed(
true)
.setSalary(
123004.5)
.setBankAccountNumber(
38495959093040944L)
.setBalance(-
100)
.build();
LOGGER.info("how many bytes protoPerson has? {}", protoPerson.toByteArray().length); // 41

var jsonPerson = new JsonPerson("T", 32, "t@email.com", true, 123004.5, 38495959093040944L, -100);
var bytes = MAPPER.writeValueAsBytes(jsonPerson);
LOGGER.info("how many bytes jsonPerson has? {}", bytes.length); // 130 = 3x more!

for (int i=0; i<5; i++) { // first run to be ignored (warmup JVM)
runTest("json", () -> json(jsonPerson));
runTest("proto", () -> proto(protoPerson)); // 7x faster!
}
}

private static void runTest(String testName, Runnable runnable) {
var start = System.currentTimeMillis();
for (int i=0; i<5_000_000; i++) {
runnable.run();
}
var end = System.currentTimeMillis();
LOGGER.info("time taken for {} = {} ms", testName, (end - start));
}

private static void proto(Person person) {
try {
var bytes = person.toByteArray();
Person.
parseFrom(bytes);
}
catch (InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
}

private static void json(JsonPerson person) {
try {
var bytes = MAPPER.writeValueAsBytes(person);
MAPPER.readValue(bytes, JsonPerson.class);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}

04 decembrie 2024

Implementarea unui Rate Limiter

public class RateLimiter {
private static final int ONE_SECOND = 1000;
private final Map<String, List<Long>> requests;
private boolean enabled = false;
private int requestsPerSecond;

public RateLimiter(Environment environment) {
requests = new HashMap<>();
if (environment.getProperty("enable.rate.limiter") != null) {
this.enabled = Boolean.parseBoolean(environment.getProperty("enable.rate.limiter"));
}
if (this.enabled) {
String property = environment.getProperty("max.requests.per.user.per.second");
Assert.notNull(property, "Max requests per second not defined!");
this.requestsPerSecond = Integer.parseInt(property);
}
}

public boolean allows(String ipAddress) {
if (!enabled) {
return true;
}

if (!requests.containsKey(ipAddress)) {
requests.put(ipAddress, new ArrayList<>());
}

Long now = System.currentTimeMillis();
cleanup(ipAddress, now);
requests.get(ipAddress).add(now);

return requests.get(ipAddress).size() <= requestsPerSecond;
}

private void cleanup(String ipAddress, Long now) {
List<Long> markedForDeletion = new ArrayList<>();
for (Long timestamp : requests.get(ipAddress)) {
if (now - timestamp > ONE_SECOND) {
markedForDeletion.add(timestamp);
}
}
requests.get(ipAddress).removeAll(markedForDeletion);
}
}

31 octombrie 2024

Test de integrare pt Kafka Consumer

@EmbeddedKafka
@SpringBootTest(properties = "spring.kafka.consumer.bootstrap-servers=${spring.embedded.kafka.brokers}")
public class ProductCreatedEventHandlerTest {
@MockBean
ProcessedEventRepository processedEventRepository;

@Autowired
KafkaTemplate<String, Object> kafkaTemplate;

@SpyBean // true object, its methods can be intercepted
ProductCreatedEventHandler productCreatedEventHandler;

@Test
public void testHandle() throws Exception {
// Arrange
ProductCreatedEvent event = new ProductCreatedEvent(UUID.randomUUID().toString(), "iPhone SE", BigDecimal.valueOf(24.5), 12);
ProducerRecord<String, Object> record = new ProducerRecord<>(PRODUCT_CREATED_EVT_TOPIC, event.getProductId(), event);
String messageId = UUID.randomUUID().toString();
record.headers().add("messageId", messageId.getBytes());
record.headers().add(KafkaHeaders.RECEIVED_KEY, event.getProductId().getBytes());

ProcessedEventEntity processedEventEntity = new ProcessedEventEntity();
when(processedEventRepository.findByMessageId(any())).thenReturn(processedEventEntity);

// Act
kafkaTemplate.send(record).get();

// Assert
ArgumentCaptor<String> messageIdCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> messageKeyCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<ProductCreatedEvent> eventCaptor = ArgumentCaptor.forClass(ProductCreatedEvent.class);
verify(productCreatedEventHandler, timeout(5000).times(1))
.handle(eventCaptor.capture(), messageIdCaptor.capture(), messageKeyCaptor.capture());
Assertions.assertEquals(messageId, messageIdCaptor.getValue());
Assertions.assertEquals(event.getProductId(), messageKeyCaptor.getValue());
Assertions.assertEquals(event.getProductId(), eventCaptor.getValue().getProductId());
}
}