001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.microservice.test;
018
019import java.time.*;
020
021import org.apache.juneau.commons.inject.*;
022import org.apache.juneau.microservice.jetty.*;
023import org.eclipse.jetty.ee11.servlet.*;
024import org.eclipse.jetty.server.*;
025
026/**
027 * A {@code @Configuration} that supplies a Jetty {@link Server} bound to an OS-assigned ephemeral port
028 * (port {@code 0}) for use by {@link MicroserviceExtension @MicroserviceTest}-driven integration tests.
029 *
030 * <p>
031 * The server has a single {@link ServerConnector} on port 0 and a single root {@link ServletContextHandler}
032 * at context path {@code "/"}.  {@code JettyServerComponent} discovers the handler via the
033 * {@code "ServletContextHandler"} server attribute (the same convention used by {@code jetty.xml}).
034 *
035 * <p>
036 * The extension installs this {@code @Configuration} automatically after the user-supplied configurations, so
037 * a user-supplied {@code @Bean Server} (if any) still wins (the bean store returns the first registered match).
038 * Tests supply their {@code @Bean Servlet} definitions, which {@code JettyServerComponent} auto-mounts at the
039 * resource's {@code @Rest(path=...)}.
040 *
041 * @since 10.0.0
042 */
043@Configuration
044public class EphemeralJettyServerConfig {
045
046   /**
047    * Provides the bean-supplied Jetty {@link Server} that {@code JettyServerComponent} consumes during
048    * {@code onStart()}.
049    *
050    * @return A configured {@link Server} bound to port 0 (OS-assigned ephemeral port).
051    */
052   @Bean
053   @SuppressWarnings({
054      "resource" // connector is added to and owned by the server; closed when the server stops.
055   })
056   public Server jettyServer() {
057      var server = new Server();
058      var connector = new ServerConnector(server);
059      connector.setPort(0);
060      server.addConnector(connector);
061      var sch = new ServletContextHandler();
062      sch.setContextPath("/");
063      server.setAttribute("ServletContextHandler", sch);
064      server.setHandler(sch);
065      return server;
066   }
067
068   /**
069    * Disables the 30s graceful-shutdown drain wait for integration tests.
070    *
071    * <p>
072    * {@code JettyServerComponent} applies a 30s {@code stopTimeout} default to support zero-downtime k8s
073    * rollouts.  In ephemeral test servers there are no load balancers or in-flight production traffic, so
074    * the drain wait only adds ~1s per test class to the suite runtime.  Setting it to zero restores fast
075    * shutdown.
076    *
077    * @return {@link JettySettings} with {@code stopTimeout} set to zero.
078    */
079   @Bean
080   public JettySettings jettySettings() {
081      return JettySettings.create()
082         .stopTimeout(Duration.ZERO)
083         .build();
084   }
085}