Path: blob/master/test/jdk/javax/net/ssl/TLSCommon/interop/BaseInteropTest.java
41154 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.FileOutputStream;24import java.io.IOException;25import java.io.PrintStream;26import java.nio.file.Path;27import java.nio.file.Paths;28import java.util.ArrayList;29import java.util.List;30import java.util.concurrent.Callable;31import java.util.concurrent.ExecutorService;32import java.util.concurrent.Executors;3334/*35* The base interop test on SSL/TLS communication.36*/37public abstract class BaseInteropTest<U extends UseCase> {3839protected final Product serverProduct;40protected final Product clientProduct;41private static final int MAX_SERVER_RETRIES = 3;4243public BaseInteropTest(Product serverProduct, Product clientProduct) {44this.serverProduct = serverProduct;45this.clientProduct = clientProduct;46}4748public boolean isJdkClient() {49return Jdk.DEFAULT.equals(clientProduct);50}5152/*53* This main entrance of the test execution.54*/55protected void execute() throws Exception {56System.out.printf("Server: %s%nClient: %s%n",57serverProduct, clientProduct);5859if (skipExecute()) {60System.out.println("This execution was skipped.");61return;62}6364List<TestCase<U>> testCases = null;6566Path logPath = getLogPath();67if (logPath != null) {68System.out.println("Log: " + logPath);6970PrintStream origStdOut = System.out;71PrintStream origStdErr = System.err;72try (PrintStream printStream = new PrintStream(73new FileOutputStream(logPath.toFile()))) {74System.setOut(printStream);75System.setErr(printStream);7677testCases = runTest();78} finally {79System.setOut(origStdOut);80System.setErr(origStdErr);81}82} else {83testCases = runTest();84}8586boolean fail = false;87System.out.println("########## Failed Cases Start ##########");88for (TestCase<U> testCase : testCases) {89if (testCase.getStatus() == Status.FAIL) {90System.out.println("--------------------");91System.out.println(testCase);92System.out.println("--------------------");93fail = true;94}95}96System.out.println("########## Failed Cases End ##########");9798if (fail) {99throw new RuntimeException(100"At least one case failed! Please check log for details.");101} else {102System.out.println("This test passed!");103}104}105106/*107* If either of server and client products is unavailable,108* just skip this test execution.109*/110protected boolean skipExecute() {111return serverProduct.getPath() == null || clientProduct.getPath() == null;112}113114/*115* Returns the log path.116* If null, no output will be redirected to local file.117*/118protected Path getLogPath() {119return Utilities.LOG_PATH == null120? null : Paths.get(Utilities.LOG_PATH);121}122123/*124* Provides a default set of test cases for testing.125*/126protected abstract List<TestCase<U>> getTestCases();127128/*129* Checks if test case should be ignored.130*/131protected boolean ignoreTestCase(TestCase<U> testCase) {132return false;133}134135/*136* Runs all test cases with the specified products as server and client137* respectively.138*/139protected List<TestCase<U>> runTest() throws Exception {140List<TestCase<U>> executedTestCases = new ArrayList<>();141142List<TestCase<U>> testCases = getTestCases();143for (TestCase<U> testCase : testCases) {144System.out.println("========== Case Start ==========");145System.out.println(testCase);146147if (!ignoreTestCase(testCase)) {148Status status = runTestCase(testCase);149testCase.setStatus(status);150151executedTestCases.add(testCase);152} else {153System.out.println("Ignored");154}155156System.out.println("========== Case End ==========");157}158159return executedTestCases;160}161162/*163* Runs a specific test case.164*/165protected Status runTestCase(TestCase<U> testCase) throws Exception {166Status serverStatus = Status.UNSTARTED;167Status clientStatus = Status.UNSTARTED;168169ExecutorService executor = Executors.newFixedThreadPool(1);170AbstractServer server = null;171try {172server = startAndGetServer(testCase.serverCase, executor);173int port = server.getPort();174System.out.println("Server is listening " + port);175serverStatus = Status.PASS;176177try (AbstractClient client = createClient(testCase.clientCase)) {178client.connect("localhost", port);179clientStatus = Status.PASS;180181if (testCase.clientCase instanceof ExtUseCase) {182ExtUseCase serverCase = (ExtUseCase) testCase.serverCase;183ExtUseCase clientCase = (ExtUseCase) testCase.clientCase;184185String[] clientAppProtocols = clientCase.getAppProtocols();186if (clientAppProtocols != null && clientAppProtocols.length > 0) {187String expectedNegoAppProtocol = Utilities.expectedNegoAppProtocol(188serverCase.getAppProtocols(),189clientAppProtocols);190System.out.println("Expected negotiated app protocol: "191+ expectedNegoAppProtocol);192String negoAppProtocol = getNegoAppProtocol(server, client);193System.out.println(194"Actual negotiated app protocol: " + negoAppProtocol);195if (!Utilities.trimStr(negoAppProtocol).equals(196Utilities.trimStr(expectedNegoAppProtocol))) {197System.out.println(198"Negotiated app protocol is unexpected");199clientStatus = Status.FAIL;200}201}202}203} catch (Exception exception) {204clientStatus = handleClientException(exception);205}206} catch (Exception exception) {207serverStatus = handleServerException(exception);208} finally {209if (server != null) {210server.signalStop();211server.close();212}213214executor.shutdown();215}216217Status caseStatus218= serverStatus == Status.PASS && clientStatus == Status.PASS219? Status.PASS220: Status.FAIL;221System.out.printf(222"ServerStatus=%s, ClientStatus=%s, CaseStatus=%s%n",223serverStatus, clientStatus, caseStatus);224return caseStatus;225}226227/*228* Return a server once it is properly started to avoid client connection issues.229* Retry operation if needed, server may fail to bind a port230*/231protected AbstractServer startAndGetServer(U useCase, ExecutorService executor)232throws Exception {233int maxRetries = getServerMaxRetries();234boolean serverAlive;235AbstractServer server;236237do {238server = createServer(useCase, executor);239serverAlive = Utilities.waitFor(Server::isAlive, server);240if (!serverAlive) {241server.signalStop();242}243244maxRetries--;245} while (!serverAlive && maxRetries > 0);246247if (!serverAlive) {248throw new RuntimeException("Server failed to start");249}250251return server;252}253254/*255* Handles server side exception, and determines the status.256*/257protected Status handleServerException(Exception exception) {258return handleException(exception);259}260261/*262* Handles client side exception, and determines the status.263*/264protected Status handleClientException(Exception exception) {265return handleException(exception);266}267268private Status handleException(Exception exception) {269if (exception == null) {270return Status.PASS;271}272273exception.printStackTrace(System.out);274return Status.FAIL;275}276277/*278* Creates server.279*/280protected AbstractServer createServer(U useCase, ExecutorService executor) throws Exception {281AbstractServer server = createServerBuilder(useCase).build();282executor.submit(new ServerTask(server));283return server;284}285286protected AbstractServer.Builder createServerBuilder(U useCase)287throws Exception {288return (JdkServer.Builder) ((JdkServer.Builder) new JdkServer.Builder()289.setProtocols(useCase.getProtocols())290.setCipherSuites(useCase.getCipherSuites())291.setCertTuple(useCase.getCertTuple()))292.setClientAuth(useCase.isClientAuth());293}294295/*296* Creates client.297*/298protected AbstractClient createClient(U useCase) throws Exception {299return createClientBuilder(useCase).build();300}301302protected AbstractClient.Builder createClientBuilder(U useCase)303throws Exception {304return (JdkClient.Builder) new JdkClient.Builder()305.setProtocols(useCase.getProtocols())306.setCipherSuites(useCase.getCipherSuites())307.setCertTuple(useCase.getCertTuple());308}309310/*311* Returns the maximum number of attempts to start a server.312*/313protected int getServerMaxRetries() {314return MAX_SERVER_RETRIES;315}316317/*318* Determines the negotiated application protocol.319* Generally, using JDK client to get this value.320*/321protected String getNegoAppProtocol(AbstractServer server,322AbstractClient client) throws SSLTestException {323return isJdkClient() ? client.getNegoAppProtocol()324: server.getNegoAppProtocol();325}326327protected static class ServerTask implements Callable<Void> {328329private final AbstractServer server;330331protected ServerTask(AbstractServer server) {332this.server = server;333}334335@Override336public Void call() throws IOException {337server.accept();338return null;339}340}341342protected static class ClientTask implements Callable<Exception> {343344private final AbstractClient client;345346private final String host;347private final int port;348349protected ClientTask(AbstractClient client, String host, int port) {350this.client = client;351352this.host = host;353this.port = port;354}355356protected ClientTask(AbstractClient client, int port) {357this(client, "localhost", port);358}359360@Override361public Exception call() {362try (AbstractClient c = client) {363c.connect(host, port);364} catch (Exception exception) {365return exception;366}367368return null;369}370}371}372373374