org.springframework.web.reactive.function.client.WebClientDataBufferAllocatingTests.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.web.reactive.function.client.WebClientDataBufferAllocatingTests.java

Source

/*
 * Copyright 2002-2018 the original author or authors.
 *
 * 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.springframework.web.reactive.function.client;

import java.time.Duration;
import java.util.Map;
import java.util.function.Function;

import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelOption;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import org.springframework.web.reactive.function.UnsupportedMediaTypeException;

import static org.junit.Assert.*;

/**
 * WebClient integration tests focusing on data buffer management.
 *
 * @author Rossen Stoyanchev
 */
public class WebClientDataBufferAllocatingTests extends AbstractDataBufferAllocatingTestCase {

    private static final Duration DELAY = Duration.ofSeconds(5);

    private MockWebServer server;

    private WebClient webClient;

    private ReactorResourceFactory factory;

    @Before
    public void setUp() {

        this.factory = new ReactorResourceFactory();
        this.factory.afterPropertiesSet();

        this.server = new MockWebServer();
        this.webClient = WebClient.builder().clientConnector(initConnector())
                .baseUrl(this.server.url("/").toString()).build();
    }

    private ReactorClientHttpConnector initConnector() {
        if (bufferFactory instanceof NettyDataBufferFactory) {
            ByteBufAllocator allocator = ((NettyDataBufferFactory) bufferFactory).getByteBufAllocator();
            return new ReactorClientHttpConnector(this.factory, httpClient -> httpClient
                    .tcpConfiguration(tcpClient -> tcpClient.option(ChannelOption.ALLOCATOR, allocator)));
        } else {
            return new ReactorClientHttpConnector();
        }
    }

    @After
    public void shutDown() throws InterruptedException {
        waitForDataBufferRelease(Duration.ofSeconds(2));
        this.factory.destroy();
    }

    @Test
    public void bodyToMonoVoid() {

        this.server.enqueue(new MockResponse().setResponseCode(201).setHeader("Content-Type", "application/json")
                .setChunkedBody("{\"foo\" : {\"bar\" : \"123\", \"baz\" : \"456\"}}", 5));

        Mono<Void> mono = this.webClient.get().uri("/json").accept(MediaType.APPLICATION_JSON).retrieve()
                .bodyToMono(Void.class);

        StepVerifier.create(mono).expectComplete().verify(Duration.ofSeconds(3));
        assertEquals(1, this.server.getRequestCount());
    }

    @Test // SPR-17482
    public void bodyToMonoVoidWithoutContentType() {

        this.server.enqueue(new MockResponse().setResponseCode(HttpStatus.ACCEPTED.value())
                .setChunkedBody("{\"foo\" : \"123\",  \"baz\" : \"456\", \"baz\" : \"456\"}", 5));

        Mono<Map<String, String>> mono = this.webClient.get().uri("/sample").accept(MediaType.APPLICATION_JSON)
                .retrieve().bodyToMono(new ParameterizedTypeReference<Map<String, String>>() {
                });

        StepVerifier.create(mono).expectError(UnsupportedMediaTypeException.class).verify(Duration.ofSeconds(3));
        assertEquals(1, this.server.getRequestCount());
    }

    @Test
    public void onStatusWithBodyNotConsumed() {
        RuntimeException ex = new RuntimeException("response error");
        testOnStatus(ex, response -> Mono.just(ex));
    }

    @Test
    public void onStatusWithBodyConsumed() {
        RuntimeException ex = new RuntimeException("response error");
        testOnStatus(ex, response -> response.bodyToMono(Void.class).thenReturn(ex));
    }

    @Test // SPR-17473
    public void onStatusWithMonoErrorAndBodyNotConsumed() {
        RuntimeException ex = new RuntimeException("response error");
        testOnStatus(ex, response -> Mono.error(ex));
    }

    @Test
    public void onStatusWithMonoErrorAndBodyConsumed() {
        RuntimeException ex = new RuntimeException("response error");
        testOnStatus(ex, response -> response.bodyToMono(Void.class).then(Mono.error(ex)));
    }

    private void testOnStatus(Throwable expected,
            Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction) {

        HttpStatus errorStatus = HttpStatus.BAD_GATEWAY;

        this.server.enqueue(new MockResponse().setResponseCode(errorStatus.value())
                .setHeader("Content-Type", "application/json")
                .setChunkedBody("{\"error\" : {\"status\" : 502, \"message\" : \"Bad gateway.\"}}", 5));

        Mono<String> mono = this.webClient.get().uri("/json").accept(MediaType.APPLICATION_JSON).retrieve()
                .onStatus(status -> status.equals(errorStatus), exceptionFunction).bodyToMono(String.class);

        StepVerifier.create(mono).expectErrorSatisfies(actual -> assertSame(expected, actual)).verify(DELAY);
        assertEquals(1, this.server.getRequestCount());
    }

}