1
+ /*
2
+ * ====================================================================
3
+ * Licensed to the Apache Software Foundation (ASF) under one
4
+ * or more contributor license agreements. See the NOTICE file
5
+ * distributed with this work for additional information
6
+ * regarding copyright ownership. The ASF licenses this file
7
+ * to you under the Apache License, Version 2.0 (the
8
+ * "License"); you may not use this file except in compliance
9
+ * with the License. You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing,
14
+ * software distributed under the License is distributed on an
15
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ * KIND, either express or implied. See the License for the
17
+ * specific language governing permissions and limitations
18
+ * under the License.
19
+ * ====================================================================
20
+ *
21
+ * This software consists of voluntary contributions made by many
22
+ * individuals on behalf of the Apache Software Foundation. For more
23
+ * information on the Apache Software Foundation, please see
24
+ * <http://www.apache.org/>.
25
+ *
26
+ */
27
+ package org .apache .hc .client5 .testing .async ;
28
+
29
+ import java .io .IOException ;
30
+ import java .util .Queue ;
31
+ import java .util .concurrent .ConcurrentLinkedQueue ;
32
+ import java .util .concurrent .CountDownLatch ;
33
+
34
+ import org .apache .hc .client5 .http .async .methods .SimpleHttpRequest ;
35
+ import org .apache .hc .client5 .http .async .methods .SimpleHttpResponse ;
36
+ import org .apache .hc .client5 .http .async .methods .SimpleRequestBuilder ;
37
+ import org .apache .hc .client5 .http .async .methods .SimpleRequestProducer ;
38
+ import org .apache .hc .client5 .http .async .methods .SimpleResponseConsumer ;
39
+ import org .apache .hc .client5 .http .protocol .HttpClientContext ;
40
+ import org .apache .hc .client5 .testing .Result ;
41
+ import org .apache .hc .client5 .testing .extension .async .ClientProtocolLevel ;
42
+ import org .apache .hc .client5 .testing .extension .async .ServerProtocolLevel ;
43
+ import org .apache .hc .client5 .testing .extension .async .TestAsyncClient ;
44
+ import org .apache .hc .core5 .concurrent .FutureCallback ;
45
+ import org .apache .hc .core5 .http .ContentType ;
46
+ import org .apache .hc .core5 .http .EntityDetails ;
47
+ import org .apache .hc .core5 .http .HttpException ;
48
+ import org .apache .hc .core5 .http .HttpHost ;
49
+ import org .apache .hc .core5 .http .HttpRequest ;
50
+ import org .apache .hc .core5 .http .HttpStatus ;
51
+ import org .apache .hc .core5 .http .RequestNotExecutedException ;
52
+ import org .apache .hc .core5 .http .URIScheme ;
53
+ import org .apache .hc .core5 .http .nio .AsyncRequestConsumer ;
54
+ import org .apache .hc .core5 .http .nio .AsyncServerRequestHandler ;
55
+ import org .apache .hc .core5 .http .nio .entity .DiscardingEntityConsumer ;
56
+ import org .apache .hc .core5 .http .nio .entity .StringAsyncEntityProducer ;
57
+ import org .apache .hc .core5 .http .nio .support .AbstractAsyncPushHandler ;
58
+ import org .apache .hc .core5 .http .nio .support .AbstractAsyncRequesterConsumer ;
59
+ import org .apache .hc .core5 .http .nio .support .AbstractServerExchangeHandler ;
60
+ import org .apache .hc .core5 .http .nio .support .BasicPushProducer ;
61
+ import org .apache .hc .core5 .http .nio .support .BasicResponseProducer ;
62
+ import org .apache .hc .core5 .http .protocol .HttpContext ;
63
+ import org .apache .hc .core5 .http .support .BasicRequestBuilder ;
64
+ import org .apache .hc .core5 .http .support .BasicResponseBuilder ;
65
+ import org .apache .hc .core5 .http2 .config .H2Config ;
66
+ import org .junit .jupiter .api .Assertions ;
67
+ import org .junit .jupiter .api .Test ;
68
+
69
+ abstract class AbstractH2AsyncFundamentalsTest extends AbstractHttpAsyncFundamentalsTest {
70
+
71
+ public AbstractH2AsyncFundamentalsTest (final URIScheme scheme , final ClientProtocolLevel clientProtocolLevel , final ServerProtocolLevel serverProtocolLevel ) {
72
+ super (scheme , clientProtocolLevel , serverProtocolLevel );
73
+ }
74
+
75
+ @ Test
76
+ void testPush () throws Exception {
77
+ configureServer (bootstrap -> bootstrap
78
+ .register ("/pushy" , () -> new AbstractServerExchangeHandler <HttpRequest >() {
79
+
80
+ @ Override
81
+ protected AsyncRequestConsumer <HttpRequest > supplyConsumer (
82
+ final HttpRequest request ,
83
+ final EntityDetails entityDetails ,
84
+ final HttpContext context ) throws HttpException {
85
+
86
+ return new AbstractAsyncRequesterConsumer <HttpRequest , Void >(new DiscardingEntityConsumer <>()) {
87
+
88
+ @ Override
89
+ protected HttpRequest buildResult (final HttpRequest request , final Void entity , final ContentType contentType ) {
90
+ return request ;
91
+ }
92
+
93
+ };
94
+ }
95
+
96
+ @ Override
97
+ protected void handle (
98
+ final HttpRequest request ,
99
+ final AsyncServerRequestHandler .ResponseTrigger responseTrigger ,
100
+ final HttpContext context ) throws HttpException , IOException {
101
+ responseTrigger .pushPromise (
102
+ BasicRequestBuilder .copy (request )
103
+ .setPath ("/aaa" )
104
+ .build (),
105
+ context ,
106
+ new BasicPushProducer (BasicResponseBuilder .create (HttpStatus .SC_OK )
107
+ .build (),
108
+ new StringAsyncEntityProducer ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" , ContentType .TEXT_PLAIN )));
109
+ responseTrigger .pushPromise (
110
+ BasicRequestBuilder .copy (request )
111
+ .setPath ("/bbb" )
112
+ .build (),
113
+ context ,
114
+ new BasicPushProducer (
115
+ BasicResponseBuilder .create (HttpStatus .SC_OK ).build (),
116
+ new StringAsyncEntityProducer ("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" , ContentType .TEXT_PLAIN )));
117
+ responseTrigger .submitResponse (
118
+ new BasicResponseProducer (
119
+ BasicResponseBuilder .create (HttpStatus .SC_OK ).build (),
120
+ new StringAsyncEntityProducer ("I am being very pushy" )
121
+ ),
122
+ context );
123
+ }
124
+
125
+ }));
126
+
127
+ configureClient (builder -> builder
128
+ .setH2Config (H2Config .custom ()
129
+ .setPushEnabled (true )
130
+ .build ()));
131
+
132
+ final HttpHost target = startServer ();
133
+
134
+ final TestAsyncClient client = startClient ();
135
+
136
+ client .start ();
137
+
138
+ final Queue <Result <String >> pushMessageQueue = new ConcurrentLinkedQueue <>();
139
+ final CountDownLatch latch = new CountDownLatch (3 );
140
+ final HttpClientContext context = HttpClientContext .create ();
141
+ final SimpleHttpRequest request = SimpleRequestBuilder .get ()
142
+ .setHttpHost (target )
143
+ .setPath ("/pushy" )
144
+ .build ();
145
+ client .execute (
146
+ SimpleRequestProducer .create (request ),
147
+ SimpleResponseConsumer .create (),
148
+ (r , c ) -> new AbstractAsyncPushHandler <SimpleHttpResponse >(SimpleResponseConsumer .create ()) {
149
+
150
+ @ Override
151
+ protected void handleResponse (final HttpRequest promise ,
152
+ final SimpleHttpResponse response ) throws IOException , HttpException {
153
+ pushMessageQueue .add (new Result <>(promise , response , response .getBodyText ()));
154
+ latch .countDown ();
155
+ }
156
+
157
+ @ Override
158
+ protected void handleError (final HttpRequest promise , final Exception cause ) {
159
+ pushMessageQueue .add (new Result <>(promise , cause ));
160
+ latch .countDown ();
161
+ }
162
+
163
+ },
164
+ context ,
165
+ new FutureCallback <SimpleHttpResponse >() {
166
+
167
+ @ Override
168
+ public void completed (final SimpleHttpResponse response ) {
169
+ pushMessageQueue .add (new Result <>(request , response , response .getBodyText ()));
170
+ latch .countDown ();
171
+ }
172
+
173
+ @ Override
174
+ public void failed (final Exception ex ) {
175
+ pushMessageQueue .add (new Result <>(request , ex ));
176
+ latch .countDown ();
177
+ }
178
+
179
+ @ Override
180
+ public void cancelled () {
181
+ pushMessageQueue .add (new Result <>(request , new RequestNotExecutedException ()));
182
+ latch .countDown ();
183
+ }
184
+
185
+ }
186
+ );
187
+ Assertions .assertTrue (latch .await (TIMEOUT .getDuration (), TIMEOUT .getTimeUnit ()));
188
+ Assertions .assertEquals (3 , pushMessageQueue .size ());
189
+ for (final Result <String > result : pushMessageQueue ) {
190
+ if (result .isOK ()) {
191
+ Assertions .assertEquals (HttpStatus .SC_OK , result .response .getCode ());
192
+ final String path = result .request .getPath ();
193
+ if (path .equals ("/pushy" )) {
194
+ Assertions .assertEquals ("I am being very pushy" , result .content );
195
+ } else if (path .equals ("/aaa" )) {
196
+ Assertions .assertEquals ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" , result .content );
197
+ } else if (path .equals ("/bbb" )) {
198
+ Assertions .assertEquals ("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" , result .content );
199
+ } else {
200
+ Assertions .fail ("Unxpected request path: " + path );
201
+ }
202
+ }
203
+ }
204
+ }
205
+
206
+ }
0 commit comments