20
20
import java .util .List ;
21
21
import java .util .function .Supplier ;
22
22
23
+ import com .google .protobuf .Message ;
24
+ import org .junit .After ;
23
25
import org .junit .Test ;
24
26
import org .reactivestreams .Publisher ;
25
27
import org .reactivestreams .Subscription ;
38
40
import org .springframework .http .client .MultipartBodyBuilder ;
39
41
import org .springframework .http .codec .json .Jackson2JsonEncoder ;
40
42
import org .springframework .http .codec .multipart .MultipartHttpMessageWriter ;
43
+ import org .springframework .http .codec .protobuf .ProtobufDecoder ;
44
+ import org .springframework .http .codec .protobuf .ProtobufEncoder ;
41
45
import org .springframework .http .codec .xml .Jaxb2XmlEncoder ;
46
+ import org .springframework .protobuf .Msg ;
47
+ import org .springframework .protobuf .SecondMsg ;
48
+ import org .springframework .util .MimeType ;
42
49
43
50
/**
44
51
* Test scenarios for data buffer leaks.
45
52
* @author Rossen Stoyanchev
46
- * @since 5.2
47
53
*/
48
- public class CodecDataBufferLeakTests {
54
+ public class CancelWithoutDemandCodecTests {
49
55
50
56
private final LeakAwareDataBufferFactory bufferFactory = new LeakAwareDataBufferFactory ();
51
57
52
58
59
+ @ After
60
+ public void tearDown () throws Exception {
61
+ this .bufferFactory .checkForLeaks ();
62
+ }
63
+
64
+
53
65
@ Test // gh-22107
54
66
public void cancelWithEncoderHttpMessageWriterAndSingleValue () {
55
67
CharSequenceEncoder encoder = CharSequenceEncoder .allMimeTypes ();
@@ -58,8 +70,6 @@ public void cancelWithEncoderHttpMessageWriterAndSingleValue() {
58
70
59
71
writer .write (Mono .just ("foo" ), ResolvableType .forType (String .class ), MediaType .TEXT_PLAIN ,
60
72
outputMessage , Collections .emptyMap ()).block (Duration .ofSeconds (5 ));
61
-
62
- this .bufferFactory .checkForLeaks ();
63
73
}
64
74
65
75
@ Test // gh-22107
@@ -73,8 +83,6 @@ public void cancelWithJackson() {
73
83
BaseSubscriber <DataBuffer > subscriber = new ZeroDemandSubscriber ();
74
84
flux .subscribe (subscriber ); // Assume sync execution (e.g. encoding with Flux.just)..
75
85
subscriber .cancel ();
76
-
77
- this .bufferFactory .checkForLeaks ();
78
86
}
79
87
80
88
@ Test // gh-22107
@@ -88,8 +96,39 @@ public void cancelWithJaxb2() {
88
96
BaseSubscriber <DataBuffer > subscriber = new ZeroDemandSubscriber ();
89
97
flux .subscribe (subscriber ); // Assume sync execution (e.g. encoding with Flux.just)..
90
98
subscriber .cancel ();
99
+ }
91
100
92
- this .bufferFactory .checkForLeaks ();
101
+ @ Test // gh-22543
102
+ public void cancelWithProtobufEncoder () {
103
+ ProtobufEncoder encoder = new ProtobufEncoder ();
104
+ Msg msg = Msg .newBuilder ().setFoo ("Foo" ).setBlah (SecondMsg .newBuilder ().setBlah (123 ).build ()).build ();
105
+
106
+ Flux <DataBuffer > flux = encoder .encode (Mono .just (msg ),
107
+ this .bufferFactory , ResolvableType .forClass (Msg .class ),
108
+ new MimeType ("application" , "x-protobuf" ), Collections .emptyMap ());
109
+
110
+ BaseSubscriber <DataBuffer > subscriber = new ZeroDemandSubscriber ();
111
+ flux .subscribe (subscriber ); // Assume sync execution (e.g. encoding with Flux.just)..
112
+ subscriber .cancel ();
113
+ }
114
+
115
+ @ Test // gh-22731
116
+ public void cancelWithProtobufDecoder () throws InterruptedException {
117
+ ProtobufDecoder decoder = new ProtobufDecoder ();
118
+
119
+ Mono <DataBuffer > input = Mono .fromCallable (() -> {
120
+ Msg msg = Msg .newBuilder ().setFoo ("Foo" ).build ();
121
+ byte [] bytes = msg .toByteArray ();
122
+ DataBuffer buffer = this .bufferFactory .allocateBuffer (bytes .length );
123
+ buffer .write (bytes );
124
+ return buffer ;
125
+ });
126
+
127
+ Flux <Message > messages = decoder .decode (input , ResolvableType .forType (Msg .class ),
128
+ new MimeType ("application" , "x-protobuf" ), Collections .emptyMap ());
129
+ ZeroDemandMessageSubscriber subscriber = new ZeroDemandMessageSubscriber ();
130
+ messages .subscribe (subscriber );
131
+ subscriber .cancel ();
93
132
}
94
133
95
134
@ Test // gh-22107
@@ -104,8 +143,6 @@ public void cancelWithMultipartContent() {
104
143
105
144
writer .write (Mono .just (builder .build ()), null , MediaType .MULTIPART_FORM_DATA ,
106
145
outputMessage , Collections .emptyMap ()).block (Duration .ofSeconds (5 ));
107
-
108
- this .bufferFactory .checkForLeaks ();
109
146
}
110
147
111
148
@ Test // gh-22107
@@ -116,8 +153,6 @@ public void cancelWithSse() {
116
153
117
154
writer .write (Mono .just (event ), ResolvableType .forClass (ServerSentEvent .class ), MediaType .TEXT_EVENT_STREAM ,
118
155
outputMessage , Collections .emptyMap ()).block (Duration .ofSeconds (5 ));
119
-
120
- this .bufferFactory .checkForLeaks ();
121
156
}
122
157
123
158
@@ -183,4 +218,13 @@ protected void hookOnSubscribe(Subscription subscription) {
183
218
// Just subscribe without requesting
184
219
}
185
220
}
221
+
222
+
223
+ private static class ZeroDemandMessageSubscriber extends BaseSubscriber <Message > {
224
+
225
+ @ Override
226
+ protected void hookOnSubscribe (Subscription subscription ) {
227
+ // Just subscribe without requesting
228
+ }
229
+ }
186
230
}
0 commit comments