DefaultAsyncHttpClientTest.java
/*
* Copyright (c) 2023 AsyncHttpClient Project. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.asynchttpclient;
import io.github.artsok.RepeatedIfExceptionsTest;
import io.netty.channel.MultiThreadIoEventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.util.Timer;
import org.asynchttpclient.cookie.CookieEvictionTask;
import org.asynchttpclient.cookie.CookieStore;
import org.asynchttpclient.cookie.ThreadSafeCookieStore;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import static org.asynchttpclient.Dsl.asyncHttpClient;
import static org.asynchttpclient.Dsl.config;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class DefaultAsyncHttpClientTest {
@RepeatedIfExceptionsTest(repeats = 5)
@EnabledOnOs(OS.LINUX)
public void testNativeTransportWithEpollOnly() throws Exception {
AsyncHttpClientConfig config = config().setUseNativeTransport(true).setUseOnlyEpollNativeTransport(true).build();
try (DefaultAsyncHttpClient client = (DefaultAsyncHttpClient) asyncHttpClient(config)) {
assertDoesNotThrow(() -> client.prepareGet("https://www.google.com").execute().get());
assertInstanceOf(EpollEventLoopGroup.class, client.channelManager().getEventLoopGroup());
}
}
@RepeatedIfExceptionsTest(repeats = 5)
@EnabledOnOs(OS.LINUX)
public void testNativeTransportWithoutEpollOnly() throws Exception {
AsyncHttpClientConfig config = config().setUseNativeTransport(true).setUseOnlyEpollNativeTransport(false).build();
try (DefaultAsyncHttpClient client = (DefaultAsyncHttpClient) asyncHttpClient(config)) {
assertDoesNotThrow(() -> client.prepareGet("https://www.google.com").execute().get());
assertInstanceOf(MultiThreadIoEventLoopGroup.class, client.channelManager().getEventLoopGroup());
}
}
@RepeatedIfExceptionsTest(repeats = 5)
@EnabledOnOs(OS.MAC)
public void testNativeTransportKQueueOnMacOs() throws Exception {
AsyncHttpClientConfig config = config().setUseNativeTransport(true).build();
try (DefaultAsyncHttpClient client = (DefaultAsyncHttpClient) asyncHttpClient(config)) {
assertDoesNotThrow(() -> client.prepareGet("https://www.google.com").execute().get());
assertInstanceOf(KQueueEventLoopGroup.class, client.channelManager().getEventLoopGroup());
}
}
@RepeatedIfExceptionsTest(repeats = 5)
public void testUseOnlyEpollNativeTransportButNativeTransportIsDisabled() {
assertThrows(IllegalArgumentException.class, () -> config().setUseNativeTransport(false).setUseOnlyEpollNativeTransport(true).build());
}
@RepeatedIfExceptionsTest(repeats = 5)
public void testUseOnlyEpollNativeTransportAndNativeTransportIsEnabled() {
assertDoesNotThrow(() -> config().setUseNativeTransport(true).setUseOnlyEpollNativeTransport(true).build());
}
@RepeatedIfExceptionsTest(repeats = 5)
public void testWithSharedNettyTimerShouldScheduleCookieEvictionOnlyOnce() throws IOException {
Timer nettyTimerMock = mock(Timer.class);
CookieStore cookieStore = new ThreadSafeCookieStore();
AsyncHttpClientConfig config = config().setNettyTimer(nettyTimerMock).setCookieStore(cookieStore).build();
try (AsyncHttpClient client1 = asyncHttpClient(config)) {
try (AsyncHttpClient client2 = asyncHttpClient(config)) {
assertEquals(cookieStore.count(), 2);
verify(nettyTimerMock, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
}
}
}
@RepeatedIfExceptionsTest(repeats = 5)
public void testWitDefaultConfigShouldScheduleCookieEvictionForEachAHC() throws IOException {
AsyncHttpClientConfig config1 = config().build();
try (AsyncHttpClient client1 = asyncHttpClient(config1)) {
AsyncHttpClientConfig config2 = config().build();
try (AsyncHttpClient client2 = asyncHttpClient(config2)) {
assertEquals(config1.getCookieStore().count(), 1);
assertEquals(config2.getCookieStore().count(), 1);
}
}
}
@RepeatedIfExceptionsTest(repeats = 5)
public void testWithSharedCookieStoreButNonSharedTimerShouldScheduleCookieEvictionForFirstAHC() throws IOException {
CookieStore cookieStore = new ThreadSafeCookieStore();
Timer nettyTimerMock1 = mock(Timer.class);
AsyncHttpClientConfig config1 = config()
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock1).build();
try (AsyncHttpClient client1 = asyncHttpClient(config1)) {
Timer nettyTimerMock2 = mock(Timer.class);
AsyncHttpClientConfig config2 = config()
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock2).build();
try (AsyncHttpClient client2 = asyncHttpClient(config2)) {
assertEquals(config1.getCookieStore().count(), 2);
verify(nettyTimerMock1, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
verify(nettyTimerMock2, never()).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
}
}
Timer nettyTimerMock3 = mock(Timer.class);
AsyncHttpClientConfig config3 = config()
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock3).build();
try (AsyncHttpClient client2 = asyncHttpClient(config3)) {
assertEquals(config1.getCookieStore().count(), 1);
verify(nettyTimerMock3, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
}
}
@RepeatedIfExceptionsTest(repeats = 5)
public void testWithSharedCookieStoreButNonSharedTimerShouldReScheduleCookieEvictionWhenFirstInstanceGetClosed() throws IOException {
CookieStore cookieStore = new ThreadSafeCookieStore();
Timer nettyTimerMock1 = mock(Timer.class);
AsyncHttpClientConfig config1 = config()
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock1).build();
try (AsyncHttpClient client1 = asyncHttpClient(config1)) {
assertEquals(config1.getCookieStore().count(), 1);
verify(nettyTimerMock1, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
}
assertEquals(config1.getCookieStore().count(), 0);
Timer nettyTimerMock2 = mock(Timer.class);
AsyncHttpClientConfig config2 = config()
.setCookieStore(cookieStore).setNettyTimer(nettyTimerMock2).build();
try (AsyncHttpClient client2 = asyncHttpClient(config2)) {
assertEquals(config1.getCookieStore().count(), 1);
verify(nettyTimerMock2, times(1)).newTimeout(any(CookieEvictionTask.class), anyLong(), any(TimeUnit.class));
}
}
@RepeatedIfExceptionsTest(repeats = 5)
public void testDisablingCookieStore() throws IOException {
AsyncHttpClientConfig config = config()
.setCookieStore(null).build();
try (AsyncHttpClient client = asyncHttpClient(config)) {
//
}
}
}