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}