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

com.comcast.drivethru.test.ResponseBuilder Maven / Gradle / Ivy

There is a newer version: 2.0.7
Show newest version
/**
 * Copyright 2013 Comcast Cable Communications Management, LLC
 *
 * 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 com.comcast.drivethru.test;

import com.comcast.cereal.CerealException;
import com.comcast.cereal.engines.JsonCerealEngine;
import com.comcast.drivethru.exception.HttpException;
import com.comcast.drivethru.utils.Method;
import com.comcast.drivethru.utils.RestResponse;

/**
 * The {@link ResponseBuilder} provides a way for building up expectations and recored actions to
 * take when a MockHttpClient gets a matching execute call. Most methods return this to
 * allow for method chaining when recording.
 *
 * @author Clark Malmgren
 */
public class ResponseBuilder {

    /* Used for matching */
    private String pattern;
    private boolean regex;
    private Method method;
    private int times;

    /* Used for replay */
    private RestResponse response;
    private HttpException exception;
    private long delay;

    /**
     * Construct a new {@link ResponseBuilder} that will match anything.
     */
    public ResponseBuilder() {
        this(null, ".*", true);
    }

    /**
     * Construct a new {@link ResponseBuilder} that will match any request whose URL matches the
     * given pattern as a regular expression.
     *
     * @param pattern
     *            the regular expression pattern to match
     */
    public ResponseBuilder(String pattern) {
        this(null, pattern, true);
    }

    /**
     * Construct a new {@link ResponseBuilder} that will match any request whose URL matches the
     * given pattern.
     *
     * @param pattern
     *            the pattern to match
     * @param regex
     *            if true, the pattern is a regular expression, otherwise the pattern
     *            is a string that must equal an incoming URL
     */
    public ResponseBuilder(String pattern, boolean regex) {
        this(null, pattern, regex);
    }

    /**
     * Construct a new {@link ResponseBuilder} that will match any request with the given method.
     *
     * @param method
     *            the method that must be matched or null to match any method
     */
    public ResponseBuilder(Method method) {
        this(method, ".*", true);
    }

    /**
     * Construct a new {@link ResponseBuilder} that will match requests with the given method whose
     * URL matches the given pattern as a regular expression.
     *
     *
     * @param method
     *            the method that must be matched or null to match any method
     * @param pattern
     *            the regular expression pattern to match
     */
    public ResponseBuilder(Method method, String pattern) {
        this(method, pattern, true);
    }

    /**
     * Construct a new {@link ResponseBuilder} that will match any request with the given method
     * whose URL matches the given pattern.
     *
     * @param method
     *            the method that must be matched or null to match any method
     * @param pattern
     *            the pattern to match
     * @param regex
     *            if true, the pattern is a regular expression, otherwise the pattern
     *            is a string that must equal an incoming URL
     */
    public ResponseBuilder(Method method, String pattern, boolean regex) {
        this.pattern = pattern;
        this.regex = regex;
        this.method = method;
        this.times = -1;

        this.response = null;
        this.exception = null;
        this.delay = -1;
    }

    /**
     * Returns true if this {@link ResponseBuilder} matches the given request.
     *
     * @param url
     *            the URL
     * @param method
     *            the method
     *
     * @return true if this {@link ResponseBuilder} matches the given request
     */
    public boolean matches(String url, Method method) {
        if (times == 0) {
            return false;
        } else if ((null != this.method) && (!this.method.equals(method))) {
            return false;
        } else if (regex) {
            return url.matches(pattern);
        } else {
            return pattern.equals(url);
        }
    }

    /**
     * Execute the recorded actions.
     *
     * @return the recorded response
     *
     * @throws HttpException
     *             the recorded exception
     */
    public RestResponse replay() throws HttpException {
        this.times--;

        if (delay > 0) {
            try {
                Thread.sleep(delay);
            } catch (InterruptedException iex) {
                Thread.interrupted(); // clear the flag
            }
        }

        if (null != exception) {
            throw exception;
        } else {
            return response;
        }
    }

    /**
     * Introduce a delay in processing. This should only be used when testing multi-threaded code
     * for synchronization.
     *
     * @param delay
     *            the delay in millisecond
     *
     * @return this
     */
    public ResponseBuilder after(long delay) {
        this.delay = delay;
        return this;
    }

    /**
     * Throw the given exception on replay.
     *
     * @param exception
     *            the exception to throw.
     *
     * @return this
     */
    public ResponseBuilder andThrow(HttpException exception) {
        this.exception = exception;
        return this;
    }

    /**
     * Get the recorded exception to throw.
     *
     * @return the recorded exception or null if none has been recorded.
     */
    public HttpException getException() {
        return exception;
    }

    /**
     * Return with the given status code on replay
     *
     * @param statusCode
     *            the status code
     *
     * @return this
     */
    public ResponseBuilder andReturn(int statusCode) {
        return this.andReturn(statusCode, "NOT_DEFINED");
    }

    /**
     * Return with the given status code and message on replay
     *
     * @param statusCode
     *            the status code
     * @param statusMessage
     *            the status message
     *
     * @return this
     */
    public ResponseBuilder andReturn(int statusCode, String statusMessage) {
        this.response = new RestResponse(statusCode, statusMessage);
        return this;
    }

    /**
     * Attach the given body to the returned response. This must be called AFTER a call to
     * {@link #andReturn(int)} or {@link #andReturn(int, String)}.
     *
     * @param body
     *            the body
     * @param contentType
     *            the content type
     *
     * @return this
     */
    public ResponseBuilder withBody(byte[] body, String contentType) {
        this.response.setBody(body);
        this.response.addHeader("Content-Type", contentType);
        return this;
    }

    /**
     * Attach the given body to the returned response. This must be called AFTER a call to
     * {@link #andReturn(int)} or {@link #andReturn(int, String)}.
     *
     * @param body
     *            the body
     * @param contentType
     *            the content type
     *
     * @return this
     */
    public ResponseBuilder withBody(String body, String contentType) {
        return withBody(body.getBytes(), contentType);
    }

    /**
     * Attach the given object encoded to JSON to the returned response. This must be called AFTER a
     * call to {@link #andReturn(int)} or {@link #andReturn(int, String)}.
     *
     * @param object
     *            the object to use as the body of the response
     *
     * @return this
     */
    public ResponseBuilder withJsonBody(Object object) throws CerealException {
        JsonCerealEngine jsonEngine = new JsonCerealEngine();
        return withBody(jsonEngine.writeToString(object), "application/json");
    }

    /**
     * Add a header to the returned response. This must be called AFTER a call to
     * {@link #andReturn(int)} or {@link #andReturn(int, String)}.
     *
     * @param name
     *            the header name
     * @param value
     *            the header value
     *
     * @return this
     */
    public ResponseBuilder withHeader(String name, String value) {
        this.response.addHeader(name, value);
        return this;
    }

    /**
     * Indicates that this response builder can replay once before it will stop matching. This
     * should be used when creating tests that should return different responses given the same URL
     * and method.
     *
     * @return this
     */
    public ResponseBuilder once() {
        return times(1);
    }

    /**
     * Indicate a maximum number of times this response builder can replay before it will stop
     * matching. This should be used when creating tests that should return different responses
     * given the same URL and method.
     *
     * @param count
     *            the maximum number of times this response builder can replay before it will stop
     *            matching
     *
     * @return this
     */
    public ResponseBuilder times(int count) {
        this.times = count;
        return this;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy