-
Notifications
You must be signed in to change notification settings - Fork 921
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: Optimize timeout handling in TimeoutSubscriber
- Loading branch information
jeong-yong-shin
authored and
jeong-yong-shin
committed
Jun 24, 2024
1 parent
2d6d00f
commit 7c52cef
Showing
2 changed files
with
263 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
227 changes: 225 additions & 2 deletions
227
core/src/test/java/com/linecorp/armeria/common/stream/TimeoutStreamMessageTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,225 @@ | ||
package com.linecorp.armeria.common.stream;public class TimeoutStreamMessageTest { | ||
} | ||
package com.linecorp.armeria.common.stream; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
||
import java.time.Duration; | ||
import java.util.concurrent.CompletableFuture; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.TimeoutException; | ||
|
||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.reactivestreams.Subscriber; | ||
import org.reactivestreams.Subscription; | ||
|
||
import io.netty.util.concurrent.DefaultEventExecutor; | ||
import io.netty.util.concurrent.EventExecutor; | ||
|
||
public class TimeoutStreamMessageTest { | ||
private EventExecutor executor; | ||
|
||
@BeforeEach | ||
public void setUp() { | ||
executor = new DefaultEventExecutor(); | ||
} | ||
|
||
@AfterEach | ||
public void tearDown() { | ||
executor.shutdownGracefully(); | ||
} | ||
|
||
|
||
@Test | ||
public void timeoutNextMode() { | ||
StreamMessage<String> timeoutStreamMessage = StreamMessage.of("message1", "message2").timeout( | ||
Duration.ofSeconds(1), StreamTimeoutMode.UNTIL_NEXT); | ||
CompletableFuture<Void> future = new CompletableFuture<>(); | ||
|
||
timeoutStreamMessage.subscribe(new Subscriber<String>() { | ||
private Subscription subscription; | ||
@Override | ||
public void onSubscribe(Subscription s) { | ||
subscription = s; | ||
subscription.request(1); | ||
} | ||
|
||
@Override | ||
public void onNext(String s) { | ||
executor.schedule(() -> subscription.request(1), 2, TimeUnit.SECONDS); | ||
} | ||
|
||
@Override | ||
public void onError(Throwable throwable) { | ||
future.completeExceptionally(throwable); | ||
} | ||
|
||
@Override | ||
public void onComplete() { | ||
future.complete(null); | ||
} | ||
}, executor); | ||
|
||
assertThatThrownBy(future::get) | ||
.isInstanceOf(ExecutionException.class) | ||
.hasCauseInstanceOf(TimeoutException.class); | ||
} | ||
|
||
@Test | ||
public void noTimeoutNextMode() throws Exception { | ||
StreamMessage<String> timeoutStreamMessage = StreamMessage.of("message1", "message2").timeout(Duration.ofSeconds(1), StreamTimeoutMode.UNTIL_NEXT); | ||
|
||
CompletableFuture<Void> future = new CompletableFuture<>(); | ||
|
||
timeoutStreamMessage.subscribe(new Subscriber<String>() { | ||
@Override | ||
public void onSubscribe(Subscription subscription) { | ||
subscription.request(2); | ||
} | ||
|
||
@Override | ||
public void onNext(String s) { | ||
} | ||
|
||
@Override | ||
public void onError(Throwable throwable) { | ||
future.completeExceptionally(throwable); | ||
} | ||
|
||
@Override | ||
public void onComplete() { | ||
future.complete(null); | ||
} | ||
}, executor); | ||
|
||
assertThat(future.get()).isNull(); | ||
} | ||
|
||
@Test | ||
public void timeoutFirstMode() { | ||
StreamMessage<String> timeoutStreamMessage = StreamMessage.of("message1", "message2").timeout(Duration.ofSeconds(1), StreamTimeoutMode.UNTIL_FIRST); | ||
CompletableFuture<Void> future = new CompletableFuture<>(); | ||
|
||
timeoutStreamMessage.subscribe(new Subscriber<String>() { | ||
private Subscription subscription; | ||
@Override | ||
public void onSubscribe(Subscription s) { | ||
subscription = s; | ||
executor.schedule(() -> subscription.request(1), 2, TimeUnit.SECONDS); | ||
} | ||
|
||
@Override | ||
public void onNext(String s) { | ||
subscription.request(1); | ||
} | ||
|
||
@Override | ||
public void onError(Throwable throwable) { | ||
future.completeExceptionally(throwable); | ||
} | ||
|
||
@Override | ||
public void onComplete() { | ||
future.complete(null); | ||
} | ||
}, executor); | ||
|
||
assertThatThrownBy(future::get) | ||
.isInstanceOf(ExecutionException.class) | ||
.hasCauseInstanceOf(TimeoutException.class); | ||
} | ||
|
||
@Test | ||
public void noTimeoutModeFirst() throws Exception { | ||
StreamMessage<String> timeoutStreamMessage = StreamMessage.of("message1", "message2").timeout(Duration.ofSeconds(1), StreamTimeoutMode.UNTIL_FIRST); | ||
CompletableFuture<Void> future = new CompletableFuture<>(); | ||
|
||
timeoutStreamMessage.subscribe(new Subscriber<String>() { | ||
@Override | ||
public void onSubscribe(Subscription subscription) { | ||
subscription.request(2); | ||
} | ||
|
||
@Override | ||
public void onNext(String s) { | ||
} | ||
|
||
@Override | ||
public void onError(Throwable throwable) { | ||
future.completeExceptionally(throwable); | ||
} | ||
|
||
@Override | ||
public void onComplete() { | ||
future.complete(null); | ||
} | ||
}, executor); | ||
|
||
assertThat(future.get()).isNull(); | ||
} | ||
|
||
@Test | ||
public void timeoutEOSMode() { | ||
StreamMessage<String> timeoutStreamMessage = StreamMessage.of("message1", "message2").timeout(Duration.ofSeconds(2), StreamTimeoutMode.UNTIL_EOS); | ||
CompletableFuture<Void> future = new CompletableFuture<>(); | ||
|
||
timeoutStreamMessage.subscribe(new Subscriber<String>() { | ||
private Subscription subscription; | ||
@Override | ||
public void onSubscribe(Subscription s) { | ||
subscription = s; | ||
executor.schedule(() -> subscription.request(1), 1, TimeUnit.SECONDS); | ||
} | ||
|
||
@Override | ||
public void onNext(String s) { | ||
executor.schedule(() -> subscription.request(1), 2, TimeUnit.SECONDS); | ||
} | ||
|
||
@Override | ||
public void onError(Throwable throwable) { | ||
future.completeExceptionally(throwable); | ||
} | ||
|
||
@Override | ||
public void onComplete() { | ||
future.complete(null); | ||
} | ||
}, executor); | ||
|
||
assertThatThrownBy(future::get) | ||
.isInstanceOf(ExecutionException.class) | ||
.hasCauseInstanceOf(TimeoutException.class); | ||
} | ||
|
||
@Test | ||
public void noTimeoutEOSMode() throws Exception { | ||
StreamMessage<String> timeoutStreamMessage = StreamMessage.of("message1", "message2").timeout(Duration.ofSeconds(2), StreamTimeoutMode.UNTIL_EOS); | ||
CompletableFuture<Void> future = new CompletableFuture<>(); | ||
|
||
timeoutStreamMessage.subscribe(new Subscriber<String>() { | ||
@Override | ||
public void onSubscribe(Subscription subscription) { | ||
subscription.request(2); | ||
} | ||
|
||
@Override | ||
public void onNext(String s) { | ||
} | ||
|
||
@Override | ||
public void onError(Throwable throwable) { | ||
future.completeExceptionally(throwable); | ||
} | ||
|
||
@Override | ||
public void onComplete() { | ||
future.complete(null); | ||
} | ||
}, executor); | ||
|
||
assertThat(future.get()).isNull(); | ||
} | ||
} |