static ThriftServerRunner createBoundServer(Supplier<ThriftServer> thriftServerSupplier,
    ImplType implType, boolean specifyFramed, boolean specifyCompact, boolean specifyBindIP,
    boolean protocolPortClash, boolean infoPortClash) throws Exception {
    if (protocolPortClash && infoPortClash) {
      throw new RuntimeException("Can't set both at same time");
    }
    boolean testClashOfFirstProtocolPort = protocolPortClash;
    boolean testClashOfFirstInfoPort = infoPortClash;
    List<String> args = new ArrayList<>();
    BoundSocketMaker bsm = null;
    int port = -1;
    ThriftServerRunner tsr = null;
    for (int i = 0; i < 100; i++) {
      args.clear();
      if (implType != null) {
        String serverTypeOption = implType.toString();
        assertTrue(serverTypeOption.startsWith("-"));
        args.add(serverTypeOption);
      }
      if (testClashOfFirstProtocolPort) {
        // Test what happens if already something bound to the socket.
        // Occupy the random port we just pulled.
        bsm = new BoundSocketMaker(() -> getRandomPort());
        port = bsm.getPort();
        testClashOfFirstProtocolPort = false;
      } else {
        port = getRandomPort();
      }
      args.add("-" + PORT_OPTION);
      args.add(String.valueOf(port));
      args.add("-" + INFOPORT_OPTION);
      int infoPort;
      if (testClashOfFirstInfoPort) {
        bsm = new BoundSocketMaker(() -> getRandomPort());
        infoPort = bsm.getPort();
        testClashOfFirstInfoPort = false;
      } else {
        infoPort = getRandomPort();
      }
      args.add(String.valueOf(infoPort));

      if (specifyFramed) {
        args.add("-" + FRAMED_OPTION);
      }
      if (specifyBindIP) {
        args.add("-" + BIND_OPTION);
        args.add(InetAddress.getLoopbackAddress().getHostName());
      }
      if (specifyCompact) {
        args.add("-" + COMPACT_OPTION);
      }
      args.add("start");

      tsr = startCmdLineThread(thriftServerSupplier, args.toArray(new String[args.size()]));
      // wait up to 10s for the server to start
      for (int ii = 0; ii < 100
        && (tsr.getThriftServer().tserver == null && tsr.getRunException() == null); ii++) {
        Threads.sleep(100);
      }
      if (isBindException(tsr.getRunException())) {
        LOG.info("BindException; trying new port", tsr.getRunException());
        try {
          tsr.close();
          tsr.join();
        } catch (IOException | InterruptedException ioe) {
          LOG.warn("Exception closing", ioe);
        }
        continue;
      }
      break;
    }
    if (bsm != null) {
      try {
        bsm.close();
      } catch (IOException ioe) {
        LOG.warn("Failed close", ioe);
      }
    }
    if (tsr.getRunException() != null) {
      throw tsr.getRunException();
    }
    if (tsr.getThriftServer().tserver != null) {
      Class<? extends TServer> expectedClass =
        implType != null ? implType.serverClass : TBoundedThreadPoolServer.class;
      assertEquals(expectedClass, tsr.getThriftServer().tserver.getClass());
    }
    return tsr;
  }
@param protocolPortClash This param is just so we can manufacture a port clash so we can test
                         the code does the right thing when this happens during actual test
                         runs. Ugly but works.
@see TestBindExceptionHandling#testProtocolPortClash()
hbase-thrift/src/test/java/org/apache/hadoop/hbase/thrift/TestThriftServerCmdLine.java