diff --git a/libraries-security/pom.xml b/libraries-security/pom.xml index 9f125361ba..17d57fe203 100644 --- a/libraries-security/pom.xml +++ b/libraries-security/pom.xml @@ -32,6 +32,12 @@ ${scribejava.version} + + com.google.crypto.tink + tink + ${tink.version} + + junit junit @@ -55,6 +61,7 @@ 5.6.0 2.3.3.RELEASE 1.3.1 + 1.2.2 1.2.2 diff --git a/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java b/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java new file mode 100644 index 0000000000..b98c698016 --- /dev/null +++ b/libraries-security/src/test/java/com/baeldung/tink/TinkUnitTest.java @@ -0,0 +1,101 @@ +package com.baeldung.tink; + +import com.google.crypto.tink.*; +import com.google.crypto.tink.aead.AeadConfig; +import com.google.crypto.tink.aead.AeadFactory; +import com.google.crypto.tink.aead.AeadKeyTemplates; +import com.google.crypto.tink.config.TinkConfig; +import com.google.crypto.tink.hybrid.HybridDecryptFactory; +import com.google.crypto.tink.hybrid.HybridEncryptFactory; +import com.google.crypto.tink.hybrid.HybridKeyTemplates; +import com.google.crypto.tink.mac.MacFactory; +import com.google.crypto.tink.mac.MacKeyTemplates; +import com.google.crypto.tink.signature.PublicKeySignFactory; +import com.google.crypto.tink.signature.PublicKeyVerifyFactory; +import com.google.crypto.tink.signature.SignatureKeyTemplates; +import org.junit.Assert; +import org.junit.Test; + +import java.security.GeneralSecurityException; + +public class TinkUnitTest { + + private static final String PLAINTEXT = "BAELDUNG"; + private static final String DATA = "TINK"; + + @Test + public void givenPlaintext_whenEncryptWithAead_thenPlaintextIsEncrypted() throws GeneralSecurityException { + + AeadConfig.register(); + + KeysetHandle keysetHandle = KeysetHandle.generateNew( + AeadKeyTemplates.AES256_GCM); + + Aead aead = AeadFactory.getPrimitive(keysetHandle); + + byte[] ciphertext = aead.encrypt(PLAINTEXT.getBytes(), + DATA.getBytes()); + + Assert.assertNotEquals(PLAINTEXT, new String(ciphertext)); + } + + @Test + public void givenData_whenComputeMAC_thenVerifyMAC() throws GeneralSecurityException { + + TinkConfig.register(); + + KeysetHandle keysetHandle = KeysetHandle.generateNew( + MacKeyTemplates.HMAC_SHA256_128BITTAG); + + Mac mac = MacFactory.getPrimitive(keysetHandle); + + byte[] tag = mac.computeMac(DATA.getBytes()); + + mac.verifyMac(tag, DATA.getBytes()); + } + + @Test + public void givenData_whenSignData_thenVerifySignature() throws GeneralSecurityException { + + TinkConfig.register(); + + KeysetHandle privateKeysetHandle = KeysetHandle.generateNew( + SignatureKeyTemplates.ECDSA_P256); + + PublicKeySign signer = PublicKeySignFactory.getPrimitive(privateKeysetHandle); + + byte[] signature = signer.sign(DATA.getBytes()); + + KeysetHandle publicKeysetHandle = + privateKeysetHandle.getPublicKeysetHandle(); + + PublicKeyVerify verifier = PublicKeyVerifyFactory.getPrimitive(publicKeysetHandle); + + verifier.verify(signature, DATA.getBytes()); + } + + @Test + public void givenPlaintext_whenEncryptWithHybridEncryption_thenVerifyDecryptedIsEqual() throws GeneralSecurityException { + + TinkConfig.register(); + + KeysetHandle privateKeysetHandle = KeysetHandle.generateNew( + HybridKeyTemplates.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256); + + KeysetHandle publicKeysetHandle = privateKeysetHandle.getPublicKeysetHandle(); + + HybridEncrypt hybridEncrypt = HybridEncryptFactory.getPrimitive(publicKeysetHandle); + + HybridDecrypt hybridDecrypt = HybridDecryptFactory.getPrimitive(privateKeysetHandle); + + String contextInfo = "Tink"; + + byte[] ciphertext = hybridEncrypt.encrypt(PLAINTEXT.getBytes(), contextInfo.getBytes()); + + byte[] plaintextDecrypted = hybridDecrypt.decrypt(ciphertext, contextInfo.getBytes()); + + Assert.assertEquals(PLAINTEXT,new String(plaintextDecrypted)); + } +} + + diff --git a/pom.xml b/pom.xml index d6cee747ec..d57fa1694e 100644 --- a/pom.xml +++ b/pom.xml @@ -540,7 +540,8 @@ software-security/sql-injection-samples tensorflow-java - + spring-boot-flowable + @@ -766,6 +767,7 @@ xstream tensorflow-java + spring-boot-flowable @@ -908,6 +910,8 @@ persistence-modules/spring-data-eclipselink persistence-modules/spring-data-solr persistence-modules/spring-hibernate-5 + + spring-boot-flowable diff --git a/spring-boot-flowable/README.md b/spring-boot-flowable/README.md new file mode 100644 index 0000000000..8fb90d953b --- /dev/null +++ b/spring-boot-flowable/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Introduction to Flowable](http://www.baeldung.com/flowable) diff --git a/spring-boot-flowable/pom.xml b/spring-boot-flowable/pom.xml new file mode 100644 index 0000000000..f9531a1e6a --- /dev/null +++ b/spring-boot-flowable/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + spring-boot-flowable + war + spring-boot-flowable + Spring Boot Flowable Module + + parent-boot-2 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-2 + + + + org.springframework.boot + spring-boot-starter-web + + + com.h2database + h2 + runtime + + + org.flowable + flowable-spring-boot-starter-rest + ${flowable.version} + + + org.flowable + flowable-spring-boot-starter-actuator + ${flowable.version} + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + 6.4.1 + + \ No newline at end of file diff --git a/spring-boot-flowable/src/main/java/com/baeldung/Application.java b/spring-boot-flowable/src/main/java/com/baeldung/Application.java new file mode 100644 index 0000000000..37dbe7dab8 --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/Application.java @@ -0,0 +1,13 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-boot-flowable/src/main/java/com/baeldung/controller/ArticleWorkflowController.java b/spring-boot-flowable/src/main/java/com/baeldung/controller/ArticleWorkflowController.java new file mode 100644 index 0000000000..3087d30af4 --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/controller/ArticleWorkflowController.java @@ -0,0 +1,32 @@ +package com.baeldung.controller; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.baeldung.domain.Approval; +import com.baeldung.domain.Article; +import com.baeldung.service.ArticleWorkflowService; + +@RestController +public class ArticleWorkflowController { + @Autowired + private ArticleWorkflowService service; + @PostMapping("/submit") + public void submit(@RequestBody Article article) { + service.startProcess(article); + } + @GetMapping("/tasks") + public List
getTasks(@RequestParam String assignee) { + return service.getTasks(assignee); + } + @PostMapping("/review") + public void review(@RequestBody Approval approval) { + service.submitReview(approval); + } +} \ No newline at end of file diff --git a/spring-boot-flowable/src/main/java/com/baeldung/domain/Approval.java b/spring-boot-flowable/src/main/java/com/baeldung/domain/Approval.java new file mode 100644 index 0000000000..b0c9c99437 --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/domain/Approval.java @@ -0,0 +1,24 @@ +package com.baeldung.domain; + +public class Approval { + + private String id; + private boolean status; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public boolean isStatus() { + return status; + } + + public void setStatus(boolean status) { + this.status = status; + } + +} diff --git a/spring-boot-flowable/src/main/java/com/baeldung/domain/Article.java b/spring-boot-flowable/src/main/java/com/baeldung/domain/Article.java new file mode 100644 index 0000000000..efa2eb431e --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/domain/Article.java @@ -0,0 +1,52 @@ +package com.baeldung.domain; + +public class Article { + + private String id; + private String author; + private String url; + + public Article() { + } + + public Article(String author, String url) { + this.author = author; + this.url = url; + } + + public Article(String id, String author, String url) { + this.id = id; + this.author = author; + this.url = url; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public String toString() { + return ("[" + this.author + " " + this.url + "]"); + } + +} diff --git a/spring-boot-flowable/src/main/java/com/baeldung/service/ArticleWorkflowService.java b/spring-boot-flowable/src/main/java/com/baeldung/service/ArticleWorkflowService.java new file mode 100644 index 0000000000..b1e2a92354 --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/service/ArticleWorkflowService.java @@ -0,0 +1,55 @@ +package com.baeldung.service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.task.api.Task; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.baeldung.domain.Approval; +import com.baeldung.domain.Article; + +@Service +public class ArticleWorkflowService { + @Autowired + private RuntimeService runtimeService; + @Autowired + private TaskService taskService; + + @Transactional + public void startProcess(Article article) { + Map variables = new HashMap(); + variables.put("author", article.getAuthor()); + variables.put("url", article.getUrl()); + runtimeService.startProcessInstanceByKey("articleReview", variables); + } + + @Transactional + public List
getTasks(String assignee) { + List tasks = taskService.createTaskQuery() + .taskCandidateGroup(assignee) + .list(); + + List
articles = tasks.stream() + .map(task -> { + Map variables = taskService.getVariables(task.getId()); + return new Article( + task.getId(), (String) variables.get("author"), (String) variables.get("url")); + }) + .collect(Collectors.toList()); + return articles; + } + + @Transactional + public void submitReview(Approval approval) { + Map variables = new HashMap(); + variables.put("approved", approval.isStatus()); + taskService.complete(approval.getId(), variables); + } +} \ No newline at end of file diff --git a/spring-boot-flowable/src/main/java/com/baeldung/service/PublishArticleService.java b/spring-boot-flowable/src/main/java/com/baeldung/service/PublishArticleService.java new file mode 100644 index 0000000000..b43f1dccdb --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/service/PublishArticleService.java @@ -0,0 +1,10 @@ +package com.baeldung.service; + +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; + +public class PublishArticleService implements JavaDelegate { + public void execute(DelegateExecution execution) { + System.out.println("Publishing the approved article."); + } +} diff --git a/spring-boot-flowable/src/main/java/com/baeldung/service/SendMailService.java b/spring-boot-flowable/src/main/java/com/baeldung/service/SendMailService.java new file mode 100644 index 0000000000..f80b16748f --- /dev/null +++ b/spring-boot-flowable/src/main/java/com/baeldung/service/SendMailService.java @@ -0,0 +1,10 @@ +package com.baeldung.service; + +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; + +public class SendMailService implements JavaDelegate { + public void execute(DelegateExecution execution) { + System.out.println("Sending rejection mail to author."); + } +} diff --git a/spring-boot-flowable/src/main/resources/application.properties b/spring-boot-flowable/src/main/resources/application.properties new file mode 100644 index 0000000000..c3afcaa0b5 --- /dev/null +++ b/spring-boot-flowable/src/main/resources/application.properties @@ -0,0 +1 @@ +management.endpoint.flowable.enabled=true \ No newline at end of file diff --git a/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml b/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml new file mode 100644 index 0000000000..6bf210dcee --- /dev/null +++ b/spring-boot-flowable/src/main/resources/processes/article-workflow.bpmn20.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java b/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java new file mode 100644 index 0000000000..ef5453623a --- /dev/null +++ b/spring-boot-flowable/src/test/java/com/baeldung/processes/ArticleWorkflowUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.processes; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.test.Deployment; +import org.flowable.spring.impl.test.FlowableSpringExtension; +import org.flowable.task.api.Task; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(FlowableSpringExtension.class) +@ExtendWith(SpringExtension.class) +public class ArticleWorkflowUnitTest { + @Autowired + private RuntimeService runtimeService; + @Autowired + private TaskService taskService; + @Test + @Deployment(resources = { "processes/article-workflow.bpmn20.xml" }) + void articleApprovalTest() { + Map variables = new HashMap(); + variables.put("author", "test@baeldung.com"); + variables.put("url", "http://baeldung.com/dummy"); + runtimeService.startProcessInstanceByKey("articleReview", variables); + Task task = taskService.createTaskQuery() + .singleResult(); + assertEquals("Review the submitted tutorial", task.getName()); + variables.put("approved", true); + taskService.complete(task.getId(), variables); + assertEquals(0, runtimeService.createProcessInstanceQuery() + .count()); + } +} \ No newline at end of file diff --git a/spring-boot-rest/src/test/java/com/baeldung/rest/GitHubUser.java b/spring-boot-rest/src/test/java/com/baeldung/rest/GitHubUser.java new file mode 100644 index 0000000000..da5085ab12 --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/rest/GitHubUser.java @@ -0,0 +1,21 @@ +package com.baeldung.rest; + +public class GitHubUser { + + private String login; + + public GitHubUser() { + super(); + } + + // API + + public String getLogin() { + return login; + } + + public void setLogin(final String login) { + this.login = login; + } + +} diff --git a/testing-modules/rest-testing/src/test/java/org/baeldung/rest/GithubBasicLiveTest.java b/spring-boot-rest/src/test/java/com/baeldung/rest/GithubBasicLiveTest.java similarity index 98% rename from testing-modules/rest-testing/src/test/java/org/baeldung/rest/GithubBasicLiveTest.java rename to spring-boot-rest/src/test/java/com/baeldung/rest/GithubBasicLiveTest.java index acac82c8f4..3082b34421 100644 --- a/testing-modules/rest-testing/src/test/java/org/baeldung/rest/GithubBasicLiveTest.java +++ b/spring-boot-rest/src/test/java/com/baeldung/rest/GithubBasicLiveTest.java @@ -1,4 +1,4 @@ -package org.baeldung.rest; +package com.baeldung.rest; import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; import static org.hamcrest.Matchers.equalTo; diff --git a/spring-boot-rest/src/test/java/com/baeldung/rest/RetrieveUtil.java b/spring-boot-rest/src/test/java/com/baeldung/rest/RetrieveUtil.java new file mode 100644 index 0000000000..0ec36bc3ae --- /dev/null +++ b/spring-boot-rest/src/test/java/com/baeldung/rest/RetrieveUtil.java @@ -0,0 +1,21 @@ +package com.baeldung.rest; + +import java.io.IOException; + +import org.apache.http.HttpResponse; +import org.apache.http.util.EntityUtils; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class RetrieveUtil { + + // API + + public static T retrieveResourceFromResponse(final HttpResponse response, final Class clazz) throws IOException { + final String jsonFromResponse = EntityUtils.toString(response.getEntity()); + final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper.readValue(jsonFromResponse, clazz); + } + +} diff --git a/spring-cloud/spring-cloud-config/client/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-config/client/src/test/java/com/baeldung/spring/cloud/config/client/SpringContextLiveTest.java similarity index 69% rename from spring-cloud/spring-cloud-config/client/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-config/client/src/test/java/com/baeldung/spring/cloud/config/client/SpringContextLiveTest.java index d727772cf9..3fb43b169d 100644 --- a/spring-cloud/spring-cloud-config/client/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-config/client/src/test/java/com/baeldung/spring/cloud/config/client/SpringContextLiveTest.java @@ -1,4 +1,4 @@ -package org.baeldung; +package com.baeldung.spring.cloud.config.client; import org.junit.Test; import org.junit.runner.RunWith; @@ -6,12 +6,15 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; -import com.baeldung.spring.cloud.config.client.ConfigClient; - +/** + * + * The app needs the server running on port 8888. Can be started with docker + * + */ @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = ConfigClient.class) @WebAppConfiguration -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void contextLoads() { } diff --git a/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextLiveTest.java b/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextIntegrationTest.java similarity index 79% rename from spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextLiveTest.java rename to spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextIntegrationTest.java index 793b4abb6c..b2c6ef85ea 100644 --- a/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextLiveTest.java +++ b/spring-cloud/spring-cloud-config/server/src/test/java/com/baeldung/spring/cloud/config/server/SpringContextIntegrationTest.java @@ -6,16 +6,10 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; - -/** - * - * The context will load successfully with some properties provided by docker - * - */ @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = ConfigServer.class) @WebAppConfiguration -public class SpringContextLiveTest { +public class SpringContextIntegrationTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { } diff --git a/spring-cloud/spring-cloud-config/server/src/test/resources/application.properties b/spring-cloud/spring-cloud-config/server/src/test/resources/application.properties new file mode 100644 index 0000000000..67cc81ff67 --- /dev/null +++ b/spring-cloud/spring-cloud-config/server/src/test/resources/application.properties @@ -0,0 +1,2 @@ +### This should be provided by the docker config +spring.cloud.config.server.git.uri=classpath:. diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties b/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties index d2f1c89dc5..571f325824 100644 --- a/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties +++ b/spring-cloud/spring-cloud-connectors-heroku/src/main/resources/application.properties @@ -4,5 +4,6 @@ spring.datasource.maxIdle=5 spring.datasource.minIdle=2 spring.datasource.initialSize=5 spring.datasource.removeAbandoned=true +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect spring.jpa.hibernate.ddl-auto=update \ No newline at end of file diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-connectors-heroku/src/test/java/com/baeldung/spring/cloud/connectors/heroku/SpringContextIntegrationTest.java similarity index 90% rename from spring-cloud/spring-cloud-connectors-heroku/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-connectors-heroku/src/test/java/com/baeldung/spring/cloud/connectors/heroku/SpringContextIntegrationTest.java index a705f18bc6..dca4c25c71 100644 --- a/spring-cloud/spring-cloud-connectors-heroku/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-connectors-heroku/src/test/java/com/baeldung/spring/cloud/connectors/heroku/SpringContextIntegrationTest.java @@ -1,4 +1,4 @@ -package org.baeldung; +package com.baeldung.spring.cloud.connectors.heroku; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/spring-cloud/spring-cloud-connectors-heroku/src/test/resources/application.properties b/spring-cloud/spring-cloud-connectors-heroku/src/test/resources/application.properties new file mode 100644 index 0000000000..7b139ae07d --- /dev/null +++ b/spring-cloud/spring-cloud-connectors-heroku/src/test/resources/application.properties @@ -0,0 +1,2 @@ +spring.jpa.hibernate.ddl-auto=create +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect \ No newline at end of file diff --git a/spring-cloud/spring-cloud-consul/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-consul/src/test/java/com/baeldung/spring/cloud/consul/SpringContextLiveTest.java similarity index 74% rename from spring-cloud/spring-cloud-consul/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-consul/src/test/java/com/baeldung/spring/cloud/consul/SpringContextLiveTest.java index 6290ccc03e..7c87add43e 100644 --- a/spring-cloud/spring-cloud-consul/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-consul/src/test/java/com/baeldung/spring/cloud/consul/SpringContextLiveTest.java @@ -1,4 +1,4 @@ -package org.baeldung; +package com.baeldung.spring.cloud.consul; import org.junit.Test; import org.junit.runner.RunWith; @@ -9,10 +9,18 @@ import com.baeldung.spring.cloud.consul.discovery.DiscoveryClientApplication; import com.baeldung.spring.cloud.consul.health.ServiceDiscoveryApplication; import com.baeldung.spring.cloud.consul.properties.DistributedPropertiesApplication; + +/** + * + * This Live test requires: + * * a Consul instance running on port 8500 + * * Consul configured with particular properties (e.g. 'my.prop') + * + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = { DiscoveryClientApplication.class, ServiceDiscoveryApplication.class, DistributedPropertiesApplication.class }) -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextLiveTest.java similarity index 66% rename from spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextLiveTest.java index 24e758ff82..eb56c16c6a 100644 --- a/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-rest/spring-cloud-rest-books-api/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -5,9 +5,15 @@ import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +/** + * + * This Live Test requires: + * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`) + * + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = BooksApiApplication.class) -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextLiveTest.java b/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextLiveTest.java new file mode 100644 index 0000000000..01266a3bda --- /dev/null +++ b/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -0,0 +1,21 @@ +package org.baeldung; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * + * This Live Test requires: + * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`) + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SpringCloudRestServerApplication.class) +public class SpringContextLiveTest { + + @Test + public void whenSpringContextIsBootstrapped_thenNoExceptions() { + } +} diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextLiveTest.java similarity index 66% rename from spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextLiveTest.java index 07d7db0505..070abd246f 100644 --- a/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-rest/spring-cloud-rest-reviews-api/src/test/java/org/baeldung/SpringContextLiveTest.java @@ -5,9 +5,15 @@ import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +/** + * + * This Live Test requires: + * * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`) + * + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = BookReviewsApiApplication.class) -public class SpringContextIntegrationTest { +public class SpringContextLiveTest { @Test public void whenSpringContextIsBootstrapped_thenNoExceptions() { diff --git a/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/com/baeldung/twitterhdfs/aggregate/SpringContextIntegrationTest.java similarity index 79% rename from spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextIntegrationTest.java rename to spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/com/baeldung/twitterhdfs/aggregate/SpringContextIntegrationTest.java index e22359a016..b5cef1b5ed 100644 --- a/spring-cloud/spring-cloud-rest/spring-cloud-rest-discovery-server/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/com/baeldung/twitterhdfs/aggregate/SpringContextIntegrationTest.java @@ -1,4 +1,4 @@ -package org.baeldung; +package com.baeldung.twitterhdfs.aggregate; import org.junit.Test; import org.junit.runner.RunWith; @@ -6,7 +6,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) -@SpringBootTest(classes = SpringCloudRestServerApplication.class) +@SpringBootTest(classes = AggregateApp.class) public class SpringContextIntegrationTest { @Test diff --git a/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/org/baeldung/SpringContextIntegrationTest.java b/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/org/baeldung/SpringContextIntegrationTest.java deleted file mode 100644 index 3d370e7b48..0000000000 --- a/spring-cloud/spring-cloud-stream-starters/twitterhdfs/src/test/java/org/baeldung/SpringContextIntegrationTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.baeldung; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import com.baeldung.twitterhdfs.aggregate.AggregateApp; -import com.baeldung.twitterhdfs.processor.ProcessorApp; -import com.baeldung.twitterhdfs.sink.SinkApp; -import com.baeldung.twitterhdfs.source.SourceApp; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = {AggregateApp.class, ProcessorApp.class, SinkApp.class, SourceApp.class}) -public class SpringContextIntegrationTest { - - @Test - public void whenSpringContextIsBootstrapped_thenNoExceptions() { - } -} diff --git a/spring-data-rest/pom.xml b/spring-data-rest/pom.xml index e563a6a3b5..525c88c9d8 100644 --- a/spring-data-rest/pom.xml +++ b/spring-data-rest/pom.xml @@ -1,9 +1,8 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 spring-data-rest - 1.0 spring-data-rest jar @@ -21,6 +20,10 @@ org.springframework.boot spring-boot-starter + + org.springframework.boot + spring-boot-starter-web + org.springframework.boot spring-boot-starter-data-rest @@ -30,12 +33,21 @@ spring-boot-starter-data-jpa - com.h2database - h2 + org.springframework.boot + spring-boot-autoconfigure org.springframework.boot - spring-boot-autoconfigure + spring-boot-starter-test + test + + + com.querydsl + querydsl-apt + + + com.querydsl + querydsl-jpa org.xerial @@ -45,9 +57,33 @@ ${project.artifactId} + + + com.mysema.maven + maven-apt-plugin + 1.0 + + + generate-sources + + process + + + target/generated-sources + com.querydsl.apt.jpa.JPAAnnotationProcessor + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + UTF-8 com.baeldung.SpringDataRestApplication diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/Application.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/Application.java new file mode 100644 index 0000000000..fe2f996d37 --- /dev/null +++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/Application.java @@ -0,0 +1,28 @@ +package com.baeldung.springdatawebsupport.application; + +import com.baeldung.springdatawebsupport.application.entities.User; +import com.baeldung.springdatawebsupport.application.repositories.UserRepository; +import java.util.stream.Stream; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + + @Bean + CommandLineRunner initialize(UserRepository userRepository) { + return args -> { + Stream.of("John", "Robert", "Nataly", "Helen", "Mary").forEach(name -> { + User user = new User(name); + userRepository.save(user); + }); + userRepository.findAll().forEach(System.out::println); + }; + } +} diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/controllers/UserController.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/controllers/UserController.java new file mode 100644 index 0000000000..8258c3b7aa --- /dev/null +++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/controllers/UserController.java @@ -0,0 +1,47 @@ +package com.baeldung.springdatawebsupport.application.controllers; + +import com.baeldung.springdatawebsupport.application.entities.User; +import com.baeldung.springdatawebsupport.application.repositories.UserRepository; +import com.querydsl.core.types.Predicate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.querydsl.binding.QuerydslPredicate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class UserController { + + private final UserRepository userRepository; + + @Autowired + public UserController(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @GetMapping("/users/{id}") + public User findUserById(@PathVariable("id") User user) { + return user; + } + + @GetMapping("/users") + public Page findAllUsers(Pageable pageable) { + return userRepository.findAll(pageable); + } + + @GetMapping("/sortedusers") + public Page findAllUsersSortedByName() { + Pageable pageable = PageRequest.of(0, 5, Sort.by("name")); + return userRepository.findAll(pageable); + } + + @GetMapping("/filteredusers") + public Iterable getUsersByQuerydslPredicate(@QuerydslPredicate(root = User.class) Predicate predicate) { + return userRepository.findAll(predicate); + } +} diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/entities/User.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/entities/User.java new file mode 100644 index 0000000000..e9aaeb119a --- /dev/null +++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/entities/User.java @@ -0,0 +1,38 @@ +package com.baeldung.springdatawebsupport.application.entities; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "users") +public class User { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private long id; + private final String name; + + public User() { + this.name = ""; + } + + public User(String name) { + this.name = name; + } + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "User{" + "id=" + id + ", name=" + name + '}'; + } +} diff --git a/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/repositories/UserRepository.java b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/repositories/UserRepository.java new file mode 100644 index 0000000000..41d7ed9d98 --- /dev/null +++ b/spring-data-rest/src/main/java/com/baeldung/springdatawebsupport/application/repositories/UserRepository.java @@ -0,0 +1,14 @@ +package com.baeldung.springdatawebsupport.application.repositories; + +import com.baeldung.springdatawebsupport.application.entities.User; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.querydsl.QuerydslPredicateExecutor; +import org.springframework.data.repository.PagingAndSortingRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends PagingAndSortingRepository, + QuerydslPredicateExecutor { + +} diff --git a/spring-data-rest/src/test/java/com/baeldung/springdatawebsupport/application/test/UserControllerIntegrationTest.java b/spring-data-rest/src/test/java/com/baeldung/springdatawebsupport/application/test/UserControllerIntegrationTest.java new file mode 100644 index 0000000000..db522b1413 --- /dev/null +++ b/spring-data-rest/src/test/java/com/baeldung/springdatawebsupport/application/test/UserControllerIntegrationTest.java @@ -0,0 +1,74 @@ +package com.baeldung.springdatawebsupport.application.test; + +import com.baeldung.springdatawebsupport.application.controllers.UserController; +import static org.assertj.core.api.Assertions.assertThat; +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.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class UserControllerIntegrationTest { + + @Autowired + private UserController userController; + + @Autowired + private MockMvc mockMvc; + + @Test + public void whenUserControllerInjected_thenNotNull() throws Exception { + assertThat(userController).isNotNull(); + } + + @Test + public void whenGetRequestToUsersEndPointWithIdPathVariable_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/users/{id}", "1") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value("1")); + } + + @Test + public void whenGetRequestToUsersEndPoint_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/users") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$['pageable']['paged']").value("true")); + + } + + @Test + public void whenGetRequestToUserEndPointWithNameRequestParameter_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/user") + .param("name", "John") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$['content'][0].['name']").value("John")); + } + + @Test + public void whenGetRequestToSorteredUsersEndPoint_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/sortedusers") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$['sort']['sorted']").value("true")); + } + + @Test + public void whenGetRequestToFilteredUsersEndPoint_thenCorrectResponse() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/filteredusers") + .param("name", "John") + .contentType(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].name").value("John")); + } +} diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java index a353961854..9fb86e7658 100644 --- a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/KerberosClientApp.java @@ -12,6 +12,8 @@ class KerberosClientApp { System.setProperty("java.security.krb5.conf", Paths.get(".\\krb-test-workdir\\krb5.conf").normalize().toAbsolutePath().toString()); System.setProperty("sun.security.krb5.debug", "true"); + // disable usage of local kerberos ticket cache + System.setProperty("http.use.global.creds", "false"); } public static void main(String[] args) { diff --git a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleService.java b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleClient.java similarity index 87% rename from spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleService.java rename to spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleClient.java index 4145cf0c1a..745193e3b0 100644 --- a/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleService.java +++ b/spring-security-sso/spring-security-sso-kerberos/src/main/java/kerberos/client/SampleClient.java @@ -5,14 +5,14 @@ import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service -class SampleService { +class SampleClient { @Value("${app.access-url}") private String endpoint; private RestTemplate restTemplate; - public SampleService(RestTemplate restTemplate) { + public SampleClient(RestTemplate restTemplate) { this.restTemplate = restTemplate; } diff --git a/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleServiceManualTest.java b/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleClientManualTest.java similarity index 59% rename from spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleServiceManualTest.java rename to spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleClientManualTest.java index d0d9f0ae4b..fdb1b12531 100644 --- a/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleServiceManualTest.java +++ b/spring-security-sso/spring-security-sso-kerberos/src/test/java/kerberos/client/SampleClientManualTest.java @@ -1,6 +1,5 @@ package kerberos.client; -import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -10,7 +9,6 @@ import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; import static org.junit.Assert.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; /** @@ -23,21 +21,19 @@ import static org.junit.jupiter.api.Assertions.assertThrows; */ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@FixMethodOrder -public class SampleServiceManualTest { +public class SampleClientManualTest { @Autowired - private SampleService sampleService; + private SampleClient sampleClient; @Test - public void a_givenKerberizedRestTemplate_whenServiceCall_thenSuccess() { - assertNotNull(sampleService); - assertEquals("data from kerberized server", sampleService.getData()); + public void givenKerberizedRestTemplate_whenServiceCall_thenSuccess() { + assertEquals("data from kerberized server", sampleClient.getData()); } @Test - public void b_givenRestTemplate_whenServiceCall_thenFail() { - sampleService.setRestTemplate(new RestTemplate()); - assertThrows(RestClientException.class, sampleService::getData); + public void givenRestTemplate_whenServiceCall_thenFail() { + sampleClient.setRestTemplate(new RestTemplate()); + assertThrows(RestClientException.class, sampleClient::getData); } } \ No newline at end of file diff --git a/testing-modules/groovy-spock/pom.xml b/testing-modules/groovy-spock/pom.xml index d6097af208..35d8f5034f 100644 --- a/testing-modules/groovy-spock/pom.xml +++ b/testing-modules/groovy-spock/pom.xml @@ -48,7 +48,7 @@ - 1.3-RC1-groovy-2.4 + 1.3-groovy-2.4 2.4.7 1.5 diff --git a/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy index 91da2ff1ec..9010481220 100644 --- a/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy +++ b/testing-modules/groovy-spock/src/test/groovy/extensions/IgnoreIfTest.groovy @@ -7,6 +7,16 @@ import spock.lang.Specification class IgnoreIfTest extends Specification { @IgnoreIf({System.getProperty("os.name").contains("windows")}) - def "I won't run on windows"() { } + def "I won't run on windows"() { + expect: + true + } + + @IgnoreIf({ os.isWindows() }) + def "I'm using Spock helper classes to run only on windows"() { + expect: + true + } + } diff --git a/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy b/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy index ed94e61cbf..4b017aeefc 100644 --- a/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy +++ b/testing-modules/groovy-spock/src/test/resources/SpockConfig.groovy @@ -2,7 +2,10 @@ import extensions.TimeoutTest import spock.lang.Issue runner { - filterStackTrace true + + if (System.getenv("FILTER_STACKTRACE") == null) { + filterStackTrace false + } report { issueNamePrefix 'Bug '