|
75 | 75 | import java.util.concurrent.atomic.AtomicReference; |
76 | 76 | import java.util.stream.Stream; |
77 | 77 | import org.assertj.core.api.Assertions; |
| 78 | +import org.assertj.core.api.Assumptions; |
78 | 79 | import org.junit.jupiter.api.AfterEach; |
79 | 80 | import org.junit.jupiter.api.BeforeEach; |
80 | 81 | import org.junit.jupiter.api.Disabled; |
|
94 | 95 | import reactor.core.publisher.FluxSink; |
95 | 96 | import reactor.core.publisher.Hooks; |
96 | 97 | import reactor.core.publisher.Mono; |
| 98 | +import reactor.core.publisher.MonoProcessor; |
97 | 99 | import reactor.core.publisher.Operators; |
98 | 100 | import reactor.core.scheduler.Scheduler; |
99 | 101 | import reactor.core.scheduler.Schedulers; |
@@ -830,13 +832,13 @@ public Flux<Payload> requestChannel(Publisher<Payload> payloads) { |
830 | 832 | rule.assertHasNoLeaks(); |
831 | 833 | } |
832 | 834 |
|
833 | | - static Stream<FrameType> fragmentationCases() { |
| 835 | + static Stream<FrameType> requestCases() { |
834 | 836 | return Stream.of(REQUEST_FNF, REQUEST_RESPONSE, REQUEST_STREAM, REQUEST_CHANNEL); |
835 | 837 | } |
836 | 838 |
|
837 | 839 | @DisplayName("reassembles payload") |
838 | 840 | @ParameterizedTest |
839 | | - @MethodSource("fragmentationCases") |
| 841 | + @MethodSource("requestCases") |
840 | 842 | void reassemblePayload(FrameType frameType) { |
841 | 843 | AtomicReference<Payload> receivedPayload = new AtomicReference<>(); |
842 | 844 | rule.setAcceptingSocket( |
@@ -891,7 +893,7 @@ public Flux<Payload> requestChannel(Publisher<Payload> payloads) { |
891 | 893 |
|
892 | 894 | @DisplayName("reassembles metadata") |
893 | 895 | @ParameterizedTest |
894 | | - @MethodSource("fragmentationCases") |
| 896 | + @MethodSource("requestCases") |
895 | 897 | void reassembleMetadataOnly(FrameType frameType) { |
896 | 898 | AtomicReference<Payload> receivedPayload = new AtomicReference<>(); |
897 | 899 | rule.setAcceptingSocket( |
@@ -948,7 +950,7 @@ public Flux<Payload> requestChannel(Publisher<Payload> payloads) { |
948 | 950 | } |
949 | 951 |
|
950 | 952 | @ParameterizedTest(name = "throws error if reassembling payload size exceeds {0}") |
951 | | - @MethodSource("fragmentationCases") |
| 953 | + @MethodSource("requestCases") |
952 | 954 | public void errorTooBigPayload(FrameType frameType) { |
953 | 955 | final int mtu = ThreadLocalRandom.current().nextInt(64, 256); |
954 | 956 | final int maxInboundPayloadSize = ThreadLocalRandom.current().nextInt(mtu + 1, 4096); |
@@ -1000,6 +1002,122 @@ public Flux<Payload> requestChannel(Publisher<Payload> payloads) { |
1000 | 1002 | rule.assertHasNoLeaks(); |
1001 | 1003 | } |
1002 | 1004 |
|
| 1005 | + @ParameterizedTest |
| 1006 | + @MethodSource("requestCases") |
| 1007 | + void receivingRequestOnStreamIdThaIsAlreadyInUseMUSTBeIgnored_ReassemblyCase( |
| 1008 | + FrameType requestType) { |
| 1009 | + AtomicReference<Payload> receivedPayload = new AtomicReference<>(); |
| 1010 | + final MonoProcessor<Void> delayer = MonoProcessor.create(); |
| 1011 | + rule.setAcceptingSocket( |
| 1012 | + new RSocket() { |
| 1013 | + |
| 1014 | + @Override |
| 1015 | + public Mono<Void> fireAndForget(Payload payload) { |
| 1016 | + receivedPayload.set(payload); |
| 1017 | + return delayer; |
| 1018 | + } |
| 1019 | + |
| 1020 | + @Override |
| 1021 | + public Mono<Payload> requestResponse(Payload payload) { |
| 1022 | + receivedPayload.set(payload); |
| 1023 | + return Mono.just(genericPayload(rule.allocator)).delaySubscription(delayer); |
| 1024 | + } |
| 1025 | + |
| 1026 | + @Override |
| 1027 | + public Flux<Payload> requestStream(Payload payload) { |
| 1028 | + receivedPayload.set(payload); |
| 1029 | + return Flux.just(genericPayload(rule.allocator)).delaySubscription(delayer); |
| 1030 | + } |
| 1031 | + |
| 1032 | + @Override |
| 1033 | + public Flux<Payload> requestChannel(Publisher<Payload> payloads) { |
| 1034 | + Flux.from(payloads).subscribe(receivedPayload::set, null, null, s -> s.request(1)); |
| 1035 | + return Flux.just(genericPayload(rule.allocator)).delaySubscription(delayer); |
| 1036 | + } |
| 1037 | + }); |
| 1038 | + final Payload randomPayload1 = fixedSizePayload(rule.allocator, 128); |
| 1039 | + final List<ByteBuf> fragments1 = |
| 1040 | + prepareFragments(rule.allocator, 64, randomPayload1, requestType); |
| 1041 | + final Payload randomPayload2 = fixedSizePayload(rule.allocator, 128); |
| 1042 | + final List<ByteBuf> fragments2 = |
| 1043 | + prepareFragments(rule.allocator, 64, randomPayload2, requestType); |
| 1044 | + randomPayload2.release(); |
| 1045 | + rule.connection.addToReceivedBuffer(fragments1.remove(0)); |
| 1046 | + rule.connection.addToReceivedBuffer(fragments2.remove(0)); |
| 1047 | + |
| 1048 | + rule.connection.addToReceivedBuffer(fragments1.toArray(new ByteBuf[0])); |
| 1049 | + if (requestType != REQUEST_CHANNEL) { |
| 1050 | + rule.connection.addToReceivedBuffer(fragments2.toArray(new ByteBuf[0])); |
| 1051 | + delayer.onComplete(); |
| 1052 | + } else { |
| 1053 | + delayer.onComplete(); |
| 1054 | + rule.connection.addToReceivedBuffer(PayloadFrameCodec.encodeComplete(rule.allocator, 1)); |
| 1055 | + rule.connection.addToReceivedBuffer(fragments2.toArray(new ByteBuf[0])); |
| 1056 | + } |
| 1057 | + |
| 1058 | + PayloadAssert.assertThat(receivedPayload.get()).isEqualTo(randomPayload1).hasNoLeaks(); |
| 1059 | + randomPayload1.release(); |
| 1060 | + |
| 1061 | + if (requestType != REQUEST_FNF) { |
| 1062 | + FrameAssert.assertThat(rule.connection.getSent().poll()) |
| 1063 | + .typeOf(requestType == REQUEST_RESPONSE ? NEXT_COMPLETE : NEXT) |
| 1064 | + .hasNoLeaks(); |
| 1065 | + |
| 1066 | + if (requestType != REQUEST_RESPONSE) { |
| 1067 | + FrameAssert.assertThat(rule.connection.getSent().poll()).typeOf(COMPLETE).hasNoLeaks(); |
| 1068 | + } |
| 1069 | + } |
| 1070 | + |
| 1071 | + rule.assertHasNoLeaks(); |
| 1072 | + } |
| 1073 | + |
| 1074 | + @ParameterizedTest |
| 1075 | + @MethodSource("requestCases") |
| 1076 | + void receivingRequestOnStreamIdThaIsAlreadyInUseMUSTBeIgnored(FrameType requestType) { |
| 1077 | + Assumptions.assumeThat(requestType).isNotEqualTo(REQUEST_FNF); |
| 1078 | + AtomicReference<Payload> receivedPayload = new AtomicReference<>(); |
| 1079 | + final MonoProcessor<Object> delayer = MonoProcessor.create(); |
| 1080 | + rule.setAcceptingSocket( |
| 1081 | + new RSocket() { |
| 1082 | + @Override |
| 1083 | + public Mono<Payload> requestResponse(Payload payload) { |
| 1084 | + receivedPayload.set(payload); |
| 1085 | + return Mono.just(genericPayload(rule.allocator)).delaySubscription(delayer); |
| 1086 | + } |
| 1087 | + |
| 1088 | + @Override |
| 1089 | + public Flux<Payload> requestStream(Payload payload) { |
| 1090 | + receivedPayload.set(payload); |
| 1091 | + return Flux.just(genericPayload(rule.allocator)).delaySubscription(delayer); |
| 1092 | + } |
| 1093 | + |
| 1094 | + @Override |
| 1095 | + public Flux<Payload> requestChannel(Publisher<Payload> payloads) { |
| 1096 | + Flux.from(payloads).subscribe(receivedPayload::set, null, null, s -> s.request(1)); |
| 1097 | + return Flux.just(genericPayload(rule.allocator)).delaySubscription(delayer); |
| 1098 | + } |
| 1099 | + }); |
| 1100 | + final Payload randomPayload1 = fixedSizePayload(rule.allocator, 64); |
| 1101 | + final Payload randomPayload2 = fixedSizePayload(rule.allocator, 64); |
| 1102 | + rule.sendRequest(1, requestType, randomPayload1.retain()); |
| 1103 | + rule.sendRequest(1, requestType, randomPayload2); |
| 1104 | + |
| 1105 | + delayer.onComplete(); |
| 1106 | + |
| 1107 | + PayloadAssert.assertThat(receivedPayload.get()).isEqualTo(randomPayload1).hasNoLeaks(); |
| 1108 | + randomPayload1.release(); |
| 1109 | + |
| 1110 | + FrameAssert.assertThat(rule.connection.getSent().poll()) |
| 1111 | + .typeOf(requestType == REQUEST_RESPONSE ? NEXT_COMPLETE : NEXT) |
| 1112 | + .hasNoLeaks(); |
| 1113 | + |
| 1114 | + if (requestType != REQUEST_RESPONSE) { |
| 1115 | + FrameAssert.assertThat(rule.connection.getSent().poll()).typeOf(COMPLETE).hasNoLeaks(); |
| 1116 | + } |
| 1117 | + |
| 1118 | + rule.assertHasNoLeaks(); |
| 1119 | + } |
| 1120 | + |
1003 | 1121 | public static class ServerSocketRule extends AbstractSocketRule<RSocketResponder> { |
1004 | 1122 |
|
1005 | 1123 | private RSocket acceptingSocket; |
|
0 commit comments