I have some App with WebFlux and i want to use BlockHound, but i need to have a possible turn on and off it through parameter in application.properties or through spring profiling or somthing else.
Also I want to override action, when the lock operation is caught so that not throw error but log warning. And firstly, i did through parameter in application.properties:
#SpringBootApplication
#Slf4j
public class GazPayApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(GazPayApplication.class, args);
BlockHoundSwitch blockHoundSwitch = (BlockHoundSwitch)context.getBean("BlockHoundSwitchBean");
if (blockHoundSwitch.isBlockHoundEnabled()) {
BlockHound.install(builder ->
builder.blockingMethodCallback(it ->
log.warn("find block operation: {}", it.toString())));
}
}
And my BlockHoundSwitch:
#Component("BlockHoundSwitchBean")
#Getter
public class BlockHoundSwitch {
#Value("${blockhound.enabled}")
private boolean blockHoundEnabled;
}
It works for me but in my opinion this solution quite difficult and a little unpredictable.
Next i tried resolve this task through profiling:
#Profile("blockhound_enabled")
#Slf4j
#Component()
public class BlockHoundSwitch {
public BlockHoundSwitch() {
BlockHound.install(builder ->
builder.blockingMethodCallback(it ->
log.warn("find block operation: {}", it.toString())));
}
}
And it works too. Well, I have a few questions:
Which way is better, why and maybe there is another solution?
I need to localize and log, where block operation happened. How can I get class name and method, where it`s happened?
I resolve it. Maybe someone it will be useful. I did it through profiling and my code bellow:
#Profile("blockhound_on")
#Slf4j
#Component()
#Getter
public class BlockHoundSwitch {
public BlockHoundSwitch() {
BlockHound.install(builder ->
builder.blockingMethodCallback(it -> {
List<StackTraceElement> itemList = Arrays.stream(new Exception(it.toString()).getStackTrace())
.filter(i -> i.toString().contains("application.package"))
.collect(Collectors.toList());
log.warn("find block operation: \n{}", itemList);
}));
}
}
where application.package - main package of my project, which i`m finding in stacktrace.
Related
I'm new to Java development and Spring/Springboot. I was tasked to create a cron job that would execute a query to a database. Although, my problem would focus on calling the function since it's already existing in the project. I'm still quite confused and learning about Dependency Injection, Design Patterns and Spring. I tried to resolve this myself, but it's taking a while now -- so I figured to ask while I'm also trying to figure it out just to save time in case they ask me for a deadline. Thank you so much in advance!
This is how the programs are generally structured:
QueryConfig.java
This is a new and only file I created. I was able to make the cron job work, as I tried to put a logger inside runQuery() and it was able to run every 5 minutes as per the configuration file.
#RefreshScope
#Component
public class QueryConfig {
#Value("${cron.job.query}")
private String sql;
String name = "Bob";
StudentMgtApiDelegate delegate = new StudentMgtApiDelegateImpl();
#Scheduled(cron = "${cron.job.schedule}", zone = "${cron.job.timezone}")
public void runQuery() {
delegate.retrieveStudents(name);
}
}
StudentMgtApiDelegateImpl.java
Please also note that this is just a representation of the code since I cannot share the actual. I'll try my best to make it as close to the real implementation. There are 3 methods for the API, but I just want to call the retrieveStudents().
#Component
public class StudentMgtApiDelegateImpl implements StudentMgtApiDelegate {
#Autowired
private StudentFacade studentFacade;
#Override
public ResponseEntity<List<Student>> retrieveStudents(String name) {
return ResponseEntity.ok(studentFacade.retrieveStudents(
...
));
}
#Override
public ResponseEntity<StudentDetails> retrieveStudentDetails(String name...) {
return ResponseEntity.ok(studentFacade.retrieveStudentDetails(
...
));
}
#Override
public ResponseEntity<List<CountBreakdown>> retrieveStudentCounts(String name) {
return ResponseEntity.ok(studentFacade.studentCountsRetrieve(
...
));
}
}
StudentFacade.java
public class StudentFacade {
private Function<DataWrapper<StudentParams<String>>, List<Student>> studentListRetrieveFn;
private Function<DataWrapper<StudentParams<String>>, StudentDetails> studentDetailsRetrieveFn;
private Function<DataWrapper<StudentRetrieveCriteria>, List<CountBreakdown>> studentCountsRetrieveFn;
public StudentFacade(Function<DataWrapper<StudentParams<String>>, List<Student>> studentListRetrieveFn, Function<DataWrapper<StudentParams<String>>, StudentDetails> studentDetailsRetrieveFn, Function<DataWrapper<StudentRetrieveCriteria>, List<CountBreakdown>> studentCountsRetrieveFn) {
this.studentListRetrieveFn = studentListRetrieveFn;
this.studentDetailsRetrieveFn = studentDetailsRetrieveFn;
this.studentCountsRetrieveFn = studentCountsRetrieveFn;
}
public List<Student> retrieveStudents(DataWrapper<StudentParams<String>> wrapper) {
return Optional.ofNullable(wrapper).map(studentListRetrieveFn).orElse(null);
}
public StudentDetails retrieveStudentDetails(DataWrapper<StudentParams<String>> wrapper) {
return Optional.ofNullable(wrapper).map(studentDetailsRetrieveFn).orElse(null);
}
public List<CountBreakdown> studentCountsRetrieve(DataWrapper<StudentRetrieveCriteria> wrapper) {
return Optional.ofNullable(wrapper).map(studentCountsRetrieveFn).orElse(null);
}
}
I apologize in advance for the many code omissions and I know some parameters won't match and make sense. But as of the current implementation in my QueryConfig.java, I am encountering this error:
[scheduling-1] ERROR o.s.s.s.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task
java.lang.NullPointerException: null
I tried to debug and see the value of delegate inside the QueryConfig.java, and it has a studentFacade that is null.
Autowire the StudentMgtApiDelegate; do not construct it manually.
#Autowired
StudentMgtApiDelegate delegate;
I'm new to Spring and trying to implement Spring Retry with a simple test.
however i can't make it work, hope someone could show me where i've done wrong.
Also I'm wondering, is it possible to write unit test to verify that Spring Retry has tried the requested maximum number of retries? because so far from google search, it seems it can only work in integration test because it needs Spring to set up the context first.
here is my main class:
#SpringBootApplication
public class SpringtestApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(SpringtestApplication.class).run(args);
}
}
the configuration class
#Configuration
#EnableRetry
public class FakeConfiguration implements ApplicationRunner {
private final FakeParser fakeParser;
public FakeConfiguration(FakeParser fakeParser) {
this.fakeParser = fakeParser;
}
#Override
public void run(ApplicationArguments args) {
this.runParser();
}
#Retryable(maxAttempts = 5, value = RuntimeException.class)
public void runParser() {
fakeParser.add();
}
}
the component/service class:
#Component
public class FakeParser {
public int add(){
int result = 113;
return result;
}
}
the retry test for it:
#RunWith(SpringRunner.class)
#SpringBootTest
class SpringtestApplicationTests {
#Autowired
private FakeConfiguration fakeConfiguration;
#MockBean
private FakeParser fakeParser;
#Test
public void retry5times(){
when(fakeParser.add()).thenThrow(RuntimeException.class);
try {
fakeConfiguration.runParser();
} catch (RuntimeException e){
}
verify(fakeParser, times(5)).add();
}
}
however, the test didn't pass:
org.mockito.exceptions.verification.TooManyActualInvocations:
fakeParser bean.add();
Wanted 5 times:
-> at com.example.springtest.SpringtestApplicationTests.retry5times(SpringtestApplicationTests.java:43)
But was 6 times:
-> at com.example.springtest.FakeConfiguration.runParser(FakeConfiguration.java:26)
-> at com.example.springtest.FakeConfiguration.runParser(FakeConfiguration.java:26)
-> at com.example.springtest.FakeConfiguration.runParser(FakeConfiguration.java:26)
-> at com.example.springtest.FakeConfiguration.runParser(FakeConfiguration.java:26)
-> at com.example.springtest.FakeConfiguration.runParser(FakeConfiguration.java:26)
-> at com.example.springtest.FakeConfiguration.runParser(FakeConfiguration.java:26)
when(someObject.someMethod()) evaluates the method and makes a real call to it. That's why you're always getting one more invocation than wanted.
If you need to count the actual invocations you could either add 1 to your verify, but that is an ugly workaround that is not recommended (and also not needed). Or you can use the Mockito.doXXX methods that don't have that problem.
In your case you could try
doThrow(new RuntimeException()).when(fakeParser).add();
This should give you the correct amount of invocations in the end. Notice the difference in the usages of when here: when(fakeParser).add() (two methods chained together) vs when(fakeParser.add()) (only one method)
Most probably you try with
Mockito.verify(fakeParser,times(5)).add(Mockito.any());
You should think about first run because when you retry 5 times and run once again. It should be 6 run even if you retry 5 times.
You are forgetting first exceptional case which is normal run behaviour
I am trying to construct a complex flow in Spring Integration where the sub flows are dynamically defined at runtime. Code that functions perfectly well in the master flow definition fails the compile in the sub flow definition. Since the construct appears identical, it is not obvious what is going on. Any explanation would be appreciated.
Thank you in advance.
The master flow definition is coded something like this:
StandardIntegrationFlow flow = IntegrationFlows
.from(setupAdapter,
c -> c.poller(Pollers.fixedRate(1000L, TimeUnit.MILLISECONDS).maxMessagesPerPoll(1)))
// This one compiles fine
.enrichHeaders(h -> h.headerExpression("start", "start\")")
.headerExpression("end", "payload[0].get(\"end\")"))
.split(tableSplitter)
.enrichHeaders(h -> h.headerExpression("object", "payload[0].get(\"object\")"))
.channel(c -> c.executor(stepTaskExecutor))
.routeToRecipients(r -> this.buildRecipientListRouterSpecForRules(r, rules))
.aggregate()
.handle(cleanupAdapter).get();
buildRecipientListRouterSpecForRules is defined as:
private RecipientListRouterSpec buildRecipientListRouterSpecForRules(RecipientListRouterSpec recipientListSpec,
Collection<RuleMetadata> rules) {
rules.forEach(
rule -> recipientListSpec.recipientFlow(getFilterExpression(rule), f -> createFlowDefForRule(f, rule)));
return recipientListSpec;
}
createFlowDefForRule() is just a switch() wrapper to choose which actual DSL to run for the flow defined by the rule. Here is a sample
public IntegrationFlowDefinition constructASpecificFlowDef(IntegrationFlowDefinition flowDef, RuleMetadata rule) {
return flowDef
// This enrichHeaders element fails to compile,
// The method headerExpression(String, String) is undefined for the type Object
.enrichHeaders(h -> h.headerExpression("ALC_operation", "payload[0].get(\"ALC_operation\")"));
}
In general, it's better to put such explanations in the question text, rather than as comments in the code snippets; I completely missed that comment.
Can you provide a stripped-down (simpler) example (complete class) that exhibits this behavior so we can play with it?
I tried to simplify what you are doing, and this compiles fine and works as expected:
#SpringBootApplication
public class So65010958Application {
public static void main(String[] args) {
SpringApplication.run(So65010958Application.class, args);
}
#Bean
IntegrationFlow flow() {
return IntegrationFlows.from("foo")
.routeToRecipients(r -> r.recipientFlow("true", f -> buildFlow(f)))
.get();
}
private IntegrationFlowDefinition<?> buildFlow(IntegrationFlowDefinition<?> f) {
return f.enrichHeaders(h -> h.headerExpression("foo", "'bar'"))
.channel(MessageChannels.queue("bar"));
}
#Bean
public ApplicationRunner runner(MessageChannel foo, PollableChannel bar) {
return args -> {
foo.send(new GenericMessage<>("foo"));
System.out.println(bar.receive(0));
};
}
}
GenericMessage [payload=foo, headers={foo=bar, id=d526b8fb-c6f8-7731-b1ad-e68e326fcc00, timestamp=1606333567749}]
So, I must be missing something.
How can I make the 3rd test to check for the existence of cause1 in the message of the exception? I also listed in the first two tests that have drawbacks. First is not checking for the message second needs a lot of boilerplate code.
public class CheckExceptionsWithMockitoTest {
#Test(expected = RuntimeException.class)
public void testExpectedException1() {
A a = new A();
a.doSomethingThatThrows();
}
#Test
public void testExpectedException2() {
A a = new A();
try {
a.doSomethingThatThrows();
fail("no exception thrown");
} catch (RuntimeException e) {
assertThat(e.getMessage(), org.hamcrest.Matchers.containsString("cause1"));
}
}
#Test
public void testExpectedException3() {
A a = new A();
A spyA = org.mockito.Mockito.spy(a);
// valid but doesnt work
// doThrow(new IllegalArgumentException()).when(spyA).doSomethingThatThrows();
// invalid but in the spirit of what i want
//chekThrow(RuntimeException.class,containsString("cause1")).when(spyA).doSomethingThatThrows();
}
}
I couldn't find in Mockito something that works but there is something that looks like could be possible (at the level of syntax) and capabilities.
Using catchexception I created the test like this
import static com.googlecode.catchexception.CatchException.*;
import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.junit.*;
public class CheckExceptionsWithMockitoTest{
//...
#Test
public void testExpectedException3() {
A a = new A();
verifyException(a,IllegalArgumentException.class)
.doSomethingThatThrows();
//if more details to be analized are needed
assertThat(
(IllegalStateException) caughtException(),
allOf(
is(IllegalStateException.class),
hasMessageThat(
containsString("is not allowed to add counterparties")),
hasNoCause()));
//more asserts could come
assertNotNull(a);
}
}
Use catch-exception library, or I guess that the solution you are looking for is your second implementation.
#expected doesn't provide any way to assert on the thrown exception except for its class, so you can't avoit try/catching (not that much boiler plate code !)
Mockito doesn't provide something likes a verifyThrows method.
So you can trade try/catching for an additional library : using catch-exception, you'll be able to catch exception in a single line and have it ready for further assertion(s).
Sample source code
A a = new A();
when(a).doSomethingThatThrows();
then(caughtException())
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("is not allowed to add counterparties")
.hasNoCause();
Dependencies
'com.googlecode.catch-exception:catch-exception:1.2.0'
If A is your system under test, it doesn't make any sense to mock it, and it rarely makes sense to spy on it. Your implementation in testExpectedException2 is the right one; the boilerplate code is necessary because without a try block Java will not let any code run after the method is intercepted (as I described in this previous SO answer).
Though Mockito won't be any help, JUnit will. The #Test(expected=foo) parameter actually has a more-flexible alternative, the built-in ExpectedException JUnit rule:
public class CheckExceptionsWithMockitoTest {
#Rule public ExpectedException thrown = ExpectedException.none();
#Test
public void testExpectedException1() {
A a = new A();
thrown.expect(RuntimeException.class);
thrown.expectMessage(containsString("cause1"));
a.doSomethingThatThrows();
}
}
Mockito would come in handy in a separate test checking whether your method wraps an arbitrary exception while preserving its message, which would look roughly like this:
#Test
public void doSomethingShouldWrapExceptionWithPassedMessage() {
Dependency dependency = Mockito.mock(Dependency.class);
when(dependency.call()).thenThrow(new IllegalArgumentException("quux"));
A a = new A(dependency);
thrown.expect(RuntimeException.class);
thrown.expectMessage(containsString("quux"));
a.doSomethingThatThrows();
}
Be careful to avoid the temptation to make this a common pattern in your tests. If you are catching an exception thrown from your system under test, you're effectively ceding control back to the SUT's consumer. There should be little left to test in the method afterwards, except the properties of the exception and MAYBE the state of your system, both of which should be rare enough that try/catch boilerplate is forgivable.
If you have the opportunity to use scala, scalaTest's fun suite has concise way of testing exceptions using intercept (http://www.scalatest.org/getting_started_with_fun_suite).
It's as simple as
test(a list get method catches exceptions){
intercept[IndexOutBoundsException]{
spyListObject.get(-1)
}
}
You could potentially write your tests to your java project in scala if you are looking for easy to write / clear test. But this may present other challenges.
Updated answer for 06/19/2015 (if you're using java 8)
Using assertj-core-3.0.0 + Java 8 Lambdas
#Test
public void shouldThrowIllegalArgumentExceptionWhenPassingBadArg() {
assertThatThrownBy(() -> myService.sumTingWong("badArg"))
.isInstanceOf(IllegalArgumentException.class);
}
Reference: http://blog.codeleak.pl/2015/04/junit-testing-exceptions-with-java-8.html
Using catchexception I created the test like this
import static com.googlecode.catchexception.CatchException.*;
import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.junit.*;
public class CheckExceptionsWithMockitoTest{
//...
#Test
public void testExpectedException3() {
A a = new A();
verifyException(a,IllegalArgumentException.class)
.doSomethingThatThrows();
//if more details to be analized are needed
assertThat(
(IllegalStateException) caughtException(),
allOf(
is(IllegalStateException.class),
hasMessageThat(
containsString("is not allowed to add counterparties")),
hasNoCause()));
//more asserts could come
assertNotNull(a);
}
}
If you have a look in Mockito.class on spy method it creates mock with spiedInstance:
public static <T> T spy(T object) {
return MOCKITO_CORE.mock((Class<T>) object.getClass(), withSettings()
.spiedInstance(object)
.defaultAnswer(CALLS_REAL_METHODS));
}
In MockSettings it is possible to register Invocation listeners: https://static.javadoc.io/org.mockito/mockito-core/3.0.0/org/mockito/listeners/InvocationListener.html
I created simple listener which stores all reported invocations:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.mockito.listeners.InvocationListener;
import org.mockito.listeners.MethodInvocationReport;
public class StoringMethodInvocationListener implements InvocationListener {
private List<MethodInvocationReport> methodInvocationReports = new ArrayList<>();
#Override
public void reportInvocation(MethodInvocationReport methodInvocationReport) {
this.methodInvocationReports.add(methodInvocationReport);
}
public List<MethodInvocationReport> getMethodInvocationReports() {
return Collections.unmodifiableList(methodInvocationReports);
}
}
After the invocation you can go through reports and find the one needed and verify that stored throwable is the one expected.
Example:
StoringMethodInvocationListener listener = new StoringMethodInvocationListener();
Consumer mock2 = mock(Consumer.class, withSettings()
.spiedInstance(consumerInstance)
.defaultAnswer(CALLS_REAL_METHODS)
.invocationListeners(listener));
try {
mock2.listen(new ConsumerRecord<String, String>(RECEIVER_TOPIC, 0, 0, null, "{}"));
} catch (Exception e){
//nothing
}
Assert.notEmpty(listener.getMethodInvocationReports(), "MethodInvocationReports list must not be empty");
Assert.isInstanceOf(BindException.class, listener.getMethodInvocationReports().get(1).getThrowable());
I'm looking to combine the flexibility of Spring Profiles and Configurations with the parallel running of JUnit tests which utilize either the Parameterized or Theories annotation. Is there any way to incorporate all of these features to get my unit tests running?
The problem I keep running into is the parameters need access to an injected bean, which isn't possible since the function annotated with #Parameters or #DataPoints is supposed to be static. I'd really hate to have to wire that into each class or even a static function somewhere because I'd like to quickly be able to switch profiles without having to change Java code. Is this possible?
Found the ticket for this request. It seems the attached file has some issues though. Looks like it's been a feature request for quite some time now.
I've been looking for a solution of this problem too. And there is one ! But as it comes from somebody's blog, I can't take the credit for it however. :-)
Unfortunately I can't find the original blog any more...
#RunWith(Parameterized.class)
#ContextConfiguration("/beans.xml")
public class MyTest {
private final File file;
public MyTest(final File file) {
this.file = file;
}
#Autowired
private PlatformTransactionManager transactionManager;
private TestContextManager testContextManager;
#Parameterized.Parameters
public static Collection<File[]> getFilesToTest() throws Exception {
return getValidFiles();
}
#Before
public void setUpSpringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this); // does the autowiring !
}
#Test
public void testInTransactionContext() throws Exception {
new TransactionTemplate(transactionManager).execute(new TransactionCallback() {
public Object doInTransaction(final TransactionStatus status) {
status.setRollbackOnly();
try {
... run the test ...
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
});
}
}