Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ static class SseLineSubscriber extends BaseSubscriber<String> {
* The response information from the HTTP response. Send with each event to
* provide context.
*/
private ResponseInfo responseInfo;
private final ResponseInfo responseInfo;

/**
* The maximum number of bytes that may accumulate for a single SSE event. A peer
Expand Down Expand Up @@ -348,16 +348,15 @@ public AggregateSubscriber(ResponseInfo responseInfo, FluxSink<ResponseEvent> si

@Override
protected void hookOnSubscribe(Subscription subscription) {
// Register disposal callback to cancel subscription when Flux is disposed
sink.onDispose(subscription::cancel);

sink.onRequest(n -> {
if (!hasRequestedDemand) {
hasRequestedDemand = true;
subscription.request(Long.MAX_VALUE);
}
hasRequestedDemand = true;
});

// Register disposal callback to cancel subscription when Flux is disposed
sink.onDispose(subscription::cancel);
}

@Override
Expand Down Expand Up @@ -410,17 +409,14 @@ public BodilessResponseLineSubscriber(ResponseInfo responseInfo, FluxSink<Respon

@Override
protected void hookOnSubscribe(Subscription subscription) {
// Register disposal callback to cancel subscription when Flux is disposed
sink.onDispose(subscription::cancel);

sink.onRequest(n -> {
if (!hasRequestedDemand) {
hasRequestedDemand = true;
subscription.request(Long.MAX_VALUE);
}
hasRequestedDemand = true;
});

// Register disposal callback to cancel subscription when Flux is disposed
sink.onDispose(() -> {
subscription.cancel();
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2024 - 2024 the original author or authors.
*/

package io.modelcontextprotocol.client.transport;

import java.net.http.HttpResponse.ResponseInfo;

import org.junit.jupiter.api.Test;

import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

class ResponseSubscribersTests {

@Test
void aggregateSubscriberEmitsResponseWhenRequestCompletesSynchronously() {
ResponseInfo responseInfo = mock(ResponseInfo.class);

Flux<ResponseSubscribers.ResponseEvent> response = Flux.create(sink -> {
var subscriber = new ResponseSubscribers.AggregateSubscriber(responseInfo, sink, Integer.MAX_VALUE);
Flux.just("payload").subscribe(subscriber);
});

StepVerifier.create(response).assertNext(event -> {
var aggregate = (ResponseSubscribers.AggregateResponseEvent) event;
assertThat(aggregate.responseInfo()).isSameAs(responseInfo);
assertThat(aggregate.data()).isEqualTo("payload\n");
}).verifyComplete();
}

@Test
void bodilessSubscriberEmitsResponseWhenRequestCompletesSynchronously() {
ResponseInfo responseInfo = mock(ResponseInfo.class);

Flux<ResponseSubscribers.ResponseEvent> response = Flux.create(sink -> {
var subscriber = new ResponseSubscribers.BodilessResponseLineSubscriber(responseInfo, sink);
Flux.<String>empty().subscribe(subscriber);
});

StepVerifier.create(response).assertNext(event -> {
var dummy = (ResponseSubscribers.DummyEvent) event;
assertThat(dummy.responseInfo()).isSameAs(responseInfo);
}).verifyComplete();
}

}