All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ee.jakarta.tck.concurrent.framework.TestClient Maven / Gradle / Ivy

/*
 * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */
package ee.jakarta.tck.concurrent.framework;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Enumeration;
import java.util.Properties;

/**
 * This class is intended to be used in conjunction with TestServlet.
 * TestServlets are deployed to the application server and has custom
 * doGet/doPost methods that will return a successful or failure message
 * depending on the test outcome.
 *
 * The TestClient class has runTest methods that will create an HTTP connection
 * to the TestServlet and provide the TestServlet with the method name it needs
 * to test. The TestClient class will then confirm that it recieved a successful
 * outcome from the test.
 *
 */
public abstract class TestClient {

    private static final TestLogger log = TestLogger.get(TestClient.class);

    public static final String SUCCESS = TestServlet.SUCCESS;
    public static final String FAILURE = TestServlet.FAILURE;
    public static final String TEST_METHOD = TestServlet.TEST_METHOD;

    public static final String nl = System.lineSeparator();

    // ###### run test without response #####

    /**
     * Runs test against servlet at baseURL, and will run against a specified
     * testName.
     */
    public void runTest(final URL baseURL, final String testName) {
        try {
            assertSuccessfulURLResponse(
                    URLBuilder.get().withBaseURL(baseURL).withPaths(getServletPath()).withTestName(testName).build(),
                    null);
        } catch (UnsupportedOperationException e) {
            throw new RuntimeException("Tried to call runTest method without overwritting getServletPath() method.", e);
        }
    }

    /**
     * Runs test against servlet using a URLBuilder. This is useful for complicated
     * testing situations.
     */
    public void runTest(final URLBuilder builder) {
        assertSuccessfulURLResponse(builder.build(), null);
    }

    // ###### run test with response ######

    /**
     * Runs test against servlet at baseURL, and will run against a specified
     * testName. Provide properties if you want them included in a POST request,
     * otherwise pass in null.
     */
    public String runTestWithResponse(final URL baseURL, final String testName, final Properties props) {
        try {
            return assertSuccessfulURLResponse(
                    URLBuilder.get().withBaseURL(baseURL).withPaths(getServletPath()).withTestName(testName).build(),
                    props);
        } catch (UnsupportedOperationException e) {
            throw new RuntimeException("Tried to call runTest method without overwritting getServletPath() method.", e);
        }
    }

    /**
     * Runs test against servlet using a URLBuilder. This is useful for complicated
     * testing situations. Provide properties if you want them included in a POST
     * request, otherwise pass in null.
     */
    public String runTestWithResponse(final URLBuilder builder, final Properties props) {
        return assertSuccessfulURLResponse(builder.build(), props);
    }

    // ##### test runner ######
    private String assertSuccessfulURLResponse(final URL url, final Properties props) {
        log.enter("assertSuccessfulURLResponse", "Calling application with URL=" + url.toString());

        boolean withProps = props != null;
        boolean pass = false;

        HttpURLConnection con = null;
        try {
            con = (HttpURLConnection) url.openConnection();
            con.setDoInput(true);
            con.setDoOutput(true);
            con.setUseCaches(false);
            con.setConnectTimeout((int) Duration.ofSeconds(30).toMillis());

            if (withProps) {
                con.setRequestMethod("POST");
                try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) {
                    wr.writeBytes(toEncodedString(props));
                }

            } else {
                con.setRequestMethod("GET");
            }

            final BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
            final StringBuilder outputBuilder = new StringBuilder();
            String line;

            while ((line = br.readLine()) != null) {
                outputBuilder.append(line).append(nl);

                if (line.contains(SUCCESS)) {
                    pass = true;
                }
            }

            log.exit("assertSuccessfulURLResponse", "Response code: " + con.getResponseCode(),
                    "Response body: " + outputBuilder.toString());

            assertTrue(con.getResponseCode() < 400, "Connection returned a response code that was greater than 400");
            assertTrue(pass, "Output did not contain successful message: " + SUCCESS);

            return outputBuilder.toString();
        } catch (IOException e) {
            throw new RuntimeException("Exception: " + e.getClass().getName() + " requesting URL=" + url.toString(), e);
        } finally {
            if (con != null) {
                con.disconnect();
            }
        }
    }

    static String toEncodedString(final Properties args) throws UnsupportedEncodingException {
        StringBuffer buf = new StringBuffer();
        Enumeration names = args.propertyNames();
        while (names.hasMoreElements()) {
            String name = (String) names.nextElement();
            String value = args.getProperty(name);

            buf.append(URLEncoder.encode(name, StandardCharsets.UTF_8.name())).append("=")
                    .append(URLEncoder.encode(value, StandardCharsets.UTF_8.name()));

            if (names.hasMoreElements())
                buf.append("&");
        }
        return buf.toString();
    }

    /**
     * Override this method to return the servlet path for the suite of tests. Used
     * for the runTest() methods.
     */
    protected String getServletPath() {
        throw new UnsupportedOperationException("Subclass did not override the getServletPath method");
    }

    /**
     * Asserts that the response from a runTestWithResponse method contains a
     * specific string.
     *
     * @param message  - message to display if test fails
     * @param expected - the expected string to find in the response
     * @param resp     - the response you received from the servlet
     */
    protected void assertStringInResponse(final String message, final String expected, final String resp) {
        assertTrue(resp.toLowerCase().contains(expected.toLowerCase()), message);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy