diff --git a/spring-boot-2-demo-app/src/main/resources/application.yml b/spring-boot-2-demo-app/src/main/resources/application.yml index 6920c2a6..2e676219 100644 --- a/spring-boot-2-demo-app/src/main/resources/application.yml +++ b/spring-boot-2-demo-app/src/main/resources/application.yml @@ -63,6 +63,8 @@ spring: enable-logging: true log-level: INFO includes: QUERY + template: + query-timeout: 1 # 1 second management: server: diff --git a/spring-boot-2-demo-app/src/test/java/io/github/mfvanek/spring/boot2/test/ApplicationTests.java b/spring-boot-2-demo-app/src/test/java/io/github/mfvanek/spring/boot2/test/ApplicationTests.java index 007db0c6..bea4d5ec 100644 --- a/spring-boot-2-demo-app/src/test/java/io/github/mfvanek/spring/boot2/test/ApplicationTests.java +++ b/spring-boot-2-demo-app/src/test/java/io/github/mfvanek/spring/boot2/test/ApplicationTests.java @@ -1,11 +1,37 @@ package io.github.mfvanek.spring.boot2.test; import io.github.mfvanek.spring.boot2.test.support.TestBase; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.dao.DataAccessResourceFailureException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; class ApplicationTests extends TestBase { @Test void contextLoads() { } + + @Test + void jdbcQueryTimeoutFromProperties() { + assertThat(jdbcTemplate.getQueryTimeout()) + .isEqualTo(1); + } + + @Test + @DisplayName("Throws exception when query exceeds timeout") + void exceptionWithLongQuery() { + assertThatThrownBy(() -> jdbcTemplate.execute("select pg_sleep(1.1);")) + .isInstanceOf(DataAccessResourceFailureException.class) + .hasMessageContaining("ERROR: canceling statement due to user request"); + } + + @Test + @DisplayName("Does not throw exception when query does not exceed timeout") + void exceptionNotThrownWithNotLongQuery() { + assertThatNoException().isThrownBy(() -> jdbcTemplate.execute("select pg_sleep(0.9);")); + } } diff --git a/spring-boot-2-demo-app/src/test/java/io/github/mfvanek/spring/boot2/test/support/TestBase.java b/spring-boot-2-demo-app/src/test/java/io/github/mfvanek/spring/boot2/test/support/TestBase.java index b423f3ac..1c1dc53b 100644 --- a/spring-boot-2-demo-app/src/test/java/io/github/mfvanek/spring/boot2/test/support/TestBase.java +++ b/spring-boot-2-demo-app/src/test/java/io/github/mfvanek/spring/boot2/test/support/TestBase.java @@ -2,6 +2,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.reactive.server.WebTestClient; @@ -13,4 +14,7 @@ public abstract class TestBase { @Autowired protected WebTestClient webTestClient; + + @Autowired + protected JdbcTemplate jdbcTemplate; } diff --git a/spring-boot-2-demo-app/src/test/resources/application-test.yml b/spring-boot-2-demo-app/src/test/resources/application-test.yml new file mode 100644 index 00000000..c088383e --- /dev/null +++ b/spring-boot-2-demo-app/src/test/resources/application-test.yml @@ -0,0 +1,4 @@ +spring: + jdbc: + template: + query-timeout: 1 # 1 second diff --git a/spring-boot-3-demo-app/src/main/resources/application.yml b/spring-boot-3-demo-app/src/main/resources/application.yml index 4726a540..f7de3c9b 100644 --- a/spring-boot-3-demo-app/src/main/resources/application.yml +++ b/spring-boot-3-demo-app/src/main/resources/application.yml @@ -118,6 +118,8 @@ jdbc: enable-logging: true log-level: INFO includes: QUERY + template: + query-timeout: 1 # 1 second --- diff --git a/spring-boot-3-demo-app/src/test/java/io/github/mfvanek/spring/boot3/test/ApplicationTests.java b/spring-boot-3-demo-app/src/test/java/io/github/mfvanek/spring/boot3/test/ApplicationTests.java index 0cbdd4e4..ecc17b19 100644 --- a/spring-boot-3-demo-app/src/test/java/io/github/mfvanek/spring/boot3/test/ApplicationTests.java +++ b/spring-boot-3-demo-app/src/test/java/io/github/mfvanek/spring/boot3/test/ApplicationTests.java @@ -7,13 +7,17 @@ import io.micrometer.tracing.Tracer; import io.micrometer.tracing.otel.bridge.OtelTracer; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; +import org.springframework.dao.DataAccessResourceFailureException; import java.util.Locale; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; class ApplicationTests extends TestBase { @@ -23,22 +27,42 @@ class ApplicationTests extends TestBase { @Test void contextLoads() { assertThat(applicationContext.containsBean("otlpMeterRegistry")) - .isFalse(); + .isFalse(); assertThat(applicationContext.getBean(ObservationRegistry.class)) - .isNotNull() - .isInstanceOf(ObservationRegistry.class); + .isNotNull() + .isInstanceOf(ObservationRegistry.class); assertThat(applicationContext.getBean(Tracer.class)) - .isNotNull() - .isInstanceOf(OtelTracer.class) - .satisfies(t -> assertThat(t.currentSpan()) - .isNotEqualTo(Span.NOOP)); + .isNotNull() + .isInstanceOf(OtelTracer.class) + .satisfies(t -> assertThat(t.currentSpan()) + .isNotEqualTo(Span.NOOP)); assertThat(applicationContext.getBean("otelJaegerGrpcSpanExporter")) - .isNotNull() - .isInstanceOf(OtlpGrpcSpanExporter.class) - .hasToString(String.format(Locale.ROOT, "OtlpGrpcSpanExporter{exporterName=otlp, type=span, " + - "endpoint=http://localhost:%d, " + - "endpointPath=/opentelemetry.proto.collector.trace.v1.TraceService/Export, timeoutNanos=5000000000, " + - "connectTimeoutNanos=10000000000, compressorEncoding=null, " + - "headers=Headers{User-Agent=OBFUSCATED}}", JaegerInitializer.getFirstMappedPort())); + .isNotNull() + .isInstanceOf(OtlpGrpcSpanExporter.class) + .hasToString(String.format(Locale.ROOT, "OtlpGrpcSpanExporter{exporterName=otlp, type=span, " + + "endpoint=http://localhost:%d, " + + "endpointPath=/opentelemetry.proto.collector.trace.v1.TraceService/Export, timeoutNanos=5000000000, " + + "connectTimeoutNanos=10000000000, compressorEncoding=null, " + + "headers=Headers{User-Agent=OBFUSCATED}}", JaegerInitializer.getFirstMappedPort())); + } + + @Test + void jdbcQueryTimeoutFromProperties() { + assertThat(jdbcTemplate.getQueryTimeout()) + .isEqualTo(1); + } + + @Test + @DisplayName("Throws exception when query exceeds timeout") + void exceptionWithLongQuery() { + assertThatThrownBy(() -> jdbcTemplate.execute("select pg_sleep(1.1);")) + .isInstanceOf(DataAccessResourceFailureException.class) + .hasMessageContaining("ERROR: canceling statement due to user request"); + } + + @Test + @DisplayName("Does not throw exception when query does not exceed timeout") + void exceptionNotThrownWithNotLongQuery() { + assertThatNoException().isThrownBy(() -> jdbcTemplate.execute("select pg_sleep(0.9);")); } } diff --git a/spring-boot-3-demo-app/src/test/java/io/github/mfvanek/spring/boot3/test/support/TestBase.java b/spring-boot-3-demo-app/src/test/java/io/github/mfvanek/spring/boot3/test/support/TestBase.java index bab30969..4e825645 100644 --- a/spring-boot-3-demo-app/src/test/java/io/github/mfvanek/spring/boot3/test/support/TestBase.java +++ b/spring-boot-3-demo-app/src/test/java/io/github/mfvanek/spring/boot3/test/support/TestBase.java @@ -3,6 +3,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.actuate.observability.AutoConfigureObservability; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.web.reactive.server.WebTestClient; @@ -15,4 +16,7 @@ public abstract class TestBase { @Autowired protected WebTestClient webTestClient; + + @Autowired + protected JdbcTemplate jdbcTemplate; } diff --git a/spring-boot-3-demo-app/src/test/resources/application-test.yml b/spring-boot-3-demo-app/src/test/resources/application-test.yml new file mode 100644 index 00000000..c088383e --- /dev/null +++ b/spring-boot-3-demo-app/src/test/resources/application-test.yml @@ -0,0 +1,4 @@ +spring: + jdbc: + template: + query-timeout: 1 # 1 second