org.springframework.boot.cli.command.init.AbstractHttpClientMockTests.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.boot.cli.command.init.AbstractHttpClientMockTests.java

Source

/*
 * Copyright 2012-2017 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.boot.cli.command.init;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicHeader;
import org.json.JSONException;
import org.json.JSONObject;
import org.mockito.ArgumentMatcher;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.StreamUtils;

import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

/**
 * Abstract base class for tests that use a mock {@link CloseableHttpClient}.
 *
 * @author Stephane Nicoll
 */
public abstract class AbstractHttpClientMockTests {

    protected final CloseableHttpClient http = mock(CloseableHttpClient.class);

    protected void mockSuccessfulMetadataTextGet() throws IOException {
        mockSuccessfulMetadataGet("metadata/service-metadata-2.1.0.txt", "text/plain", true);
    }

    protected void mockSuccessfulMetadataGet(boolean serviceCapabilities) throws IOException {
        mockSuccessfulMetadataGet("metadata/service-metadata-2.1.0.json", "application/vnd.initializr.v2.1+json",
                serviceCapabilities);
    }

    protected void mockSuccessfulMetadataGetV2(boolean serviceCapabilities) throws IOException {
        mockSuccessfulMetadataGet("metadata/service-metadata-2.0.0.json", "application/vnd.initializr.v2+json",
                serviceCapabilities);
    }

    protected void mockSuccessfulMetadataGet(String contentPath, String contentType, boolean serviceCapabilities)
            throws IOException {
        CloseableHttpResponse response = mock(CloseableHttpResponse.class);
        byte[] content = readClasspathResource(contentPath);
        mockHttpEntity(response, content, contentType);
        mockStatus(response, 200);
        given(this.http.execute(argThat(getForMetadata(serviceCapabilities)))).willReturn(response);
    }

    protected byte[] readClasspathResource(String contentPath) throws IOException {
        Resource resource = new ClassPathResource(contentPath);
        return StreamUtils.copyToByteArray(resource.getInputStream());
    }

    protected void mockSuccessfulProjectGeneration(MockHttpProjectGenerationRequest request) throws IOException {
        // Required for project generation as the metadata is read first
        mockSuccessfulMetadataGet(false);
        CloseableHttpResponse response = mock(CloseableHttpResponse.class);
        mockHttpEntity(response, request.content, request.contentType);
        mockStatus(response, 200);
        String header = (request.fileName != null ? contentDispositionValue(request.fileName) : null);
        mockHttpHeader(response, "Content-Disposition", header);
        given(this.http.execute(argThat(getForNonMetadata()))).willReturn(response);
    }

    protected void mockProjectGenerationError(int status, String message) throws IOException, JSONException {
        // Required for project generation as the metadata is read first
        mockSuccessfulMetadataGet(false);
        CloseableHttpResponse response = mock(CloseableHttpResponse.class);
        mockHttpEntity(response, createJsonError(status, message).getBytes(), "application/json");
        mockStatus(response, status);
        given(this.http.execute(isA(HttpGet.class))).willReturn(response);
    }

    protected void mockMetadataGetError(int status, String message) throws IOException, JSONException {
        CloseableHttpResponse response = mock(CloseableHttpResponse.class);
        mockHttpEntity(response, createJsonError(status, message).getBytes(), "application/json");
        mockStatus(response, status);
        given(this.http.execute(isA(HttpGet.class))).willReturn(response);
    }

    protected HttpEntity mockHttpEntity(CloseableHttpResponse response, byte[] content, String contentType) {
        try {
            HttpEntity entity = mock(HttpEntity.class);
            given(entity.getContent()).willReturn(new ByteArrayInputStream(content));
            Header contentTypeHeader = contentType != null ? new BasicHeader("Content-Type", contentType) : null;
            given(entity.getContentType()).willReturn(contentTypeHeader);
            given(response.getEntity()).willReturn(entity);
            return entity;
        } catch (IOException ex) {
            throw new IllegalStateException("Should not happen", ex);
        }
    }

    protected void mockStatus(CloseableHttpResponse response, int status) {
        StatusLine statusLine = mock(StatusLine.class);
        given(statusLine.getStatusCode()).willReturn(status);
        given(response.getStatusLine()).willReturn(statusLine);
    }

    protected void mockHttpHeader(CloseableHttpResponse response, String headerName, String value) {
        Header header = value != null ? new BasicHeader(headerName, value) : null;
        given(response.getFirstHeader(headerName)).willReturn(header);
    }

    private ArgumentMatcher<HttpGet> getForMetadata(boolean serviceCapabilities) {
        if (!serviceCapabilities) {
            return new HasAcceptHeader(InitializrService.ACCEPT_META_DATA, true);
        }
        return new HasAcceptHeader(InitializrService.ACCEPT_SERVICE_CAPABILITIES, true);
    }

    private ArgumentMatcher<HttpGet> getForNonMetadata() {
        return new HasAcceptHeader(InitializrService.ACCEPT_META_DATA, false);
    }

    private String contentDispositionValue(String fileName) {
        return "attachment; filename=\"" + fileName + "\"";
    }

    private String createJsonError(int status, String message) throws JSONException {
        JSONObject json = new JSONObject();
        json.put("status", status);
        if (message != null) {
            json.put("message", message);
        }
        return json.toString();
    }

    protected static class MockHttpProjectGenerationRequest {

        String contentType;

        String fileName;

        byte[] content = new byte[] { 0, 0, 0, 0 };

        public MockHttpProjectGenerationRequest(String contentType, String fileName) {
            this(contentType, fileName, new byte[] { 0, 0, 0, 0 });
        }

        public MockHttpProjectGenerationRequest(String contentType, String fileName, byte[] content) {
            this.contentType = contentType;
            this.fileName = fileName;
            this.content = content;
        }

    }

    private static class HasAcceptHeader implements ArgumentMatcher<HttpGet> {

        private final String value;

        private final boolean shouldMatch;

        HasAcceptHeader(String value, boolean shouldMatch) {
            this.value = value;
            this.shouldMatch = shouldMatch;
        }

        @Override
        public boolean matches(HttpGet get) {
            if (get == null) {
                return false;
            }
            Header acceptHeader = get.getFirstHeader(HttpHeaders.ACCEPT);
            if (this.shouldMatch) {
                return acceptHeader != null && this.value.equals(acceptHeader.getValue());
            }
            return acceptHeader == null || !this.value.equals(acceptHeader.getValue());
        }

    }

}