11package ru .tinkoff .kora .http .server .common ;
22
3+ import static java .time .Instant .now ;
4+ import static org .assertj .core .api .Assertions .assertThat ;
5+ import static org .assertj .core .api .Assertions .assertThatThrownBy ;
6+ import static org .junit .jupiter .api .Assertions .fail ;
7+ import static org .mockito .Mockito .never ;
8+ import static org .mockito .Mockito .timeout ;
9+ import static org .mockito .Mockito .verify ;
10+ import static org .mockito .Mockito .when ;
11+ import static ru .tinkoff .kora .http .common .HttpMethod .GET ;
12+ import static ru .tinkoff .kora .http .common .HttpMethod .POST ;
13+
314import io .opentelemetry .api .trace .Span ;
15+ import java .io .IOException ;
16+ import java .io .OutputStream ;
17+ import java .nio .ByteBuffer ;
18+ import java .nio .charset .StandardCharsets ;
19+ import java .time .Duration ;
20+ import java .util .ArrayList ;
21+ import java .util .List ;
22+ import java .util .Optional ;
23+ import java .util .concurrent .CompletableFuture ;
24+ import java .util .concurrent .ConcurrentLinkedDeque ;
25+ import java .util .concurrent .ExecutionException ;
26+ import java .util .concurrent .Executors ;
27+ import java .util .concurrent .ForkJoinPool ;
28+ import java .util .concurrent .ThreadLocalRandom ;
29+ import java .util .concurrent .TimeUnit ;
30+ import java .util .function .Supplier ;
431import okhttp3 .ConnectionPool ;
532import okhttp3 .OkHttpClient ;
633import okhttp3 .Request ;
734import okhttp3 .RequestBody ;
835import okio .BufferedSink ;
936import org .jetbrains .annotations .NotNull ;
1037import org .jspecify .annotations .Nullable ;
11- import org .junit .jupiter .api .*;
38+ import org .junit .jupiter .api .AfterEach ;
39+ import org .junit .jupiter .api .Assertions ;
40+ import org .junit .jupiter .api .Nested ;
41+ import org .junit .jupiter .api .Test ;
42+ import org .junit .jupiter .api .TestInstance ;
1243import org .mockito .AdditionalAnswers ;
1344import org .mockito .ArgumentMatchers ;
1445import org .mockito .Mockito ;
3263import ru .tinkoff .kora .http .server .common .privateapi .MetricsHandler ;
3364import ru .tinkoff .kora .http .server .common .privateapi .ReadinessHandler ;
3465import ru .tinkoff .kora .http .server .common .router .HttpServerHandler ;
35- import ru .tinkoff .kora .http .server .common .telemetry .*;
66+ import ru .tinkoff .kora .http .server .common .telemetry .$HttpServerTelemetryConfig_ConfigValueExtractor ;
67+ import ru .tinkoff .kora .http .server .common .telemetry .$HttpServerTelemetryConfig_HttpServerLoggingConfig_ConfigValueExtractor ;
68+ import ru .tinkoff .kora .http .server .common .telemetry .$HttpServerTelemetryConfig_HttpServerMetricsConfig_ConfigValueExtractor ;
69+ import ru .tinkoff .kora .http .server .common .telemetry .$HttpServerTelemetryConfig_HttpServerTracingConfig_ConfigValueExtractor ;
70+ import ru .tinkoff .kora .http .server .common .telemetry .HttpServerObservation ;
71+ import ru .tinkoff .kora .http .server .common .telemetry .HttpServerTelemetry ;
72+ import ru .tinkoff .kora .http .server .common .telemetry .NoopHttpServerTelemetry ;
3673import ru .tinkoff .kora .telemetry .common .MetricsScraper ;
3774
38- import java .io .IOException ;
39- import java .io .OutputStream ;
40- import java .nio .ByteBuffer ;
41- import java .nio .charset .StandardCharsets ;
42- import java .time .Duration ;
43- import java .util .ArrayList ;
44- import java .util .List ;
45- import java .util .Optional ;
46- import java .util .concurrent .*;
47- import java .util .function .Supplier ;
48-
49- import static java .time .Instant .now ;
50- import static org .assertj .core .api .Assertions .assertThat ;
51- import static org .assertj .core .api .Assertions .assertThatThrownBy ;
52- import static org .junit .jupiter .api .Assertions .fail ;
53- import static org .mockito .Mockito .*;
54- import static ru .tinkoff .kora .http .common .HttpMethod .GET ;
55- import static ru .tinkoff .kora .http .common .HttpMethod .POST ;
56-
5775@ TestInstance (TestInstance .Lifecycle .PER_METHOD )
5876public abstract class HttpServerTestKit {
5977 protected static MetricsScraper registry = Mockito .mock (MetricsScraper .class );
@@ -74,6 +92,7 @@ public abstract class HttpServerTestKit {
7492
7593 private volatile HttpServer httpServer = null ;
7694 private volatile HttpServer privateHttpServer = null ;
95+ private volatile HttpServer internalHttpServer = null ;
7796
7897 protected final OkHttpClient client = new OkHttpClient .Builder ()
7998 .connectionPool (new ConnectionPool (0 , 1 , TimeUnit .MICROSECONDS ))
@@ -190,6 +209,84 @@ void testReadinessFailureOnUninitializedProbe() throws IOException {
190209 }
191210
192211
212+ @ Nested
213+ public class InternalApiTest {
214+ @ Test
215+ void testNoopHttpServerWhenNoHandlers () {
216+ var noopServer = NoopHttpServer .INSTANCE ;
217+ assertThat (noopServer .port ()).isEqualTo (-1 );
218+ Assertions .assertDoesNotThrow (noopServer ::init );
219+ Assertions .assertDoesNotThrow (noopServer ::release );
220+ }
221+
222+ @ Test
223+ void testInternalApiHelloWorld () throws IOException {
224+ var httpResponse = HttpServerResponse .of (200 , HttpBody .plaintext ("internal hello" ));
225+ var handler = handler (GET , "/internal" , (_ ) -> httpResponse );
226+ startInternalHttpServer (handler );
227+
228+ var request = internalApiRequest ("/internal" )
229+ .get ()
230+ .build ();
231+
232+ try (var response = client .newCall (request ).execute ()) {
233+ assertThat (response .code ()).isEqualTo (200 );
234+ assertThat (response .body ().string ()).isEqualTo ("internal hello" );
235+ }
236+ }
237+
238+ @ Test
239+ void testInternalApiUnknownPath () throws IOException {
240+ var handler = handler (GET , "/internal" , (_ ) -> HttpServerResponse .of (200 ));
241+ startInternalHttpServer (handler );
242+
243+ var request = internalApiRequest ("/unknown" )
244+ .get ()
245+ .build ();
246+
247+ try (var response = client .newCall (request ).execute ()) {
248+ assertThat (response .code ()).isEqualTo (404 );
249+ }
250+ }
251+
252+ @ Test
253+ void testInternalApiWithInterceptor () throws IOException {
254+ var httpResponse = HttpServerResponse .of (200 , HttpBody .plaintext ("internal hello" ));
255+ var handler = handler (GET , "/internal" , (_ ) -> httpResponse );
256+ var interceptor = new HttpServerInterceptor () {
257+ @ Override
258+ public HttpServerResponse intercept (HttpServerRequest request , InterceptChain chain ) throws Exception {
259+ var header = request .headers ().getFirst ("x-internal-block" );
260+ if (header != null ) {
261+ request .body ().close ();
262+ return HttpServerResponse .of (403 , HttpBody .plaintext ("blocked" ));
263+ }
264+ return chain .process (request );
265+ }
266+ };
267+ startInternalHttpServer (List .of (interceptor ), handler );
268+
269+ var request = internalApiRequest ("/internal" )
270+ .get ()
271+ .build ();
272+
273+ try (var response = client .newCall (request ).execute ()) {
274+ assertThat (response .code ()).isEqualTo (200 );
275+ assertThat (response .body ().string ()).isEqualTo ("internal hello" );
276+ }
277+
278+ var blockedRequest = internalApiRequest ("/internal" )
279+ .header ("x-internal-block" , "true" )
280+ .get ()
281+ .build ();
282+
283+ try (var response = client .newCall (blockedRequest ).execute ()) {
284+ assertThat (response .code ()).isEqualTo (403 );
285+ assertThat (response .body ().string ()).isEqualTo ("blocked" );
286+ }
287+ }
288+ }
289+
193290 @ Nested
194291 public class PublicApiTest {
195292 @ Test
@@ -990,6 +1087,34 @@ protected void startPrivateHttpServer() {
9901087 }
9911088 }
9921089
1090+ protected void startInternalHttpServer (HttpServerRequestHandler ... handlers ) {
1091+ startInternalHttpServer (List .of (), handlers );
1092+ }
1093+
1094+ protected void startInternalHttpServer (List <HttpServerInterceptor > interceptors , HttpServerRequestHandler ... handlers ) {
1095+ var config = new HttpServerConfig_Impl (
1096+ 0 ,
1097+ false ,
1098+ Duration .ofSeconds (1 ),
1099+ Duration .ofSeconds (1 ),
1100+ false ,
1101+ Duration .ofMillis (1 ),
1102+ new $HttpServerTelemetryConfig_ConfigValueExtractor .HttpServerTelemetryConfig_Impl (
1103+ new $HttpServerTelemetryConfig_HttpServerLoggingConfig_ConfigValueExtractor .HttpServerLoggingConfig_Defaults (),
1104+ new $HttpServerTelemetryConfig_HttpServerMetricsConfig_ConfigValueExtractor .HttpServerMetricsConfig_Defaults (),
1105+ new $HttpServerTelemetryConfig_HttpServerTracingConfig_ConfigValueExtractor .HttpServerTracingConfig_Defaults ()
1106+ ),
1107+ Size .of (1 , Size .Type .GiB )
1108+ );
1109+ var internalApiHandler = new HttpServerHandler (List .of (handlers ), interceptors , config );
1110+ this .internalHttpServer = this .httpServer (valueOf (config ), internalApiHandler , this .telemetry );
1111+ try {
1112+ this .internalHttpServer .init ();
1113+ } catch (Exception e ) {
1114+ throw new RuntimeException (e );
1115+ }
1116+ }
1117+
9931118 @ AfterEach
9941119 void tearDown () throws Exception {
9951120 if (this .httpServer != null ) {
@@ -1000,6 +1125,10 @@ void tearDown() throws Exception {
10001125 this .privateHttpServer .release ();
10011126 this .privateHttpServer = null ;
10021127 }
1128+ if (this .internalHttpServer != null ) {
1129+ this .internalHttpServer .release ();
1130+ this .internalHttpServer = null ;
1131+ }
10031132 this .readinessProbePromise .setValue (readinessProbe );
10041133 this .livenessProbePromise .setValue (livenessProbe );
10051134 }
@@ -1021,6 +1150,10 @@ protected Request.Builder privateApiRequest(String path) {
10211150 return request (this .privateHttpServer .port (), path );
10221151 }
10231152
1153+ protected Request .Builder internalApiRequest (String path ) {
1154+ return request (this .internalHttpServer .port (), path );
1155+ }
1156+
10241157 protected Request .Builder request (String path ) {
10251158 return request (this .httpServer .port (), path );
10261159 }
0 commit comments