View Javadoc
1   /*
2    * Copyright 2023 Adrian Herscu
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package dev.aherscu.qa.testing.example;
17  
18  import java.io.*;
19  import java.net.*;
20  
21  import org.mockserver.client.*;
22  import org.mockserver.integration.*;
23  import org.testng.annotations.*;
24  
25  import dev.aherscu.qa.jgiven.commons.model.*;
26  import dev.aherscu.qa.jgiven.commons.steps.*;
27  import dev.aherscu.qa.jgiven.commons.utils.*;
28  import dev.aherscu.qa.testing.utils.config.*;
29  import jakarta.ws.rs.core.*;
30  import lombok.*;
31  import lombok.extern.slf4j.*;
32  
33  /**
34   * Contains REST sample tests just to ensure that the testing infrastructure
35   * works as required.
36   *
37   * @author aherscu
38   * @param <T>
39   *            type of scenario
40   * @param <GIVEN>
41   *            type of fixtures
42   * @param <WHEN>
43   *            type of actions
44   * @param <THEN>
45   *            type of verifications
46   *
47   */
48  @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
49      value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE",
50      justification = "JGiven framework limitation")
51  @Slf4j
52  abstract public class AbstractMockServerTest<T extends AnyScenarioType, GIVEN extends GenericFixtures<T, ?> & ScenarioType<T>, WHEN extends GenericActions<T, ?> & ScenarioType<T>, THEN extends GenericVerifications<T, ?> & ScenarioType<T>>
53      extends
54      ConfigurableScenarioTest<BaseConfiguration, T, GIVEN, WHEN, THEN> {
55  
56      public static final int          DEFAULT_PORT = 1080;
57  
58      protected final MockServerClient mockServer;
59  
60      private final boolean            usingOutOfProcessMockServer;
61  
62      /**
63       * If port 1080 is free will initiate an in-process MockServer, otherwise
64       * will try connecting to port 1080.
65       */
66      protected AbstractMockServerTest() {
67          super(BaseConfiguration.class);
68  
69          usingOutOfProcessMockServer = canUseOutOfProcessMockServer();
70  
71          log.debug("using out-of-process MockServer: {}",
72              usingOutOfProcessMockServer);
73  
74          mockServer = usingOutOfProcessMockServer
75              ? new MockServerClient("localhost", outOfProcessPort())
76              : ClientAndServer.startClientAndServer(0);
77      }
78  
79      private boolean canUseOutOfProcessMockServer() {
80          try (val socket = new ServerSocket(outOfProcessPort())) {
81              socket.close();
82              return false;
83          } catch (final IOException ioe) {
84              return true;
85          }
86      }
87  
88      protected int outOfProcessPort() {
89          return DEFAULT_PORT;
90      }
91  
92      @BeforeClass
93      protected void beforeClassClearMockServer() {
94          mockServer.reset();
95      }
96  
97      @AfterClass(alwaysRun = true)
98      protected void afterClassStopInProcessMockRestServer() {
99          if (!usingOutOfProcessMockServer)
100             mockServer.stop();
101     }
102 
103     protected URI mockServerUri() {
104         return UriBuilder.fromUri("http://{host}:{port}")
105             .build("localhost", mockServer.getPort());
106     }
107 }