001/*
002 * Copyright 2002-2017 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.servlet.htmlunit;
018
019import com.gargoylesoftware.htmlunit.WebClient;
020
021import org.springframework.lang.Nullable;
022import org.springframework.test.web.servlet.MockMvc;
023import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
024import org.springframework.util.Assert;
025import org.springframework.web.context.WebApplicationContext;
026
027/**
028 * {@code MockMvcWebClientBuilder} simplifies the creation of an HtmlUnit
029 * {@link WebClient} that delegates to a {@link MockMvc} instance.
030 *
031 * <p>The {@code MockMvc} instance used by the builder may be
032 * {@linkplain #mockMvcSetup supplied directly} or created transparently
033 * from a {@link #webAppContextSetup WebApplicationContext}.
034 *
035 * @author Rob Winch
036 * @author Sam Brannen
037 * @since 4.2
038 * @see #mockMvcSetup(MockMvc)
039 * @see #webAppContextSetup(WebApplicationContext)
040 * @see #webAppContextSetup(WebApplicationContext, MockMvcConfigurer)
041 * @see #withDelegate(WebClient)
042 * @see #build()
043 */
044public class MockMvcWebClientBuilder extends MockMvcWebConnectionBuilderSupport<MockMvcWebClientBuilder> {
045
046        @Nullable
047        private WebClient webClient;
048
049
050        protected MockMvcWebClientBuilder(MockMvc mockMvc) {
051                super(mockMvc);
052        }
053
054        protected MockMvcWebClientBuilder(WebApplicationContext context) {
055                super(context);
056        }
057
058        protected MockMvcWebClientBuilder(WebApplicationContext context, MockMvcConfigurer configurer) {
059                super(context, configurer);
060        }
061
062
063        /**
064         * Create a new {@code MockMvcWebClientBuilder} based on the supplied
065         * {@link MockMvc} instance.
066         * @param mockMvc the {@code MockMvc} instance to use; never {@code null}
067         * @return the MockMvcWebClientBuilder to customize
068         */
069        public static MockMvcWebClientBuilder mockMvcSetup(MockMvc mockMvc) {
070                Assert.notNull(mockMvc, "MockMvc must not be null");
071                return new MockMvcWebClientBuilder(mockMvc);
072        }
073
074        /**
075         * Create a new {@code MockMvcWebClientBuilder} based on the supplied
076         * {@link WebApplicationContext}.
077         * @param context the {@code WebApplicationContext} to create a {@link MockMvc}
078         * instance from; never {@code null}
079         * @return the MockMvcWebClientBuilder to customize
080         */
081        public static MockMvcWebClientBuilder webAppContextSetup(WebApplicationContext context) {
082                Assert.notNull(context, "WebApplicationContext must not be null");
083                return new MockMvcWebClientBuilder(context);
084        }
085
086        /**
087         * Create a new {@code MockMvcWebClientBuilder} based on the supplied
088         * {@link WebApplicationContext} and {@link MockMvcConfigurer}.
089         * @param context the {@code WebApplicationContext} to create a {@link MockMvc}
090         * instance from; never {@code null}
091         * @param configurer the {@code MockMvcConfigurer} to apply; never {@code null}
092         * @return the MockMvcWebClientBuilder to customize
093         */
094        public static MockMvcWebClientBuilder webAppContextSetup(WebApplicationContext context, MockMvcConfigurer configurer) {
095                Assert.notNull(context, "WebApplicationContext must not be null");
096                Assert.notNull(configurer, "MockMvcConfigurer must not be null");
097                return new MockMvcWebClientBuilder(context, configurer);
098        }
099
100        /**
101         * Supply the {@code WebClient} that the client {@linkplain #build built}
102         * by this builder should delegate to when processing
103         * non-{@linkplain WebRequestMatcher matching} requests.
104         * @param webClient the {@code WebClient} to delegate to for requests
105         * that do not match; never {@code null}
106         * @return this builder for further customization
107         * @see #build()
108         */
109        public MockMvcWebClientBuilder withDelegate(WebClient webClient) {
110                Assert.notNull(webClient, "WebClient must not be null");
111                webClient.setWebConnection(createConnection(webClient));
112                this.webClient = webClient;
113                return this;
114        }
115
116        /**
117         * Build the {@link WebClient} configured via this builder.
118         * <p>The returned client will use the configured {@link MockMvc} instance
119         * for processing any {@linkplain WebRequestMatcher matching} requests
120         * and a delegate {@code WebClient} for all other requests.
121         * <p>If a {@linkplain #withDelegate delegate} has been explicitly configured,
122         * it will be used; otherwise, a default {@code WebClient} will be configured
123         * as the delegate.
124         * @return the {@code WebClient} to use
125         * @see #withDelegate(WebClient)
126         */
127        public WebClient build() {
128                return (this.webClient != null ? this.webClient : withDelegate(new WebClient()).build());
129        }
130
131}