Fix bug when parsing Spring Boot, spring.session.timeout property with java.time.Duration styling.

Resolves gh-113.
This commit is contained in:
John Blum
2022-03-02 13:54:13 -08:00
parent aabcb04a0e
commit 33f9d4bd41
11 changed files with 373 additions and 7 deletions

View File

@@ -17,6 +17,7 @@ package org.springframework.geode.boot.autoconfigure;
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
import java.time.Duration;
import java.util.Properties;
import java.util.Set;
@@ -40,6 +41,8 @@ import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.geode.boot.autoconfigure.support.EnableSubscriptionConfiguration;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
@@ -108,11 +111,13 @@ public class SpringSessionAutoConfiguration {
if (isSet(environment, SPRING_SESSION_TIMEOUT_PROPERTY)) {
springSessionProperties.setProperty(SPRING_SESSION_DATA_GEMFIRE_SESSION_EXPIRATION_TIMEOUT,
environment.getProperty(SPRING_SESSION_TIMEOUT_PROPERTY));
toSecondsAsString(environment.getProperty(SPRING_SESSION_TIMEOUT_PROPERTY, Duration.class,
getDefaultSessionTimeout())));
}
else if (isSet(environment, SERVER_SERVLET_SESSION_TIMEOUT_PROPERTY)) {
springSessionProperties.setProperty(SPRING_SESSION_DATA_GEMFIRE_SESSION_EXPIRATION_TIMEOUT,
environment.getProperty(SERVER_SERVLET_SESSION_TIMEOUT_PROPERTY));
toSecondsAsString(environment.getProperty(SERVER_SERVLET_SESSION_TIMEOUT_PROPERTY,
Duration.class, getDefaultSessionTimeout())));
}
if (!springSessionProperties.isEmpty()) {
@@ -127,6 +132,20 @@ public class SpringSessionAutoConfiguration {
}
}
protected static @NonNull Duration getDefaultSessionTimeout() {
return Duration.ofSeconds(GemFireHttpSessionConfiguration.DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS);
}
protected static int toSeconds(@Nullable Duration duration) {
return duration != null ? Long.valueOf(duration.getSeconds()).intValue()
: GemFireHttpSessionConfiguration.DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS;
}
protected static @NonNull String toSecondsAsString(@Nullable Duration duration) {
return String.valueOf(toSeconds(duration));
}
protected static boolean isNotSet(ConfigurableEnvironment environment, String propertyName) {
return !isSet(environment, propertyName);
}

View File

@@ -15,11 +15,14 @@
*/
package org.springframework.geode.boot.autoconfigure.configuration;
import java.time.Duration;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
/**
* Spring Boot {@link ConfigurationProperties} used to configure Spring Session for Apache Geode (SSDG) in order to
@@ -190,6 +193,15 @@ public class SpringSessionProperties {
public void setMaxInactiveIntervalSeconds(int maxInactiveIntervalSeconds) {
this.maxInactiveIntervalSeconds = maxInactiveIntervalSeconds;
}
public void setMaxInactiveInterval(Duration duration) {
int maxInactiveIntervalInSeconds = duration != null
? Long.valueOf(duration.toSeconds()).intValue()
: GemFireHttpSessionConfiguration.DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS;
setMaxInactiveIntervalSeconds(maxInactiveIntervalInSeconds);
}
}
public static class SessionRegionProperties {

View File

@@ -113,7 +113,7 @@ public class SpringSessionPropertiesIntegrationTests extends IntegrationTestsSup
PdxSerializer pdxSerializer = this.clientCache.getPdxSerializer();
assertThat(pdxSerializer).isInstanceOf(PdxSerializerSessionSerializerAdapter.class);
assertThat(((PdxSerializerSessionSerializerAdapter) pdxSerializer).getSessionSerializer())
assertThat(((PdxSerializerSessionSerializerAdapter<?>) pdxSerializer).getSessionSerializer())
.isEqualTo(mockSessionSerializer);
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2017-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.boot.autoconfigure.session;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport;
import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.session.data.gemfire.GemFireOperationsSessionRepository;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
/**
* Abstract base test class for {@link Session} {@literal} in the configured {@literal time unit},
* for example: seconds, minutes, etc.
*
* @author John Blum
* @see org.junit.Test
* @see org.springframework.boot.autoconfigure.SpringBootApplication
* @see org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport
* @see org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects
* @see org.springframework.session.Session
* @see org.springframework.session.SessionRepository
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @since 2.0.0
*/
@SuppressWarnings("unused")
public abstract class AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests extends IntegrationTestsSupport {
@Autowired
private GemFireHttpSessionConfiguration configuration;
@Autowired
private SessionRepository<Session> repository;
protected int getExpectedMaxInactiveIntervalInSeconds() {
return GemFireHttpSessionConfiguration.DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS;
}
@Test
public void sessionTimeoutConfigurationIsCorrect() {
int expectedMaxInactiveIntervalInSeconds = getExpectedMaxInactiveIntervalInSeconds();
assertThat(this.configuration).isNotNull();
assertThat(this.configuration.getMaxInactiveIntervalInSeconds()).isEqualTo(expectedMaxInactiveIntervalInSeconds);
assertThat(this.repository).isInstanceOf(GemFireOperationsSessionRepository.class);
Session session = this.repository.createSession();
assertThat(session).isNotNull();
assertThat(session.getMaxInactiveInterval().getSeconds()).isEqualTo(expectedMaxInactiveIntervalInSeconds);
}
@SpringBootApplication
@EnableGemFireMockObjects
static class TestConfiguration { }
}

View File

@@ -109,7 +109,7 @@ public class CustomConfiguredSessionCachingIntegrationTests extends SpringBootAp
private Function<SpringApplicationBuilder, SpringApplicationBuilder> newSpringBootSessionPropertiesConfigurationFunction() {
return springApplicationBuilder ->
springApplicationBuilder.properties(singletonProperties("spring.session.timeout", "300"));
springApplicationBuilder.properties(singletonProperties("spring.session.timeout", "300s"));
}
private Function<ConfigurableApplicationContext, ConfigurableApplicationContext> newSpringSessionGemFirePropertiesConfigurationFunction() {
@@ -134,7 +134,7 @@ public class CustomConfiguredSessionCachingIntegrationTests extends SpringBootAp
private Function<SpringApplicationBuilder, SpringApplicationBuilder> newWebServerSessionPropertiesConfigurationFunction() {
return springApplicationBuilder ->
springApplicationBuilder.properties(singletonProperties("server.servlet.session.timeout", "3600"));
springApplicationBuilder.properties(singletonProperties("server.servlet.session.timeout", "3600s"));
}
@Override
@@ -259,10 +259,10 @@ public class CustomConfiguredSessionCachingIntegrationTests extends SpringBootAp
.isEqualTo(3600);
}
//@SpringBootApplication
@SpringBootConfiguration
@EnableAutoConfiguration
@EnableGemFireMockObjects
//@SpringBootApplication
static class TestConfiguration {
@Bean("MockSessionSerializer")

View File

@@ -17,6 +17,7 @@ package org.springframework.geode.boot.autoconfigure.session;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import jakarta.annotation.Resource;
@@ -62,9 +63,10 @@ import org.springframework.test.context.junit4.SpringRunner;
*/
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = SessionExpirationIntegrationTests.TestConfiguration.class,
properties = {
"spring.session.data.gemfire.cache.client.region.shortcut=LOCAL",
"spring.session.timeout=1",
"spring.session.timeout=1s",
},
webEnvironment = SpringBootTest.WebEnvironment.MOCK
)
@@ -98,6 +100,7 @@ public class SessionExpirationIntegrationTests extends IntegrationTestsSupport {
assertThat(session).isNotNull();
assertThat(session.getId()).isNotBlank();
assertThat(session.isExpired()).isFalse();
assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration.ofSeconds(1));
this.sessionRepository.save(session);

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2017-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.boot.autoconfigure.session;
import java.time.Duration;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.session.Session;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration Tests for {@link Session} {@literal expiration timeout} in {@literal days}.
*
* @author John Blum
* @see java.time.Duration
* @see org.springframework.boot.test.context.SpringBootTest
* @see org.springframework.geode.boot.autoconfigure.session.AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests
* @see org.springframework.session.Session
* @see org.springframework.test.context.junit4.SpringRunner
* @since 2.0.0
*/
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests.TestConfiguration.class,
properties = "spring.session.timeout=5d",
webEnvironment = SpringBootTest.WebEnvironment.MOCK
)
public class SessionExpirationTimeoutInDaysIntegrationTests
extends AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests {
@Override
protected int getExpectedMaxInactiveIntervalInSeconds() {
return Long.valueOf(Duration.ofDays(5).toSeconds()).intValue();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2017-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.boot.autoconfigure.session;
import java.time.Duration;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.session.Session;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration Tests for {@link Session} {@literal expiration timeout} in {@literal hours}.
*
* @author John Blum
* @see java.time.Duration
* @see org.springframework.boot.test.context.SpringBootTest
* @see org.springframework.geode.boot.autoconfigure.session.AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests
* @see org.springframework.session.Session
* @see org.springframework.test.context.junit4.SpringRunner
* @since 2.0.0
*/
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests.TestConfiguration.class,
properties = "spring.session.timeout=2h",
webEnvironment = SpringBootTest.WebEnvironment.MOCK
)
public class SessionExpirationTimeoutInHoursIntegrationTests
extends AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests{
@Override
protected int getExpectedMaxInactiveIntervalInSeconds() {
return Long.valueOf(Duration.ofHours(2).toSeconds()).intValue();
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2017-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.boot.autoconfigure.session;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.Duration;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.session.Session;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration Tests for {@link Session} {@literal expiration timeout} in {@literal milliseconds}.
*
* @author John Blum
* @see java.time.Duration
* @see org.springframework.boot.test.context.SpringBootTest
* @see org.springframework.geode.boot.autoconfigure.session.AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests
* @see org.springframework.session.Session
* @see org.springframework.test.context.junit4.SpringRunner
* @since 2.0.0
*/
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests.TestConfiguration.class,
properties = "spring.session.timeout=250ms",
webEnvironment = SpringBootTest.WebEnvironment.MOCK
)
public class SessionExpirationTimeoutInMillisecondsIntegrationTests
extends AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests {
@Override
protected int getExpectedMaxInactiveIntervalInSeconds() {
int maxInactiveIntervalInSeconds = Long.valueOf(Duration.ofMillis(250).toSeconds()).intValue();
assertThat(maxInactiveIntervalInSeconds).isZero();
return maxInactiveIntervalInSeconds;
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2017-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.boot.autoconfigure.session;
import java.time.Duration;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.session.Session;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration Tests for {@link Session} {@literal expiration timeout} in {@literal minutes}.
*
* @author John Blum
* @see java.time.Duration
* @see org.springframework.boot.test.context.SpringBootTest
* @see org.springframework.geode.boot.autoconfigure.session.AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests
* @see org.springframework.session.Session
* @see org.springframework.test.context.junit4.SpringRunner
* @since 2.0.0
*/
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests.TestConfiguration.class,
properties = "spring.session.timeout=5m",
webEnvironment = SpringBootTest.WebEnvironment.MOCK
)
public class SessionExpirationTimeoutInMinutesIntegrationTests
extends AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests {
@Override
protected int getExpectedMaxInactiveIntervalInSeconds() {
return Long.valueOf(Duration.ofMinutes(5).toSeconds()).intValue();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2017-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.springframework.geode.boot.autoconfigure.session;
import java.time.Duration;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.session.Session;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration Tests for {@link Session} {@literal expiration timeout} in {@literal seconds}.
*
* @author John Blum
* @see java.time.Duration
* @see org.springframework.boot.test.context.SpringBootTest
* @see org.springframework.geode.boot.autoconfigure.session.AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests
* @see org.springframework.session.Session
* @see org.springframework.test.context.junit4.SpringRunner
* @since 2.0.0
*/
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests.TestConfiguration.class,
properties = "spring.session.timeout=600s",
webEnvironment = SpringBootTest.WebEnvironment.MOCK
)
public class SessionExpirationTimeoutInSecondsIntegrationTests
extends AbstractSessionExpirationTimeoutInTimeUnitIntegrationTests {
@Override
protected int getExpectedMaxInactiveIntervalInSeconds() {
return Long.valueOf(Duration.ofSeconds(600).toSeconds()).intValue();
}
}