001/*
002 * Copyright 2002-2016 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.test.web.client;
018
019import java.io.IOException;
020import java.util.LinkedList;
021import java.util.List;
022
023import org.springframework.http.client.ClientHttpRequest;
024import org.springframework.http.client.ClientHttpResponse;
025import org.springframework.util.Assert;
026
027/**
028 * Default implementation of {@code RequestExpectation} that simply delegates
029 * to the request matchers and the response creator it contains.
030 *
031 * @author Rossen Stoyanchev
032 * @since 4.3
033 */
034public class DefaultRequestExpectation implements RequestExpectation {
035
036        private final RequestCount requestCount;
037
038        private final List<RequestMatcher> requestMatchers = new LinkedList<RequestMatcher>();
039
040        private ResponseCreator responseCreator;
041
042
043        /**
044         * Create a new request expectation that should be called a number of times
045         * as indicated by {@code RequestCount}.
046         * @param expectedCount the expected request expectedCount
047         */
048        public DefaultRequestExpectation(ExpectedCount expectedCount, RequestMatcher requestMatcher) {
049                Assert.notNull(expectedCount, "ExpectedCount is required");
050                Assert.notNull(requestMatcher, "RequestMatcher is required");
051                this.requestCount = new RequestCount(expectedCount);
052                this.requestMatchers.add(requestMatcher);
053        }
054
055
056        protected RequestCount getRequestCount() {
057                return this.requestCount;
058        }
059
060        protected List<RequestMatcher> getRequestMatchers() {
061                return this.requestMatchers;
062        }
063
064        protected ResponseCreator getResponseCreator() {
065                return this.responseCreator;
066        }
067
068        @Override
069        public ResponseActions andExpect(RequestMatcher requestMatcher) {
070                Assert.notNull(requestMatcher, "RequestMatcher is required");
071                this.requestMatchers.add(requestMatcher);
072                return this;
073        }
074
075        @Override
076        public void andRespond(ResponseCreator responseCreator) {
077                Assert.notNull(responseCreator, "ResponseCreator is required");
078                this.responseCreator = responseCreator;
079        }
080
081        @Override
082        public void match(ClientHttpRequest request) throws IOException {
083                for (RequestMatcher matcher : getRequestMatchers()) {
084                        matcher.match(request);
085                }
086        }
087
088        @Override
089        public ClientHttpResponse createResponse(ClientHttpRequest request) throws IOException {
090                ResponseCreator responseCreator = getResponseCreator();
091                if (responseCreator == null) {
092                        throw new IllegalStateException("createResponse called before ResponseCreator was set");
093                }
094                getRequestCount().incrementAndValidate();
095                return responseCreator.createResponse(request);
096        }
097
098        @Override
099        public boolean hasRemainingCount() {
100                return getRequestCount().hasRemainingCount();
101        }
102
103        @Override
104        public boolean isSatisfied() {
105                return getRequestCount().isSatisfied();
106        }
107
108
109        /**
110         * Helper class that keeps track of actual vs expected request count.
111         */
112        protected static class RequestCount {
113
114                private final ExpectedCount expectedCount;
115
116                private int matchedRequestCount;
117
118                public RequestCount(ExpectedCount expectedCount) {
119                        this.expectedCount = expectedCount;
120                }
121
122                public ExpectedCount getExpectedCount() {
123                        return this.expectedCount;
124                }
125
126                public int getMatchedRequestCount() {
127                        return this.matchedRequestCount;
128                }
129
130                public void incrementAndValidate() {
131                        this.matchedRequestCount++;
132                        if (getMatchedRequestCount() > getExpectedCount().getMaxCount()) {
133                                throw new AssertionError("No more calls expected.");
134                        }
135                }
136
137                public boolean hasRemainingCount() {
138                        return (getMatchedRequestCount() < getExpectedCount().getMaxCount());
139                }
140
141                public boolean isSatisfied() {
142                        // Only validate min count since max count is checked on every request...
143                        return (getMatchedRequestCount() >= getExpectedCount().getMinCount());
144                }
145        }
146
147}