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.reactive.server; 018 019import java.util.Arrays; 020import java.util.function.Consumer; 021 022import org.hamcrest.Matcher; 023import org.hamcrest.MatcherAssert; 024 025import org.springframework.http.CacheControl; 026import org.springframework.http.ContentDisposition; 027import org.springframework.http.HttpHeaders; 028import org.springframework.http.MediaType; 029import org.springframework.lang.Nullable; 030import org.springframework.test.util.AssertionErrors; 031 032/** 033 * Assertions on headers of the response. 034 * 035 * @author Rossen Stoyanchev 036 * @author Brian Clozel 037 * @author Sam Brannen 038 * @since 5.0 039 * @see WebTestClient.ResponseSpec#expectHeader() 040 */ 041public class HeaderAssertions { 042 043 private final ExchangeResult exchangeResult; 044 045 private final WebTestClient.ResponseSpec responseSpec; 046 047 048 HeaderAssertions(ExchangeResult result, WebTestClient.ResponseSpec spec) { 049 this.exchangeResult = result; 050 this.responseSpec = spec; 051 } 052 053 054 /** 055 * Expect a header with the given name to match the specified values. 056 */ 057 public WebTestClient.ResponseSpec valueEquals(String headerName, String... values) { 058 return assertHeader(headerName, Arrays.asList(values), getHeaders().get(headerName)); 059 } 060 061 /** 062 * Match the first value of the response header with a regex. 063 * @param name the header name 064 * @param pattern the regex pattern 065 */ 066 public WebTestClient.ResponseSpec valueMatches(String name, String pattern) { 067 String value = getRequiredValue(name); 068 String message = getMessage(name) + "=[" + value + "] does not match [" + pattern + "]"; 069 this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertTrue(message, value.matches(pattern))); 070 return this.responseSpec; 071 } 072 073 /** 074 * Assert the first value of the response header with a Hamcrest {@link Matcher}. 075 * @param name the header name 076 * @param matcher the matcher to use 077 * @since 5.1 078 */ 079 public WebTestClient.ResponseSpec value(String name, Matcher<? super String> matcher) { 080 String value = getRequiredValue(name); 081 this.exchangeResult.assertWithDiagnostics(() -> MatcherAssert.assertThat(value, matcher)); 082 return this.responseSpec; 083 } 084 085 /** 086 * Consume the first value of the response header. 087 * @param name the header name 088 * @param consumer the consumer to use 089 * @since 5.1 090 */ 091 public WebTestClient.ResponseSpec value(String name, Consumer<String> consumer) { 092 String value = getRequiredValue(name); 093 this.exchangeResult.assertWithDiagnostics(() -> consumer.accept(value)); 094 return this.responseSpec; 095 } 096 097 private String getRequiredValue(String name) { 098 String value = getHeaders().getFirst(name); 099 if (value == null) { 100 AssertionErrors.fail(getMessage(name) + " not found"); 101 } 102 return value; 103 } 104 105 /** 106 * Expect that the header with the given name is present. 107 * @since 5.0.3 108 */ 109 public WebTestClient.ResponseSpec exists(String name) { 110 if (!getHeaders().containsKey(name)) { 111 String message = getMessage(name) + " does not exist"; 112 this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message)); 113 } 114 return this.responseSpec; 115 } 116 117 /** 118 * Expect that the header with the given name is not present. 119 */ 120 public WebTestClient.ResponseSpec doesNotExist(String name) { 121 if (getHeaders().containsKey(name)) { 122 String message = getMessage(name) + " exists with value=[" + getHeaders().getFirst(name) + "]"; 123 this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message)); 124 } 125 return this.responseSpec; 126 } 127 128 /** 129 * Expect a "Cache-Control" header with the given value. 130 */ 131 public WebTestClient.ResponseSpec cacheControl(CacheControl cacheControl) { 132 return assertHeader("Cache-Control", cacheControl.getHeaderValue(), getHeaders().getCacheControl()); 133 } 134 135 /** 136 * Expect a "Content-Disposition" header with the given value. 137 */ 138 public WebTestClient.ResponseSpec contentDisposition(ContentDisposition contentDisposition) { 139 return assertHeader("Content-Disposition", contentDisposition, getHeaders().getContentDisposition()); 140 } 141 142 /** 143 * Expect a "Content-Length" header with the given value. 144 */ 145 public WebTestClient.ResponseSpec contentLength(long contentLength) { 146 return assertHeader("Content-Length", contentLength, getHeaders().getContentLength()); 147 } 148 149 /** 150 * Expect a "Content-Type" header with the given value. 151 */ 152 public WebTestClient.ResponseSpec contentType(MediaType mediaType) { 153 return assertHeader("Content-Type", mediaType, getHeaders().getContentType()); 154 } 155 156 /** 157 * Expect a "Content-Type" header with the given value. 158 */ 159 public WebTestClient.ResponseSpec contentType(String mediaType) { 160 return contentType(MediaType.parseMediaType(mediaType)); 161 } 162 163 /** 164 * Expect a "Content-Type" header compatible with the given value. 165 */ 166 public WebTestClient.ResponseSpec contentTypeCompatibleWith(MediaType mediaType) { 167 MediaType actual = getHeaders().getContentType(); 168 String message = getMessage("Content-Type") + "=[" + actual + "] is not compatible with [" + mediaType + "]"; 169 this.exchangeResult.assertWithDiagnostics(() -> 170 AssertionErrors.assertTrue(message, (actual != null && actual.isCompatibleWith(mediaType)))); 171 return this.responseSpec; 172 } 173 174 /** 175 * Expect a "Content-Type" header compatible with the given value. 176 */ 177 public WebTestClient.ResponseSpec contentTypeCompatibleWith(String mediaType) { 178 return contentTypeCompatibleWith(MediaType.parseMediaType(mediaType)); 179 } 180 181 /** 182 * Expect an "Expires" header with the given value. 183 */ 184 public WebTestClient.ResponseSpec expires(long expires) { 185 return assertHeader("Expires", expires, getHeaders().getExpires()); 186 } 187 188 /** 189 * Expect a "Last-Modified" header with the given value. 190 */ 191 public WebTestClient.ResponseSpec lastModified(long lastModified) { 192 return assertHeader("Last-Modified", lastModified, getHeaders().getLastModified()); 193 } 194 195 196 private HttpHeaders getHeaders() { 197 return this.exchangeResult.getResponseHeaders(); 198 } 199 200 private String getMessage(String headerName) { 201 return "Response header '" + headerName + "'"; 202 } 203 204 private WebTestClient.ResponseSpec assertHeader(String name, @Nullable Object expected, @Nullable Object actual) { 205 this.exchangeResult.assertWithDiagnostics(() -> { 206 String message = getMessage(name); 207 AssertionErrors.assertEquals(message, expected, actual); 208 }); 209 return this.responseSpec; 210 } 211 212}