1578979df7
Reviewed-by: chegar, dfuchs
175 lines
6.9 KiB
Java
175 lines
6.9 KiB
Java
/*
|
|
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
import java.io.IOException;
|
|
import java.net.DatagramSocket;
|
|
import java.net.MulticastSocket;
|
|
import java.net.ServerSocket;
|
|
import java.net.Socket;
|
|
import java.net.SocketOption;
|
|
import java.nio.channels.DatagramChannel;
|
|
import java.nio.channels.NetworkChannel;
|
|
import java.nio.channels.ServerSocketChannel;
|
|
import java.nio.channels.SocketChannel;
|
|
import java.util.Set;
|
|
import java.util.stream.Stream;
|
|
import org.testng.annotations.Test;
|
|
import org.testng.annotations.DataProvider;
|
|
|
|
import static java.net.StandardSocketOptions.*;
|
|
|
|
/*
|
|
* @test
|
|
* @bug 8235141
|
|
* @summary verifies that our implementation supports the set
|
|
* of SocketOptions that are required by the API documentation.
|
|
* @run testng/othervm RequiredOptions
|
|
*/
|
|
public class RequiredOptions {
|
|
|
|
static final Set<SocketOption<?>> DATAGRAM_OPTIONS =
|
|
Set.of(SO_BROADCAST, SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR, IP_TOS);
|
|
static final Set<SocketOption<?>> MULTICAST_OPTIONS =
|
|
concat(DATAGRAM_OPTIONS, Set.of(IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL));
|
|
static final Set<SocketOption<?>> SOCKET_OPTIONS =
|
|
Set.of(SO_KEEPALIVE, SO_LINGER, SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR, TCP_NODELAY);
|
|
static final Set<SocketOption<?>> SERVER_OPTIONS =
|
|
Set.of(SO_RCVBUF, SO_REUSEADDR);
|
|
|
|
static Set<SocketOption<?>> concat(Set<SocketOption<?>> ...options) {
|
|
return Set.of(Stream.of(options).flatMap(Set::stream).distinct().toArray(SocketOption[]::new));
|
|
}
|
|
|
|
@DataProvider(name = "sockets")
|
|
static Object[][] provider() throws IOException {
|
|
return new Object[][] {
|
|
// UDP
|
|
{ Configurable.of(new DatagramSocket(null)), DATAGRAM_OPTIONS },
|
|
{ Configurable.of(new MulticastSocket(null)), MULTICAST_OPTIONS },
|
|
// TCP
|
|
{ Configurable.of(new Socket()), SOCKET_OPTIONS },
|
|
{ Configurable.of(new ServerSocket()), SERVER_OPTIONS },
|
|
// Adaptors
|
|
{ Configurable.of(DatagramChannel.open().socket()), MULTICAST_OPTIONS },
|
|
{ Configurable.of(SocketChannel.open().socket()), SOCKET_OPTIONS },
|
|
{ Configurable.of(ServerSocketChannel.open().socket()), SERVER_OPTIONS },
|
|
};
|
|
}
|
|
|
|
@Test(dataProvider = "sockets")
|
|
public <R, E extends Exception>
|
|
void test(Configurable<R,E> socket, Set<SocketOption<?>> options) throws E {
|
|
try (var s = socket) {
|
|
var impl = socket.socket().getClass();
|
|
System.out.println("Testing " + impl + " with " + options);
|
|
Set<SocketOption<?>> supported = socket.supportedOptions();
|
|
if (!supported.containsAll(options)) {
|
|
for (var option : options) {
|
|
if (!supported.contains(option)) {
|
|
System.err.println("Option " + option + " not supported by " + impl);
|
|
}
|
|
}
|
|
throw new AssertionError("Not all documented options are supported by " + impl);
|
|
}
|
|
}
|
|
}
|
|
|
|
static interface Configurable<R, E extends Exception> extends AutoCloseable {
|
|
<T> R setOption(SocketOption<T> name, T value) throws E;
|
|
<T> T getOption(SocketOption<T> name) throws E;
|
|
Set<SocketOption<?>> supportedOptions() throws E;
|
|
R socket();
|
|
void close() throws E;
|
|
|
|
static Configurable<DatagramSocket, IOException> of(DatagramSocket socket) {
|
|
return new ConfigurableImpl<>(socket, socket::setOption,
|
|
socket::getOption, socket::supportedOptions, socket::close);
|
|
}
|
|
static Configurable<Socket, IOException> of(Socket socket) {
|
|
return new ConfigurableImpl<>(socket, socket::setOption,
|
|
socket::getOption, socket::supportedOptions, socket::close);
|
|
}
|
|
static Configurable<ServerSocket, IOException> of(ServerSocket socket) {
|
|
return new ConfigurableImpl<>(socket, socket::setOption,
|
|
socket::getOption, socket::supportedOptions, socket::close);
|
|
}
|
|
}
|
|
|
|
static final class ConfigurableImpl<R, E extends Exception> implements Configurable<R, E> {
|
|
@FunctionalInterface
|
|
interface SetOption<R, E extends Exception> {
|
|
<T> R setOption(SocketOption<T> name, T value) throws E;
|
|
}
|
|
@FunctionalInterface
|
|
interface GetOption<E extends Exception> {
|
|
<T> T getOption(SocketOption<T> name) throws E;
|
|
}
|
|
@FunctionalInterface
|
|
interface SupportedOption<E extends Exception> {
|
|
Set<SocketOption<?>> supportedOptions() throws E;
|
|
}
|
|
@FunctionalInterface
|
|
interface Closer<E extends Exception> {
|
|
void close() throws E;
|
|
}
|
|
|
|
private final R socket;
|
|
private final SetOption<R, E> setter;
|
|
private final GetOption<E> getter;
|
|
private final SupportedOption<E> support;
|
|
private final Closer<E> closer;
|
|
|
|
public ConfigurableImpl(R socket, SetOption<R, E> setter, GetOption<E> getter,
|
|
SupportedOption<E> support, Closer<E> closer) {
|
|
this.socket = socket;
|
|
this.setter = setter;
|
|
this.getter = getter;
|
|
this.support = support;
|
|
this.closer = closer;
|
|
}
|
|
|
|
@Override
|
|
public <T> R setOption(SocketOption<T> name, T value) throws E {
|
|
return setter.setOption(name, value);
|
|
}
|
|
@Override
|
|
public <T> T getOption(SocketOption<T> name) throws E {
|
|
return getter.getOption(name);
|
|
}
|
|
@Override
|
|
public Set<SocketOption<?>> supportedOptions() throws E {
|
|
return support.supportedOptions();
|
|
}
|
|
@Override
|
|
public R socket() {
|
|
return socket;
|
|
}
|
|
@Override
|
|
public void close() throws E {
|
|
closer.close();
|
|
}
|
|
}
|
|
|
|
|
|
}
|