diff --git a/spring-core-2/README.md b/spring-core-2/README.md index ec6eb91306..027c049163 100644 --- a/spring-core-2/README.md +++ b/spring-core-2/README.md @@ -16,4 +16,5 @@ This module contains articles about core Spring functionality - [Spring Null-Safety Annotations](https://www.baeldung.com/spring-null-safety-annotations) - [Using @Autowired in Abstract Classes](https://www.baeldung.com/spring-autowired-abstract-class) - [Guide to the Spring BeanFactory](https://www.baeldung.com/spring-beanfactory) -- More articles: [[<-- prev]](/spring-core) +- [Read HttpServletRequest Multiple Times](https://www.baeldung.com/spring-reading-httpservletrequest-multiple-times) +- More articles: [[<-- prev]](/spring-core) \ No newline at end of file diff --git a/spring-core-2/src/main/java/org/baeldung/cachedrequest/CachedBodyHttpServletRequest.java b/spring-core-2/src/main/java/org/baeldung/cachedrequest/CachedBodyHttpServletRequest.java new file mode 100644 index 0000000000..b6d4905653 --- /dev/null +++ b/spring-core-2/src/main/java/org/baeldung/cachedrequest/CachedBodyHttpServletRequest.java @@ -0,0 +1,37 @@ +package org.baeldung.cachedrequest; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.springframework.util.StreamUtils; + +public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper { + + private byte[] cachedBody; + + public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException { + super(request); + InputStream requestInputStream = request.getInputStream(); + this.cachedBody = StreamUtils.copyToByteArray(requestInputStream); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return new CachedBodyServletInputStream(this.cachedBody); + } + + @Override + public BufferedReader getReader() throws IOException { + // Create a reader from cachedContent + // and return it + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(this.cachedBody); + return new BufferedReader(new InputStreamReader(byteArrayInputStream)); + } +} \ No newline at end of file diff --git a/spring-core-2/src/main/java/org/baeldung/cachedrequest/CachedBodyServletInputStream.java b/spring-core-2/src/main/java/org/baeldung/cachedrequest/CachedBodyServletInputStream.java new file mode 100644 index 0000000000..a18de30788 --- /dev/null +++ b/spring-core-2/src/main/java/org/baeldung/cachedrequest/CachedBodyServletInputStream.java @@ -0,0 +1,43 @@ +package org.baeldung.cachedrequest; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; + +public class CachedBodyServletInputStream extends ServletInputStream { + + private InputStream cachedBodyInputStream; + + public CachedBodyServletInputStream(byte[] cachedBody) { + this.cachedBodyInputStream = new ByteArrayInputStream(cachedBody); + } + + @Override + public boolean isFinished() { + try { + return cachedBodyInputStream.available() == 0; + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return false; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + throw new UnsupportedOperationException(); + } + + @Override + public int read() throws IOException { + return cachedBodyInputStream.read(); + } +} diff --git a/spring-core-2/src/main/java/org/baeldung/cachedrequest/ContentCachingFilter.java b/spring-core-2/src/main/java/org/baeldung/cachedrequest/ContentCachingFilter.java new file mode 100644 index 0000000000..e3f3b7a060 --- /dev/null +++ b/spring-core-2/src/main/java/org/baeldung/cachedrequest/ContentCachingFilter.java @@ -0,0 +1,27 @@ +package org.baeldung.cachedrequest; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +@Order(value = Ordered.HIGHEST_PRECEDENCE) +@Component +@WebFilter(filterName = "ContentCachingFilter", urlPatterns = "/*") +public class ContentCachingFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { + System.out.println("IN ContentCachingFilter "); + CachedBodyHttpServletRequest cachedBodyHttpServletRequest = new CachedBodyHttpServletRequest(httpServletRequest); + filterChain.doFilter(cachedBodyHttpServletRequest, httpServletResponse); + } +} diff --git a/spring-core-2/src/main/java/org/baeldung/cachedrequest/HttpRequestDemoConfig.java b/spring-core-2/src/main/java/org/baeldung/cachedrequest/HttpRequestDemoConfig.java new file mode 100644 index 0000000000..9194bcf27c --- /dev/null +++ b/spring-core-2/src/main/java/org/baeldung/cachedrequest/HttpRequestDemoConfig.java @@ -0,0 +1,17 @@ +package org.baeldung.cachedrequest; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +/** + * To initialize the WebApplication, Please see + * {@link org.baeldung.spring.config.MainWebAppInitializer} + */ + +@EnableWebMvc +@Configuration +@ComponentScan(basePackages = "org.baeldung.cachedrequest") +public class HttpRequestDemoConfig implements WebMvcConfigurer { + +} \ No newline at end of file diff --git a/spring-core-2/src/main/java/org/baeldung/cachedrequest/Person.java b/spring-core-2/src/main/java/org/baeldung/cachedrequest/Person.java new file mode 100644 index 0000000000..594b6f2360 --- /dev/null +++ b/spring-core-2/src/main/java/org/baeldung/cachedrequest/Person.java @@ -0,0 +1,47 @@ +package org.baeldung.cachedrequest; + +public class Person { + private String firstName; + + private String lastName; + + private int age; + + public Person() { + } + + public Person(String firstName, String lastName, int age) { + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @Override + public String toString() { + return "Person{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", age=" + age + '}'; + } +} diff --git a/spring-core-2/src/main/java/org/baeldung/cachedrequest/PersonController.java b/spring-core-2/src/main/java/org/baeldung/cachedrequest/PersonController.java new file mode 100644 index 0000000000..6f241b3fb3 --- /dev/null +++ b/spring-core-2/src/main/java/org/baeldung/cachedrequest/PersonController.java @@ -0,0 +1,26 @@ +package org.baeldung.cachedrequest; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class PersonController { + + @PostMapping(value = "/person") + @ResponseStatus(value = HttpStatus.NO_CONTENT) + public void printPerson(@RequestBody Person person) { + + System.out.println("In Demo Controller. Person " + "is : " + person); + } + + @GetMapping(value = "/person") + @ResponseStatus(value = HttpStatus.NO_CONTENT) + public void getPerson() { + + System.out.println("In Demo Controller get method."); + } +} \ No newline at end of file diff --git a/spring-core-2/src/main/java/org/baeldung/cachedrequest/PrintRequestContentFilter.java b/spring-core-2/src/main/java/org/baeldung/cachedrequest/PrintRequestContentFilter.java new file mode 100644 index 0000000000..55455f590f --- /dev/null +++ b/spring-core-2/src/main/java/org/baeldung/cachedrequest/PrintRequestContentFilter.java @@ -0,0 +1,31 @@ +package org.baeldung.cachedrequest; + + +import java.io.IOException; +import java.io.InputStream; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.StreamUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +@Order(Ordered.LOWEST_PRECEDENCE) +@Component +@WebFilter(filterName = "printRequestContentFilter", urlPatterns = "/*") +public class PrintRequestContentFilter extends OncePerRequestFilter { + @Override + protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { + System.out.println("IN PrintRequestContentFilter "); + InputStream inputStream = httpServletRequest.getInputStream(); + byte[] body = StreamUtils.copyToByteArray(inputStream); + System.out.println("In PrintRequestContentFilter. Request body is: " + new String(body)); + filterChain.doFilter(httpServletRequest, httpServletResponse); + } +} diff --git a/spring-core-2/src/test/java/org/baeldung/cachedrequest/CachedBodyHttpServletRequestUnitTest.java b/spring-core-2/src/test/java/org/baeldung/cachedrequest/CachedBodyHttpServletRequestUnitTest.java new file mode 100644 index 0000000000..1fe9dd4c82 --- /dev/null +++ b/spring-core-2/src/test/java/org/baeldung/cachedrequest/CachedBodyHttpServletRequestUnitTest.java @@ -0,0 +1,62 @@ +package org.baeldung.cachedrequest; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.util.StreamUtils; + +import junit.framework.TestCase; + +@RunWith(MockitoJUnitRunner.class) +public class CachedBodyHttpServletRequestUnitTest extends TestCase { + + private CachedBodyServletInputStream servletInputStream; + + @After + public void cleanUp() throws IOException { + if (null != servletInputStream) { + servletInputStream.close(); + } + } + + @Test + public void testGivenHttpServletRequestWithBody_whenCalledGetInputStream_ThenGetsServletInputStreamWithSameBody() throws IOException { + // Given + byte[] cachedBody = "{\"firstName\" :\"abc\",\"lastName\" : \"xyz\",\"age\" : 30\"}".getBytes(); + MockHttpServletRequest mockeddHttpServletRequest = new MockHttpServletRequest(); + mockeddHttpServletRequest.setContent(cachedBody); + CachedBodyHttpServletRequest request = new CachedBodyHttpServletRequest(mockeddHttpServletRequest); + + // when + InputStream inputStream = request.getInputStream(); + + // then + assertEquals(new String(cachedBody), new String(StreamUtils.copyToByteArray(inputStream))); + } + + @Test + public void testGivenHttpServletRequestWithBody_whenCalledGetReader_ThenGetBufferedReaderWithSameBody() throws IOException { + // Given + byte[] cachedBody = "{\"firstName\" :\"abc\",\"lastName\" : \"xyz\",\"age\" : 30\"}".getBytes(); + MockHttpServletRequest mockeddHttpServletRequest = new MockHttpServletRequest(); + mockeddHttpServletRequest.setContent(cachedBody); + CachedBodyHttpServletRequest request = new CachedBodyHttpServletRequest(mockeddHttpServletRequest); + + // when + BufferedReader bufferedReader = request.getReader(); + + // then + String line = ""; + StringBuilder builder = new StringBuilder(); + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + assertEquals(new String(cachedBody), builder.toString()); + } +} diff --git a/spring-core-2/src/test/java/org/baeldung/cachedrequest/CachedBodyServletInputStreamUnitTest.java b/spring-core-2/src/test/java/org/baeldung/cachedrequest/CachedBodyServletInputStreamUnitTest.java new file mode 100644 index 0000000000..d7000d91ee --- /dev/null +++ b/spring-core-2/src/test/java/org/baeldung/cachedrequest/CachedBodyServletInputStreamUnitTest.java @@ -0,0 +1,98 @@ +package org.baeldung.cachedrequest; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import javax.servlet.ReadListener; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.util.StreamUtils; + +import junit.framework.TestCase; + +@RunWith(MockitoJUnitRunner.class) +public class CachedBodyServletInputStreamUnitTest extends TestCase { + + private CachedBodyServletInputStream servletInputStream; + + @After + public void cleanUp() throws IOException { + if (null != servletInputStream) { + servletInputStream.close(); + } + } + + @Test + public void testGivenServletInputStreamCreated_whenCalledisFinished_Thenfalse() { + // Given + byte[] cachedBody = "{\"firstName\" :\"abc\",\"lastName\" : \"xyz\",\"age\" : 30\"}".getBytes(); + servletInputStream = new CachedBodyServletInputStream(cachedBody); + + // when + boolean finished = servletInputStream.isFinished(); + + // then + assertFalse(finished); + } + + @Test + public void testGivenServletInputStreamCreatedAndBodyRead_whenCalledisFinished_ThenTrue() throws IOException { + // Given + byte[] cachedBody = "{\"firstName\" :\"abc\",\"lastName\" : \"xyz\",\"age\" : 30\"}".getBytes(); + servletInputStream = new CachedBodyServletInputStream(cachedBody); + StreamUtils.copyToByteArray(servletInputStream); + + // when + boolean finished = servletInputStream.isFinished(); + + // then + assertTrue(finished); + } + + @Test + public void testGivenServletInputStreamCreatedAndBodyRead_whenCalledIsReady_ThenTrue() throws IOException { + // Given + byte[] cachedBody = "{\"firstName\" :\"abc\",\"lastName\" : \"xyz\",\"age\" : 30\"}".getBytes(); + servletInputStream = new CachedBodyServletInputStream(cachedBody); + + // when + boolean ready = servletInputStream.isReady(); + + // then + assertTrue(ready); + } + + @Test + public void testGivenServletInputStreamCreated_whenCalledIsRead_ThenReturnsBody() throws IOException { + // Given + byte[] cachedBody = "{\"firstName\" :\"abc\",\"lastName\" : \"xyz\",\"age\" : 30\"}".getBytes(); + servletInputStream = new CachedBodyServletInputStream(cachedBody); + + // when + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + int len = 0; + byte[] buffer = new byte[1024]; + while ((len = servletInputStream.read(buffer)) != -1) { + byteArrayOutputStream.write(buffer, 0, len); + } + + // then + assertEquals(new String(cachedBody), new String(byteArrayOutputStream.toByteArray())); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGivenServletInputStreamCreated_whenCalledIsRead_ThenThrowsException() throws IOException { + // Given + byte[] cachedBody = "{\"firstName\" :\"abc\",\"lastName\" : \"xyz\",\"age\" : 30\"}".getBytes(); + servletInputStream = new CachedBodyServletInputStream(cachedBody); + + // when + servletInputStream.setReadListener(Mockito.mock(ReadListener.class)); + + } + +} diff --git a/spring-core-2/src/test/java/org/baeldung/cachedrequest/ContentCachingFilterUnitTest.java b/spring-core-2/src/test/java/org/baeldung/cachedrequest/ContentCachingFilterUnitTest.java new file mode 100644 index 0000000000..057f1ac627 --- /dev/null +++ b/spring-core-2/src/test/java/org/baeldung/cachedrequest/ContentCachingFilterUnitTest.java @@ -0,0 +1,39 @@ +package org.baeldung.cachedrequest; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import junit.framework.TestCase; + +@RunWith(MockitoJUnitRunner.class) +public class ContentCachingFilterUnitTest extends TestCase { + + @InjectMocks + private ContentCachingFilter filterToTest; + + @Test + public void testGivenHttpRequest_WhenDoFilter_thenCreatesRequestWrapperObject() throws IOException, ServletException { + // Given + MockHttpServletRequest mockedRequest = new MockHttpServletRequest(); + MockHttpServletResponse mockedResponse = new MockHttpServletResponse(); + FilterChain mockedFilterChain = Mockito.mock(FilterChain.class); + + // when + filterToTest.doFilter(mockedRequest, mockedResponse, mockedFilterChain); + + // then + Mockito.verify(mockedFilterChain, Mockito.times(1)) + .doFilter(Mockito.any(CachedBodyHttpServletRequest.class), Mockito.any(MockHttpServletResponse.class)); + } + +} diff --git a/spring-core-2/src/test/java/org/baeldung/cachedrequest/PersonControllerIntegrationTest.java b/spring-core-2/src/test/java/org/baeldung/cachedrequest/PersonControllerIntegrationTest.java new file mode 100644 index 0000000000..77d6a816e3 --- /dev/null +++ b/spring-core-2/src/test/java/org/baeldung/cachedrequest/PersonControllerIntegrationTest.java @@ -0,0 +1,46 @@ +package org.baeldung.cachedrequest; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.IOException; + +import javax.print.attribute.PrintRequestAttribute; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { HttpRequestDemoConfig.class, ContentCachingFilter.class, PrintRequestAttribute.class }) +@AutoConfigureMockMvc +public class PersonControllerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + ObjectMapper objectMapper = new ObjectMapper(); + + @Test + public void whenValidInput_thenCreateBook() throws IOException, Exception { + // assign - given + Person book = new Person("sumit", "abc", 100); + + // act - when + ResultActions result = mockMvc.perform(post("/person").accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(book))); + + // assert - then + result.andExpect(status().isNoContent()); + } + +} diff --git a/spring-core-2/src/test/java/org/baeldung/cachedrequest/PrintRequestContentFilterUnitTest.java b/spring-core-2/src/test/java/org/baeldung/cachedrequest/PrintRequestContentFilterUnitTest.java new file mode 100644 index 0000000000..ca2d5c600b --- /dev/null +++ b/spring-core-2/src/test/java/org/baeldung/cachedrequest/PrintRequestContentFilterUnitTest.java @@ -0,0 +1,40 @@ +package org.baeldung.cachedrequest; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import junit.framework.TestCase; + +@RunWith(MockitoJUnitRunner.class) +public class PrintRequestContentFilterUnitTest extends TestCase { + + @InjectMocks + private PrintRequestContentFilter filterToTest; + + @Test + public void testGivenHttpRequest_WhenDoFilter_thenReadsBody() throws IOException, ServletException { + // Given + MockHttpServletRequest mockedRequest = new MockHttpServletRequest(); + MockHttpServletResponse mockedResponse = new MockHttpServletResponse(); + FilterChain mockedFilterChain = Mockito.mock(FilterChain.class); + CachedBodyHttpServletRequest cachedBodyHttpServletRequest = new CachedBodyHttpServletRequest(mockedRequest); + + // when + filterToTest.doFilter(cachedBodyHttpServletRequest, mockedResponse, mockedFilterChain); + + // then + Mockito.verify(mockedFilterChain, Mockito.times(1)) + .doFilter(cachedBodyHttpServletRequest, mockedResponse); + } + +} diff --git a/testing-modules/gatling/Jenkinsfile b/testing-modules/gatling/Jenkinsfile new file mode 100644 index 0000000000..0786788406 --- /dev/null +++ b/testing-modules/gatling/Jenkinsfile @@ -0,0 +1,20 @@ +pipeline { + agent any + stages { + stage("Build Maven") { + steps { + sh 'mvn -B clean package' + } + } + stage("Run Gatling") { + steps { + sh 'mvn gatling:test' + } + post { + always { + gatlingArchive() + } + } + } + } +} \ No newline at end of file diff --git a/testing-modules/gatling/pom.xml b/testing-modules/gatling/pom.xml index 37693ebfee..d105cc8b3e 100644 --- a/testing-modules/gatling/pom.xml +++ b/testing-modules/gatling/pom.xml @@ -1,13 +1,13 @@ - 4.0.0 - org.baeldung - gatling - 1.0-SNAPSHOT - gatling - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + org.baeldung + gatling + 1.0-SNAPSHOT + gatling + com.baeldung parent-modules @@ -15,122 +15,106 @@ ../../ - - - - io.gatling - gatling-app - ${gatling.version} - - - io.gatling - gatling-recorder - ${gatling.version} - - - io.gatling.highcharts - gatling-charts-highcharts - ${gatling.version} - - - org.scala-lang - scala-library - ${scala.version} - - - - - - - io.gatling.highcharts - gatling-charts-highcharts - - - io.gatling - gatling-app - - - io.gatling - gatling-recorder - - - org.scala-lang - scala-library - - - - src/test/scala - - - - net.alchim31.maven - scala-maven-plugin - ${scala-maven-plugin.version} - - - - - - net.alchim31.maven - scala-maven-plugin - - - - testCompile - - - - - -Ydelambdafy:method - -target:jvm-1.8 - -deprecation - -feature - -unchecked - -language:implicitConversions - -language:postfixOps - - - - - - - - - - - simulation - - - - io.gatling - gatling-maven-plugin - ${gatling-maven-plugin.version} - - - test - - execute - - - true - - - - - - - - + + + + io.gatling + gatling-app + ${gatling.version} + + + io.gatling + gatling-recorder + ${gatling.version} + + + io.gatling.highcharts + gatling-charts-highcharts + ${gatling.version} + + + org.scala-lang + scala-library + ${scala.version} + + + - - 1.8 - 1.8 - UTF-8 - 2.12.6 - 2.3.1 - 3.2.2 - 2.2.4 - + + + io.gatling.highcharts + gatling-charts-highcharts + + + io.gatling + gatling-app + + + io.gatling + gatling-recorder + + + org.scala-lang + scala-library + + + + + src/test/scala + + + + net.alchim31.maven + scala-maven-plugin + ${scala-maven-plugin.version} + + + + + + net.alchim31.maven + scala-maven-plugin + + + + testCompile + + + + + -Ydelambdafy:method + -target:jvm-1.8 + -deprecation + -feature + -unchecked + -language:implicitConversions + -language:postfixOps + + + + + + + io.gatling + gatling-maven-plugin + ${gatling-maven-plugin.version} + + org.baeldung.RecordedSimulation + + + + + + + + 1.8 + 1.8 + UTF-8 + 2.12.6 + 3.3.1 + 4.3.0 + 3.0.4 + diff --git a/testing-modules/gatling/src/test/scala/Engine.scala b/testing-modules/gatling/src/test/scala/Engine.scala index c2884fc218..a34d3eaf60 100644 --- a/testing-modules/gatling/src/test/scala/Engine.scala +++ b/testing-modules/gatling/src/test/scala/Engine.scala @@ -3,11 +3,10 @@ import io.gatling.core.config.GatlingPropertiesBuilder object Engine extends App { - val props = new GatlingPropertiesBuilder - props.dataDirectory(IDEPathHelper.dataDirectory.toString) - props.resultsDirectory(IDEPathHelper.resultsDirectory.toString) - props.bodiesDirectory(IDEPathHelper.bodiesDirectory.toString) - props.binariesDirectory(IDEPathHelper.mavenBinariesDirectory.toString) + val props = new GatlingPropertiesBuilder() + .resourcesDirectory(IDEPathHelper.resourcesDirectory.toString) + .resultsDirectory(IDEPathHelper.resultsDirectory.toString) + .binariesDirectory(IDEPathHelper.mavenBinariesDirectory.toString) - Gatling.fromMap(props.build) + Gatling.fromMap(props.build) } diff --git a/testing-modules/gatling/src/test/scala/IDEPathHelper.scala b/testing-modules/gatling/src/test/scala/IDEPathHelper.scala index 9fb1d7d5c8..6aef6707b2 100644 --- a/testing-modules/gatling/src/test/scala/IDEPathHelper.scala +++ b/testing-modules/gatling/src/test/scala/IDEPathHelper.scala @@ -4,7 +4,7 @@ import io.gatling.commons.util.PathHelper._ object IDEPathHelper { - val gatlingConfUrl: Path = getClass.getClassLoader.getResource("gatling.conf").toURI + val gatlingConfUrl: Path = getClass.getClassLoader.getResource("gatling.conf") val projectRootDir = gatlingConfUrl.ancestor(3) val mavenSourcesDirectory = projectRootDir / "src" / "test" / "scala" @@ -12,11 +12,8 @@ object IDEPathHelper { val mavenTargetDirectory = projectRootDir / "target" val mavenBinariesDirectory = mavenTargetDirectory / "test-classes" - val dataDirectory = mavenResourcesDirectory / "data" - val bodiesDirectory = mavenResourcesDirectory / "bodies" - - val recorderOutputDirectory = mavenSourcesDirectory + val resourcesDirectory = mavenResourcesDirectory + val recorderSimulationsDirectory = mavenSourcesDirectory val resultsDirectory = mavenTargetDirectory / "gatling" - val recorderConfigFile = mavenResourcesDirectory / "recorder.conf" } diff --git a/testing-modules/gatling/src/test/scala/Recorder.scala b/testing-modules/gatling/src/test/scala/Recorder.scala index 9c38e52f12..187f566aac 100644 --- a/testing-modules/gatling/src/test/scala/Recorder.scala +++ b/testing-modules/gatling/src/test/scala/Recorder.scala @@ -3,10 +3,10 @@ import io.gatling.recorder.config.RecorderPropertiesBuilder object Recorder extends App { - val props = new RecorderPropertiesBuilder - props.simulationOutputFolder(IDEPathHelper.recorderOutputDirectory.toString) - props.simulationPackage("org.baeldung") - props.bodiesFolder(IDEPathHelper.bodiesDirectory.toString) + val props = new RecorderPropertiesBuilder() + .simulationsFolder(IDEPathHelper.recorderSimulationsDirectory.toString) + .simulationPackage("org.baeldung") + .resourcesFolder(IDEPathHelper.resourcesDirectory.toString) GatlingRecorder.fromMap(props.build, Some(IDEPathHelper.recorderConfigFile)) } diff --git a/testing-modules/gatling/src/test/scala/org/baeldung/RecordedSimulation.scala b/testing-modules/gatling/src/test/scala/org/baeldung/RecordedSimulation.scala index dece393478..9902f91e0f 100644 --- a/testing-modules/gatling/src/test/scala/org/baeldung/RecordedSimulation.scala +++ b/testing-modules/gatling/src/test/scala/org/baeldung/RecordedSimulation.scala @@ -9,7 +9,7 @@ import io.gatling.jdbc.Predef._ class RecordedSimulation extends Simulation { val httpProtocol = http - .baseURL("http://computer-database.gatling.io") + .baseUrl("http://computer-database.gatling.io") .inferHtmlResources(BlackList(""".*\.css""", """.*\.js""", """.*\.ico"""), WhiteList()) .acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") .acceptEncodingHeader("gzip, deflate") diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/fluentapi/Pizza.java b/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/fluentapi/Pizza.java new file mode 100644 index 0000000000..0a37a2cbbd --- /dev/null +++ b/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/fluentapi/Pizza.java @@ -0,0 +1,102 @@ +package com.baeldung.mockito.fluentapi; + +import java.util.ArrayList; +import java.util.List; + +public class Pizza { + + public enum PizzaSize { + LARGE, MEDIUM, SMALL; + } + + private String name; + private PizzaSize size; + private List toppings; + private boolean stuffedCrust; + private boolean collect; + private Integer discount; + + private Pizza(PizzaBuilder builder) { + this.name = builder.name; + this.size = builder.size; + this.toppings = builder.toppings; + this.stuffedCrust = builder.stuffedCrust; + this.collect = builder.collect; + this.discount = builder.discount; + } + + public String getName() { + return name; + } + + public PizzaSize getSize() { + return size; + } + + public List getToppings() { + return toppings; + } + + public boolean isStuffedCrust() { + return stuffedCrust; + } + + public boolean isCollecting() { + return collect; + } + + public Integer getDiscount() { + return discount; + } + + public static class PizzaBuilder { + private String name; + private PizzaSize size; + + private List toppings; + private boolean stuffedCrust; + private boolean collect; + private Integer discount = null; + + public PizzaBuilder() { + } + + public PizzaBuilder name(String name) { + this.name = name; + return this; + } + + public PizzaBuilder size(PizzaSize size) { + this.size = size; + return this; + } + + public PizzaBuilder withExtraTopping(String extraTopping) { + if (this.toppings == null) { + toppings = new ArrayList<>(); + } + this.toppings.add(extraTopping); + return this; + } + + public PizzaBuilder withStuffedCrust(boolean stuffedCrust) { + this.stuffedCrust = stuffedCrust; + return this; + } + + public PizzaBuilder willCollect(boolean collect) { + this.collect = collect; + return this; + } + + public PizzaBuilder applyDiscount(Integer discount) { + this.discount = discount; + return this; + } + + public Pizza build() { + return new Pizza(this); + } + } + +} diff --git a/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/fluentapi/PizzaService.java b/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/fluentapi/PizzaService.java new file mode 100644 index 0000000000..0f9d5c6b18 --- /dev/null +++ b/testing-modules/mockito-2/src/main/java/com/baeldung/mockito/fluentapi/PizzaService.java @@ -0,0 +1,23 @@ +package com.baeldung.mockito.fluentapi; + +import com.baeldung.mockito.fluentapi.Pizza.PizzaSize; + +public class PizzaService { + + private Pizza.PizzaBuilder builder; + + public PizzaService(Pizza.PizzaBuilder builder) { + this.builder = builder; + } + + public Pizza orderHouseSpecial() { + return builder.name("Special") + .size(PizzaSize.LARGE) + .withExtraTopping("Mushrooms") + .withStuffedCrust(true) + .withExtraTopping("Chilli") + .willCollect(true) + .applyDiscount(20) + .build(); + } +} diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/fluentapi/PizzaServiceUnitTest.java b/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/fluentapi/PizzaServiceUnitTest.java new file mode 100644 index 0000000000..b5dd10b1d4 --- /dev/null +++ b/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/fluentapi/PizzaServiceUnitTest.java @@ -0,0 +1,88 @@ +package com.baeldung.mockito.fluentapi; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Answers; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import com.baeldung.mockito.fluentapi.Pizza.PizzaBuilder; +import com.baeldung.mockito.fluentapi.Pizza.PizzaSize; + +public class PizzaServiceUnitTest { + + @Mock + private Pizza expectedPizza; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private PizzaBuilder anotherbuilder; + + @Captor + private ArgumentCaptor stringCaptor; + @Captor + private ArgumentCaptor sizeCaptor; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void givenTraditonalMocking_whenServiceInvoked_thenPizzaIsBuilt() { + PizzaBuilder nameBuilder = Mockito.mock(Pizza.PizzaBuilder.class); + PizzaBuilder sizeBuilder = Mockito.mock(Pizza.PizzaBuilder.class); + PizzaBuilder firstToppingBuilder = Mockito.mock(Pizza.PizzaBuilder.class); + PizzaBuilder secondToppingBuilder = Mockito.mock(Pizza.PizzaBuilder.class); + PizzaBuilder stuffedBuilder = Mockito.mock(Pizza.PizzaBuilder.class); + PizzaBuilder willCollectBuilder = Mockito.mock(Pizza.PizzaBuilder.class); + PizzaBuilder discountBuilder = Mockito.mock(Pizza.PizzaBuilder.class); + + PizzaBuilder builder = Mockito.mock(Pizza.PizzaBuilder.class); + when(builder.name(anyString())).thenReturn(nameBuilder); + when(nameBuilder.size(any(Pizza.PizzaSize.class))).thenReturn(sizeBuilder); + when(sizeBuilder.withExtraTopping(anyString())).thenReturn(firstToppingBuilder); + when(firstToppingBuilder.withStuffedCrust(anyBoolean())).thenReturn(stuffedBuilder); + when(stuffedBuilder.withExtraTopping(anyString())).thenReturn(secondToppingBuilder); + when(secondToppingBuilder.willCollect(anyBoolean())).thenReturn(willCollectBuilder); + when(willCollectBuilder.applyDiscount(anyInt())).thenReturn(discountBuilder); + when(discountBuilder.build()).thenReturn(expectedPizza); + + PizzaService service = new PizzaService(builder); + assertEquals("Expected Pizza", expectedPizza, service.orderHouseSpecial()); + + verify(builder).name(stringCaptor.capture()); + assertEquals("Pizza name: ", "Special", stringCaptor.getValue()); + + verify(nameBuilder).size(sizeCaptor.capture()); + assertEquals("Pizza size: ", PizzaSize.LARGE, sizeCaptor.getValue()); + + } + + @Test + public void givenDeepStubs_whenServiceInvoked_thenPizzaIsBuilt() { + Mockito.when(anotherbuilder.name(anyString()) + .size(any(Pizza.PizzaSize.class)) + .withExtraTopping(anyString()) + .withStuffedCrust(anyBoolean()) + .withExtraTopping(anyString()) + .willCollect(anyBoolean()) + .applyDiscount(anyInt()) + .build()) + .thenReturn(expectedPizza); + + PizzaService service = new PizzaService(anotherbuilder); + assertEquals("Expected Pizza", expectedPizza, service.orderHouseSpecial()); + } + +} diff --git a/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/fluentapi/PizzaUnitTest.java b/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/fluentapi/PizzaUnitTest.java new file mode 100644 index 0000000000..1486cb7f2f --- /dev/null +++ b/testing-modules/mockito-2/src/test/java/com/baeldung/mockito/fluentapi/PizzaUnitTest.java @@ -0,0 +1,32 @@ +package com.baeldung.mockito.fluentapi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.baeldung.mockito.fluentapi.Pizza.PizzaSize; + +public class PizzaUnitTest { + + @Test + public void givenFluentPizzaApi_whenBuilt_thenPizzaHasCorrectAttributes() { + Pizza pizza = new Pizza.PizzaBuilder() + .name("Margherita") + .size(PizzaSize.LARGE) + .withExtraTopping("Mushroom") + .withStuffedCrust(false) + .willCollect(true) + .applyDiscount(20) + .build(); + + assertEquals("Pizza name: ", "Margherita", pizza.getName()); + assertEquals("Pizza size: ", PizzaSize.LARGE, pizza.getSize()); + assertEquals("Extra toppings: ", "Mushroom", pizza.getToppings() + .get(0)); + assertFalse("Has stuffed crust: ", pizza.isStuffedCrust()); + assertTrue("Will collect: ", pizza.isCollecting()); + assertEquals("Discounts: ", Integer.valueOf(20), pizza.getDiscount()); + } +}