All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.proofpoint.http.client.testing.TestingResponse Maven / Gradle / Ivy

The newest version!
package com.proofpoint.http.client.testing;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.io.CountingInputStream;
import com.google.common.net.HttpHeaders;
import com.google.common.net.MediaType;
import com.proofpoint.http.client.HeaderName;
import com.proofpoint.http.client.HttpStatus;
import com.proofpoint.http.client.Response;
import com.proofpoint.json.ObjectMapperProvider;
import jakarta.annotation.Nullable;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.Map;

import static com.google.common.base.MoreObjects.toStringHelper;
import static com.google.common.base.Preconditions.checkState;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Objects.requireNonNull;
import static java.util.Objects.requireNonNullElse;

public class TestingResponse
        implements Response
{
    private final HttpStatus status;
    private final ListMultimap headers;
    private final CountingInputStream countingInputStream;

    private TestingResponse(HttpStatus status, ListMultimap headers, byte[] bytes)
    {
        this(status, headers, new ByteArrayInputStream(requireNonNull(bytes, "bytes is null")));
    }

    private TestingResponse(HttpStatus status, ListMultimap headers, InputStream input)
    {
        this.status = requireNonNull(status, "status is null");
        this.headers = ImmutableListMultimap.copyOf(toHeaderMap(requireNonNull(headers, "headers is null")));
        this.countingInputStream = new CountingInputStream(requireNonNull(input, "input is null"));
    }

    @Override
    public int getStatusCode()
    {
        return status.code();
    }

    @Override
    public String getStatusMessage()
    {
        return status.reason();
    }

    @Override
    public ListMultimap getHeaders()
    {
        return headers;
    }

    @Override
    public long getBytesRead()
    {
        return countingInputStream.getCount();
    }

    @Override
    public InputStream getInputStream()
    {
        return countingInputStream;
    }

    @Override
    public String toString()
    {
        return toStringHelper(this)
                .add("statusCode", getStatusCode())
                .add("statusMessage", getStatusMessage())
                .add("headers", getHeaders())
                .toString();
    }

    public static ListMultimap contentType(MediaType type)
    {
        return ImmutableListMultimap.of(HttpHeaders.CONTENT_TYPE, type.toString());
    }

    /**
     * Returns a response with the specified status.
     */
    public static Response mockResponse(HttpStatus status)
    {
        return new TestingResponse(status, ImmutableListMultimap.of(), new byte[0]);
    }

    /**
     * Returns a new builder.
     */
    public static Builder mockResponse()
    {
        return new Builder();
    }

    /**
     * A builder for creating {@link TestingResponse} instances.
     */
    public static class Builder
    {
        private static final byte[] ZERO_LENGTH_BYTES = new byte[0];

        private HttpStatus status;
        private final ListMultimap headers = ArrayListMultimap.create();
        private byte[] bytes;
        private InputStream inputStream;
        private String defaultContentType;

        private Builder()
        {
        }

        /**
         * Sets the response's status.
         *
         * If this method is not called, the builder uses {@link HttpStatus#OK}
         * if the body is set or {@link HttpStatus#NO_CONTENT} if the body is not set.
         */
        public Builder status(HttpStatus status)
        {
            checkState(this.status == null, "status is already set");
            this.status = requireNonNull(status, "status is null");
            return this;
        }

        /**
         * Adds a header to the response. May be called multiple times.
         */
        public Builder header(String field, String value)
        {
            headers.put(requireNonNull(field, "field is null"), requireNonNull(value, "value is null"));
            return this;
        }

        /**
         * Adds headers to the response. May be called multiple times.
         */
        public Builder headers(ListMultimap headers)
        {
            this.headers.putAll(requireNonNull(headers, "headers is null"));
            return this;
        }

        /**
         * Adds a Content-Type: header to the response.
         */
        public Builder contentType(MediaType type)
        {
            return header(HttpHeaders.CONTENT_TYPE, type.toString());
        }

        /**
         * Adds a Content-Type: header to the response.
         */
        public Builder contentType(String type)
        {
            return header(HttpHeaders.CONTENT_TYPE, type);
        }

        /**
         * Sets the response's body to a byte array.
         */
        public Builder body(byte[] bytes)
        {
            requireNonNull(bytes, "bytes is null");
            checkState(this.bytes == null && this.inputStream == null, "body is already set");
            this.bytes = Arrays.copyOf(bytes, bytes.length);
            return this;
        }

        /**
         * Sets the response's body to the UTF-8 encoding of a string
         */
        public Builder body(String content)
        {
            requireNonNull(content, "content is null");
            checkState(this.bytes == null && this.inputStream == null, "body is already set");
            bytes = content.getBytes(UTF_8);
            return this;
        }

        /**
         * Sets the response's body to an {@link InputStream}.
         */
        public Builder body(InputStream inputStream)
        {
            checkState(this.bytes == null && this.inputStream == null, "body is already set");
            this.inputStream = requireNonNull(inputStream, "inputStream is null");
            return this;
        }

        /**
         * Sets the response's body to the JSON encoding of an entity. Defaults the
         * Content-Type: header to "application/json; charset=utf-8".
         */
        public Builder jsonBody(@Nullable Object entity)
        {
            checkState(this.bytes == null && this.inputStream == null, "body is already set");
            defaultContentType = APPLICATION_JSON;
            try {
                bytes = new ObjectMapperProvider().get().writeValueAsBytes(entity);
            }
            catch (JsonProcessingException e) {
                throw new UncheckedIOException(e);
            }
            return this;
        }

        /**
         * Returns a newly created TestingResponse.
         */
        public TestingResponse build()
        {
            if (status == null) {
                if (bytes == null && this.inputStream == null) {
                    status = HttpStatus.NO_CONTENT;
                }
                else {
                    status = HttpStatus.OK;
                }
            }

            if (defaultContentType != null) {
                boolean haveType = false;
                for (String header : headers.keys()) {
                    if ("content-type".equalsIgnoreCase(header)) {
                        haveType = true;
                        break;
                    }
                }
                if (!haveType) {
                    header("Content-Type", defaultContentType);
                }
            }

            if (inputStream != null) {
                return new TestingResponse(status, headers, inputStream);
            }

            return new TestingResponse(status, headers, requireNonNullElse(bytes, ZERO_LENGTH_BYTES));
        }
    }

    private static ListMultimap toHeaderMap(ListMultimap headers)
    {
        ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder();
        for (Map.Entry entry : headers.entries()) {
            builder.put(HeaderName.of(entry.getKey()), entry.getValue());
        }
        return builder.build();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy