Compare commits

...

55 Commits

Author SHA1 Message Date
Rob Winch
a39295c02b Release 2.0.3 2018-05-08 13:57:03 -05:00
Vedran Pavic
02cd5a6301 Upgrade test dependencies 2018-05-08 19:20:48 +02:00
Vedran Pavic
5824566621 Upgrade Spring Security to 5.0.5.RELEASE
Closes gh-1060
2018-05-08 18:43:03 +02:00
Vedran Pavic
b2711600e2 Polish contribution
Closes gh-1014
2018-05-08 17:35:49 +02:00
Ivan Sopov
06eb768721 Remove redundant index in JDBC schema scripts
See gh-1014
2018-05-08 17:33:16 +02:00
Vedran Pavic
fb05fa70c7 Upgrade Hazelcast to 3.9.4
Closes gh-1067
2018-05-08 17:29:28 +02:00
Vedran Pavic
1e93fe87db Upgrade test dependencies 2018-05-08 17:14:07 +02:00
Vedran Pavic
e67f84c6b6 Upgrade Spring Data to Kay-SR7
See gh-1059
2018-05-08 16:27:17 +02:00
Vedran Pavic
dfb2f2f334 Upgrade Reactor to Bismuth-SR9
See gh-1057
2018-05-08 16:26:27 +02:00
Vedran Pavic
c8e9630fdd Upgrade Spring Framework to 5.0.6.RELEASE
See gh-1058
2018-05-08 16:25:34 +02:00
Vedran Pavic
751375338c Optimize session resolution in SessionRepositoryFilter
This commit optimizes SessionRepositoryFilter to avoid multiple retrievals of session from SessionRepository.

Closes gh-1048
2018-05-04 21:26:35 +02:00
Vedran Pavic
538712d162 Fix compilation warnings 2018-05-04 18:05:39 +02:00
Vedran Pavic
941fdb46f2 Replace use of Test.expected with AssertJ
See gh-1032
2018-05-04 18:05:38 +02:00
Vedran Pavic
bb1c099094 Optimize batch operations in JdbcOperationsSessionRepository
This commit optimizes session attribute saving by ensuring batch updates are used whenever possible. To make this possible, delta now tracks operations for each attribute change in order to be able to deduce SQL operation.

Additionally, if there is only a single attribute change, regular update is executed rather than batch operation.

Closes gh-1051
2018-05-04 16:33:47 +02:00
Vedran Pavic
1d1253e643 Rename expiration key on changeSessionId in RedisOperationsSessionRepository
This commit ensures existing expiration key is renamed on changeSessionId operation in RedisOperationsSessionRepository. Previously, this key wasn't renamed which caused invalid invocations of SessionDestroyedEvent handling when key expired.

Closes gh-1029
2018-04-20 23:08:50 +02:00
Vedran Pavic
0e7e2eaf5c Upgrade samples to Spring Boot 2.0.1.RELEASE
Closes gh-1061
2018-04-20 15:58:19 +02:00
Vedran Pavic
e601e03e1e Upgrade dependencies
This commit harmonizes project dependencies with Spring IO Platform Cairo levels.
2018-04-20 15:56:30 +02:00
Vedran Pavic
2c81e50b5e Upgrade Spring Security to 5.0.4.RELEASE
Closes gh-1060
2018-04-20 15:18:30 +02:00
Vedran Pavic
ac5ff996f4 Upgrade Spring Data to Kay-SR6
Closes gh-1059
2018-04-20 15:17:58 +02:00
Vedran Pavic
44130cba80 Upgrade Spring Framework to 5.0.5.RELEASE
Closes gh-1058
2018-04-20 15:17:18 +02:00
Vedran Pavic
2cd8063c7c Upgrade Reactor to Bismuth-SR8
Closes gh-1057
2018-04-20 15:16:41 +02:00
Vedran Pavic
f42a6c7d1c Upgrade Gradle to 4.7 2018-04-20 14:10:54 +02:00
Vedran Pavic
6c2f6c26cc Update integration tests
- upgrade TestContainers to 1.7.1
- update Docker images
- improve MariaDB/MySQL tests to use UTF-8

Closes gh-1034
2018-04-20 14:10:52 +02:00
Vedran Pavic
91b4efc5bd Fix attribute mapping in ReactiveRedisOperationsSessionRepository
This commit ensures that attributes with null values are correctly mapped to session on retrieval from Redis.

Closes gh-1035
2018-04-19 15:31:08 +02:00
Vedran Pavic
6f8359ba16 Fix lastAccessedTime handling in SpringSessionWebSessionStore
This commit ensures lastAccessedTime is updated when session is retrieved, as per WebSessionStore API.

Closes gh-1039
2018-04-19 12:11:16 +02:00
Vedran Pavic
62bfeb3f05 Fix ReactiveRedisOperationsSessionRepository tests 2018-04-19 11:08:45 +02:00
Vedran Pavic
2395582fe6 Optimize session retrieval in JdbcOperationsSessionRepository
Previously, SessionResultSetExtractor used JdbcSession.setAttribute which had a side effect of freshly loaded session potentially having a non-empty delta and/or changed flag set. This commit optimizes session retrieval to invoke setAttribute directly on the delegate, therefore preventing unnecessary modifications of delta and change flags.

Closes gh-1042
2018-04-16 08:58:16 +02:00
Vedran Pavic
5173026aa8 Improve RedisOperationsSessionRepository tests 2018-04-16 08:52:43 +02:00
Vedran Pavic
d97ad2ca3e Polish 2018-03-31 08:32:18 +02:00
Vedran Pavic
a780ee0264 Replace use of ExpectedException rule with AssertJ
Closes gh-1032
2018-03-31 08:32:16 +02:00
Vedran Pavic
d8e7a2aa9f Add support for EditorConfig 2018-03-26 19:06:35 +02:00
Rob Winch
45b18dec84 Add CVE Reporting to Issue Template 2018-03-20 22:43:50 -05:00
Rob Winch
ec5406fb01 Add CVE Reporting in PR Template 2018-03-20 22:43:27 -05:00
Vedran Pavic
3c2f0fd485 Fix broken links in Spring Boot samples guides
Closes gh-1023
2018-03-20 10:57:03 +01:00
Vedran Pavic
cdfa557442 Update guides for Spring Boot based samples
Closes gh-1025
2018-03-20 10:44:51 +01:00
Vedran Pavic
edc8a7efff Upgrade Spring Boot to 2.0.0.RELEASE
Closes gh-1007
2018-03-09 07:23:38 +01:00
Vedran Pavic
a7a30dad30 Polish contribution
Closes gh-1009
2018-03-09 07:23:38 +01:00
Josh Cummings
be1d3d30a8 Upgrade Gradle to 4.6
See gh-1009
2018-03-09 07:23:28 +01:00
Vedran Pavic
010aa5f013 Next development version 2018-02-20 14:28:45 +01:00
Vedran Pavic
bfcb4afef7 Release 2.0.2.RELEASE 2018-02-20 14:24:54 +01:00
Vedran Pavic
72a902009e Upgrade spring-build-conventions to 0.0.13.RELEASE 2018-02-20 07:34:06 +01:00
Vedran Pavic
1e799f211f Upgrade Spring Security to 5.0.2.RELEASE
Closes gh-998
2018-02-20 07:32:35 +01:00
Vedran Pavic
90599b9bd3 Upgrade Spring Data to Kay-SR4
Closes gh-997
2018-02-19 22:29:17 +01:00
Vedran Pavic
8d7136072a Upgrade Spring Framework to 5.0.4.RELEASE
Closes gh-996
2018-02-19 13:05:58 +01:00
Vedran Pavic
4f0f3806a2 Update integration tests
This commit updates TestContainers dependency and versions of Docker images used in integration tests.
2018-02-19 09:14:56 +01:00
Vedran Pavic
a18037759c Upgrade dependencies
This commit harmonizes project dependencies with Spring IO Platform Cairo levels.
2018-02-19 09:06:26 +01:00
Vedran Pavic
eb479af1d4 Upgrade Reactor to Bismuth-SR6
Closes gh-999
2018-02-16 19:56:49 +01:00
Vedran Pavic
d0b472e8e2 Ignore SQL Server integration tests 2018-02-12 20:22:39 +01:00
Vedran Pavic
17ee9d51f2 Update integration tests
This commit updates TestContainers dependency and versions of Docker images used in integration tests.
2018-02-12 19:07:59 +01:00
Vedran Pavic
003996a1b3 Upgrade Gradle to 4.5.1 2018-02-06 15:30:09 +01:00
Vedran Pavic
13c0e325b4 Adapt to Spring WebSocket configuration deprecations
Closes gh-994
2018-02-06 15:30:09 +01:00
Vedran Pavic
7acdeffe22 Remove outdated sample docs
Closes gh-989
2018-02-06 15:30:09 +01:00
Vedran Pavic
de03b20619 Upgrade Spring Boot to 2.0.0.RC1
Closes gh-988
2018-02-06 15:30:02 +01:00
Vedran Pavic
becee53dbf Restore CookieSerializer.CookieValue constructor visibility
Closes gh-978
2018-02-05 19:11:08 +01:00
Vedran Pavic
4eb64e8140 Next development version 2018-01-25 18:52:21 +01:00
100 changed files with 1433 additions and 893 deletions

19
.editorconfig Normal file
View File

@@ -0,0 +1,19 @@
root = true
[*]
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 120
[*.java]
indent_style = tab
indent_size = 4
charset = latin1
continuation_indent_size = 8
[*.xml]
indent_style = tab
indent_size = 4
charset = latin1
continuation_indent_size = 8

View File

@@ -1,3 +1,7 @@
<!--
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
-->
<!--
Thanks for raising a Spring Session issue. Please provide a brief description of your problem along with the version of Spring Session that you are using. If possible, please also consider putting together a sample application that reproduces the issue.
-->

View File

@@ -1,3 +1,7 @@
<!--
For Security Vulnerabilities, please use https://pivotal.io/security#reporting
-->
<!--
Thanks for contributing to Spring Session. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with #).
-->

2
.gitignore vendored
View File

@@ -10,6 +10,6 @@ target
out
.springBeans
*.rdb
!eclispe/.checkstyle
.checkstyle
!etc/eclipse/.checkstyle
!**/src/**/build

View File

@@ -1,6 +1,6 @@
buildscript {
dependencies {
classpath 'io.spring.gradle:spring-build-conventions:0.0.9.RELEASE'
classpath 'io.spring.gradle:spring-build-conventions:0.0.13.RELEASE'
classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
}
repositories {

View File

@@ -38,6 +38,7 @@ asciidoctor {
'lettuce-version': versions['io.lettuce:lettuce-core'],
'samples-dir': "$rootProject.projectDir.path/samples/",
'session-jdbc-main-resources-dir': "${project(':spring-session-jdbc').projectDir.path}/src/main/resources/",
'spring-boot-version': project.springBootVersion,
'spring-data-redis-version': versions['org.springframework.data:spring-data-redis'],
'spring-framework-version': versions['org.springframework:spring-core'],
'spring-security-version': versions['org.springframework.security:spring-security-core'],

View File

@@ -37,7 +37,7 @@ Thanks to first-class auto configuration support, setting up Spring Session back
.src/main/resources/application.properties
----
spring.session.store-type=jdbc
spring.session.store-type=jdbc # Session store type.
----
Under the hood, Spring Boot will apply configuration that is equivalent to manually adding `@EnableJdbcHttpSession` annotation.
@@ -48,10 +48,10 @@ Further customization is possible using `application.properties`:
.src/main/resources/application.properties
----
server.session.timeout= # Session timeout in seconds.
spring.session.jdbc.initializer.enabled= # Create the required session tables on startup if necessary. Enabled automatically if the default table name is set or a custom schema is configured.
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds will be used.
spring.session.jdbc.initialize-schema=embedded # Database schema initialization mode.
spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema.
spring.session.jdbc.table-name=SPRING_SESSION # Name of database table used to store sessions.
spring.session.jdbc.table-name=SPRING_SESSION # Name of the database table used to store sessions.
----
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-session[Spring Session] portion of the Spring Boot documentation.
@@ -65,9 +65,9 @@ For example, you can include the following in your *application.properties*
.src/main/resources/application.properties
----
spring.datasource.url=jdbc:postgresql://localhost:5432/myapp
spring.datasource.username=myapp
spring.datasource.password=secret
spring.datasource.url= # JDBC URL of the database.
spring.datasource.username= # Login username of the database.
spring.datasource.password= # Login password of the database.
----
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-configure-datasource[Configure a DataSource] portion of the Spring Boot documentation.

View File

@@ -35,7 +35,7 @@ Thanks to first-class auto configuration support, setting up Spring Session back
.src/main/resources/application.properties
----
spring.session.store-type=redis
spring.session.store-type=redis # Session store type.
----
Under the hood, Spring Boot will apply configuration that is equivalent to manually adding `@EnableRedisHttpSession` annotation.
@@ -46,9 +46,9 @@ Further customization is possible using `application.properties`:
.src/main/resources/application.properties
----
server.session.timeout= # Session timeout in seconds.
spring.session.redis.flush-mode= # Sessions flush mode.
spring.session.redis.namespace= # Namespace for keys used to store sessions.
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds will be used.
spring.session.redis.flush-mode=on-save # Sessions flush mode.
spring.session.redis.namespace=spring:session # Namespace for keys used to store sessions.
----
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-session[Spring Session] portion of the Spring Boot documentation.
@@ -62,9 +62,9 @@ For example, you can include the following in your *application.properties*
.src/main/resources/application.properties
----
spring.redis.host=localhost
spring.redis.password=secret
spring.redis.port=6379
spring.redis.host=localhost # Redis server host.
spring.redis.password= # Login password of the redis server.
spring.redis.port=6379 # Redis server port.
----
For more information, refer to https://docs.spring.io/spring-boot/docs/{spring-boot-version}/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation.

View File

@@ -24,7 +24,7 @@ Please make sure you have already integrated Spring Session with the HttpSession
[[websocket-spring-configuration]]
== Spring Configuration
In a typical Spring WebSocket application users would extend `AbstractWebSocketMessageBrokerConfigurer`.
In a typical Spring WebSocket application users would implement `WebSocketMessageBrokerConfigurer`.
For example, the configuration might look something like the following:
[source,java]
@@ -43,7 +43,7 @@ include::{samples-dir}boot/websocket/src/main/java/sample/config/WebSocketConfig
To hook in the Spring Session support we only need to change two things:
<1> Instead of extending `AbstractWebSocketMessageBrokerConfigurer` we extend `AbstractSessionWebSocketMessageBrokerConfigurer`
<1> Instead of implementing `WebSocketMessageBrokerConfigurer` we extend `AbstractSessionWebSocketMessageBrokerConfigurer`
<2> We rename the `registerStompEndpoints` method to `configureStompEndpoints`
What does `AbstractSessionWebSocketMessageBrokerConfigurer` do behind the scenes?
@@ -77,7 +77,7 @@ For the purposes of testing session expiration, you may want to change the sessi
.src/main/resources/application.properties
----
server.session.timeout=60
server.servlet.session.timeout=1m # Session timeout. If a duration suffix is not specified, seconds will be used.
----
====

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -67,8 +67,8 @@ public class RememberMeSecurityConfiguration extends WebSecurityConfigurerAdapte
@Override
@Bean
public InMemoryUserDetailsManager userDetailsService() {
return new InMemoryUserDetailsManager(User.withDefaultPasswordEncoder()
.username("user").password("password").roles("USER").build());
return new InMemoryUserDetailsManager(User.withUsername("user")
.password("{noop}password").roles("USER").build());
}
@Bean

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2018 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.
@@ -19,9 +19,9 @@ package docs.websocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* @author Rob Winch
@@ -30,7 +30,7 @@ import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {

View File

@@ -1,2 +1,2 @@
springBootVersion=2.0.0.M7
version=2.0.1.RELEASE
springBootVersion=2.0.1.RELEASE
version=2.0.3.RELEASE

View File

@@ -1,39 +1,31 @@
dependencyManagement {
imports {
mavenBom 'com.fasterxml.jackson:jackson-bom:2.9.4'
mavenBom 'io.projectreactor:reactor-bom:Bismuth-SR5'
mavenBom 'org.springframework:spring-framework-bom:5.0.3.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-SR3'
mavenBom 'org.springframework.security:spring-security-bom:5.0.1.RELEASE'
mavenBom 'io.projectreactor:reactor-bom:Bismuth-SR9'
mavenBom 'org.springframework:spring-framework-bom:5.0.6.RELEASE'
mavenBom 'org.springframework.data:spring-data-releasetrain:Kay-SR7'
mavenBom 'org.springframework.security:spring-security-bom:5.0.5.RELEASE'
mavenBom 'org.testcontainers:testcontainers-bom:1.7.2'
}
dependencies {
dependencySet(group: 'com.hazelcast', version: '3.9.2') {
dependencySet(group: 'com.hazelcast', version: '3.9.4') {
entry 'hazelcast'
entry 'hazelcast-client'
}
dependencySet(group: 'org.testcontainers', version: '1.5.1') {
entry 'mariadb'
entry 'mssqlserver'
entry 'mysql'
entry 'postgresql'
entry 'testcontainers'
}
dependency 'com.h2database:h2:1.4.196'
dependency 'com.microsoft.sqlserver:mssql-jdbc:6.2.2.jre8'
dependency 'com.h2database:h2:1.4.197'
dependency 'com.microsoft.sqlserver:mssql-jdbc:6.4.0.jre8'
dependency 'edu.umd.cs.mtc:multithreadedtc:1.01'
dependency 'io.lettuce:lettuce-core:5.0.1.RELEASE'
dependency 'io.lettuce:lettuce-core:5.0.4.RELEASE'
dependency 'javax.servlet:javax.servlet-api:3.1.0'
dependency 'junit:junit:4.12'
dependency 'mysql:mysql-connector-java:5.1.45'
dependency 'org.apache.derby:derby:10.14.1.0'
dependency 'org.assertj:assertj-core:3.9.0'
dependency 'mysql:mysql-connector-java:8.0.11'
dependency 'org.apache.derby:derby:10.14.2.0'
dependency 'org.assertj:assertj-core:3.9.1'
dependency 'org.hsqldb:hsqldb:2.4.0'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.2.1'
dependency 'org.mockito:mockito-core:2.13.0'
dependency 'org.postgresql:postgresql:42.2.0'
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.29.0'
dependency 'org.mariadb.jdbc:mariadb-java-client:2.2.3'
dependency 'org.mockito:mockito-core:2.18.3'
dependency 'org.postgresql:postgresql:42.2.2'
}
}

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-bin.zip

View File

@@ -1,4 +0,0 @@
Demonstrates using Spring Session to lookup a user's session by the username.
The sample provides a hook to add the current username to the session (required for finding the user) by providing a custom implementation of Spring Security's `AuthenticationSuccessHandler`.
NOTE: This product includes GeoLite2 data created by MaxMind, available from http://www.maxmind.com

View File

@@ -10,7 +10,7 @@ dependencies {
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator"
compile "org.webjars:webjars-locator-core"
compile "com.maxmind.geoip2:geoip2"
compile "org.apache.httpcomponents:httpclient"

View File

@@ -17,8 +17,9 @@
package sample;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
@@ -49,12 +50,21 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
@ContextConfiguration(initializers = FindByUsernameTests.Initializer.class)
public class FindByUsernameTests {
private static final String DOCKER_IMAGE = "redis:4.0.7";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@ClassRule
public static GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Autowired
private MockMvc mockMvc;
@@ -93,8 +103,8 @@ public class FindByUsernameTests {
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + redisContainer.getContainerIpAddress(),
"spring.redis.port=" + redisContainer.getFirstMappedPort())
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -16,14 +16,10 @@
package sample.config;
import org.springframework.boot.autoconfigure.security.StaticResourceRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
/**
* Spring Security configuration.
@@ -34,20 +30,13 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(User.withDefaultPasswordEncoder()
.username("user").password("password").roles("USER").build());
}
// @formatter:off
// tag::config[]
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(StaticResourceRequest.toCommonLocations()).permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()

View File

@@ -0,0 +1 @@
spring.security.user.password=password

View File

@@ -1 +0,0 @@
Demonstrates using Spring Session with Spring Boot and Spring Security. You can log in with the username "user" and the password "password".

View File

@@ -9,7 +9,7 @@ dependencies {
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator"
compile "org.webjars:webjars-locator-core"
compile "com.h2database:h2"
testCompile "org.springframework.boot:spring-boot-starter-test"

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -16,15 +16,11 @@
package sample.config;
import org.springframework.boot.autoconfigure.security.StaticResourceRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
/**
* Spring Security configuration.
@@ -35,18 +31,11 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(User.withDefaultPasswordEncoder()
.username("user").password("password").roles("USER").build());
}
// @formatter:off
@Override
public void configure(WebSecurity web) throws Exception {
public void configure(WebSecurity web) {
web
.ignoring().antMatchers("/h2-console/**");
.ignoring().requestMatchers(PathRequest.toH2Console());
}
// @formatter:on
@@ -56,7 +45,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(StaticResourceRequest.toCommonLocations()).permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()

View File

@@ -1 +1,2 @@
spring.security.user.password=password
spring.h2.console.enabled=true

View File

@@ -10,7 +10,7 @@ dependencies {
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator"
compile "org.webjars:webjars-locator-core"
compile "org.apache.httpcomponents:httpclient"
testCompile "org.springframework.boot:spring-boot-starter-test"

View File

@@ -19,8 +19,9 @@ package sample;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
@@ -53,12 +54,21 @@ import static org.assertj.core.api.Assertions.assertThat;
@ContextConfiguration(initializers = HttpRedisJsonTest.Initializer.class)
public class HttpRedisJsonTest {
private static final String DOCKER_IMAGE = "redis:4.0.7";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@ClassRule
public static GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Autowired
private MockMvc mockMvc;
@@ -117,8 +127,8 @@ public class HttpRedisJsonTest {
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + redisContainer.getContainerIpAddress(),
"spring.redis.port=" + redisContainer.getFirstMappedPort())
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
}

View File

@@ -16,7 +16,8 @@
package sample;
import org.junit.ClassRule;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.testcontainers.containers.GenericContainer;
@@ -42,12 +43,21 @@ import static org.assertj.core.api.Assertions.assertThat;
@ContextConfiguration(initializers = RedisSerializerTest.Initializer.class)
public class RedisSerializerTest {
private static final String DOCKER_IMAGE = "redis:4.0.7";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@ClassRule
public static GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@SpringSessionRedisOperations
private RedisTemplate<Object, Object> sessionRedisTemplate;
@@ -66,8 +76,8 @@ public class RedisSerializerTest {
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + redisContainer.getContainerIpAddress(),
"spring.redis.port=" + redisContainer.getFirstMappedPort())
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -16,14 +16,10 @@
package sample.config;
import org.springframework.boot.autoconfigure.security.StaticResourceRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
/**
* Spring Security configuration.
@@ -34,19 +30,12 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(User.withDefaultPasswordEncoder()
.username("user").password("password").roles("USER").build());
}
// @formatter:off
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(StaticResourceRequest.toCommonLocations()).permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()

View File

@@ -0,0 +1 @@
spring.security.user.password=password

View File

@@ -1 +0,0 @@
Demonstrates using Spring Session with Spring Boot and Spring Security. You can log in with the username "user" and the password "password".

View File

@@ -10,7 +10,7 @@ dependencies {
compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect"
compile "org.webjars:bootstrap"
compile "org.webjars:html5shiv"
compile "org.webjars:webjars-locator"
compile "org.webjars:webjars-locator-core"
testCompile "org.springframework.boot:spring-boot-starter-test"

View File

@@ -17,8 +17,9 @@
package sample;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
@@ -48,12 +49,21 @@ import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDr
@ContextConfiguration(initializers = BootTests.Initializer.class)
public class BootTests {
private static final String DOCKER_IMAGE = "redis:4.0.7";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@ClassRule
public static GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Autowired
private MockMvc mockMvc;
@@ -99,8 +109,8 @@ public class BootTests {
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + redisContainer.getContainerIpAddress(),
"spring.redis.port=" + redisContainer.getFirstMappedPort())
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -16,14 +16,10 @@
package sample.config;
import org.springframework.boot.autoconfigure.security.StaticResourceRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
/**
* Spring Security configuration.
@@ -34,20 +30,13 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(User.withDefaultPasswordEncoder()
.username("user").password("password").roles("USER").build());
}
// @formatter:off
// tag::config[]
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(StaticResourceRequest.toCommonLocations()).permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()

View File

@@ -0,0 +1 @@
spring.security.user.password=password

View File

@@ -19,8 +19,9 @@ package sample;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;
@@ -49,12 +50,21 @@ import static org.assertj.core.api.Assertions.assertThat;
@ContextConfiguration(initializers = AttributeTests.Initializer.class)
public class AttributeTests {
private static final String DOCKER_IMAGE = "redis:4.0.7";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@ClassRule
public static GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@LocalServerPort
private int port;
@@ -106,8 +116,8 @@ public class AttributeTests {
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + redisContainer.getContainerIpAddress(),
"spring.redis.port=" + redisContainer.getFirstMappedPort())
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
}

View File

@@ -18,7 +18,7 @@ dependencies {
compile "org.webjars:knockout"
compile "org.webjars:sockjs-client"
compile "org.webjars:stomp-websocket"
compile "org.webjars:webjars-locator"
compile "org.webjars:webjars-locator-core"
compile "com.h2database:h2"
testCompile "org.springframework.boot:spring-boot-starter-test"

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -17,30 +17,20 @@
package sample.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.StaticResourceRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(User.withDefaultPasswordEncoder()
.username("user").password("password").roles("USER").build());
}
// @formatter:off
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth,
@@ -53,9 +43,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// @formatter:off
@Override
public void configure(WebSecurity web) throws Exception {
public void configure(WebSecurity web) {
web
.ignoring().antMatchers("/h2-console/**");
.ignoring().requestMatchers(PathRequest.toH2Console());
}
// @formatter:on
@@ -64,7 +54,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(StaticResourceRequest.toCommonLocations()).permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()

View File

@@ -1,2 +1,2 @@
#server.session.timeout=60
#server.servlet.session.timeout=1m
spring.h2.console.enabled=true

View File

@@ -20,10 +20,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.testcontainers.containers.GenericContainer;
@@ -46,6 +45,8 @@ import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.Transport;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* @author Rob Winch
* @author Vedran Pavic
@@ -55,14 +56,20 @@ import org.springframework.web.socket.sockjs.client.WebSocketTransport;
@ContextConfiguration(initializers = ApplicationTests.Initializer.class)
public class ApplicationTests {
private static final String DOCKER_IMAGE = "redis:4.0.7";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@ClassRule
public static GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@Rule
public final ExpectedException thrown = ExpectedException.none();
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Value("${local.server.port}")
private String port;
@@ -71,7 +78,7 @@ public class ApplicationTests {
private WebSocketHandler webSocketHandler;
@Test
public void run() throws Exception {
public void run() {
List<Transport> transports = new ArrayList<>(2);
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
transports.add(new RestTemplateXhrTransport());
@@ -80,8 +87,8 @@ public class ApplicationTests {
ListenableFuture<WebSocketSession> wsSession = sockJsClient.doHandshake(
this.webSocketHandler, "ws://localhost:" + this.port + "/sockjs");
this.thrown.expect(ExecutionException.class);
wsSession.get().sendMessage(new TextMessage("a"));
assertThatThrownBy(() -> wsSession.get().sendMessage(new TextMessage("a")))
.isInstanceOf(ExecutionException.class);
}
static class Initializer
@@ -91,8 +98,8 @@ public class ApplicationTests {
public void initialize(
ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.redis.host=" + redisContainer.getContainerIpAddress(),
"spring.redis.port=" + redisContainer.getFirstMappedPort())
.of("spring.redis.host=" + container.getContainerIpAddress(),
"spring.redis.port=" + container.getFirstMappedPort())
.applyTo(configurableApplicationContext.getEnvironment());
}

View File

@@ -5,6 +5,7 @@ dependencyManagement {
dependency 'javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:1.2.1'
dependency 'javax.servlet.jsp:javax.servlet.jsp-api:2.3.2-b02'
dependency 'org.apache.taglibs:taglibs-standard-jstlel:1.2.5'
dependency 'org.seleniumhq.selenium:htmlunit-driver:2.29.3'
dependency 'org.slf4j:jcl-over-slf4j:1.7.25'
dependency 'org.slf4j:log4j-over-slf4j:1.7.25'
dependency 'org.webjars:bootstrap:2.3.2'

View File

@@ -16,8 +16,6 @@
package sample;
import java.io.IOException;
import org.testcontainers.containers.GenericContainer;
import org.springframework.context.annotation.Bean;
@@ -30,23 +28,11 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
@Profile("embedded-redis")
public class EmbeddedRedisConfig {
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.7";
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.9";
@Bean(initMethod = "start")
public GenericContainer redisContainer() {
return new GenericContainer(REDIS_DOCKER_IMAGE) {
@Override
public void close() {
super.close();
try {
this.dockerClient.close();
}
catch (IOException ignored) {
}
}
}.withExposedPorts(6379);
return new GenericContainer(REDIS_DOCKER_IMAGE).withExposedPorts(6379);
}
@Bean

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2018 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.
@@ -28,7 +28,7 @@ import org.springframework.security.core.userdetails.User;
public class SecurityConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser(User.withDefaultPasswordEncoder()
.username("user").password("password").roles("USER").build());
auth.inMemoryAuthentication().withUser(User.withUsername("user")
.password("{noop}password").roles("USER").build());
}
}

View File

@@ -16,8 +16,6 @@
package sample;
import java.io.IOException;
import org.testcontainers.containers.GenericContainer;
import org.springframework.context.annotation.Bean;
@@ -30,23 +28,11 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
@Profile("embedded-redis")
public class EmbeddedRedisConfig {
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.7";
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.9";
@Bean(initMethod = "start")
public GenericContainer redisContainer() {
return new GenericContainer(REDIS_DOCKER_IMAGE) {
@Override
public void close() {
super.close();
try {
this.dockerClient.close();
}
catch (IOException ignored) {
}
}
}.withExposedPorts(6379);
return new GenericContainer(REDIS_DOCKER_IMAGE).withExposedPorts(6379);
}
@Bean

View File

@@ -17,7 +17,6 @@ dependencies {
testCompile "org.springframework.security:spring-security-test"
testCompile "org.assertj:assertj-core"
testCompile "org.springframework:spring-test"
testCompile "commons-codec:commons-codec"
integrationTestCompile "org.testcontainers:testcontainers"
}

View File

@@ -16,8 +16,9 @@
package rest;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.testcontainers.containers.GenericContainer;
@@ -55,12 +56,21 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@WebAppConfiguration
public class RestMockMvcTests {
private static final String DOCKER_IMAGE = "redis:4.0.7";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@ClassRule
public static GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Autowired
private SessionRepositoryFilter<? extends Session> sessionRepositoryFilter;
@@ -99,8 +109,8 @@ public class RestMockMvcTests {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisContainer.getContainerIpAddress(),
redisContainer.getFirstMappedPort());
return new LettuceConnectionFactory(container.getContainerIpAddress(),
container.getFirstMappedPort());
}
@Bean

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -17,8 +17,8 @@
package sample;
import java.util.Arrays;
import java.util.Base64;
import org.apache.commons.codec.binary.Base64;
import org.junit.Before;
import org.junit.Test;
@@ -32,6 +32,7 @@ import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* @author Pool Dolorier
@@ -52,13 +53,14 @@ public class RestTests {
this.restTemplate = new RestTemplate();
}
@Test(expected = HttpClientErrorException.class)
@Test
public void unauthenticatedUserSentToLogInPage() {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
ResponseEntity<String> entity = getForUser(this.baseUrl + "/",
headers, String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
assertThatThrownBy(() -> getForUser(this.baseUrl + "/", headers, String.class))
.isInstanceOf(HttpClientErrorException.class)
.satisfies(e -> assertThat(((HttpClientErrorException) e).getStatusCode())
.isEqualTo(HttpStatus.UNAUTHORIZED));
}
@Test
@@ -122,6 +124,6 @@ public class RestTests {
private String getAuth(String user, String password) {
String auth = user + ":" + password;
return new String(Base64.encodeBase64(auth.getBytes()));
return Base64.getEncoder().encodeToString(auth.getBytes());
}
}

View File

@@ -16,8 +16,6 @@
package sample;
import java.io.IOException;
import org.testcontainers.containers.GenericContainer;
import org.springframework.context.annotation.Bean;
@@ -30,23 +28,11 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
@Profile("embedded-redis")
public class EmbeddedRedisConfig {
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.7";
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.9";
@Bean(initMethod = "start")
public GenericContainer redisContainer() {
return new GenericContainer(REDIS_DOCKER_IMAGE) {
@Override
public void close() {
super.close();
try {
this.dockerClient.close();
}
catch (IOException ignored) {
}
}
}.withExposedPorts(6379);
return new GenericContainer(REDIS_DOCKER_IMAGE).withExposedPorts(6379);
}
@Bean

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2018 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.
@@ -43,7 +43,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser(User.withDefaultPasswordEncoder()
.username("user").password("password").roles("USER").build());
auth.inMemoryAuthentication().withUser(User.withUsername("user")
.password("{noop}password").roles("USER").build());
}
}

View File

@@ -16,8 +16,6 @@
package sample;
import java.io.IOException;
import org.testcontainers.containers.GenericContainer;
import org.springframework.context.annotation.Bean;
@@ -30,23 +28,11 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
@Profile("embedded-redis")
public class EmbeddedRedisConfig {
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.7";
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.9";
@Bean(initMethod = "start")
public GenericContainer redisContainer() {
return new GenericContainer(REDIS_DOCKER_IMAGE) {
@Override
public void close() {
super.close();
try {
this.dockerClient.close();
}
catch (IOException ignored) {
}
}
}.withExposedPorts(6379);
return new GenericContainer(REDIS_DOCKER_IMAGE).withExposedPorts(6379);
}
@Bean

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2018 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.
@@ -28,7 +28,7 @@ import org.springframework.security.core.userdetails.User;
public class SecurityConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser(User.withDefaultPasswordEncoder()
.username("user").password("password").roles("USER").build());
auth.inMemoryAuthentication().withUser(User.withUsername("user")
.password("{noop}password").roles("USER").build());
}
}

View File

@@ -16,8 +16,6 @@
package sample;
import java.io.IOException;
import org.testcontainers.containers.GenericContainer;
import org.springframework.context.annotation.Bean;
@@ -30,23 +28,11 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
@Profile("embedded-redis")
public class EmbeddedRedisConfig {
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.7";
private static final String REDIS_DOCKER_IMAGE = "redis:4.0.9";
@Bean(initMethod = "start")
public GenericContainer redisContainer() {
return new GenericContainer(REDIS_DOCKER_IMAGE) {
@Override
public void close() {
super.close();
try {
this.dockerClient.close();
}
catch (IOException ignored) {
}
}
}.withExposedPorts(6379);
return new GenericContainer(REDIS_DOCKER_IMAGE).withExposedPorts(6379);
}
@Bean

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -78,7 +78,7 @@ public interface CookieSerializer {
* modified by the {@link CookieSerializer} when writing to the actual cookie so
* long as the original value is returned when the cookie is read.
*/
CookieValue(HttpServletRequest request, HttpServletResponse response,
public CookieValue(HttpServletRequest request, HttpServletResponse response,
String cookieValue) {
this.request = request;
this.response = response;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -18,6 +18,7 @@ package org.springframework.session.web.http;
import java.io.IOException;
import java.time.Instant;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
@@ -196,14 +197,18 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
private final class SessionRepositoryRequestWrapper
extends HttpServletRequestWrapper {
private Boolean requestedSessionIdValid;
private boolean requestedSessionInvalidated;
private final HttpServletResponse response;
private final ServletContext servletContext;
private S requestedSession;
private boolean requestedSessionCached;
private Boolean requestedSessionIdValid;
private boolean requestedSessionInvalidated;
private SessionRepositoryRequestWrapper(HttpServletRequest request,
HttpServletResponse response, ServletContext servletContext) {
super(request);
@@ -225,7 +230,7 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
}
else {
S session = wrappedSession.getSession();
SessionRepositoryFilter.this.sessionRepository.save(session);
saveSession(session);
String sessionId = session.getId();
if (!isRequestedSessionIdValid()
|| !sessionId.equals(getRequestedSessionId())) {
@@ -265,9 +270,11 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
@Override
public boolean isRequestedSessionIdValid() {
if (this.requestedSessionIdValid == null) {
String sessionId = getRequestedSessionId();
S session = sessionId == null ? null : getSession(sessionId);
return isRequestedSessionIdValid(session);
S requestedSession = getRequestedSession();
if (requestedSession != null) {
requestedSession.setLastAccessedTime(Instant.now());
}
return isRequestedSessionIdValid(requestedSession);
}
return this.requestedSessionIdValid;
@@ -284,28 +291,18 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
return getCurrentSession() == null && this.requestedSessionInvalidated;
}
private S getSession(String sessionId) {
S session = SessionRepositoryFilter.this.sessionRepository
.findById(sessionId);
if (session == null) {
return null;
}
session.setLastAccessedTime(Instant.now());
return session;
}
@Override
public HttpSessionWrapper getSession(boolean create) {
HttpSessionWrapper currentSession = getCurrentSession();
if (currentSession != null) {
return currentSession;
}
String requestedSessionId = getRequestedSessionId();
if (requestedSessionId != null) {
S requestedSession = getRequestedSession();
if (requestedSession != null) {
if (getAttribute(INVALID_SESSION_ID_ATTR) == null) {
S session = getSession(requestedSessionId);
requestedSession.setLastAccessedTime(Instant.now());
this.requestedSessionIdValid = true;
currentSession = new HttpSessionWrapper(session, getServletContext());
currentSession = new HttpSessionWrapper(requestedSession, getServletContext());
currentSession.setNew(false);
setCurrentSession(currentSession);
return currentSession;
@@ -353,11 +350,31 @@ public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFi
@Override
public String getRequestedSessionId() {
return SessionRepositoryFilter.this.httpSessionIdResolver
.resolveSessionIds(this).stream()
.filter(sessionId -> SessionRepositoryFilter.this.sessionRepository
.findById(sessionId) != null)
.findFirst().orElse(null);
S requestedSession = getRequestedSession();
return (requestedSession != null ? requestedSession.getId() : null);
}
private S getRequestedSession() {
if (!this.requestedSessionCached) {
List<String> sessionIds = SessionRepositoryFilter.this.httpSessionIdResolver
.resolveSessionIds(this);
for (String sessionId : sessionIds) {
S session = SessionRepositoryFilter.this.sessionRepository
.findById(sessionId);
if (session != null) {
this.requestedSession = session;
break;
}
}
this.requestedSessionCached = true;
}
return this.requestedSession;
}
private void saveSession(S session) {
this.requestedSessionCached = false;
this.requestedSession = null;
SessionRepositoryFilter.this.sessionRepository.save(session);
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -46,6 +46,7 @@ import org.springframework.web.server.session.WebSessionStore;
*
* @param <S> the {@link Session} type
* @author Rob Winch
* @author Vedran Pavic
* @since 2.0
*/
public class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore {
@@ -94,7 +95,9 @@ public class SpringSessionWebSessionStore<S extends Session> implements WebSessi
@Override
public Mono<WebSession> retrieveSession(String sessionId) {
return this.sessions.findById(sessionId).map(this::existingSession);
return this.sessions.findById(sessionId)
.doOnNext(session -> session.setLastAccessedTime(this.clock.instant()))
.map(this::existingSession);
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -25,10 +25,10 @@ import org.springframework.session.SessionRepository;
import org.springframework.session.web.socket.handler.WebSocketConnectHandlerDecoratorFactory;
import org.springframework.session.web.socket.handler.WebSocketRegistryListener;
import org.springframework.session.web.socket.server.SessionRepositoryMessageInterceptor;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.StompWebSocketEndpointRegistration;
import org.springframework.web.socket.config.annotation.WebMvcStompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
import org.springframework.web.socket.messaging.StompSubProtocolErrorHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
@@ -75,7 +75,7 @@ import org.springframework.web.util.UrlPathHelper;
* @since 1.0
*/
public abstract class AbstractSessionWebSocketMessageBrokerConfigurer<S extends Session>
extends AbstractWebSocketMessageBrokerConfigurer {
implements WebSocketMessageBrokerConfigurer {
@Autowired
@SuppressWarnings("rawtypes")

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -24,6 +24,7 @@ import org.junit.Before;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class MapSessionTests {
@@ -35,9 +36,11 @@ public class MapSessionTests {
this.session.setLastAccessedTime(Instant.ofEpochMilli(1413258262962L));
}
@Test(expected = IllegalArgumentException.class)
@Test
public void constructorNullSession() {
new MapSession((Session) null);
assertThatThrownBy(() -> new MapSession((Session) null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("session cannot be null");
}
@Test
@@ -65,9 +68,11 @@ public class MapSessionTests {
assertThat(result).isEqualTo(attrValue);
}
@Test(expected = IllegalArgumentException.class)
@Test
public void getRequiredAttributeWhenNullThenException() {
this.session.getRequiredAttribute("attrName");
assertThatThrownBy(() -> this.session.getRequiredAttribute("attrName"))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Required attribute 'attrName' is missing.");
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -27,6 +27,7 @@ import org.junit.Before;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link ReactiveMapSessionRepository}.
@@ -57,10 +58,11 @@ public class ReactiveMapSessionRepositoryTests {
assertThat(findByIdSession.getId()).isEqualTo(this.session.getId());
}
@Test(expected = IllegalArgumentException.class)
@Test
public void constructorMapWhenNullThenThrowsIllegalArgumentException() {
Map<String, Session> sessions = null;
new ReactiveMapSessionRepository(sessions);
assertThatThrownBy(() -> new ReactiveMapSessionRepository(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("sessions cannot be null");
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -49,6 +49,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
/**
@@ -82,6 +83,9 @@ public class EnableSpringHttpSessionCustomCookieSerializerTests {
@Before
public void setup() {
this.chain = new MockFilterChain();
reset(this.sessionRepository);
reset(this.cookieSerializer);
}
@Test
@@ -99,7 +103,7 @@ public class EnableSpringHttpSessionCustomCookieSerializerTests {
@Test
public void usesWrite() throws Exception {
given(this.sessionRepository.findById(anyString())).willReturn(new MapSession());
given(this.sessionRepository.createSession()).willReturn(new MapSession());
this.sessionRepositoryFilter.doFilter(this.request, this.response,
new MockFilterChain() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -21,11 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletContext;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -42,18 +38,15 @@ import org.springframework.session.web.http.SessionRepositoryFilter;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link SpringHttpSessionConfiguration}.
*
* @author Vedran Pavic
*/
@RunWith(MockitoJUnitRunner.class)
public class SpringHttpSessionConfigurationTests {
@Rule
public final ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@After
@@ -70,10 +63,9 @@ public class SpringHttpSessionConfigurationTests {
@Test
public void noSessionRepositoryConfiguration() {
this.thrown.expect(UnsatisfiedDependencyException.class);
this.thrown.expectMessage("org.springframework.session.SessionRepository");
registerAndRefresh(EmptyConfiguration.class);
assertThatThrownBy(() -> registerAndRefresh(EmptyConfiguration.class))
.isInstanceOf(UnsatisfiedDependencyException.class)
.hasMessageContaining("org.springframework.session.SessionRepository");
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -20,15 +20,14 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@@ -43,9 +42,6 @@ import static org.mockito.Mockito.verifyZeroInteractions;
*/
public class SpringSessionRememberMeServicesTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
private SpringSessionRememberMeServices rememberMeServices;
@Test
@@ -71,10 +67,10 @@ public class SpringSessionRememberMeServicesTests {
@Test
public void createWithNullParameter() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("rememberMeParameterName cannot be empty or null");
this.rememberMeServices = new SpringSessionRememberMeServices();
this.rememberMeServices.setRememberMeParameterName(null);
assertThatThrownBy(() -> this.rememberMeServices.setRememberMeParameterName(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("rememberMeParameterName cannot be empty or null");
}
@Test
@@ -114,7 +110,8 @@ public class SpringSessionRememberMeServicesTests {
this.rememberMeServices = new SpringSessionRememberMeServices();
this.rememberMeServices.loginFail(request, response);
verify(request, times(1)).getSession(eq(false));
verify(session, times(1)).removeAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
verify(session, times(1)).removeAttribute(
HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
verifyZeroInteractions(request, response, session);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -21,9 +21,7 @@ import java.util.Base64;
import javax.servlet.http.Cookie;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@@ -34,6 +32,7 @@ import org.springframework.session.web.http.CookieSerializer.CookieValue;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link DefaultCookieSerializer}.
@@ -50,9 +49,6 @@ public class DefaultCookieSerializerTests {
return new Object[] { false, true };
}
@Rule
public ExpectedException thrown = ExpectedException.none();
private boolean useBase64Encoding;
private String cookieName;
@@ -214,10 +210,12 @@ public class DefaultCookieSerializerTests {
assertThat(getCookie().getDomain()).isEqualTo(domainName);
}
@Test(expected = IllegalStateException.class)
@Test
public void setDomainNameAndDomainNamePatternThrows() {
this.serializer.setDomainName("example.com");
this.serializer.setDomainNamePattern(".*");
assertThatThrownBy(() -> this.serializer.setDomainNamePattern(".*"))
.isInstanceOf(IllegalStateException.class)
.hasMessage("Cannot set both domainName and domainNamePattern");
}
// --- domainNamePattern ---
@@ -246,10 +244,12 @@ public class DefaultCookieSerializerTests {
}
}
@Test(expected = IllegalStateException.class)
@Test
public void setDomainNamePatternAndDomainNameThrows() {
this.serializer.setDomainNamePattern(".*");
this.serializer.setDomainName("example.com");
assertThatThrownBy(() -> this.serializer.setDomainName("example.com"))
.isInstanceOf(IllegalStateException.class)
.hasMessage("Cannot set both domainName and domainNamePattern");
}
// --- cookieName ---
@@ -271,9 +271,11 @@ public class DefaultCookieSerializerTests {
assertThat(getCookie().getName()).isEqualTo(cookieName);
}
@Test(expected = IllegalArgumentException.class)
@Test
public void setCookieNameNullThrows() {
this.serializer.setCookieName(null);
assertThatThrownBy(() -> this.serializer.setCookieName(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("cookieName cannot be null");
}
// --- cookiePath ---

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -20,15 +20,14 @@ import java.util.Collections;
import java.util.UUID;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests for {@link HeaderHttpSessionIdResolver}.
@@ -37,9 +36,6 @@ public class HeaderHttpSessionIdResolverTests {
private static final String HEADER_X_AUTH_TOKEN = "X-Auth-Token";
@Rule
public ExpectedException thrown = ExpectedException.none();
private MockHttpServletRequest request;
private MockHttpServletResponse response;
@@ -47,7 +43,7 @@ public class HeaderHttpSessionIdResolverTests {
private HeaderHttpSessionIdResolver resolver;
@Before
public void setup() throws Exception {
public void setup() {
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
this.resolver = HeaderHttpSessionIdResolver.xAuthToken();
@@ -78,9 +74,9 @@ public class HeaderHttpSessionIdResolverTests {
@Test
public void createResolverWithNullHeaderName() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("headerName cannot be null");
new HeaderHttpSessionIdResolver(null);
assertThatThrownBy(() -> new HeaderHttpSessionIdResolver(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("headerName cannot be null");
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -58,6 +58,7 @@ import org.springframework.session.SessionRepository;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
@@ -1343,15 +1344,19 @@ public class SessionRepositoryFilterTests {
}
// We want the filter to work without any dependencies on Spring
@Test(expected = ClassCastException.class)
@Test
@SuppressWarnings("unused")
public void doesNotImplementOrdered() {
Ordered o = (Ordered) this.filter;
assertThatThrownBy(() -> {
Ordered o = (Ordered) this.filter;
}).isInstanceOf(ClassCastException.class);
}
@Test(expected = IllegalArgumentException.class)
@Test
public void setHttpSessionIdResolverNull() {
this.filter.setHttpSessionIdResolver(null);
assertThatThrownBy(() -> this.filter.setHttpSessionIdResolver(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("httpSessionIdResolver cannot be null");
}
// --- helper methods

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -33,6 +33,7 @@ import org.springframework.session.Session;
import org.springframework.web.server.WebSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
@@ -41,7 +42,7 @@ import static org.mockito.Mockito.verify;
* Tests for {@link SpringSessionWebSessionStore}.
*
* @author Rob Winch
* @since 5.0
* @author Vedran Pavic
*/
@RunWith(MockitoJUnitRunner.class)
public class SpringSessionWebSessionStoreTests<S extends Session> {
@@ -66,9 +67,11 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
.willReturn(Mono.just(this.createSession));
}
@Test(expected = IllegalArgumentException.class)
@Test
public void constructorWhenNullRepositoryThenThrowsIllegalArgumentException() {
new SpringSessionWebSessionStore<S>(null);
assertThatThrownBy(() -> new SpringSessionWebSessionStore<S>(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("reactiveSessionRepository cannot be null");
}
@Test
@@ -268,6 +271,7 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
.retrieveSession(id).block();
assertThat(retrievedWebSession.isStarted()).isTrue();
verify(this.findByIdSession).setLastAccessedTime(any());
}
@Test
@@ -280,8 +284,11 @@ public class SpringSessionWebSessionStoreTests<S extends Session> {
verify(this.sessionRepository).deleteById(sessionId);
}
@Test(expected = IllegalArgumentException.class)
@Test
public void setClockWhenNullThenException() {
this.webSessionStore.setClock(null);
assertThatThrownBy(() -> this.webSessionStore.setClock(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("clock cannot be null");
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -31,6 +31,7 @@ import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.verify;
@@ -53,9 +54,11 @@ public class WebSocketConnectHandlerDecoratorFactoryTests {
this.factory = new WebSocketConnectHandlerDecoratorFactory(this.eventPublisher);
}
@Test(expected = IllegalArgumentException.class)
@Test
public void constructorNullEventPublisher() {
new WebSocketConnectHandlerDecoratorFactory(null);
assertThatThrownBy(() -> new WebSocketConnectHandlerDecoratorFactory(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("eventPublisher cannot be null");
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -43,6 +43,7 @@ import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
@@ -79,9 +80,11 @@ public class SessionRepositoryMessageInterceptorTests {
given(this.sessionRepository.findById(sessionId)).willReturn(this.session);
}
@Test(expected = IllegalArgumentException.class)
@Test
public void preSendconstructorNullRepository() {
new SessionRepositoryMessageInterceptor<>(null);
assertThatThrownBy(() -> new SessionRepositoryMessageInterceptor<>(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("sessionRepository cannot be null");
}
@Test
@@ -129,14 +132,19 @@ public class SessionRepositoryMessageInterceptorTests {
verifyZeroInteractions(this.sessionRepository);
}
@Test(expected = IllegalArgumentException.class)
@Test
public void setMatchingMessageTypesNull() {
this.interceptor.setMatchingMessageTypes(null);
assertThatThrownBy(() -> this.interceptor.setMatchingMessageTypes(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("matchingMessageTypes cannot be null or empty");
}
@Test(expected = IllegalArgumentException.class)
@Test
public void setMatchingMessageTypesEmpty() {
this.interceptor.setMatchingMessageTypes(Collections.emptySet());
assertThatThrownBy(
() -> this.interceptor.setMatchingMessageTypes(Collections.emptySet()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("matchingMessageTypes cannot be null or empty");
}
@Test

View File

@@ -16,7 +16,8 @@
package org.springframework.session.data.redis;
import org.junit.ClassRule;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.testcontainers.containers.GenericContainer;
import org.springframework.context.annotation.Bean;
@@ -30,19 +31,27 @@ import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactor
*/
public abstract class AbstractRedisITests {
private static final String DOCKER_IMAGE = "redis:4.0.7";
private static final String DOCKER_IMAGE = "redis:4.0.9";
@ClassRule
public static GenericContainer redisContainer = new GenericContainer(DOCKER_IMAGE)
private static GenericContainer container = new GenericContainer(DOCKER_IMAGE)
.withExposedPorts(6379);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
protected static class BaseConfig {
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(
redisContainer.getContainerIpAddress(),
redisContainer.getFirstMappedPort());
container.getContainerIpAddress(), container.getFirstMappedPort());
return new LettuceConnectionFactory(configuration);
}

View File

@@ -22,7 +22,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
@@ -149,8 +148,7 @@ public class ReactiveRedisOperationsSessionRepository implements
String sessionKey = getSessionKey(id);
return this.sessionRedisOperations.opsForHash().entries(sessionKey)
.collect(
Collectors.toMap(e -> e.getKey().toString(), Map.Entry::getValue))
.collectMap(e -> e.getKey().toString(), Map.Entry::getValue)
.filter(map -> !map.isEmpty()).map(new SessionMapper(id))
.filter(session -> !session.isExpired()).map(RedisSession::new)
.switchIfEmpty(Mono.defer(() -> deleteById(id).then(Mono.empty())));

View File

@@ -808,7 +808,12 @@ public class RedisOperationsSessionRepository implements
if (!isNew()) {
String originalSessionIdKey = getSessionKey(this.originalSessionId);
String sessionIdKey = getSessionKey(sessionId);
RedisOperationsSessionRepository.this.sessionRedisOperations.rename(originalSessionIdKey, sessionIdKey);
RedisOperationsSessionRepository.this.sessionRedisOperations.rename(
originalSessionIdKey, sessionIdKey);
String originalExpiredKey = getExpiredKey(this.originalSessionId);
String expiredKey = getExpiredKey(sessionId);
RedisOperationsSessionRepository.this.sessionRedisOperations.rename(
originalExpiredKey, expiredKey);
}
this.originalSessionId = sessionId;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -23,9 +23,7 @@ import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -34,13 +32,16 @@ import reactor.test.StepVerifier;
import org.springframework.data.redis.core.ReactiveHashOperations;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.session.MapSession;
import org.springframework.session.data.redis.ReactiveRedisOperationsSessionRepository.RedisSession;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
@@ -50,9 +51,6 @@ import static org.mockito.Mockito.verifyZeroInteractions;
*/
public class ReactiveRedisOperationsSessionRepositoryTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@SuppressWarnings("unchecked")
private ReactiveRedisOperations<String, Object> redisOperations = mock(
ReactiveRedisOperations.class);
@@ -67,18 +65,24 @@ public class ReactiveRedisOperationsSessionRepositoryTests {
private ReactiveRedisOperationsSessionRepository repository;
private MapSession cached;
@Before
public void setUp() throws Exception {
public void setUp() {
this.repository = new ReactiveRedisOperationsSessionRepository(
this.redisOperations);
this.cached = new MapSession();
this.cached.setId("session-id");
this.cached.setCreationTime(Instant.ofEpochMilli(1404360000000L));
this.cached.setLastAccessedTime(Instant.ofEpochMilli(1404360000000L));
}
@Test
public void constructorWithNullReactiveRedisOperations() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("sessionRedisOperations cannot be null");
new ReactiveRedisOperationsSessionRepository(null);
assertThatThrownBy(() -> new ReactiveRedisOperationsSessionRepository(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("sessionRedisOperations cannot be null");
}
@Test
@@ -91,18 +95,16 @@ public class ReactiveRedisOperationsSessionRepositoryTests {
@Test
public void nullRedisKeyNamespace() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("namespace cannot be null or empty");
this.repository.setRedisKeyNamespace(null);
assertThatThrownBy(() -> this.repository.setRedisKeyNamespace(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("namespace cannot be null or empty");
}
@Test
public void emptyRedisKeyNamespace() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("namespace cannot be null or empty");
this.repository.setRedisKeyNamespace("");
assertThatThrownBy(() -> this.repository.setRedisKeyNamespace(""))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("namespace cannot be null or empty");
}
@Test
@@ -123,148 +125,147 @@ public class ReactiveRedisOperationsSessionRepositoryTests {
@Test
public void nullRedisFlushMode() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("redisFlushMode cannot be null");
this.repository.setRedisFlushMode(null);
assertThatThrownBy(() -> this.repository.setRedisFlushMode(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("redisFlushMode cannot be null");
}
@Test
public void createSessionDefaultMaxInactiveInterval() {
Mono<ReactiveRedisOperationsSessionRepository.RedisSession> session = this.repository
.createSession();
StepVerifier.create(session).expectNextMatches(predicate -> {
assertThat(predicate.getMaxInactiveInterval()).isEqualTo(
Duration.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS));
return true;
});
StepVerifier.create(this.repository.createSession()).consumeNextWith(
session -> assertThat(session.getMaxInactiveInterval()).isEqualTo(Duration
.ofSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS)))
.verifyComplete();
}
@Test
public void createSessionCustomMaxInactiveInterval() {
this.repository.setDefaultMaxInactiveInterval(600);
Mono<ReactiveRedisOperationsSessionRepository.RedisSession> session = this.repository
.createSession();
StepVerifier.create(session).expectNextMatches(predicate -> {
assertThat(predicate.getMaxInactiveInterval())
.isEqualTo(Duration.ofSeconds(600));
return true;
});
StepVerifier.create(this.repository.createSession())
.consumeNextWith(session -> assertThat(session.getMaxInactiveInterval())
.isEqualTo(Duration.ofSeconds(600)))
.verifyComplete();
}
@Test
public void saveNewSession() {
given(this.redisOperations.opsForHash()).willReturn(this.hashOperations);
given(this.hashOperations.putAll(anyString(), this.delta.capture()))
.willReturn(Mono.just(true));
given(this.hashOperations.putAll(anyString(), any())).willReturn(Mono.just(true));
given(this.redisOperations.expire(anyString(), any()))
.willReturn(Mono.just(true));
ReactiveRedisOperationsSessionRepository.RedisSession session = this.repository.new RedisSession();
Mono<Void> result = this.repository.save(session);
StepVerifier
.create(this.repository.createSession().doOnNext(this.repository::save))
.consumeNextWith(session -> {
verify(this.redisOperations).opsForHash();
verify(this.hashOperations).putAll(anyString(), this.delta.capture());
verify(this.redisOperations).expire(anyString(), any());
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.hashOperations);
StepVerifier.create(result).expectNextMatches(predicate -> {
Map<String, Object> delta = this.delta.getAllValues().get(0);
assertThat(delta.size()).isEqualTo(3);
Object creationTime = delta
.get(ReactiveRedisOperationsSessionRepository.CREATION_TIME_KEY);
assertThat(creationTime).isEqualTo(session.getCreationTime().toEpochMilli());
assertThat(delta.get(
ReactiveRedisOperationsSessionRepository.MAX_INACTIVE_INTERVAL_KEY))
.isEqualTo((int) Duration.ofSeconds(
MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS)
.getSeconds());
assertThat(delta
.get(ReactiveRedisOperationsSessionRepository.LAST_ACCESSED_TIME_KEY))
.isEqualTo(session.getCreationTime().toEpochMilli());
return true;
});
Map<String, Object> delta = this.delta.getAllValues().get(0);
assertThat(delta.size()).isEqualTo(3);
assertThat(delta.get(
ReactiveRedisOperationsSessionRepository.CREATION_TIME_KEY))
.isEqualTo(session.getCreationTime().toEpochMilli());
assertThat(delta.get(
ReactiveRedisOperationsSessionRepository.MAX_INACTIVE_INTERVAL_KEY))
.isEqualTo((int) Duration.ofSeconds(
MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS)
.getSeconds());
assertThat(delta.get(
ReactiveRedisOperationsSessionRepository.LAST_ACCESSED_TIME_KEY))
.isEqualTo(
session.getLastAccessedTime().toEpochMilli());
}).verifyComplete();
}
@Test
public void saveSessionNothingChanged() {
ReactiveRedisOperationsSessionRepository.RedisSession session = this.repository.new RedisSession(
new MapSession());
given(this.redisOperations.expire(anyString(), any()))
.willReturn(Mono.just(true));
Mono<Void> result = this.repository.save(session);
RedisSession session = this.repository.new RedisSession(
new MapSession(this.cached));
StepVerifier.create(result).expectNextMatches(predicate -> {
verifyZeroInteractions(this.redisOperations);
return true;
});
StepVerifier.create(this.repository.save(session)).verifyComplete();
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.hashOperations);
}
@Test
public void saveLastAccessChanged() {
given(this.redisOperations.opsForHash()).willReturn(this.hashOperations);
given(this.hashOperations.putAll(anyString(), this.delta.capture()))
.willReturn(Mono.just(true));
given(this.hashOperations.putAll(anyString(), any())).willReturn(Mono.just(true));
given(this.redisOperations.expire(anyString(), any()))
.willReturn(Mono.just(true));
ReactiveRedisOperationsSessionRepository.RedisSession session = this.repository.new RedisSession(
new MapSession());
RedisSession session = this.repository.new RedisSession(this.cached);
session.setLastAccessedTime(Instant.ofEpochMilli(12345678L));
Mono<Void> result = this.repository.save(session);
Mono.just(session).subscribe(this.repository::save);
StepVerifier.create(result).expectNextMatches(predicate -> {
assertThat(this.delta.getAllValues().get(0))
.isEqualTo(map(RedisOperationsSessionRepository.LAST_ACCESSED_ATTR,
session.getLastAccessedTime().toEpochMilli()));
return true;
});
verify(this.redisOperations).opsForHash();
verify(this.hashOperations).putAll(anyString(), this.delta.capture());
verify(this.redisOperations).expire(anyString(), any());
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.hashOperations);
assertThat(this.delta.getAllValues().get(0))
.isEqualTo(map(RedisOperationsSessionRepository.LAST_ACCESSED_ATTR,
session.getLastAccessedTime().toEpochMilli()));
}
@Test
public void saveSetAttribute() {
given(this.redisOperations.opsForHash()).willReturn(this.hashOperations);
given(this.hashOperations.putAll(anyString(), this.delta.capture()))
.willReturn(Mono.just(true));
given(this.hashOperations.putAll(anyString(), any())).willReturn(Mono.just(true));
given(this.redisOperations.expire(anyString(), any()))
.willReturn(Mono.just(true));
String attrName = "attrName";
ReactiveRedisOperationsSessionRepository.RedisSession session = this.repository.new RedisSession(
new MapSession());
RedisSession session = this.repository.new RedisSession(this.cached);
session.setAttribute(attrName, "attrValue");
Mono<Void> result = this.repository.save(session);
Mono.just(session).subscribe(this.repository::save);
StepVerifier.create(result).expectNextMatches(predicate -> {
assertThat(this.delta.getAllValues().get(0)).isEqualTo(
map(RedisOperationsSessionRepository.getSessionAttrNameKey(attrName),
session.getAttribute(attrName)));
return true;
});
verify(this.redisOperations).opsForHash();
verify(this.hashOperations).putAll(anyString(), this.delta.capture());
verify(this.redisOperations).expire(anyString(), any());
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.hashOperations);
assertThat(this.delta.getAllValues().get(0)).isEqualTo(
map(RedisOperationsSessionRepository.getSessionAttrNameKey(attrName),
session.getAttribute(attrName)));
}
@Test
public void saveRemoveAttribute() {
given(this.redisOperations.opsForHash()).willReturn(this.hashOperations);
given(this.hashOperations.putAll(anyString(), this.delta.capture()))
.willReturn(Mono.just(true));
given(this.hashOperations.putAll(anyString(), any())).willReturn(Mono.just(true));
given(this.redisOperations.expire(anyString(), any()))
.willReturn(Mono.just(true));
String attrName = "attrName";
ReactiveRedisOperationsSessionRepository.RedisSession session = this.repository.new RedisSession(
new MapSession());
RedisSession session = this.repository.new RedisSession(new MapSession());
session.removeAttribute(attrName);
Mono<Void> result = this.repository.save(session);
Mono.just(session).subscribe(this.repository::save);
StepVerifier.create(result).expectNextMatches(predicate -> {
assertThat(this.delta.getAllValues().get(0)).isEqualTo(
map(RedisOperationsSessionRepository.getSessionAttrNameKey(attrName),
null));
return true;
});
verify(this.redisOperations).opsForHash();
verify(this.hashOperations).putAll(anyString(), this.delta.capture());
verify(this.redisOperations).expire(anyString(), any());
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.hashOperations);
assertThat(this.delta.getAllValues().get(0)).isEqualTo(map(
RedisOperationsSessionRepository.getSessionAttrNameKey(attrName), null));
}
@Test
public void redisSessionGetAttributes() {
String attrName = "attrName";
ReactiveRedisOperationsSessionRepository.RedisSession session = this.repository.new RedisSession();
RedisSession session = this.repository.new RedisSession(this.cached);
assertThat(session.getAttributeNames()).isEmpty();
session.setAttribute(attrName, "attrValue");
@@ -278,88 +279,94 @@ public class ReactiveRedisOperationsSessionRepositoryTests {
public void delete() {
given(this.redisOperations.delete(anyString())).willReturn(Mono.just(1L));
ReactiveRedisOperationsSessionRepository.RedisSession session = this.repository.new RedisSession(
new MapSession());
Mono<Void> result = this.repository.deleteById(session.getId());
StepVerifier.create(this.repository.deleteById("test")).verifyComplete();
StepVerifier.create(result).expectNextMatches(predicate -> {
assertThat(result).isEqualTo(1);
return true;
});
verify(this.redisOperations).delete(anyString());
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.hashOperations);
}
@Test
public void getSessionNotFound() {
given(this.redisOperations.opsForHash()).willReturn(this.hashOperations);
given(this.hashOperations.entries(anyString())).willReturn(Flux.empty());
given(this.redisOperations.delete(anyString())).willReturn(Mono.just(0L));
Mono<ReactiveRedisOperationsSessionRepository.RedisSession> session = this.repository
.findById("test");
StepVerifier.create(this.repository.findById("test")).verifyComplete();
StepVerifier.create(session).expectNextMatches(predicate -> {
assertThat(predicate).isEqualTo(Mono.empty());
return true;
});
verify(this.redisOperations).opsForHash();
verify(this.hashOperations).entries(anyString());
verify(this.redisOperations).delete(anyString());
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.hashOperations);
}
@Test
@SuppressWarnings("unchecked")
public void getSessionFound() {
given(this.redisOperations.opsForHash()).willReturn(this.hashOperations);
String attrName = "attrName";
MapSession expected = new MapSession();
String attribute1 = "attribute1";
String attribute2 = "attribute2";
MapSession expected = new MapSession("test");
expected.setLastAccessedTime(Instant.now().minusSeconds(60));
expected.setAttribute(attrName, "attrValue");
Map map = map(RedisOperationsSessionRepository.getSessionAttrNameKey(attrName),
expected.getAttribute(attrName),
RedisOperationsSessionRepository.CREATION_TIME_ATTR,
expected.setAttribute(attribute1, "test");
expected.setAttribute(attribute2, null);
Map map = map(
ReactiveRedisOperationsSessionRepository.ATTRIBUTE_PREFIX + attribute1,
expected.getAttribute(attribute1),
ReactiveRedisOperationsSessionRepository.ATTRIBUTE_PREFIX + attribute2,
expected.getAttribute(attribute2),
ReactiveRedisOperationsSessionRepository.CREATION_TIME_KEY,
expected.getCreationTime().toEpochMilli(),
RedisOperationsSessionRepository.MAX_INACTIVE_ATTR,
ReactiveRedisOperationsSessionRepository.MAX_INACTIVE_INTERVAL_KEY,
(int) expected.getMaxInactiveInterval().getSeconds(),
RedisOperationsSessionRepository.LAST_ACCESSED_ATTR,
ReactiveRedisOperationsSessionRepository.LAST_ACCESSED_TIME_KEY,
expected.getLastAccessedTime().toEpochMilli());
given(this.hashOperations.entries(anyString()))
.willReturn(Flux.fromIterable(map.entrySet()));
Mono<ReactiveRedisOperationsSessionRepository.RedisSession> session = this.repository
.findById("test");
StepVerifier.create(this.repository.findById("test")).consumeNextWith(session -> {
verify(this.redisOperations).opsForHash();
verify(this.hashOperations).entries(anyString());
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.hashOperations);
StepVerifier.create(session).expectNextMatches(predicate -> {
assertThat(predicate.getId()).isEqualTo(expected.getId());
assertThat(predicate.getAttributeNames())
assertThat(session.getId()).isEqualTo(expected.getId());
assertThat(session.getAttributeNames())
.isEqualTo(expected.getAttributeNames());
assertThat(predicate.<String>getAttribute(attrName))
.isEqualTo(expected.getAttribute(attrName));
assertThat(predicate.getCreationTime()).isEqualTo(expected.getCreationTime());
assertThat(predicate.getMaxInactiveInterval())
assertThat(session.<String>getAttribute(attribute1))
.isEqualTo(expected.getAttribute(attribute1));
assertThat(session.<String>getAttribute(attribute2))
.isEqualTo(expected.getAttribute(attribute2));
assertThat(session.getCreationTime()).isEqualTo(expected.getCreationTime());
assertThat(session.getMaxInactiveInterval())
.isEqualTo(expected.getMaxInactiveInterval());
assertThat(predicate.getLastAccessedTime())
assertThat(session.getLastAccessedTime())
.isEqualTo(expected.getLastAccessedTime());
return true;
});
}).verifyComplete();
}
@Test
@SuppressWarnings("unchecked")
public void getSessionExpired() {
given(this.redisOperations.opsForHash()).willReturn(this.hashOperations);
Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 1,
RedisOperationsSessionRepository.LAST_ACCESSED_ATTR,
Map map = map(ReactiveRedisOperationsSessionRepository.CREATION_TIME_KEY, 0L,
ReactiveRedisOperationsSessionRepository.MAX_INACTIVE_INTERVAL_KEY, 1,
ReactiveRedisOperationsSessionRepository.LAST_ACCESSED_TIME_KEY,
Instant.now().minus(5, ChronoUnit.MINUTES).toEpochMilli());
given(this.hashOperations.entries(anyString()))
.willReturn(Flux.fromIterable(map.entrySet()));
given(this.redisOperations.delete(anyString())).willReturn(Mono.just(0L));
Mono<ReactiveRedisOperationsSessionRepository.RedisSession> session = this.repository
.findById("test");
StepVerifier.create(this.repository.findById("test")).verifyComplete();
StepVerifier.create(session).expectNextMatches(predicate -> {
assertThat(predicate).isNull();
return true;
});
verify(this.redisOperations).opsForHash();
verify(this.hashOperations).entries(anyString());
verify(this.redisOperations).delete(anyString());
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.hashOperations);
}
// TODO
private Map<String, Object> map(Object... objects) {
Map<String, Object> result = new HashMap<>();
if (objects == null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -58,9 +58,11 @@ import org.springframework.session.data.redis.RedisOperationsSessionRepository.R
import org.springframework.session.events.AbstractSessionEvent;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
@@ -110,21 +112,54 @@ public class RedisOperationsSessionRepositoryTests {
this.cached.setLastAccessedTime(Instant.ofEpochMilli(1404360000000L));
}
@Test(expected = IllegalArgumentException.class)
@Test
public void setApplicationEventPublisherNull() {
this.redisRepository.setApplicationEventPublisher(null);
assertThatThrownBy(() -> this.redisRepository.setApplicationEventPublisher(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("applicationEventPublisher cannot be null");
}
@Test
public void changeSessionId() {
public void changeSessionIdWhenNotSaved() {
given(this.redisOperations.boundHashOps(anyString()))
.willReturn(this.boundHashOperations);
given(this.redisOperations.boundSetOps(anyString()))
.willReturn(this.boundSetOperations);
given(this.redisOperations.boundValueOps(anyString()))
.willReturn(this.boundValueOperations);
RedisSession createSession = this.redisRepository.createSession();
String originalId = createSession.getId();
String changeSessionId = createSession.changeSessionId();
this.redisRepository.save(createSession);
verify(this.redisOperations, never()).rename(anyString(), anyString());
assertThat(originalId).isNotEqualTo(changeSessionId);
assertThat(createSession.getId()).isEqualTo(createSession.getId());
}
@Test
public void changeSessionIdWhenSaved() {
given(this.redisOperations.boundHashOps(anyString()))
.willReturn(this.boundHashOperations);
given(this.redisOperations.boundSetOps(anyString()))
.willReturn(this.boundSetOperations);
given(this.redisOperations.boundValueOps(anyString()))
.willReturn(this.boundValueOperations);
RedisSession session = this.redisRepository.new RedisSession(this.cached);
session.setLastAccessedTime(session.getLastAccessedTime());
String originalId = session.getId();
String changeSessionId = session.changeSessionId();
this.redisRepository.save(session);
verify(this.redisOperations, times(2)).rename(anyString(), anyString());
assertThat(originalId).isNotEqualTo(changeSessionId);
assertThat(session.getId()).isEqualTo(session.getId());
}
@Test
public void createSessionDefaultMaxInactiveInterval() throws Exception {
Session session = this.redisRepository.createSession();
@@ -369,14 +404,18 @@ public class RedisOperationsSessionRepositoryTests {
@Test
public void getSessionFound() {
String attrName = "attrName";
String attribute1 = "attribute1";
String attribute2 = "attribute2";
MapSession expected = new MapSession();
expected.setLastAccessedTime(Instant.now().minusSeconds(60));
expected.setAttribute(attrName, "attrValue");
expected.setAttribute(attribute1, "test");
expected.setAttribute(attribute2, null);
given(this.redisOperations.boundHashOps(getKey(expected.getId())))
.willReturn(this.boundHashOperations);
Map map = map(RedisOperationsSessionRepository.getSessionAttrNameKey(attrName),
expected.getAttribute(attrName),
Map map = map(RedisOperationsSessionRepository.getSessionAttrNameKey(attribute1),
expected.getAttribute(attribute1),
RedisOperationsSessionRepository.getSessionAttrNameKey(attribute2),
expected.getAttribute(attribute2),
RedisOperationsSessionRepository.CREATION_TIME_ATTR,
expected.getCreationTime().toEpochMilli(),
RedisOperationsSessionRepository.MAX_INACTIVE_ATTR,
@@ -388,8 +427,10 @@ public class RedisOperationsSessionRepositoryTests {
RedisSession session = this.redisRepository.findById(expected.getId());
assertThat(session.getId()).isEqualTo(expected.getId());
assertThat(session.getAttributeNames()).isEqualTo(expected.getAttributeNames());
assertThat(session.<String>getAttribute(attrName))
.isEqualTo(expected.getAttribute(attrName));
assertThat(session.<String>getAttribute(attribute1))
.isEqualTo(expected.getAttribute(attribute1));
assertThat(session.<String>getAttribute(attribute2))
.isEqualTo(expected.getAttribute(attribute2));
assertThat(session.getCreationTime()).isEqualTo(expected.getCreationTime());
assertThat(session.getMaxInactiveInterval())
.isEqualTo(expected.getMaxInactiveInterval());
@@ -517,6 +558,104 @@ public class RedisOperationsSessionRepositoryTests {
verify(this.defaultSerializer).deserialize(body);
}
@Test
public void onMessageDeletedSessionFound() throws Exception {
String deletedId = "deleted-id";
given(this.redisOperations.boundHashOps(getKey(deletedId)))
.willReturn(this.boundHashOperations);
Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 0,
RedisOperationsSessionRepository.LAST_ACCESSED_ATTR,
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
given(this.boundHashOperations.entries()).willReturn(map);
String channel = "__keyevent@0__:del";
String body = "spring:session:sessions:expires:" + deletedId;
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
this.redisRepository.setApplicationEventPublisher(this.publisher);
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
verify(this.redisOperations).boundHashOps(eq(getKey(deletedId)));
verify(this.boundHashOperations).entries();
verify(this.publisher).publishEvent(this.event.capture());
assertThat(this.event.getValue().getSessionId()).isEqualTo(deletedId);
verifyZeroInteractions(this.defaultSerializer);
verifyZeroInteractions(this.publisher);
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.boundHashOperations);
}
@Test
public void onMessageDeletedSessionNotFound() throws Exception {
String deletedId = "deleted-id";
given(this.redisOperations.boundHashOps(getKey(deletedId)))
.willReturn(this.boundHashOperations);
given(this.boundHashOperations.entries()).willReturn(map());
String channel = "__keyevent@0__:del";
String body = "spring:session:sessions:expires:" + deletedId;
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
this.redisRepository.setApplicationEventPublisher(this.publisher);
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
verify(this.redisOperations).boundHashOps(eq(getKey(deletedId)));
verify(this.boundHashOperations).entries();
verifyZeroInteractions(this.defaultSerializer);
verifyZeroInteractions(this.publisher);
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.boundHashOperations);
}
@Test
public void onMessageExpiredSessionFound() throws Exception {
String expiredId = "expired-id";
given(this.redisOperations.boundHashOps(getKey(expiredId)))
.willReturn(this.boundHashOperations);
Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 1,
RedisOperationsSessionRepository.LAST_ACCESSED_ATTR,
System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5));
given(this.boundHashOperations.entries()).willReturn(map);
String channel = "__keyevent@0__:expired";
String body = "spring:session:sessions:expires:" + expiredId;
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
this.redisRepository.setApplicationEventPublisher(this.publisher);
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
verify(this.redisOperations).boundHashOps(eq(getKey(expiredId)));
verify(this.boundHashOperations).entries();
verify(this.publisher).publishEvent(this.event.capture());
assertThat(this.event.getValue().getSessionId()).isEqualTo(expiredId);
verifyZeroInteractions(this.defaultSerializer);
verifyZeroInteractions(this.publisher);
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.boundHashOperations);
}
@Test
public void onMessageExpiredSessionNotFound() throws Exception {
String expiredId = "expired-id";
given(this.redisOperations.boundHashOps(getKey(expiredId)))
.willReturn(this.boundHashOperations);
given(this.boundHashOperations.entries()).willReturn(map());
String channel = "__keyevent@0__:expired";
String body = "spring:session:sessions:expires:" + expiredId;
DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body.getBytes("UTF-8"));
this.redisRepository.setApplicationEventPublisher(this.publisher);
this.redisRepository.onMessage(message, "".getBytes("UTF-8"));
verify(this.redisOperations).boundHashOps(eq(getKey(expiredId)));
verify(this.boundHashOperations).entries();
verifyZeroInteractions(this.defaultSerializer);
verifyZeroInteractions(this.publisher);
verifyZeroInteractions(this.redisOperations);
verifyZeroInteractions(this.boundHashOperations);
}
@Test
public void resolvePrincipalIndex() {
PrincipalNameResolver resolver = RedisOperationsSessionRepository.PRINCIPAL_NAME_RESOLVER;
@@ -688,9 +827,11 @@ public class RedisOperationsSessionRepositoryTests {
session.getLastAccessedTime().toEpochMilli()));
}
@Test(expected = IllegalArgumentException.class)
@Test
public void setRedisFlushModeNull() {
this.redisRepository.setRedisFlushMode(null);
assertThatThrownBy(() -> this.redisRepository.setRedisFlushMode(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("redisFlushMode cannot be null");
}
@Test
@@ -713,14 +854,18 @@ public class RedisOperationsSessionRepositoryTests {
.boundValueOps(namespace + ":sessions:expires:" + id);
}
@Test(expected = IllegalArgumentException.class)
@Test
public void setRedisKeyNamespaceNullNamespace() {
this.redisRepository.setRedisKeyNamespace(null);
assertThatThrownBy(() -> this.redisRepository.setRedisKeyNamespace(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("namespace cannot be null or empty");
}
@Test(expected = IllegalArgumentException.class)
@Test
public void setRedisKeyNamespaceEmptyNamespace() {
this.redisRepository.setRedisKeyNamespace(" ");
assertThatThrownBy(() -> this.redisRepository.setRedisKeyNamespace(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("namespace cannot be null or empty");
}
private String getKey(String id) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -20,9 +20,7 @@ import java.util.Properties;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -39,6 +37,7 @@ import org.springframework.session.data.redis.config.annotation.SpringSessionRed
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@@ -54,9 +53,6 @@ public class RedisHttpSessionConfigurationTests {
private static final String CLEANUP_CRON_EXPRESSION = "0 0 * * * *";
@Rule
public final ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context;
@Before
@@ -188,10 +184,10 @@ public class RedisHttpSessionConfigurationTests {
@Test
public void multipleConnectionFactoryRedisConfig() {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("expected single matching bean but found 2");
registerAndRefresh(RedisConfig.class, MultipleConnectionFactoryRedisConfig.class);
assertThatThrownBy(() -> registerAndRefresh(RedisConfig.class,
MultipleConnectionFactoryRedisConfig.class))
.isInstanceOf(BeanCreationException.class)
.hasMessageContaining("expected single matching bean but found 2");
}
private void registerAndRefresh(Class<?>... annotatedClasses) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -18,9 +18,7 @@ package org.springframework.session.data.redis.config.annotation.web.server;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -35,6 +33,7 @@ import org.springframework.session.data.redis.config.annotation.SpringSessionRed
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
/**
@@ -48,9 +47,6 @@ public class RedisWebSessionConfigurationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 600;
@Rule
public final ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context;
@Before
@@ -179,10 +175,10 @@ public class RedisWebSessionConfigurationTests {
@Test
public void multipleConnectionFactoryRedisConfig() {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("expected single matching bean but found 2");
registerAndRefresh(RedisConfig.class, MultipleConnectionFactoryRedisConfig.class);
assertThatThrownBy(() -> registerAndRefresh(RedisConfig.class,
MultipleConnectionFactoryRedisConfig.class))
.isInstanceOf(BeanCreationException.class)
.hasMessageContaining("expected single matching bean but found 2");
}
private void registerAndRefresh(Class<?>... annotatedClasses) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -29,12 +29,7 @@ import com.hazelcast.map.EntryProcessor;
import com.hazelcast.map.listener.MapListener;
import com.hazelcast.query.impl.predicates.EqualPredicate;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
@@ -44,12 +39,14 @@ import org.springframework.session.MapSession;
import org.springframework.session.hazelcast.HazelcastSessionRepository.HazelcastSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -60,19 +57,14 @@ import static org.mockito.Mockito.verifyZeroInteractions;
* @author Vedran Pavic
* @author Aleksandar Stojsavljevic
*/
@RunWith(MockitoJUnitRunner.class)
public class HazelcastSessionRepositoryTests {
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
@Rule
public ExpectedException thrown = ExpectedException.none();
private HazelcastInstance hazelcastInstance = mock(HazelcastInstance.class);
@Mock
private HazelcastInstance hazelcastInstance;
@Mock
private IMap<String, MapSession> sessions;
@SuppressWarnings("unchecked")
private IMap<String, MapSession> sessions = mock(IMap.class);
private HazelcastSessionRepository repository;
@@ -86,14 +78,13 @@ public class HazelcastSessionRepositoryTests {
@Test
public void constructorNullHazelcastInstance() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("HazelcastInstance must not be null");
new HazelcastSessionRepository(null);
assertThatThrownBy(() -> new HazelcastSessionRepository(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("HazelcastInstance must not be null");
}
@Test
public void createSessionDefaultMaxInactiveInterval() throws Exception {
public void createSessionDefaultMaxInactiveInterval() {
verify(this.sessions, times(1)).addEntryListener(any(MapListener.class),
anyBoolean());
@@ -105,7 +96,7 @@ public class HazelcastSessionRepositoryTests {
}
@Test
public void createSessionCustomMaxInactiveInterval() throws Exception {
public void createSessionCustomMaxInactiveInterval() {
verify(this.sessions, times(1)).addEntryListener(any(MapListener.class),
anyBoolean());

View File

@@ -19,9 +19,7 @@ package org.springframework.session.hazelcast.config.annotation.web.http;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -34,6 +32,7 @@ import org.springframework.session.hazelcast.config.annotation.SpringSessionHaze
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
@@ -52,9 +51,6 @@ public class HazelcastHttpSessionConfigurationTests {
private static final HazelcastFlushMode HAZELCAST_FLUSH_MODE = HazelcastFlushMode.IMMEDIATE;
@Rule
public final ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@After
@@ -66,10 +62,10 @@ public class HazelcastHttpSessionConfigurationTests {
@Test
public void noHazelcastInstanceConfiguration() {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("HazelcastInstance");
registerAndRefresh(NoHazelcastInstanceConfiguration.class);
assertThatThrownBy(
() -> registerAndRefresh(NoHazelcastInstanceConfiguration.class))
.isInstanceOf(BeanCreationException.class)
.hasMessageContaining("HazelcastInstance");
}
@Test
@@ -210,10 +206,10 @@ public class HazelcastHttpSessionConfigurationTests {
@Test
public void multipleHazelcastInstanceConfiguration() {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("expected single matching bean but found 2");
registerAndRefresh(MultipleHazelcastInstanceConfiguration.class);
assertThatThrownBy(
() -> registerAndRefresh(MultipleHazelcastInstanceConfiguration.class))
.isInstanceOf(BeanCreationException.class)
.hasMessageContaining("expected single matching bean but found 2");
}
private void registerAndRefresh(Class<?>... annotatedClasses) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -37,7 +37,6 @@ import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.MapSession;
import org.springframework.session.Session;
import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
@@ -82,8 +81,11 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
.createSession();
this.repository.save(toSave);
JdbcOperationsSessionRepository.JdbcSession session = this.repository.findById(toSave.getId());
assertThat(this.repository.findById(toSave.getId())).isNotNull();
assertThat(session).isNotNull();
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
}
@Test
@@ -104,9 +106,11 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
this.repository.save(toSave);
Session session = this.repository.findById(toSave.getId());
JdbcOperationsSessionRepository.JdbcSession session = this.repository.findById(toSave.getId());
assertThat(session.getId()).isEqualTo(toSave.getId());
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames());
assertThat(session.<String>getAttribute(expectedAttributeName))
.isEqualTo(toSave.getAttribute(expectedAttributeName));
@@ -139,7 +143,9 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
this.repository.save(toSave);
toSave = this.repository.findById(toSave.getId());
Session session = this.repository.findById(toSave.getId());
JdbcOperationsSessionRepository.JdbcSession session = this.repository.findById(toSave.getId());
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
assertThat(session.getAttributeNames().size()).isEqualTo(2);
assertThat(session.<String>getAttribute("a")).isEqualTo("b");
assertThat(session.<String>getAttribute("1")).isEqualTo("2");
@@ -160,9 +166,11 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
toSave.setLastAccessedTime(lastAccessedTime);
this.repository.save(toSave);
Session session = this.repository.findById(toSave.getId());
JdbcOperationsSessionRepository.JdbcSession session = this.repository.findById(toSave.getId());
assertThat(session).isNotNull();
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
assertThat(session.isExpired()).isFalse();
assertThat(session.getLastAccessedTime()).isEqualTo(lastAccessedTime);
}
@@ -229,6 +237,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
findByPrincipalName.values().forEach(session -> {
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
});
}
@Test
@@ -251,6 +263,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
findByPrincipalName.values().forEach(session -> {
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
});
}
@Test
@@ -293,6 +309,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
findByPrincipalName.values().forEach(session -> {
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
});
}
@Test
@@ -340,6 +360,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
findByPrincipalName.values().forEach(session -> {
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
});
}
@Test
@@ -399,6 +423,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
findByPrincipalName.values().forEach(session -> {
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
});
}
@Test
@@ -420,6 +448,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
findByPrincipalName.values().forEach(session -> {
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
});
}
@Test
@@ -459,6 +491,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
findByPrincipalName.values().forEach(session -> {
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
});
}
@Test
@@ -503,6 +539,10 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
findByPrincipalName.values().forEach(session -> {
assertThat(session.isChanged()).isFalse();
assertThat(session.getDelta()).isEmpty();
});
}
@Test
@@ -585,6 +625,8 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
JdbcOperationsSessionRepository.JdbcSession findByChangeSessionId = this.repository.findById(changeSessionId);
assertThat(findByChangeSessionId.isChanged()).isFalse();
assertThat(findByChangeSessionId.getDelta()).isEmpty();
assertThat(findByChangeSessionId.<String>getAttribute(attrName)).isEqualTo(attrValue);
}
@@ -627,6 +669,8 @@ public abstract class AbstractJdbcOperationsSessionRepositoryITests {
JdbcOperationsSessionRepository.JdbcSession findByChangeSessionId = this.repository.findById(changeSessionId);
assertThat(findByChangeSessionId.isChanged()).isFalse();
assertThat(findByChangeSessionId.getDelta()).isEmpty();
assertThat(findByChangeSessionId.<String>getAttribute(attrName)).isEqualTo(attrValue);
}

View File

@@ -20,7 +20,8 @@ import java.sql.SQLException;
import javax.sql.DataSource;
import org.junit.ClassRule;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.mariadb.jdbc.MariaDbDataSource;
import org.testcontainers.containers.MariaDBContainer;
@@ -43,23 +44,29 @@ import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class MariaDB10JdbcOperationsSessionRepositoryITests
public class MariaDb10JdbcOperationsSessionRepositoryITests
extends AbstractJdbcOperationsSessionRepositoryITests {
private static final String DOCKER_IMAGE = "mariadb:10.2.12";
private static MariaDBContainer container = new MariaDb10Container();
@ClassRule
public static MariaDBContainer mariaDBContainer = new MariaDBContainer(DOCKER_IMAGE);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Configuration
static class Config extends BaseConfig {
@Bean
public DataSource dataSource() throws SQLException {
MariaDbDataSource dataSource = new MariaDbDataSource(
mariaDBContainer.getJdbcUrl());
dataSource.setUserName(mariaDBContainer.getUsername());
dataSource.setPassword(mariaDBContainer.getPassword());
MariaDbDataSource dataSource = new MariaDbDataSource(container.getJdbcUrl());
dataSource.setUserName(container.getUsername());
dataSource.setPassword(container.getPassword());
return dataSource;
}
@@ -76,4 +83,19 @@ public class MariaDB10JdbcOperationsSessionRepositoryITests
}
private static class MariaDb10Container extends MariaDBContainer<MariaDb10Container> {
MariaDb10Container() {
super("mariadb:10.2.14");
}
@Override
protected void configure() {
super.configure();
setCommand("mysqld", "--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci");
}
}
}

View File

@@ -20,7 +20,8 @@ import java.sql.SQLException;
import javax.sql.DataSource;
import org.junit.ClassRule;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.mariadb.jdbc.MariaDbDataSource;
import org.testcontainers.containers.MariaDBContainer;
@@ -43,23 +44,29 @@ import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class MariaDB5JdbcOperationsSessionRepositoryITests
public class MariaDb5JdbcOperationsSessionRepositoryITests
extends AbstractJdbcOperationsSessionRepositoryITests {
private static final String DOCKER_IMAGE = "mariadb:5.5.59";
private static MariaDBContainer container = new MariaDb5Container();
@ClassRule
public static MariaDBContainer mariaDBContainer = new MariaDBContainer(DOCKER_IMAGE);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Configuration
static class Config extends BaseConfig {
@Bean
public DataSource dataSource() throws SQLException {
MariaDbDataSource dataSource = new MariaDbDataSource(
mariaDBContainer.getJdbcUrl());
dataSource.setUserName(mariaDBContainer.getUsername());
dataSource.setPassword(mariaDBContainer.getPassword());
MariaDbDataSource dataSource = new MariaDbDataSource(container.getJdbcUrl());
dataSource.setUserName(container.getUsername());
dataSource.setPassword(container.getPassword());
return dataSource;
}
@@ -76,4 +83,20 @@ public class MariaDB5JdbcOperationsSessionRepositoryITests
}
private static class MariaDb5Container extends MariaDBContainer<MariaDb5Container> {
MariaDb5Container() {
super("mariadb:5.5.60");
}
@Override
protected void configure() {
super.configure();
setCommand("mysqld", "--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci", "--innodb_large_prefix",
"--innodb_file_format=barracuda", "--innodb-file-per-table");
}
}
}

View File

@@ -18,8 +18,9 @@ package org.springframework.session.jdbc;
import javax.sql.DataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import org.junit.ClassRule;
import com.mysql.cj.jdbc.MysqlDataSource;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.testcontainers.containers.MySQLContainer;
@@ -40,13 +41,20 @@ import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class MySQL5JdbcOperationsSessionRepositoryITests
public class MySql5JdbcOperationsSessionRepositoryITests
extends AbstractJdbcOperationsSessionRepositoryITests {
private static final String DOCKER_IMAGE = "mysql:5.7.21";
private static MySQLContainer container = new MySql5Container();
@ClassRule
public static MySQLContainer mySQLContainer = new MySQLContainer(DOCKER_IMAGE);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Configuration
static class Config extends BaseConfig {
@@ -54,9 +62,9 @@ public class MySQL5JdbcOperationsSessionRepositoryITests
@Bean
public DataSource dataSource() {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setUrl(mySQLContainer.getJdbcUrl());
dataSource.setUser(mySQLContainer.getUsername());
dataSource.setPassword(mySQLContainer.getPassword());
dataSource.setUrl(container.getJdbcUrl());
dataSource.setUser(container.getUsername());
dataSource.setPassword(container.getPassword());
return dataSource;
}
@@ -73,4 +81,19 @@ public class MySQL5JdbcOperationsSessionRepositoryITests
}
private static class MySql5Container extends MySQLContainer<MySql5Container> {
MySql5Container() {
super("mysql:5.7.22");
}
@Override
protected void configure() {
super.configure();
setCommand("mysqld", "--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci");
}
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2014-2018 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
*
* http://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.session.jdbc;
import javax.sql.DataSource;
import com.mysql.cj.jdbc.MysqlDataSource;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.testcontainers.containers.MySQLContainer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
/**
* Integration tests for {@link JdbcOperationsSessionRepository} using MySQL 8.x database.
*
* @author Vedran Pavic
*/
@Ignore
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class MySql8JdbcOperationsSessionRepositoryITests
extends AbstractJdbcOperationsSessionRepositoryITests {
private static MySQLContainer container = new MySql8Container();
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Configuration
static class Config extends BaseConfig {
@Bean
public DataSource dataSource() {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setUrl(container.getJdbcUrl());
dataSource.setUser(container.getUsername());
dataSource.setPassword(container.getPassword());
return dataSource;
}
@Bean
public DataSourceInitializer initializer(DataSource dataSource,
ResourceLoader resourceLoader) {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
initializer.setDatabasePopulator(
new ResourceDatabasePopulator(resourceLoader.getResource(
"classpath:org/springframework/session/jdbc/schema-mysql.sql")));
return initializer;
}
}
private static class MySql8Container extends MySQLContainer<MySql8Container> {
MySql8Container() {
super("mysql:8.0.11");
}
@Override
protected void configure() {
super.configure();
setCommand("mysqld", "--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci");
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -18,7 +18,8 @@ package org.springframework.session.jdbc;
import javax.sql.DataSource;
import org.junit.ClassRule;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.postgresql.ds.PGSimpleDataSource;
import org.testcontainers.containers.PostgreSQLContainer;
@@ -41,14 +42,20 @@ import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class PostgreSQL10JdbcOperationsSessionRepositoryITests
public class PostgreSql10JdbcOperationsSessionRepositoryITests
extends AbstractJdbcOperationsSessionRepositoryITests {
private static final String DOCKER_IMAGE = "postgres:10.1";
private static PostgreSQLContainer container = new PostgreSql10Container();
@ClassRule
public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(
DOCKER_IMAGE);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Configuration
static class Config extends BaseConfig {
@@ -56,9 +63,9 @@ public class PostgreSQL10JdbcOperationsSessionRepositoryITests
@Bean
public DataSource dataSource() {
PGSimpleDataSource dataSource = new PGSimpleDataSource();
dataSource.setUrl(postgreSQLContainer.getJdbcUrl());
dataSource.setUser(postgreSQLContainer.getUsername());
dataSource.setPassword(postgreSQLContainer.getPassword());
dataSource.setUrl(container.getJdbcUrl());
dataSource.setUser(container.getUsername());
dataSource.setPassword(container.getPassword());
return dataSource;
}
@@ -75,4 +82,13 @@ public class PostgreSQL10JdbcOperationsSessionRepositoryITests
}
private static class PostgreSql10Container
extends PostgreSQLContainer<PostgreSql10Container> {
PostgreSql10Container() {
super("postgres:10.3");
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -18,7 +18,8 @@ package org.springframework.session.jdbc;
import javax.sql.DataSource;
import org.junit.ClassRule;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.postgresql.ds.PGSimpleDataSource;
import org.testcontainers.containers.PostgreSQLContainer;
@@ -41,14 +42,20 @@ import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class PostgreSQL9JdbcOperationsSessionRepositoryITests
public class PostgreSql9JdbcOperationsSessionRepositoryITests
extends AbstractJdbcOperationsSessionRepositoryITests {
private static final String DOCKER_IMAGE = "postgres:9.6.6";
private static PostgreSQLContainer container = new PostgreSql9Container();
@ClassRule
public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(
DOCKER_IMAGE);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Configuration
static class Config extends BaseConfig {
@@ -56,9 +63,9 @@ public class PostgreSQL9JdbcOperationsSessionRepositoryITests
@Bean
public DataSource dataSource() {
PGSimpleDataSource dataSource = new PGSimpleDataSource();
dataSource.setUrl(postgreSQLContainer.getJdbcUrl());
dataSource.setUser(postgreSQLContainer.getUsername());
dataSource.setPassword(postgreSQLContainer.getPassword());
dataSource.setUrl(container.getJdbcUrl());
dataSource.setUser(container.getUsername());
dataSource.setPassword(container.getPassword());
return dataSource;
}
@@ -75,4 +82,13 @@ public class PostgreSQL9JdbcOperationsSessionRepositoryITests
}
private static class PostgreSql9Container
extends PostgreSQLContainer<PostgreSql9Container> {
PostgreSql9Container() {
super("postgres:9.6.8");
}
}
}

View File

@@ -19,7 +19,8 @@ package org.springframework.session.jdbc;
import javax.sql.DataSource;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
import org.junit.ClassRule;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.testcontainers.containers.MSSQLServerContainer;
@@ -43,13 +44,20 @@ import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class SQLServerJdbcOperationsSessionRepositoryITests
public class SqlServerJdbcOperationsSessionRepositoryITests
extends AbstractJdbcOperationsSessionRepositoryITests {
private static final String DOCKER_IMAGE = "microsoft/mssql-server-linux:2017-CU3";
private static MSSQLServerContainer container = new SqlServer2007Container();
@ClassRule
public static MSSQLServerContainer container = new MSSQLServerContainer(DOCKER_IMAGE);
@BeforeClass
public static void setUpClass() {
container.start();
}
@AfterClass
public static void tearDownClass() {
container.stop();
}
@Configuration
static class Config extends BaseConfig {
@@ -76,4 +84,13 @@ public class SQLServerJdbcOperationsSessionRepositoryITests
}
private static class SqlServer2007Container
extends MSSQLServerContainer<SqlServer2007Container> {
SqlServer2007Container() {
super("microsoft/mssql-server-linux:2017-CU6");
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -28,6 +28,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -382,24 +383,7 @@ public class JdbcOperationsSessionRepository implements
});
if (!session.getAttributeNames().isEmpty()) {
final List<String> attributeNames = new ArrayList<>(session.getAttributeNames());
JdbcOperationsSessionRepository.this.jdbcOperations.batchUpdate(
JdbcOperationsSessionRepository.this.createSessionAttributeQuery,
new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
String attributeName = attributeNames.get(i);
ps.setString(1, session.primaryKey);
ps.setString(2, attributeName);
serialize(ps, 3, session.getAttribute(attributeName));
}
@Override
public int getBatchSize() {
return attributeNames.size();
}
});
insertSessionAttributes(session, attributeNames);
}
}
@@ -422,37 +406,21 @@ public class JdbcOperationsSessionRepository implements
ps.setString(6, session.primaryKey);
});
}
Map<String, Object> delta = session.getDelta();
if (!delta.isEmpty()) {
for (final Map.Entry<String, Object> entry : delta.entrySet()) {
if (entry.getValue() == null) {
JdbcOperationsSessionRepository.this.jdbcOperations.update(
JdbcOperationsSessionRepository.this.deleteSessionAttributeQuery,
ps -> {
ps.setString(1, session.primaryKey);
ps.setString(2, entry.getKey());
});
}
else {
int updatedCount = JdbcOperationsSessionRepository.this.jdbcOperations.update(
JdbcOperationsSessionRepository.this.updateSessionAttributeQuery,
ps -> {
serialize(ps, 1, entry.getValue());
ps.setString(2, session.primaryKey);
ps.setString(3, entry.getKey());
});
if (updatedCount == 0) {
JdbcOperationsSessionRepository.this.jdbcOperations.update(
JdbcOperationsSessionRepository.this.createSessionAttributeQuery,
ps -> {
ps.setString(1, session.primaryKey);
ps.setString(2, entry.getKey());
serialize(ps, 3, entry.getValue());
});
}
}
}
}
List<String> addedAttributeNames = session.delta.entrySet().stream()
.filter(entry -> entry.getValue() == DeltaValue.ADDED)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
insertSessionAttributes(session, addedAttributeNames);
List<String> updatedAttributeNames = session.delta.entrySet().stream()
.filter(entry -> entry.getValue() == DeltaValue.UPDATED)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
updateSessionAttributes(session, updatedAttributeNames);
List<String> removedAttributeNames = session.delta.entrySet().stream()
.filter(entry -> entry.getValue() == DeltaValue.REMOVED)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
deleteSessionAttributes(session, removedAttributeNames);
}
});
@@ -521,6 +489,100 @@ public class JdbcOperationsSessionRepository implements
return sessionMap;
}
private void insertSessionAttributes(JdbcSession session, List<String> attributeNames) {
if (attributeNames == null || attributeNames.isEmpty()) {
return;
}
if (attributeNames.size() > 1) {
this.jdbcOperations.batchUpdate(this.createSessionAttributeQuery, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
String attributeName = attributeNames.get(i);
ps.setString(1, session.primaryKey);
ps.setString(2, attributeName);
serialize(ps, 3, session.getAttribute(attributeName));
}
@Override
public int getBatchSize() {
return attributeNames.size();
}
});
}
else {
this.jdbcOperations.update(this.createSessionAttributeQuery, ps -> {
String attributeName = attributeNames.get(0);
ps.setString(1, session.primaryKey);
ps.setString(2, attributeName);
serialize(ps, 3, session.getAttribute(attributeName));
});
}
}
private void updateSessionAttributes(JdbcSession session, List<String> attributeNames) {
if (attributeNames == null || attributeNames.isEmpty()) {
return;
}
if (attributeNames.size() > 1) {
this.jdbcOperations.batchUpdate(this.updateSessionAttributeQuery, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
String attributeName = attributeNames.get(i);
serialize(ps, 1, session.getAttribute(attributeName));
ps.setString(2, session.primaryKey);
ps.setString(3, attributeName);
}
@Override
public int getBatchSize() {
return attributeNames.size();
}
});
}
else {
this.jdbcOperations.update(this.updateSessionAttributeQuery, ps -> {
String attributeName = attributeNames.get(0);
serialize(ps, 1, session.getAttribute(attributeName));
ps.setString(2, session.primaryKey);
ps.setString(3, attributeName);
});
}
}
private void deleteSessionAttributes(JdbcSession session, List<String> attributeNames) {
if (attributeNames == null || attributeNames.isEmpty()) {
return;
}
if (attributeNames.size() > 1) {
this.jdbcOperations.batchUpdate(this.deleteSessionAttributeQuery, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
String attributeName = attributeNames.get(i);
ps.setString(1, session.primaryKey);
ps.setString(2, attributeName);
}
@Override
public int getBatchSize() {
return attributeNames.size();
}
});
}
else {
this.jdbcOperations.update(this.deleteSessionAttributeQuery, ps -> {
String attributeName = attributeNames.get(0);
ps.setString(1, session.primaryKey);
ps.setString(2, attributeName);
});
}
}
public void cleanUpExpiredSessions() {
Integer deletedCount = this.transactionOperations.execute(transactionStatus ->
JdbcOperationsSessionRepository.this.jdbcOperations.update(
@@ -585,6 +647,12 @@ public class JdbcOperationsSessionRepository implements
TypeDescriptor.valueOf(Object.class));
}
private enum DeltaValue {
ADDED, UPDATED, REMOVED
}
/**
* The {@link Session} to use for {@link JdbcOperationsSessionRepository}.
*
@@ -600,7 +668,7 @@ public class JdbcOperationsSessionRepository implements
private boolean changed;
private Map<String, Object> delta = new HashMap<>();
private Map<String, DeltaValue> delta = new HashMap<>();
JdbcSession() {
this.delegate = new MapSession();
@@ -623,7 +691,7 @@ public class JdbcOperationsSessionRepository implements
return this.changed;
}
Map<String, Object> getDelta() {
Map<String, DeltaValue> getDelta() {
return this.delta;
}
@@ -664,8 +732,16 @@ public class JdbcOperationsSessionRepository implements
@Override
public void setAttribute(String attributeName, Object attributeValue) {
if (attributeValue == null) {
this.delta.put(attributeName, DeltaValue.REMOVED);
}
else if (this.delegate.getAttribute(attributeName) != null) {
this.delta.put(attributeName, DeltaValue.UPDATED);
}
else {
this.delta.put(attributeName, DeltaValue.ADDED);
}
this.delegate.setAttribute(attributeName, attributeValue);
this.delta.put(attributeName, attributeValue);
if (PRINCIPAL_NAME_INDEX_NAME.equals(attributeName) ||
SPRING_SECURITY_CONTEXT.equals(attributeName)) {
this.changed = true;
@@ -674,8 +750,7 @@ public class JdbcOperationsSessionRepository implements
@Override
public void removeAttribute(String attributeName) {
this.delegate.removeAttribute(attributeName);
this.delta.put(attributeName, null);
setAttribute(attributeName, null);
}
@Override
@@ -758,7 +833,7 @@ public class JdbcOperationsSessionRepository implements
}
String attributeName = rs.getString("ATTRIBUTE_NAME");
if (attributeName != null) {
session.setAttribute(attributeName, deserialize(rs, "ATTRIBUTE_BYTES"));
session.delegate.setAttribute(attributeName, deserialize(rs, "ATTRIBUTE_BYTES"));
}
sessions.add(session);
}

View File

@@ -20,5 +20,3 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES (
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);

View File

@@ -20,5 +20,3 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES (
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);

View File

@@ -20,5 +20,3 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES (
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);

View File

@@ -20,5 +20,3 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES (
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);

View File

@@ -7,7 +7,7 @@ CREATE TABLE SPRING_SESSION (
EXPIRY_TIME BIGINT NOT NULL,
PRINCIPAL_NAME VARCHAR(100),
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
) ENGINE=InnoDB;
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
@@ -19,6 +19,4 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES (
ATTRIBUTE_BYTES BLOB NOT NULL,
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
) ENGINE=InnoDB;
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

View File

@@ -20,5 +20,3 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES (
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);

View File

@@ -20,5 +20,3 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES (
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);

View File

@@ -20,5 +20,3 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES (
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);

View File

@@ -20,5 +20,3 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES (
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);

View File

@@ -20,5 +20,3 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES (
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
) LOCK DATAROWS;
CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -24,13 +24,8 @@ import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcOperations;
@@ -46,17 +41,16 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.AdditionalMatchers.and;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
@@ -65,222 +59,194 @@ import static org.mockito.Mockito.verifyZeroInteractions;
* @author Vedran Pavic
* @since 1.2.0
*/
@RunWith(MockitoJUnitRunner.class)
public class JdbcOperationsSessionRepositoryTests {
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
@Rule
public ExpectedException thrown = ExpectedException.none();
private JdbcOperations jdbcOperations = mock(JdbcOperations.class);
@Mock
private JdbcOperations jdbcOperations;
@Mock
private PlatformTransactionManager transactionManager;
private PlatformTransactionManager transactionManager = mock(PlatformTransactionManager.class);
private JdbcOperationsSessionRepository repository;
@Before
public void setUp() {
this.repository = new JdbcOperationsSessionRepository(
this.jdbcOperations, this.transactionManager);
this.repository = new JdbcOperationsSessionRepository(this.jdbcOperations, this.transactionManager);
}
@Test
public void constructorNullJdbcOperations() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("JdbcOperations must not be null");
new JdbcOperationsSessionRepository((JdbcOperations) null, this.transactionManager);
assertThatThrownBy(
() -> new JdbcOperationsSessionRepository(null, this.transactionManager))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("JdbcOperations must not be null");
}
@Test
public void constructorNullTransactionManager() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Property 'transactionManager' is required");
new JdbcOperationsSessionRepository(this.jdbcOperations, null);
assertThatThrownBy(
() -> new JdbcOperationsSessionRepository(this.jdbcOperations, null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Property 'transactionManager' is required");
}
@Test
public void setTableNameNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Table name must not be empty");
this.repository.setTableName(null);
assertThatThrownBy(() -> this.repository.setTableName(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Table name must not be empty");
}
@Test
public void setTableNameEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Table name must not be empty");
this.repository.setTableName(" ");
assertThatThrownBy(() -> this.repository.setTableName(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Table name must not be empty");
}
@Test
public void setCreateSessionQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setCreateSessionQuery(null);
assertThatThrownBy(() -> this.repository.setCreateSessionQuery(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setCreateSessionQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setCreateSessionQuery(" ");
assertThatThrownBy(() -> this.repository.setCreateSessionQuery(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setCreateSessionAttributeQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setCreateSessionAttributeQuery(null);
assertThatThrownBy(() -> this.repository.setCreateSessionAttributeQuery(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setCreateSessionAttributeQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setCreateSessionAttributeQuery(" ");
assertThatThrownBy(() -> this.repository.setCreateSessionAttributeQuery(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setGetSessionQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setGetSessionQuery(null);
assertThatThrownBy(() -> this.repository.setGetSessionQuery(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setGetSessionQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setGetSessionQuery(" ");
assertThatThrownBy(() -> this.repository.setGetSessionQuery(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setUpdateSessionQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setUpdateSessionQuery(null);
assertThatThrownBy(() -> this.repository.setUpdateSessionQuery(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setUpdateSessionQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setUpdateSessionQuery(" ");
assertThatThrownBy(() -> this.repository.setUpdateSessionQuery(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setUpdateSessionAttributeQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setUpdateSessionAttributeQuery(null);
assertThatThrownBy(() -> this.repository.setUpdateSessionAttributeQuery(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setUpdateSessionAttributeQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setUpdateSessionAttributeQuery(" ");
assertThatThrownBy(() -> this.repository.setUpdateSessionAttributeQuery(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setDeleteSessionAttributeQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionAttributeQuery(null);
assertThatThrownBy(() -> this.repository.setDeleteSessionAttributeQuery(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setDeleteSessionAttributeQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionAttributeQuery(" ");
assertThatThrownBy(() -> this.repository.setDeleteSessionAttributeQuery(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setDeleteSessionQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionQuery(null);
assertThatThrownBy(() -> this.repository.setDeleteSessionQuery(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setDeleteSessionQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionQuery(" ");
assertThatThrownBy(() -> this.repository.setDeleteSessionQuery(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setListSessionsByPrincipalNameQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setListSessionsByPrincipalNameQuery(null);
assertThatThrownBy(
() -> this.repository.setListSessionsByPrincipalNameQuery(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setListSessionsByPrincipalNameQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setListSessionsByPrincipalNameQuery(" ");
assertThatThrownBy(() -> this.repository.setListSessionsByPrincipalNameQuery(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setDeleteSessionsByLastAccessTimeQueryNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionsByExpiryTimeQuery(null);
assertThatThrownBy(() -> this.repository.setDeleteSessionsByExpiryTimeQuery(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setDeleteSessionsByLastAccessTimeQueryEmpty() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Query must not be empty");
this.repository.setDeleteSessionsByExpiryTimeQuery(" ");
assertThatThrownBy(() -> this.repository.setDeleteSessionsByExpiryTimeQuery(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Query must not be empty");
}
@Test
public void setLobHandlerNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("LobHandler must not be null");
this.repository.setLobHandler(null);
assertThatThrownBy(() -> this.repository.setLobHandler(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("LobHandler must not be null");
}
@Test
public void setConversionServiceNull() {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("conversionService must not be null");
this.repository.setConversionService(null);
assertThatThrownBy(() -> this.repository.setConversionService(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("conversionService must not be null");
}
@Test
public void createSessionDefaultMaxInactiveInterval() throws Exception {
public void createSessionDefaultMaxInactiveInterval() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository
.createSession();
@@ -291,7 +257,7 @@ public class JdbcOperationsSessionRepositoryTests {
}
@Test
public void createSessionCustomMaxInactiveInterval() throws Exception {
public void createSessionCustomMaxInactiveInterval() {
int interval = 1;
this.repository.setDefaultMaxInactiveInterval(interval);
@@ -314,11 +280,11 @@ public class JdbcOperationsSessionRepositoryTests {
assertPropagationRequiresNew();
verify(this.jdbcOperations, times(1)).update(startsWith("INSERT"),
isA(PreparedStatementSetter.class));
verifyNoMoreInteractions(this.jdbcOperations);
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveNewWithAttributes() {
public void saveNewWithSingleAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository
.createSession();
session.setAttribute("testName", "testValue");
@@ -327,15 +293,37 @@ public class JdbcOperationsSessionRepositoryTests {
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations, times(1)).update(startsWith("INSERT"),
verify(this.jdbcOperations, times(1)).update(
startsWith("INSERT INTO SPRING_SESSION("),
isA(PreparedStatementSetter.class));
verify(this.jdbcOperations, times(1)).batchUpdate(
and(startsWith("INSERT"), contains("ATTRIBUTE_BYTES")),
isA(BatchPreparedStatementSetter.class));
verify(this.jdbcOperations, times(1)).update(
startsWith("INSERT INTO SPRING_SESSION_ATTRIBUTES("),
isA(PreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveUpdatedAttributes() {
public void saveNewWithMultipleAttributes() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository
.createSession();
session.setAttribute("testName1", "testValue1");
session.setAttribute("testName2", "testValue2");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations, times(1)).update(
startsWith("INSERT INTO SPRING_SESSION("),
isA(PreparedStatementSetter.class));
verify(this.jdbcOperations, times(1)).batchUpdate(
startsWith("INSERT INTO SPRING_SESSION_ATTRIBUTES("),
isA(BatchPreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveUpdatedAddSingleAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.setAttribute("testName", "testValue");
@@ -345,8 +333,102 @@ public class JdbcOperationsSessionRepositoryTests {
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations, times(1)).update(
and(startsWith("UPDATE"), contains("ATTRIBUTE_BYTES")),
startsWith("INSERT INTO SPRING_SESSION_ATTRIBUTES("),
isA(PreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveUpdatedAddMultipleAttributes() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.setAttribute("testName1", "testValue1");
session.setAttribute("testName2", "testValue2");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations, times(1)).batchUpdate(
startsWith("INSERT INTO SPRING_SESSION_ATTRIBUTES("),
isA(BatchPreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveUpdatedModifySingleAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.setAttribute("testName", "testValue");
session.clearChangeFlags();
session.setAttribute("testName", "testValue");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations, times(1)).update(
startsWith("UPDATE SPRING_SESSION_ATTRIBUTES SET"),
isA(PreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveUpdatedModifyMultipleAttributes() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.setAttribute("testName1", "testValue1");
session.setAttribute("testName2", "testValue2");
session.clearChangeFlags();
session.setAttribute("testName1", "testValue1");
session.setAttribute("testName2", "testValue2");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations, times(1)).batchUpdate(
startsWith("UPDATE SPRING_SESSION_ATTRIBUTES SET"),
isA(BatchPreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveUpdatedRemoveSingleAttribute() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.setAttribute("testName", "testValue");
session.clearChangeFlags();
session.removeAttribute("testName");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations, times(1)).update(
startsWith("DELETE FROM SPRING_SESSION_ATTRIBUTES WHERE"),
isA(PreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test
public void saveUpdatedRemoveMultipleAttributes() {
JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession("primaryKey",
new MapSession());
session.setAttribute("testName1", "testValue1");
session.setAttribute("testName2", "testValue2");
session.clearChangeFlags();
session.removeAttribute("testName1");
session.removeAttribute("testName2");
this.repository.save(session);
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations, times(1)).batchUpdate(
startsWith("DELETE FROM SPRING_SESSION_ATTRIBUTES WHERE"),
isA(BatchPreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test
@@ -360,8 +442,9 @@ public class JdbcOperationsSessionRepositoryTests {
assertThat(session.isNew()).isFalse();
assertPropagationRequiresNew();
verify(this.jdbcOperations, times(1)).update(
and(startsWith("UPDATE"), contains("LAST_ACCESS_TIME")),
startsWith("UPDATE SPRING_SESSION SET"),
isA(PreparedStatementSetter.class));
verifyZeroInteractions(this.jdbcOperations);
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
@@ -19,9 +19,7 @@ package org.springframework.session.jdbc.config.annotation.web.http;
import javax.sql.DataSource;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -39,6 +37,7 @@ import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.transaction.PlatformTransactionManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
/**
@@ -56,9 +55,6 @@ public class JdbcHttpSessionConfigurationTests {
private static final String CLEANUP_CRON_EXPRESSION = "0 0 * * * *";
@Rule
public final ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@After
@@ -70,11 +66,9 @@ public class JdbcHttpSessionConfigurationTests {
@Test
public void noDataSourceConfiguration() {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage(
"expected at least 1 bean which qualifies as autowire candidate");
registerAndRefresh(NoDataSourceConfiguration.class);
assertThatThrownBy(() -> registerAndRefresh(NoDataSourceConfiguration.class))
.isInstanceOf(BeanCreationException.class).hasMessageContaining(
"expected at least 1 bean which qualifies as autowire candidate");
}
@Test
@@ -230,11 +224,10 @@ public class JdbcHttpSessionConfigurationTests {
@Test
public void multipleDataSourceConfiguration() {
this.thrown.expect(BeanCreationException.class);
this.thrown.expectMessage("expected single matching bean but found 2");
registerAndRefresh(DataSourceConfiguration.class,
MultipleDataSourceConfiguration.class);
assertThatThrownBy(() -> registerAndRefresh(DataSourceConfiguration.class,
MultipleDataSourceConfiguration.class))
.isInstanceOf(BeanCreationException.class)
.hasMessageContaining("expected single matching bean but found 2");
}
@Test