001/* 002 * Copyright 2002-2018 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.lang.Nullable; 026import org.springframework.util.Assert; 027 028/** 029 * Default implementation of {@code RequestExpectation} that simply delegates 030 * to the request matchers and the response creator it contains. 031 * 032 * @author Rossen Stoyanchev 033 * @since 4.3 034 */ 035public class DefaultRequestExpectation implements RequestExpectation { 036 037 private final RequestCount requestCount; 038 039 private final List<RequestMatcher> requestMatchers = new LinkedList<>(); 040 041 @Nullable 042 private ResponseCreator responseCreator; 043 044 045 /** 046 * Create a new request expectation that should be called a number of times 047 * as indicated by {@code RequestCount}. 048 * @param expectedCount the expected request expectedCount 049 */ 050 public DefaultRequestExpectation(ExpectedCount expectedCount, RequestMatcher requestMatcher) { 051 Assert.notNull(expectedCount, "ExpectedCount is required"); 052 Assert.notNull(requestMatcher, "RequestMatcher is required"); 053 this.requestCount = new RequestCount(expectedCount); 054 this.requestMatchers.add(requestMatcher); 055 } 056 057 058 protected RequestCount getRequestCount() { 059 return this.requestCount; 060 } 061 062 protected List<RequestMatcher> getRequestMatchers() { 063 return this.requestMatchers; 064 } 065 066 @Nullable 067 protected ResponseCreator getResponseCreator() { 068 return this.responseCreator; 069 } 070 071 @Override 072 public ResponseActions andExpect(RequestMatcher requestMatcher) { 073 Assert.notNull(requestMatcher, "RequestMatcher is required"); 074 this.requestMatchers.add(requestMatcher); 075 return this; 076 } 077 078 @Override 079 public void andRespond(ResponseCreator responseCreator) { 080 Assert.notNull(responseCreator, "ResponseCreator is required"); 081 this.responseCreator = responseCreator; 082 } 083 084 @Override 085 public void match(ClientHttpRequest request) throws IOException { 086 for (RequestMatcher matcher : getRequestMatchers()) { 087 matcher.match(request); 088 } 089 } 090 091 /** 092 * Note that as of 5.0.3, the creation of the response, which may block 093 * intentionally, is separated from request count tracking, and this 094 * method no longer increments the count transparently. Instead 095 * {@link #incrementAndValidate()} must be invoked independently. 096 */ 097 @Override 098 public ClientHttpResponse createResponse(@Nullable ClientHttpRequest request) throws IOException { 099 ResponseCreator responseCreator = getResponseCreator(); 100 Assert.state(responseCreator != null, "createResponse() called before ResponseCreator was set"); 101 return responseCreator.createResponse(request); 102 } 103 104 @Override 105 public boolean hasRemainingCount() { 106 return getRequestCount().hasRemainingCount(); 107 } 108 109 @Override 110 public void incrementAndValidate() { 111 getRequestCount().incrementAndValidate(); 112 } 113 114 @Override 115 public boolean isSatisfied() { 116 return getRequestCount().isSatisfied(); 117 } 118 119 120 /** 121 * Helper class that keeps track of actual vs expected request count. 122 */ 123 protected static class RequestCount { 124 125 private final ExpectedCount expectedCount; 126 127 private int matchedRequestCount; 128 129 public RequestCount(ExpectedCount expectedCount) { 130 this.expectedCount = expectedCount; 131 } 132 133 public ExpectedCount getExpectedCount() { 134 return this.expectedCount; 135 } 136 137 public int getMatchedRequestCount() { 138 return this.matchedRequestCount; 139 } 140 141 public void incrementAndValidate() { 142 this.matchedRequestCount++; 143 if (getMatchedRequestCount() > getExpectedCount().getMaxCount()) { 144 throw new AssertionError("No more calls expected."); 145 } 146 } 147 148 public boolean hasRemainingCount() { 149 return (getMatchedRequestCount() < getExpectedCount().getMaxCount()); 150 } 151 152 public boolean isSatisfied() { 153 // Only validate min count since max count is checked on every request... 154 return (getMatchedRequestCount() >= getExpectedCount().getMinCount()); 155 } 156 } 157 158}